[llvm] [WebAssembly] Select relaxed_trunc for vector fptosi/fptoui with +relaxed-simd (PR #214148)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 01:06:49 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-webassembly
Author: Gauarv Chaudhary (ANAMASGARD)
<details>
<summary>Changes</summary>
Fixes #<!-- -->211273
When `+relaxed-simd` is enabled, plain vector `fptosi`/`fptoui` from `<4 x float>` to `<4 x i32>` is still lowered to `i32x4.trunc_sat_f32x4_{s,u}`. The relaxed SIMD instructions already exist in the backend, but they were only wired to the
WebAssembly-specific `llvm.wasm.relaxed.trunc.*` intrinsics—not to generic `fptosi`/`fptoui` IR.
This matters for frontends like LDC that emit ordinary `fptosi` for SIMD casts (e.g. `_mm_cvttps_epi32`-style code). With `+simd128,+relaxed-simd`, we should prefer `i32x4.relaxed_trunc_f32x4_{s,u}`, which typically lowers more efficiently
on native SIMD hardware.
The fix adds two TableGen selection patterns in `WebAssemblyInstrSIMD.td`, gated on `HasRelaxedSIMD` with `AddedComplexity = 1`, so they win over the existing `fp_to_sint`/`fp_to_uint` → `trunc_sat` patterns when relaxed SIMD is available.
This does not require fast-math: for representable inputs, relaxed truncation matches LLVM semantics; for NaN/out-of-range inputs, `fptosi`/`fptoui` already produce poison, so the backend is not required to preserve `trunc_sat`'s
saturating behavior.
Explicit saturating conversions (`llvm.fptosi.sat` / `fp_to_sint_sat`) and `+simd128`-only targets are unchanged.
## Test plan
- [x] `llvm-lit llvm/test/CodeGen/WebAssembly/simd-relaxed-fptoint.ll`
- [x] `llvm-lit llvm/test/CodeGen/WebAssembly/simd-conversions.ll`
- [x] `llvm-lit llvm/test/CodeGen/WebAssembly/simd-intrinsics.ll`
---
Full diff: https://github.com/llvm/llvm-project/pull/214148.diff
2 Files Affected:
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td (+10)
- (added) llvm/test/CodeGen/WebAssembly/simd-relaxed-fptoint.ll (+29)
``````````diff
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
index a93fb1ccc3dd9..bf4b9e643a023 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
@@ -1756,6 +1756,16 @@ defm "" : RelaxedConvert<I32x4, F64x2, int_wasm_relaxed_trunc_signed_zero,
defm "" : RelaxedConvert<I32x4, F64x2, int_wasm_relaxed_trunc_unsigned_zero,
"relaxed_trunc_f64x2_u_zero", 0x104>;
+// Prefer relaxed truncation for generic fp_to_sint/fp_to_uint when relaxed
+// SIMD is available. fptosi/fptoui produce poison for NaN or unrepresentable
+// inputs, while relaxed truncation agrees with them for representable inputs.
+let Predicates = [HasRelaxedSIMD], AddedComplexity = 1 in {
+ def : Pat<(v4i32 (fp_to_sint (v4f32 V128:$vec))),
+ (int_wasm_relaxed_trunc_signed_I32x4 $vec)>;
+ def : Pat<(v4i32 (fp_to_uint (v4f32 V128:$vec))),
+ (int_wasm_relaxed_trunc_unsigned_I32x4 $vec)>;
+}
+
//===----------------------------------------------------------------------===//
// Relaxed (Negative) Multiply-Add (madd/nmadd)
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/WebAssembly/simd-relaxed-fptoint.ll b/llvm/test/CodeGen/WebAssembly/simd-relaxed-fptoint.ll
new file mode 100644
index 0000000000000..da59e1cc05303
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/simd-relaxed-fptoint.ll
@@ -0,0 +1,29 @@
+; RUN: llc < %s -verify-machineinstrs -mcpu=mvp -mattr=+simd128 \
+; RUN: | FileCheck %s --check-prefix=NO-RELAXED
+; RUN: llc < %s -verify-machineinstrs -mcpu=mvp -mattr=+simd128,+relaxed-simd \
+; RUN: | FileCheck %s --check-prefix=RELAXED
+
+; Test that generic vector floating-point-to-integer conversions use relaxed
+; SIMD instructions when relaxed SIMD is enabled.
+
+target triple = "wasm32-unknown-unknown"
+
+define <4 x i32> @fptosi_v4f32_v4i32(<4 x float> %a) {
+; NO-RELAXED-LABEL: fptosi_v4f32_v4i32:
+; NO-RELAXED: i32x4.trunc_sat_f32x4_s
+;
+; RELAXED-LABEL: fptosi_v4f32_v4i32:
+; RELAXED: i32x4.relaxed_trunc_f32x4_s
+ %r = fptosi <4 x float> %a to <4 x i32>
+ ret <4 x i32> %r
+}
+
+define <4 x i32> @fptoui_v4f32_v4i32(<4 x float> %a) {
+; NO-RELAXED-LABEL: fptoui_v4f32_v4i32:
+; NO-RELAXED: i32x4.trunc_sat_f32x4_u
+;
+; RELAXED-LABEL: fptoui_v4f32_v4i32:
+; RELAXED: i32x4.relaxed_trunc_f32x4_u
+ %r = fptoui <4 x float> %a to <4 x i32>
+ ret <4 x i32> %r
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/214148
More information about the llvm-commits
mailing list