-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Redundant checks in floating point to integer casts on WASM #73591
Copy link
Copy link
Closed
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.Category: This is a bug.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.O-wasmTarget: WASM (WebAssembly), http://webassembly.org/Target: WASM (WebAssembly), http://webassembly.org/
Metadata
Metadata
Assignees
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.Category: This is a bug.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.O-wasmTarget: WASM (WebAssembly), http://webassembly.org/Target: WASM (WebAssembly), http://webassembly.org/
Type
Fields
Give feedbackNo fields configured for issues without a type.
If you compile the following Rust code to WASM:
it compiles to the following with Rust 1.45:
example::cast: block local.get 0 f64.const 0x1p32 f64.lt local.get 0 f64.const 0x0p0 f64.ge i32.and i32.eqz br_if 0 local.get 0 i32.trunc_f64_u return end_block i32.const 0 end_functionThe same happens in Rust <1.45 if you use
as _. In both cases the following LLVM IR is emitted:fptoui is explicitly defined to be UB if an out of range value is provided.
However it seems like the WASM backend in LLVM ignores that and emits additional bounds checks.
Additionally this gets even worse in Rust 1.45 if you use
as _instead:example::cast: local.get 0 f64.const 0x1.fep7 f64.gt local.set 1 block block local.get 0 f64.const 0x0p0 local.get 0 f64.const 0x0p0 f64.gt f64.select local.tee 0 f64.const 0x1p32 f64.lt local.get 0 f64.const 0x0p0 f64.ge i32.and i32.eqz br_if 0 local.get 0 i32.trunc_f64_u local.set 2 br 1 end_block i32.const 0 local.set 2 end_block i32.const -1 local.get 2 local.get 1 i32.select end_functionThis means that in the end in the WASM VM will do 3 range checks (the one emitted by rust, the one emitted by the llvm backend, and the one it needs to do to possibly trap).
Additionally Rust's saturating checks don't play well with WASM's
nontrapping-fptointtarget-feature as there's still redundant checks:example::cast: i64.const 9223372036854775807 local.get 0 f32.const -0x1p63 local.get 0 f32.const -0x1p63 f32.gt f32.select i64.trunc_sat_f32_s local.get 0 f32.const 0x1.fffffep62 f32.gt i64.select i64.const 0 local.get 0 local.get 0 f32.eq i64.select end_function