From f0a2110b2ae1c83c3009ab42e6d1cb4d265b5d06 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 19 Aug 2026 01:09:47 -0700 Subject: [PATCH] [wasm2js] Support nontrapping float-to-int conversions directly in JS Now that 64-bit `trunc_sat` instructions are supported directly in `I64ToI32Lowering` (#9017), and 32-bit `trunc_sat` instructions are handled directly in `wasm2js` (`~~expr` and `~~expr >>> 0`), we no longer need to run `llvm-nontrapping-fptoint-lowering` when `--emscripten` is passed. In `wasm2js`, trapping float-to-int operations (`i32.trunc_*` and `i64.trunc_*`) are already lowered to non-trapping JS conversions (`~~expr` and float arithmetic in `I64ToI32Lowering`), which do not trap on out-of-range values or NaN/Infinity (matching C/C++ UB semantics rather than strict Wasm trapping semantics). Removing `llvm-nontrapping-fptoint-lowering` extends that same direct approach to `trunc_sat` instructions under `--emscripten`, eliminating branching overhead and reducing code size. --- src/passes/LLVMNontrappingFPToIntLowering.cpp | 4 + src/wasm2js.h | 3 - .../conversions-emscripten-modified.2asm.js | 160 ++++++------------ ...onversions-emscripten-modified.2asm.js.opt | 66 ++------ 4 files changed, 64 insertions(+), 169 deletions(-) diff --git a/src/passes/LLVMNontrappingFPToIntLowering.cpp b/src/passes/LLVMNontrappingFPToIntLowering.cpp index 382d4155b36..e7653135f08 100644 --- a/src/passes/LLVMNontrappingFPToIntLowering.cpp +++ b/src/passes/LLVMNontrappingFPToIntLowering.cpp @@ -4,6 +4,10 @@ #include #include +// Note: This pass is no longer used either in emscripten, or internally by any +// other part of binaryen. Unless there are other uses that show up we may +// consider this pass for removal. + // By default LLVM emits nontrapping float-to-int instructions to implement its // fptoui/fptosi conversion instructions. This pass replaces these instructions // with code sequences which also implement LLVM's fptoui/fptosi, but which are diff --git a/src/wasm2js.h b/src/wasm2js.h index 11b6a3d1417..9f912414ff1 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -360,9 +360,6 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) { // First, do the lowering to a JS-friendly subset. { PassRunner runner(wasm, options); - if (flags.emscripten) { - runner.add("llvm-nontrapping-fptoint-lowering"); - } // TODO: only legalize if necessary - emscripten would already do so, and // likely other toolchains. but spec test suite needs that. runner.add("legalize-js-interface"); diff --git a/test/wasm2js/conversions-emscripten-modified.2asm.js b/test/wasm2js/conversions-emscripten-modified.2asm.js index 0bb42c14220..4c7695454c8 100644 --- a/test/wasm2js/conversions-emscripten-modified.2asm.js +++ b/test/wasm2js/conversions-emscripten-modified.2asm.js @@ -17,166 +17,102 @@ function asmFunc(imports) { ; function $0(x) { x = Math_fround(x); - var $1_1 = Math_fround(0), $8 = 0; - $1_1 = x; - if (Math_fround(Math_abs($1_1)) < Math_fround(2147483648.0)) { - $8 = ~~$1_1 - } else { - $8 = -2147483648 - } - return $8 | 0; + return ~~x | 0; } function $1(x) { x = Math_fround(x); - var $1_1 = Math_fround(0), $10 = 0; - $1_1 = x; - if ($1_1 < Math_fround(4294967296.0) & $1_1 >= Math_fround(0.0) | 0) { - $10 = ~~$1_1 >>> 0 - } else { - $10 = 0 - } - return $10 | 0; + return ~~x >>> 0 | 0; } function $2(x) { x = +x; - var $1_1 = 0.0, $8 = 0; - $1_1 = x; - if (Math_abs($1_1) < 2147483647.0) { - $8 = ~~$1_1 - } else { - $8 = -2147483648 - } - return $8 | 0; + return ~~x | 0; } function $3(x) { x = +x; - var $1_1 = 0.0, $10 = 0; - $1_1 = x; - if ($1_1 < 4294967295.0 & $1_1 >= 0.0 | 0) { - $10 = ~~$1_1 >>> 0 - } else { - $10 = 0 - } - return $10 | 0; + return ~~x >>> 0 | 0; } function $4(x) { x = Math_fround(x); - var i64toi32_i32$0 = Math_fround(0), i64toi32_i32$1 = 0, $1_1 = Math_fround(0), $6_1 = 0, $7_1 = 0, $8 = 0, $8$hi = 0; - $1_1 = x; - if (Math_fround(Math_abs($1_1)) < Math_fround(9223372036854775808.0)) { - i64toi32_i32$0 = $1_1; - if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { - if (i64toi32_i32$0 > Math_fround(0.0)) { - $6_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0 - } else { - $6_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0 - } - $7_1 = $6_1; + var i64toi32_i32$0 = Math_fround(0), $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { + if (i64toi32_i32$0 > Math_fround(0.0)) { + $4_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0 } else { - $7_1 = 0 + $4_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0 } - i64toi32_i32$1 = $7_1; - $8 = ~~i64toi32_i32$0 >>> 0; - $8$hi = i64toi32_i32$1; + $5_1 = $4_1; } else { - i64toi32_i32$1 = -2147483648; - $8 = 0; - $8$hi = i64toi32_i32$1; + $5_1 = 0 } - i64toi32_i32$1 = $8$hi; + i64toi32_i32$1 = $5_1; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; i64toi32_i32$HIGH_BITS = i64toi32_i32$1; - return $8 | 0; + return i64toi32_i32$2 | 0; } function $5(x) { x = Math_fround(x); - var i64toi32_i32$0 = Math_fround(0), i64toi32_i32$1 = 0, $1_1 = Math_fround(0), $6_1 = 0, $7_1 = 0, $10 = 0, $10$hi = 0; - $1_1 = x; - if ($1_1 < Math_fround(18446744073709551615.0) & $1_1 >= Math_fround(0.0) | 0) { - i64toi32_i32$0 = $1_1; - if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { - if (i64toi32_i32$0 > Math_fround(0.0)) { - $6_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0 - } else { - $6_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0 - } - $7_1 = $6_1; + var i64toi32_i32$0 = Math_fround(0), $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_fround(Math_abs(i64toi32_i32$0)) >= Math_fround(1.0)) { + if (i64toi32_i32$0 > Math_fround(0.0)) { + $4_1 = ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround(i64toi32_i32$0 / Math_fround(4294967296.0)))), Math_fround(Math_fround(4294967296.0) - Math_fround(1.0)))) >>> 0 } else { - $7_1 = 0 + $4_1 = ~~Math_fround(Math_ceil(Math_fround(Math_fround(i64toi32_i32$0 - Math_fround(~~i64toi32_i32$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0 } - i64toi32_i32$1 = $7_1; - $10 = ~~i64toi32_i32$0 >>> 0; - $10$hi = i64toi32_i32$1; + $5_1 = $4_1; } else { - i64toi32_i32$1 = 0; - $10 = 0; - $10$hi = i64toi32_i32$1; + $5_1 = 0 } - i64toi32_i32$1 = $10$hi; + i64toi32_i32$1 = $5_1; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; i64toi32_i32$HIGH_BITS = i64toi32_i32$1; - return $10 | 0; + return i64toi32_i32$2 | 0; } function $6(x) { x = +x; - var i64toi32_i32$0 = 0.0, i64toi32_i32$1 = 0, $1_1 = 0.0, $6_1 = 0, $7_1 = 0, $8 = 0, $8$hi = 0; - $1_1 = x; - if (Math_abs($1_1) < 9223372036854775808.0) { - i64toi32_i32$0 = $1_1; - if (Math_abs(i64toi32_i32$0) >= 1.0) { - if (i64toi32_i32$0 > 0.0) { - $6_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0 - } else { - $6_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0 - } - $7_1 = $6_1; + var i64toi32_i32$0 = 0.0, $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_abs(i64toi32_i32$0) >= 1.0) { + if (i64toi32_i32$0 > 0.0) { + $4_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0 } else { - $7_1 = 0 + $4_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0 } - i64toi32_i32$1 = $7_1; - $8 = ~~i64toi32_i32$0 >>> 0; - $8$hi = i64toi32_i32$1; + $5_1 = $4_1; } else { - i64toi32_i32$1 = -2147483648; - $8 = 0; - $8$hi = i64toi32_i32$1; + $5_1 = 0 } - i64toi32_i32$1 = $8$hi; + i64toi32_i32$1 = $5_1; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; i64toi32_i32$HIGH_BITS = i64toi32_i32$1; - return $8 | 0; + return i64toi32_i32$2 | 0; } function $7(x) { x = +x; - var i64toi32_i32$0 = 0.0, i64toi32_i32$1 = 0, $1_1 = 0.0, $6_1 = 0, $7_1 = 0, $10 = 0, $10$hi = 0; - $1_1 = x; - if ($1_1 < 18446744073709551615.0 & $1_1 >= 0.0 | 0) { - i64toi32_i32$0 = $1_1; - if (Math_abs(i64toi32_i32$0) >= 1.0) { - if (i64toi32_i32$0 > 0.0) { - $6_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0 - } else { - $6_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0 - } - $7_1 = $6_1; + var i64toi32_i32$0 = 0.0, $4_1 = 0, $5_1 = 0, i64toi32_i32$1 = 0, i64toi32_i32$2 = 0; + i64toi32_i32$0 = x; + if (Math_abs(i64toi32_i32$0) >= 1.0) { + if (i64toi32_i32$0 > 0.0) { + $4_1 = ~~Math_min(Math_floor(i64toi32_i32$0 / 4294967296.0), 4294967296.0 - 1.0) >>> 0 } else { - $7_1 = 0 + $4_1 = ~~Math_ceil((i64toi32_i32$0 - +(~~i64toi32_i32$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0 } - i64toi32_i32$1 = $7_1; - $10 = ~~i64toi32_i32$0 >>> 0; - $10$hi = i64toi32_i32$1; + $5_1 = $4_1; } else { - i64toi32_i32$1 = 0; - $10 = 0; - $10$hi = i64toi32_i32$1; + $5_1 = 0 } - i64toi32_i32$1 = $10$hi; + i64toi32_i32$1 = $5_1; + i64toi32_i32$2 = ~~i64toi32_i32$0 >>> 0; i64toi32_i32$HIGH_BITS = i64toi32_i32$1; - return $10 | 0; + return i64toi32_i32$2 | 0; } function legalstub$4($0_1) { diff --git a/test/wasm2js/conversions-emscripten-modified.2asm.js.opt b/test/wasm2js/conversions-emscripten-modified.2asm.js.opt index d29f8f21f2e..860a022df46 100644 --- a/test/wasm2js/conversions-emscripten-modified.2asm.js.opt +++ b/test/wasm2js/conversions-emscripten-modified.2asm.js.opt @@ -17,50 +17,29 @@ function asmFunc(imports) { ; function $0($0_1) { $0_1 = Math_fround($0_1); - return (Math_fround(Math_abs($0_1)) < Math_fround(2147483648.0) ? ~~$0_1 : -2147483648) | 0; + return ~~$0_1 | 0; } function $1($0_1) { $0_1 = Math_fround($0_1); - return ($0_1 < Math_fround(4294967296.0) & $0_1 >= Math_fround(0.0) ? ~~$0_1 >>> 0 : 0) | 0; + return ~~$0_1 >>> 0 | 0; } function $2($0_1) { $0_1 = +$0_1; - return (Math_abs($0_1) < 2147483647.0 ? ~~$0_1 : -2147483648) | 0; + return ~~$0_1 | 0; } function $3($0_1) { $0_1 = +$0_1; - return ($0_1 < 4294967295.0 & $0_1 >= 0.0 ? ~~$0_1 >>> 0 : 0) | 0; + return ~~$0_1 >>> 0 | 0; } function legalstub$4($0_1) { var $1_1 = 0, $2_1 = 0; - if (Math_fround(Math_abs($0_1)) < Math_fround(9223372036854775808.0)) { - $2_1 = ~~$0_1 >>> 0; - if (Math_fround(Math_abs($0_1)) >= Math_fround(1.0)) { - $1_1 = ~~($0_1 > Math_fround(0.0) ? Math_fround(Math_min(Math_fround(Math_floor(Math_fround($0_1 * Math_fround(2.3283064365386963e-10)))), Math_fround(4294967296.0))) : Math_fround(Math_ceil(Math_fround(Math_fround($0_1 - Math_fround(~~$0_1 >>> 0 >>> 0)) * Math_fround(2.3283064365386963e-10))))) >>> 0 - } else { - $1_1 = 0 - } - } else { - $1_1 = -2147483648 - } - i64toi32_i32$HIGH_BITS = $1_1; - setTempRet0(i64toi32_i32$HIGH_BITS | 0); - return $2_1; - } - - function legalstub$5($0_1) { - var $1_1 = 0, $2_1 = 0; - if ($0_1 < Math_fround(18446744073709551615.0) & $0_1 >= Math_fround(0.0)) { - $2_1 = ~~$0_1 >>> 0; - if (Math_fround(Math_abs($0_1)) >= Math_fround(1.0)) { - $1_1 = ~~($0_1 > Math_fround(0.0) ? Math_fround(Math_min(Math_fround(Math_floor(Math_fround($0_1 * Math_fround(2.3283064365386963e-10)))), Math_fround(4294967296.0))) : Math_fround(Math_ceil(Math_fround(Math_fround($0_1 - Math_fround(~~$0_1 >>> 0 >>> 0)) * Math_fround(2.3283064365386963e-10))))) >>> 0 - } else { - $1_1 = 0 - } + $2_1 = ~~$0_1 >>> 0; + if (Math_fround(Math_abs($0_1)) >= Math_fround(1.0)) { + $1_1 = ~~($0_1 > Math_fround(0.0) ? Math_fround(Math_min(Math_fround(Math_floor(Math_fround($0_1 * Math_fround(2.3283064365386963e-10)))), Math_fround(4294967296.0))) : Math_fround(Math_ceil(Math_fround(Math_fround($0_1 - Math_fround(~~$0_1 >>> 0 >>> 0)) * Math_fround(2.3283064365386963e-10))))) >>> 0 } else { $1_1 = 0 } @@ -71,30 +50,9 @@ function asmFunc(imports) { function legalstub$6($0_1) { var $1_1 = 0, $2_1 = 0; - if (Math_abs($0_1) < 9223372036854775808.0) { - $2_1 = ~~$0_1 >>> 0; - if (Math_abs($0_1) >= 1.0) { - $1_1 = ~~($0_1 > 0.0 ? Math_min(Math_floor($0_1 * 2.3283064365386963e-10), 4294967295.0) : Math_ceil(($0_1 - +(~~$0_1 >>> 0 >>> 0)) * 2.3283064365386963e-10)) >>> 0 - } else { - $1_1 = 0 - } - } else { - $1_1 = -2147483648 - } - i64toi32_i32$HIGH_BITS = $1_1; - setTempRet0(i64toi32_i32$HIGH_BITS | 0); - return $2_1; - } - - function legalstub$7($0_1) { - var $1_1 = 0, $2_1 = 0; - if ($0_1 < 18446744073709551615.0 & $0_1 >= 0.0) { - $2_1 = ~~$0_1 >>> 0; - if (Math_abs($0_1) >= 1.0) { - $1_1 = ~~($0_1 > 0.0 ? Math_min(Math_floor($0_1 * 2.3283064365386963e-10), 4294967295.0) : Math_ceil(($0_1 - +(~~$0_1 >>> 0 >>> 0)) * 2.3283064365386963e-10)) >>> 0 - } else { - $1_1 = 0 - } + $2_1 = ~~$0_1 >>> 0; + if (Math_abs($0_1) >= 1.0) { + $1_1 = ~~($0_1 > 0.0 ? Math_min(Math_floor($0_1 * 2.3283064365386963e-10), 4294967295.0) : Math_ceil(($0_1 - +(~~$0_1 >>> 0 >>> 0)) * 2.3283064365386963e-10)) >>> 0 } else { $1_1 = 0 } @@ -111,9 +69,9 @@ function asmFunc(imports) { "i32_trunc_sat_f64_s": $2, "i32_trunc_sat_f64_u": $3, "i64_trunc_sat_f32_s": legalstub$4, - "i64_trunc_sat_f32_u": legalstub$5, + "i64_trunc_sat_f32_u": legalstub$4, "i64_trunc_sat_f64_s": legalstub$6, - "i64_trunc_sat_f64_u": legalstub$7 + "i64_trunc_sat_f64_u": legalstub$6 }; }