llvm / llvm/llvm-project

[InstCombine] Missed optimization for constant-LHS fsub of integer-to-float cast

Open
#213,517 1 comment 0 reactions 1 assignee Claimed by @AsparticGuan View on GitHub
llvm:instcombine missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

### Description

InstCombine folds floating-point binary operations whose operands come from integer-to-floating-point casts, including the form `(fp_binop (s|u)itofp(X), C)`. It currently misses the constant-left-hand-side subtraction form:

```llvm
fsub C, (s|u)itofp(X)
```

When the conversions are exact and the corresponding integer subtraction cannot overflow, this can be folded to:

```llvm
(s|u)itofp(C_int - X)
```

### Real-world example

This pattern occurs in FFmpeg's AMR-WB decoder:

https://github.com/FFmpeg/FFmpeg/blob/a7e72069f15efbef1e25b25d35c4e0511b43262e/libavcodec/amrwbdec.c#L915-L917

```c
for (i = 0; i < AMRWB_SFR_SIZE_16k; i++)
hb_exc[i] = 32768.0 - (uint16_t) av_lfg_get(&ctx->prng);
```

The relevant optimized IR contains:

```llvm
%x = and i32 %x_in, 65535
%xf = uitofp i32 %x to float
%r = fsub nsz float 32768.0, %xf
```

### Reproducer

Run with `opt -passes=instcombine -S`:

```llvm
define float @test(i32 %x_in) {
%x = and i32 %x_in, 65535
%xf = uitofp i32 %x to float
%r = fsub nsz float 32768.0, %xf
ret float %r
}
```

### Current result

```llvm
%x = and i32 %x_in, 65535
%xf = uitofp nneg i32 %x to float
%r = fsub nsz float 32768.0, %xf
```

### Expected result

```llvm
%x = and i32 %x_in, 65535
%sub = sub nsw i32 32768, %x
%r = sitofp i32 %sub to float
```

The fold must be rejected when the floating-point constant is not exactly representable as the required integer or when the integer subtraction may overflow.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.