Repository navigation
Conversation
C floating-point casts have undefined behavior outside the destination integer range, even if lowering eventually uses a saturating instruction. LLVM can remove the round-trip check used by the fast conversion helpers and accept an out-of-range input. Use Wasm saturating conversion intrinsics instead. Retain the established 64-bit restriction that prevents saturated integers rounding back to an overflowing double. Add dynamic integer-conversion and unsigned-shift regressions.
lavenzg
reviewed
Oct 29, 2026
lavenzg
requested changes
Oct 29, 2026
The saturating conversion builtins require __wasm_nontrapping_fptoint__. Using them unconditionally prevents compilation for Wasm targets with that feature disabled. Gate the builtins on the target feature and range-check C casts on other Wasm targets. Ordered comparisons reject NaN and infinities, while the 32-bit bounds preserve truncation for fractional inputs whose integer parts fit. Exclusive 64-bit upper bounds avoid rounding INT64_MAX and UINT64_MAX into accepted overflowing doubles. The guarded path therefore does not need the saturated-result mitigation. Add dynamic helper regressions for non-integers, overflow, and fractional 32-bit endpoint inputs. Verify the actual header with Clang 24 in C and C++ at O0 and O3, with the Wasm feature enabled and disabled: all eight configurations pass 400,424 conversion checks each. Feature-disabled assembly contains no saturating conversions. All seven focused native conversion unit tests pass.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Wasm fast conversion helpers currently use C casts and then round-trip the integer back to a double to check the range. The casts are undefined for out-of-range inputs, so LLVM can optimize away that check before Wasm instruction selection. This can miscompile dynamic unsigned shifts and other callers relying on range rejection.
Use the defined Wasm saturating conversion intrinsics when
__wasm_nontrapping_fptoint__is available. The 64-bit intrinsic helpers retain the existing mitigation used on other architectures: a saturated integer can otherwise round back to the overflowing double.For Wasm targets without that feature, guard every C cast with ordered range comparisons. These reject NaN, infinities, and overflow while preserving the 32-bit helpers' truncation contract for fractional inputs near the integer endpoints. Exclusive 64-bit upper bounds avoid rounding
INT64_MAXandUINT64_MAXup into accepted overflowing doubles, so the guarded path does not need saturated-result masking. Comments explain these constraints. Native-target implementations are unchanged.Test Plan
--target=wasm32 -ffreestanding, in C11 and C++14, at both-O0and-O3, with explicit-mnontrapping-fptointand-mno-nontrapping-fptoint. Executed all eight configurations in Node's WebAssembly runtime. Each passed 400,424 conversion checks over 100,106 inputs: integer boundaries and adjacent doubles, fractional endpoints, infinities, NaN, subnormals, and 100,000 deterministic generated IEEE-754 values. Checks cover acceptance, returned values, valid 32-bit truncation, and absence of 64-bit false positives.unittests/Support/test_sh_fp_trunc.cppwith the repository's GoogleTest sources at-O3on x86-64. All seven tests passed, including the new dynamic non-integer, overflow, and fractional endpoint regressions.-mno-nontrapping-fptointfailed because the builtins requirenontrapping-fptoint.-2147483649as representable byint32_t.ConversionsTest.cppand the optimized/unoptimized Static Hermes unsigned-shift regression remain in the PR. The fullHermesSupportTestsand Static Hermes engine test targets have not been run on this extracted branch.Minimal reproducer for the undefined round-trip optimization:
After optimized Wasm compilation,
accepts(-2147483649.0)must return zero, with or withoutnontrapping-fptoint.