[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