Skip to content

Conversation

@badumbatish
Copy link
Contributor

Add a few patterns for extadd pairwise.

I tried to incorporate this into relaxed dot add but it's currently not working and would need some refactoring into PatFrag to reuse the patterns.

@badumbatish badumbatish requested a review from lukel97 November 13, 2025 21:45
@badumbatish badumbatish marked this pull request as ready for review November 14, 2025 19:59
@llvmbot
Copy link
Member

llvmbot commented Nov 14, 2025

@llvm/pr-subscribers-backend-webassembly

Author: Jasmine Tang (badumbatish)

Changes

Add a few patterns for extadd pairwise.

I tried to incorporate this into relaxed dot add but it's currently not working and would need some refactoring into PatFrag to reuse the patterns.


Full diff: https://github.com/llvm/llvm-project/pull/167960.diff

2 Files Affected:

  • (modified) llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td (+26)
  • (added) llvm/test/CodeGen/WebAssembly/simd-extadd.ll (+89)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
index 14097d7b40a9c..748935b7d2c08 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
@@ -1541,6 +1541,32 @@ def : Pat<(v4i32 (int_wasm_extadd_pairwise_signed (v8i16 V128:$in))),
 def : Pat<(v8i16 (int_wasm_extadd_pairwise_signed (v16i8 V128:$in))),
           (extadd_pairwise_s_I16x8 V128:$in)>;
 
+multiclass ExtAddPairwiseShuffle<ValueType from_ty, ValueType to_ty, string suffix,
+                              int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
+                              int b0, int b1, int b2, int b3, int b4, int b5, int b6, int b7> {
+  foreach sign = ["s", "u"] in {
+    def : Pat<(to_ty (add
+                    (!cast<SDNode>("extend_low_"#sign) (from_ty (wasm_shuffle (from_ty V128:$vec), (from_ty V128:$undef),
+                                  (i32 a0), (i32 a1), (i32 a2), (i32 a3),
+                                  (i32 a4), (i32 a5), (i32 a6), (i32 a7),
+                                  (i32 srcvalue), (i32 srcvalue), (i32 srcvalue), (i32 srcvalue),
+                                  (i32 srcvalue), (i32 srcvalue), (i32 srcvalue), (i32 srcvalue)))),
+                    (!cast<SDNode>("extend_low_"#sign) (from_ty (wasm_shuffle (from_ty V128:$vec), (from_ty V128:$undef),
+                                  (i32 b0), (i32 b1), (i32 b2), (i32 b3),
+                                  (i32 b4), (i32 b5), (i32 b6), (i32 b7),
+                                  (i32 srcvalue), (i32 srcvalue), (i32 srcvalue), (i32 srcvalue),
+                                  (i32 srcvalue), (i32 srcvalue), (i32 srcvalue), (i32 srcvalue)))))),
+              (!cast<Instruction>("extadd_pairwise_"#sign#"_"#suffix) V128:$vec)>;
+  }
+}
+
+defm : ExtAddPairwiseShuffle<v8i16, v4i32, "I32x4",
+                         0, 1, 4, 5, 8, 9, 12, 13,
+                         2, 3, 6, 7, 10, 11, 14, 15>;
+defm : ExtAddPairwiseShuffle<v16i8, v8i16, "I16x8",
+                         0, 2, 4, 6, 8, 10, 12, 14,
+                         1, 3, 5, 7, 9, 11, 13, 15>;
+
 // f64x2 <-> f32x4 conversions
 def demote_t : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>]>;
 def demote_zero : SDNode<"WebAssemblyISD::DEMOTE_ZERO", demote_t>;
