LLVM miscompiles consecutive half
operations by using too much precision on several backends #97975
Description
Consider the following IR:
define half @f(half %a, half %b, half %c) {
%d = fadd half %a, %b
%e = fadd half %d, %c
ret half %e
}
On backends without native half
support, LLVM generally lowers half
by converting to float
, performing the desired operation, and then converting back to half
. For this to be a valid lowering, a conversion back to f16
must occur after each operation, otherwise the excess precision of float
will affect the result. For example 65504.0 + 65504.0 + -65504.0
equals infinity if each operation is done at half
precision, but will result in 65504.0
if the intermediate value is not rounded to a half
but instead kept as a float
. This excess runtime precision can lead to miscompilations similar to #89885.
However, it appears that on several backends LLVM will fail to round the intermediate result of consecutive half
operations, leading to these kind of bugs. I'm filing this as a single issue rather than a separate issue for each backend as I believe this is an issue with LLVM's default handling of half
operations rather than a problem in any specific backend (for instance, AFAIK the only backend-specific code LoongArch has for handling half
was added in #94456).
By inspecting the assembly LLVM emits, I've discovered that at least the following backends appear to be affected (in brackets are a specific target triple that I've checked):
- AVR (
avr-unknown-unknown
) - C-SKY (
csky-unknown-linux-gnuabiv2
) - Hexagon (
hexagon-unknown-linux-musl
) - LoongArch (
loongarch64-unknown-linux-gnu
): Fixed by [loongarch][DAG][FREEZE] Fix crash when FREEZE a half(f16) type on loongarch #107791 - M68k (
m68k-unknown-linux-gnu
) - MIPS (
mips64el-unknown-linux-gnuabi64
): Fixed by [MIPS] Use softPromoteHalf legalization for fp16 rather than PromoteFloat #110199 - MSP430 (
msp430-none-elf
) - PowerPC (
powerpc64le-unknown-linux-gnu
) - SPARC (
sparc64-unknown-linux-gnu
) - WASM (
wasm32-unknown-wasi
): Already reported in Onwasm32
,half
operation results aren't correctly rounded between each operation #96437 - Xtensa (
xtensa-none-elf
)
I also noticed that 32-bit ARM has this problem in LLVM 18 but not on the main
branch. Looking through the issue tracker, it seems it's likely that this was fixed by #80440.
Related to #97981.