[llvm] [WebAssembly] Select lane stores for floating-point vectors (PR #219186)

Anutosh Bhat via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 04:32:53 PDT 2026


https://github.com/anutosh491 created https://github.com/llvm/llvm-project/pull/219186

This extends the existing integer vector lane-store patterns to the equivalent floating-point vector types. The underlying WebAssembly instructions are type-agnostic lane stores. 

That being said I think something like `STORE_LANE_I32x4_A32` can be misleading when dealing with floating-point vectors. (should there be a rename or something ?)

>From 844d1ef2774f82fb559eea97fe14dbdc668516bd Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Thu, 27 Aug 2026 16:57:23 +0530
Subject: [PATCH] [WebAssembly] Select lane stores for floating-point vectors

---
 .../WebAssembly/WebAssemblyInstrSIMD.td       | 31 ++++---
 .../WebAssembly/simd-load-lane-offset.ll      | 90 +++++++++++++++++++
 2 files changed, 109 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
index 3e9783a9d1f25..17f9379e5453e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
@@ -442,16 +442,18 @@ defm "" : SIMDStoreLane<I16x8, 0x59>;
 defm "" : SIMDStoreLane<I32x4, 0x5a>;
 defm "" : SIMDStoreLane<I64x2, 0x5b>;
 
-multiclass StoreLanePat<Vec vec, SDPatternOperator kind> {
+multiclass StoreLanePat<Vec vec, Vec instVec, SDPatternOperator kind> {
   def : Pat<(kind (AddrOps32 offset32_op:$offset, I32:$addr),
                   (vec.vt V128:$vec),
                   (i32 vec.lane_idx:$idx)),
-            (!cast<NI>("STORE_LANE_"#vec#"_A32") 0, $offset, imm:$idx, $addr, $vec)>,
+            (!cast<NI>("STORE_LANE_"#instVec#"_A32") 0, $offset, imm:$idx,
+                                                       $addr, $vec)>,
         Requires<[HasAddr32]>;
   def : Pat<(kind (AddrOps64 offset64_op:$offset, I64:$addr),
                   (vec.vt V128:$vec),
                   (i32 vec.lane_idx:$idx)),
-            (!cast<NI>("STORE_LANE_"#vec#"_A64") 0, $offset, imm:$idx, $addr, $vec)>,
+            (!cast<NI>("STORE_LANE_"#instVec#"_A64") 0, $offset, imm:$idx,
+                                                       $addr, $vec)>,
         Requires<[HasAddr64]>;
 }
 
@@ -462,18 +464,23 @@ def store16_lane :
   PatFrag<(ops node:$ptr, node:$vec, node:$idx),
           (truncstorei16 (i32 (vector_extract $vec, $idx)), $ptr)>;
 def store32_lane :
-  PatFrag<(ops node:$ptr, node:$vec, node:$idx),
-          (store (i32 (vector_extract $vec, $idx)), $ptr)>;
+  PatFrags<(ops node:$ptr, node:$vec, node:$idx), [
+           (store (i32 (vector_extract $vec, $idx)), $ptr),
+           (store (f32 (vector_extract $vec, $idx)), $ptr)
+]>;
 def store64_lane :
-  PatFrag<(ops node:$ptr, node:$vec, node:$idx),
-          (store (i64 (vector_extract $vec, $idx)), $ptr)>;
-// TODO: floating point lanes as well
+  PatFrags<(ops node:$ptr, node:$vec, node:$idx), [
+           (store (i64 (vector_extract $vec, $idx)), $ptr),
+           (store (f64 (vector_extract $vec, $idx)), $ptr)
+]>;
 
 let AddedComplexity = 1 in {
-defm : StoreLanePat<I8x16, store8_lane>;
-defm : StoreLanePat<I16x8, store16_lane>;
-defm : StoreLanePat<I32x4, store32_lane>;
-defm : StoreLanePat<I64x2, store64_lane>;
+defm : StoreLanePat<I8x16, I8x16, store8_lane>;
+defm : StoreLanePat<I16x8, I16x8, store16_lane>;
+defm : StoreLanePat<I32x4, I32x4, store32_lane>;
+defm : StoreLanePat<I64x2, I64x2, store64_lane>;
+defm : StoreLanePat<F32x4, I32x4, store32_lane>;
+defm : StoreLanePat<F64x2, I64x2, store64_lane>;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/WebAssembly/simd-load-lane-offset.ll b/llvm/test/CodeGen/WebAssembly/simd-load-lane-offset.ll
index ff31d342b84f5..2e2dfcb26d5ac 100644
--- a/llvm/test/CodeGen/WebAssembly/simd-load-lane-offset.ll
+++ b/llvm/test/CodeGen/WebAssembly/simd-load-lane-offset.ll
@@ -1594,3 +1594,93 @@ define void @store_lane_i64_from_global_address(<2 x i64> %v) {
   store i64 %x, ptr @gv_i64
   ret void
 }
+
+;===----------------------------------------------------------------------------
+; Floating-point lane stores
+;===----------------------------------------------------------------------------
+
+define void @store_lane_f32_no_offset(<4 x float> %v, ptr %p) {
+; CHECK-LABEL: store_lane_f32_no_offset:
+; CHECK:         .functype store_lane_f32_no_offset (v128, i32) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    v128.store32_lane 0, 2
+; CHECK-NEXT:    # fallthrough-return
+;
+; MEM64-LABEL: store_lane_f32_no_offset:
+; MEM64:         .functype store_lane_f32_no_offset (v128, i64) -> ()
+; MEM64-NEXT:  # %bb.0:
+; MEM64-NEXT:    local.get 1
+; MEM64-NEXT:    local.get 0
+; MEM64-NEXT:    v128.store32_lane 0, 2
+; MEM64-NEXT:    # fallthrough-return
+  %x = extractelement <4 x float> %v, i32 2
+  store float %x, ptr %p
+  ret void
+}
+
+define void @store_lane_f32_with_folded_gep_offset(<4 x float> %v, ptr %p) {
+; CHECK-LABEL: store_lane_f32_with_folded_gep_offset:
+; CHECK:         .functype store_lane_f32_with_folded_gep_offset (v128, i32) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    v128.store32_lane 24, 2
+; CHECK-NEXT:    # fallthrough-return
+;
+; MEM64-LABEL: store_lane_f32_with_folded_gep_offset:
+; MEM64:         .functype store_lane_f32_with_folded_gep_offset (v128, i64) -> ()
+; MEM64-NEXT:  # %bb.0:
+; MEM64-NEXT:    local.get 1
+; MEM64-NEXT:    local.get 0
+; MEM64-NEXT:    v128.store32_lane 24, 2
+; MEM64-NEXT:    # fallthrough-return
+  %s = getelementptr inbounds float, ptr %p, i32 6
+  %x = extractelement <4 x float> %v, i32 2
+  store float %x, ptr %s
+  ret void
+}
+
+define void @store_lane_f64_no_offset(<2 x double> %v, ptr %p) {
+; CHECK-LABEL: store_lane_f64_no_offset:
+; CHECK:         .functype store_lane_f64_no_offset (v128, i32) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    v128.store64_lane 0, 1
+; CHECK-NEXT:    # fallthrough-return
+;
+; MEM64-LABEL: store_lane_f64_no_offset:
+; MEM64:         .functype store_lane_f64_no_offset (v128, i64) -> ()
+; MEM64-NEXT:  # %bb.0:
+; MEM64-NEXT:    local.get 1
+; MEM64-NEXT:    local.get 0
+; MEM64-NEXT:    v128.store64_lane 0, 1
+; MEM64-NEXT:    # fallthrough-return
+  %x = extractelement <2 x double> %v, i32 1
+  store double %x, ptr %p
+  ret void
+}
+
+define void @store_lane_f64_with_folded_gep_offset(<2 x double> %v, ptr %p) {
+; CHECK-LABEL: store_lane_f64_with_folded_gep_offset:
+; CHECK:         .functype store_lane_f64_with_folded_gep_offset (v128, i32) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    v128.store64_lane 48, 1
+; CHECK-NEXT:    # fallthrough-return
+;
+; MEM64-LABEL: store_lane_f64_with_folded_gep_offset:
+; MEM64:         .functype store_lane_f64_with_folded_gep_offset (v128, i64) -> ()
+; MEM64-NEXT:  # %bb.0:
+; MEM64-NEXT:    local.get 1
+; MEM64-NEXT:    local.get 0
+; MEM64-NEXT:    v128.store64_lane 48, 1
+; MEM64-NEXT:    # fallthrough-return
+  %s = getelementptr inbounds double, ptr %p, i32 6
+  %x = extractelement <2 x double> %v, i32 1
+  store double %x, ptr %s
+  ret void
+}



More information about the llvm-commits mailing list