On wasm32
, half
operation results aren't correctly rounded between each operation · Issue #96437 · llvm/llvm-project (original) (raw)
The following IR (compiler explorer):
target triple = "wasm32-unknown-wasi"
define half @f(half %x) { start: %y = fmul half %x, 0xH4000 ; 0xH4000 == 2.0 %z = fdiv half %y, 0xH4000 ; 0xH4000 == 2.0 ret half %z }
define half @callf() {
%res = call half @f(half 0xH7BFF) ; 0xH7BFF = maximum finite f16
ret half %res
}
Is compiled into the following WASM:
f: # @f local.get 0 call __truncsfhf2 call __extendhfsf2 local.tee 0 local.get 0 f32.add f32.const 0x1p-1 f32.mul end_function callf: # @callf f32.const 0x1.ffcp15 call f end_function
callf
should return positive infinity (0xH7C00
), but on WASM it will return 0xH7BFF
due to the extra range of the f32
used to store the intermediate result.
This Rust program, when compiled with rustc 1.81.0-nightly (3cb521a43 2024-06-22)
with rustc --target wasm32-wasip1 code.rs
and run with wasmtime
, demonstrates the issue.
#![feature(f16)]
fn f(x: f16) -> f16 { x * 2.0 / 2.0 }
fn main() { assert_eq!(f(f16::MAX), 1.0 / 0.0); }
The assertion should succeed, but on WASM it fails.