[llvm] [WebAssembly] Add patterns for extadd pairwise (PR #167960)
Jasmine Tang via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 17 07:24:24 PST 2025
https://github.com/badumbatish updated https://github.com/llvm/llvm-project/pull/167960
>From 97980394024505266c85a3c6301bb6409f0e4e8f Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Wed, 12 Nov 2025 12:26:14 -0800
Subject: [PATCH 1/3] precommit
---
llvm/test/CodeGen/WebAssembly/simd-extadd.ll | 117 +++++++++++++++++++
1 file changed, 117 insertions(+)
create mode 100644 llvm/test/CodeGen/WebAssembly/simd-extadd.ll
diff --git a/llvm/test/CodeGen/WebAssembly/simd-extadd.ll b/llvm/test/CodeGen/WebAssembly/simd-extadd.ll
new file mode 100644
index 0000000000000..537c757231282
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/simd-extadd.ll
@@ -0,0 +1,117 @@
+; 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: local.get 0
+; CHECK-NEXT: i8x16.shuffle 0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0
+; CHECK-NEXT: i16x8.extend_low_i8x16_s
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i8x16.shuffle 1, 3, 5, 7, 9, 11, 13, 15, 0, 0, 0, 0, 0, 0, 0, 0
+; CHECK-NEXT: i16x8.extend_low_i8x16_s
+; CHECK-NEXT: i16x8.add
+; 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: local.get 0
+; CHECK-NEXT: i8x16.shuffle 0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0
+; CHECK-NEXT: i16x8.extend_low_i8x16_u
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i8x16.shuffle 1, 3, 5, 7, 9, 11, 13, 15, 0, 0, 0, 0, 0, 0, 0, 0
+; CHECK-NEXT: i16x8.extend_low_i8x16_u
+; CHECK-NEXT: i16x8.add
+; 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: local.get 0
+; CHECK-NEXT: i8x16.shuffle 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 0, 1, 0, 1, 0, 1
+; CHECK-NEXT: i32x4.extend_low_i16x8_s
+; 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_s
+; CHECK-NEXT: i32x4.add
+; 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: local.get 0
+; CHECK-NEXT: i8x16.shuffle 0, 1, 4, 5, 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 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
+}
>From c8363abcb35f08d291fbf31e174ada90a511bf99 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Wed, 12 Nov 2025 12:30:39 -0800
Subject: [PATCH 2/3] Add supporting patterns for extadd pairwise
---
.../WebAssembly/WebAssemblyInstrSIMD.td | 26 ++++++++++++++
llvm/test/CodeGen/WebAssembly/simd-extadd.ll | 36 +++----------------
2 files changed, 30 insertions(+), 32 deletions(-)
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
index 537c757231282..dfc47a6abf03a 100644
--- a/llvm/test/CodeGen/WebAssembly/simd-extadd.ll
+++ b/llvm/test/CodeGen/WebAssembly/simd-extadd.ll
@@ -10,14 +10,7 @@ define <8 x i16> @test_extadd_pairwise_i8x16_s(<16 x i8> %v) {
; CHECK: .functype test_extadd_pairwise_i8x16_s (v128) -> (v128)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i8x16.shuffle 0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0
-; CHECK-NEXT: i16x8.extend_low_i8x16_s
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i8x16.shuffle 1, 3, 5, 7, 9, 11, 13, 15, 0, 0, 0, 0, 0, 0, 0, 0
-; CHECK-NEXT: i16x8.extend_low_i8x16_s
-; CHECK-NEXT: i16x8.add
+; 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>
@@ -32,14 +25,7 @@ define <8 x i16> @test_extadd_pairwise_i8x16_u(<16 x i8> %v) {
; CHECK: .functype test_extadd_pairwise_i8x16_u (v128) -> (v128)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i8x16.shuffle 0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0
-; CHECK-NEXT: i16x8.extend_low_i8x16_u
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i8x16.shuffle 1, 3, 5, 7, 9, 11, 13, 15, 0, 0, 0, 0, 0, 0, 0, 0
-; CHECK-NEXT: i16x8.extend_low_i8x16_u
-; CHECK-NEXT: i16x8.add
+; 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>
@@ -54,14 +40,7 @@ define <4 x i32> @test_extadd_pairwise_i16x8_s(<8 x i16> %v) {
; CHECK: .functype test_extadd_pairwise_i16x8_s (v128) -> (v128)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i8x16.shuffle 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 0, 1, 0, 1, 0, 1
-; CHECK-NEXT: i32x4.extend_low_i16x8_s
-; 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_s
-; CHECK-NEXT: i32x4.add
+; 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>
@@ -76,14 +55,7 @@ define <4 x i32> @test_extadd_pairwise_i16x8_u(<8 x i16> %v) {
; CHECK: .functype 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, 4, 5, 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: 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>
>From 23ff186d51f02e0885ed352fac5c2bb4b6aec2ef Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Mon, 17 Nov 2025 07:24:07 -0800
Subject: [PATCH 3/3] Change 2nd param to srcvalue
---
llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
index 748935b7d2c08..0bdddcffd723d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
@@ -1546,12 +1546,12 @@ multiclass ExtAddPairwiseShuffle<ValueType from_ty, ValueType to_ty, string suff
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),
+ (!cast<SDNode>("extend_low_"#sign) (from_ty (wasm_shuffle (from_ty V128:$vec), (from_ty srcvalue),
(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),
+ (!cast<SDNode>("extend_low_"#sign) (from_ty (wasm_shuffle (from_ty V128:$vec), (from_ty srcvalue),
(i32 b0), (i32 b1), (i32 b2), (i32 b3),
(i32 b4), (i32 b5), (i32 b6), (i32 b7),
(i32 srcvalue), (i32 srcvalue), (i32 srcvalue), (i32 srcvalue),
More information about the llvm-commits
mailing list