[llvm] [WebAssembly] Select relaxed_trunc for vector fptosi/fptoui with +relaxed-simd (PR #214148)

Gauarv Chaudhary via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 01:05:37 PDT 2026


https://github.com/ANAMASGARD created https://github.com/llvm/llvm-project/pull/214148

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`

>From f385d6900f9e4354ae93fabedcd2637eac2000d5 Mon Sep 17 00:00:00 2001
From: Gaurav Chaudhary <chaudharygaurav2004 at gmail.com>
Date: Wed, 5 Aug 2026 13:33:51 +0530
Subject: [PATCH] [WebAssembly] Select relaxed_trunc for vector fptosi with
 +relaxed-simd When relaxed-simd is enabled, lower plain fptosi/fptoui from
 v4f32 to v4i32 using i32x4.relaxed_trunc_f32x4_{s,u} instead of trunc_sat.
 Explicit saturating conversions and simd128-only targets are unchanged. Fixes
 #211273

Signed-off-by: Gaurav Chaudhary <chaudharygaurav2004 at gmail.com>
---
 .../WebAssembly/WebAssemblyInstrSIMD.td       | 10 +++++++
 .../WebAssembly/simd-relaxed-fptoint.ll       | 29 +++++++++++++++++++
 2 files changed, 39 insertions(+)
 create mode 100644 llvm/test/CodeGen/WebAssembly/simd-relaxed-fptoint.ll

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
+}



More information about the llvm-commits mailing list