diff --git a/llvm/test/CodeGen/WebAssembly/simd-extadd.ll b/llvm/test/CodeGen/WebAssembly/simd-extadd.ll
new file mode 100644
index 0000000000000..dfc47a6abf03a
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/simd-extadd.ll
@@ -0,0 +1,89 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -O2 -mtriple=wasm32 -mattr=+simd128 | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+; Test that adding two extended shuffles from the same vector that ends w/ an add converts to extadd_pairwise
+
+define <8 x i16> @test_extadd_pairwise_i8x16_s(<16 x i8> %v) {
+; CHECK-LABEL: test_extadd_pairwise_i8x16_s:
+; CHECK:         .functype test_extadd_pairwise_i8x16_s (v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i16x8.extadd_pairwise_i8x16_s
+; CHECK-NEXT:    # fallthrough-return
+  %even = shufflevector <16 x i8> %v, <16 x i8> poison, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
+  %odd = shufflevector <16 x i8> %v, <16 x i8> poison, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
+  %even_ext = sext <8 x i8> %even to <8 x i16>
+  %odd_ext = sext <8 x i8> %odd to <8 x i16>
+  %result = add <8 x i16> %even_ext, %odd_ext
+  ret <8 x i16> %result
+}
+
+define <8 x i16> @test_extadd_pairwise_i8x16_u(<16 x i8> %v) {
+; CHECK-LABEL: test_extadd_pairwise_i8x16_u:
+; CHECK:         .functype test_extadd_pairwise_i8x16_u (v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i16x8.extadd_pairwise_i8x16_u
+; CHECK-NEXT:    # fallthrough-return
+  %even = shufflevector <16 x i8> %v, <16 x i8> poison, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
+  %odd = shufflevector <16 x i8> %v, <16 x i8> poison, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
+  %even_ext = zext <8 x i8> %even to <8 x i16>
+  %odd_ext = zext <8 x i8> %odd to <8 x i16>
+  %result = add <8 x i16> %even_ext, %odd_ext
+  ret <8 x i16> %result
+}
+
+define <4 x i32> @test_extadd_pairwise_i16x8_s(<8 x i16> %v) {
+; CHECK-LABEL: test_extadd_pairwise_i16x8_s:
+; CHECK:         .functype test_extadd_pairwise_i16x8_s (v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i32x4.extadd_pairwise_i16x8_s
+; CHECK-NEXT:    # fallthrough-return
+  %even = shufflevector <8 x i16> %v, <8 x i16> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+  %odd = shufflevector <8 x i16> %v, <8 x i16> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+  %even_ext = sext <4 x i16> %even to <4 x i32>
+  %odd_ext = sext <4 x i16> %odd to <4 x i32>
+  %result = add <4 x i32> %even_ext, %odd_ext
+  ret <4 x i32> %result
+}
+
+define <4 x i32> @test_extadd_pairwise_i16x8_u(<8 x i16> %v) {
+; CHECK-LABEL: test_extadd_pairwise_i16x8_u:
+; CHECK:         .functype test_extadd_pairwise_i16x8_u (v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i32x4.extadd_pairwise_i16x8_u
+; CHECK-NEXT:    # fallthrough-return
+  %even = shufflevector <8 x i16> %v, <8 x i16> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+  %odd = shufflevector <8 x i16> %v, <8 x i16> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+  %even_ext = zext <4 x i16> %even to <4 x i32>
+  %odd_ext = zext <4 x i16> %odd to <4 x i32>
+  %result = add <4 x i32> %even_ext, %odd_ext
+  ret <4 x i32> %result
+}
+
+; Negative test: shuffling mask doesn't fit pattern
+define <4 x i32> @negative_test_extadd_pairwise_i16x8_u(<8 x i16> %v) {
+; CHECK-LABEL: negative_test_extadd_pairwise_i16x8_u:
+; CHECK:         .functype negative_test_extadd_pairwise_i16x8_u (v128) -> (v128)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i8x16.shuffle 0, 1, 6, 7, 8, 9, 12, 13, 0, 1, 0, 1, 0, 1, 0, 1
+; CHECK-NEXT:    i32x4.extend_low_i16x8_u
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i8x16.shuffle 2, 3, 6, 7, 10, 11, 14, 15, 0, 1, 0, 1, 0, 1, 0, 1
+; CHECK-NEXT:    i32x4.extend_low_i16x8_u
+; CHECK-NEXT:    i32x4.add
+; CHECK-NEXT:    # fallthrough-return
+  %even = shufflevector <8 x i16> %v, <8 x i16> poison, <4 x i32> <i32 0, i32 3, i32 4, i32 6>
+  %odd = shufflevector <8 x i16> %v, <8 x i16> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+  %even_ext = zext <4 x i16> %even to <4 x i32>
+  %odd_ext = zext <4 x i16> %odd to <4 x i32>
+  %result = add <4 x i32> %even_ext, %odd_ext
+  ret <4 x i32> %result
+}

Copy link
Contributor

@sparker-arm sparker-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@badumbatish
Copy link
Contributor Author

ty for the review everyone, i'll merge this after good ci

Copy link
Contributor

@lukel97 lukel97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@badumbatish badumbatish merged commit 672757b into llvm:main Nov 18, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants