Consider the following IR:
define half @to_half(i16 %bits) {
%f = bitcast i16 %bits to half
ret half %f
}
define i16 @from_half(half %f) {
%bits = bitcast half %f to i16
ret i16 %bits
}
As the only operation involved is a bitcast (in particular, there are no floating point type conversions in the LLVM IR), the values returned from to_half and from_half should be bit-for-bit identical to the value passed to them as their only argument (just a different type). However, several targets pass/return half as a float. On these targets, LLVM will use the default float conversion builtins (such as __gnu_h2f_ieee and __gnu_f2h_ieee) to convert between half and float. The issue is that these builtins silence signalling NaNs which changes the NaN payload, meaning that the roundtrip of half -> float -> half is not lossless and causes the generated ASM to violate the semantics of LLVM IR. This miscompilation is similar to #66803.
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):
As none of these target's ABI specifications (that I've been able to find) specify how half should be passed (nor does Clang support _Float16 on any of these targets), and given that these targets are a subset of those affected by #97975, I'm filing this as a single issue as the ABI has probably been selected as an automatic default by LLVM rather than a deliberate choice by the backends. Ultimately there are two possible solutions: either fix LLVM to codegen lossless conversions between half and float when needed for the ABI (one way to do this would be with a new pair of builtins that don't silence signalling NaNs), or change the ABIs to pass/return half without converting it to float (probably using the same ABI as i16, but some targets might have better options).
Related to #97975.
Consider the following IR:
As the only operation involved is a bitcast (in particular, there are no floating point type conversions in the LLVM IR), the values returned from
to_halfandfrom_halfshould be bit-for-bit identical to the value passed to them as their only argument (just a different type). However, several targets pass/returnhalfas afloat. On these targets, LLVM will use the default float conversion builtins (such as__gnu_h2f_ieeeand__gnu_f2h_ieee) to convert betweenhalfandfloat. The issue is that these builtins silence signalling NaNs which changes the NaN payload, meaning that the roundtrip ofhalf->float->halfis not lossless and causes the generated ASM to violate the semantics of LLVM IR. This miscompilation is similar to #66803.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):
csky-unknown-linux-gnuabiv2with-mcpu=ck860fv -mattr=+hard-float)hexagon-unknown-linux-musl): Fixed by [HEXAGON] Add support to lower "FREEZE a half(f16)" instruction on Hexagon and fix the isel-buildvector-v2f16.ll assertion #130977loongarch64-unknown-linux-gnuwith-mattr=+f): Fixed by [loongarch][DAG][FREEZE] Fix crash when FREEZE a half(f16) type on loongarch #107791mips64el-unknown-linux-gnuabi64): Fixed by [MIPS] Use softPromoteHalf legalization for fp16 rather than PromoteFloat #110199powerpc64le-unknown-linux-gnu): Fixed by [PowerPC] Changehalfto use soft promotion rather thanPromoteFloat#152632sparc64-unknown-linux-gnu): Fixed by [SPARC] Changehalfto use soft promotion rather thanPromoteFloat#152727wasm32-unknown-wasi): Already reported inwasm32queitenshalfsignalling NaNs in some situations when passing/returning them #96438, fixed by [WebAssembly] Changehalfto use soft promotion rather thanPromoteFloat#152833As none of these target's ABI specifications (that I've been able to find) specify how
halfshould be passed (nor does Clang support_Float16on any of these targets), and given that these targets are a subset of those affected by #97975, I'm filing this as a single issue as the ABI has probably been selected as an automatic default by LLVM rather than a deliberate choice by the backends. Ultimately there are two possible solutions: either fix LLVM to codegen lossless conversions betweenhalfandfloatwhen needed for the ABI (one way to do this would be with a new pair of builtins that don't silence signalling NaNs), or change the ABIs to pass/returnhalfwithout converting it tofloat(probably using the same ABI asi16, but some targets might have better options).Related to #97975.