-
Notifications
You must be signed in to change notification settings - Fork 12.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wasm32
queitens half
signalling NaNs in some situations when passing/returning them
#96438
Comments
wasm32
queitens half
signalling NaNs when passing/returning themwasm32
queitens half
signalling NaNs in some situations when passing/returning them
@llvm/issue-subscribers-backend-webassembly Author: None (beetrees)
The following IR ([compiler explorer](https://godbolt.org/z/6cP4Mq9dz)):
target triple = "wasm32-unknown-wasi"
define half @<!-- -->from_bits(i16 %x) {
%res = bitcast i16 %x to half
ret half %res
}
define i16 @<!-- -->to_bits(half %x) {
%res = bitcast half %x to i16
ret i16 %res
}
define i16 @<!-- -->roundtrip() {
%h = call half @<!-- -->from_bits(i16 64513) ; A bitpattern of a signalling NaN
%res = call i16 @<!-- -->to_bits(half %h)
ret i16 %res
} Is compiled into the following WASM: from_bits: # @<!-- -->from_bits
local.get 0
call __extendhfsf2
end_function
to_bits: # @<!-- -->to_bits
local.get 0
call __truncsfhf2
i32.const 65535
i32.and
end_function
roundtrip: # @<!-- -->roundtrip
i32.const 64513
call from_bits
call to_bits
end_function
This Rust program, when compiled with #![feature(f16)]
fn main() {
assert_eq!(f16::from_bits(0xfc01).to_bits(), 0xfc01);
} The assertion should succeed, but on WASM it fails. This solution to this is probably to either:
|
Quitting signaling NaNs is expected behavior, Wasm spec explicitly states that. That said, if the value is never represented as a Wasm f32, then it might be fine to not quiet it (until Wasm does add a f16 type, of course). |
At the LLVM IR level, signalling NaNs are only quietened when conversions are explicitly done between different float types (or when floating point arithmetic is done; as a side note, to allow more scope for optimisations LLVM IR doesn't guarantee that signalling NaNs are quietened, merely allows it). LLVM IR guarantees that the exact bitpattern of a float is preserved when passing/returning floats to and from functions; this is all stated in the LangRef. WASM itself has similar guarantees. For instance, the equivalent Rust program for fn main() {
assert_eq!(f32::from_bits(0xff80_0001).to_bits(), 0xff80_0001);
} does not fail the assertion when run on WASM, whereas the To put it a different way, this should not quieten signalling NaNs: define half @func1(i16 %x) {
%res = bitcast i16 %x to half
ret half %res
} Whereas this may quieten signalling NaNs: define float @func2(i16 %x) {
%f = bitcast i16 %x to half
%res = fpext half %f to float
ret float %res
} However,, both of the above functions result in the exact same WASM which quietens signalling NaNs (compiler explorer): func1: # @func1
local.get 0
call __extendhfsf2
end_function
func2: # @func2
local.get 0
call __extendhfsf2
end_function |
cc @brendandahl, this may be related to your recent work |
The following IR (compiler explorer):
Is compiled into the following WASM:
rountrip
should return64513
(0xfc01), as allfrom_bits
andto_bits
do is bitcast to and fromhalf
. However, on WASM it instead returns65025
(0xfe01), as__extendhfsf2
and__truncsfhf2
both quieten signalling NaNs.This Rust program, when compiled with
rustc 1.81.0-nightly (3cb521a43 2024-06-22)
withrustc --target wasm32-wasip1 code.rs
and run withwasmtime
, demonstrates the issue.The assertion should succeed, but on WASM it fails.
This solution to this is probably to either:
half
ABI to be passed and returned in the low bits of a WASMi32
, the same as a LLVMi16
. This would match the ABI ofhalf
in the__extendhfsf2
and__truncsfhf2
builtins. I noticed that the ABI for 16-bit floats is not specified in the WASM Basic C ABI document, and Clang doesn't support_Float16
on WASM either, so this might be possible with regards to backwards compatibility concerns.half
to and fromf32
losslessly with regards to NaN bits. This would mean either adding extra codegen around the relevant__extendhfsf2
and__truncsfhf2
calls to ensure that signalling NaNs don't get quietened, or adding new builtins that are the same as__extendhfsf2
and__truncsfhf2
but don't quieten signalling NaNs.The text was updated successfully, but these errors were encountered: