[llvm] [WebAssembly] Optimize away mask of 63 for shl ( zext (and i32 63))) (PR #152397)
Jasmine Tang via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 1 03:03:06 PST 2025
https://github.com/badumbatish updated https://github.com/llvm/llvm-project/pull/152397
>From b707a7dffc37f9ee1c79377c2234d73969a9523e Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Wed, 6 Aug 2025 15:06:18 -0700
Subject: [PATCH 1/4] Precommit test
---
llvm/test/CodeGen/WebAssembly/masked-shifts.ll | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/llvm/test/CodeGen/WebAssembly/masked-shifts.ll b/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
index 5bcb023e546b5..47b3b5c9fdc0f 100644
--- a/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
+++ b/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
@@ -18,6 +18,23 @@ define i32 @shl_i32(i32 %v, i32 %x) {
ret i32 %a
}
+define i64 @shl_i64_i32(i64 %v, i32 %x) {
+; CHECK-LABEL: shl_i64_i32:
+; CHECK: .functype shl_i64_i32 (i64, i32) -> (i64)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.const 63
+; CHECK-NEXT: i32.and
+; CHECK-NEXT: i64.extend_i32_u
+; CHECK-NEXT: i64.shl
+; CHECK-NEXT: # fallthrough-return
+ %m = and i32 %x, 63
+ %z = zext i32 %m to i64
+ %a = shl i64 %v, %z
+ ret i64 %a
+}
+
define i32 @sra_i32(i32 %v, i32 %x) {
; CHECK-LABEL: sra_i32:
; CHECK: .functype sra_i32 (i32, i32) -> (i32)
>From 40e9092ace4dec089eaea6c65d480c9bd79eafcd Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Thu, 7 Aug 2025 10:38:23 -0700
Subject: [PATCH 2/4] Optimize away mask of 63 for shl ( zext (and i32 63)))
---
.../WebAssembly/WebAssemblyISelDAGToDAG.cpp | 35 +++++++++++++++++++
.../WebAssembly/WebAssemblyISelLowering.cpp | 1 -
.../WebAssembly/WebAssemblyInstrInfo.td | 2 +-
.../WebAssembly/WebAssemblyInstrInteger.td | 7 ++++
.../test/CodeGen/WebAssembly/masked-shifts.ll | 2 --
5 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index b03b35028c69c..202c770bf8e8f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -70,6 +70,11 @@ class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
bool SelectAddrOperands32(SDValue Op, SDValue &Offset, SDValue &Addr);
bool SelectAddrOperands64(SDValue Op, SDValue &Offset, SDValue &Addr);
+ bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt);
+
+ bool selectShiftMask64FromI32(SDValue N, SDValue &ShAmt) {
+ return selectShiftMask(N, 64, ShAmt);
+ }
// Include the pieces autogenerated from the target description.
#include "WebAssemblyGenDAGISel.inc"
@@ -539,6 +544,36 @@ bool WebAssemblyDAGToDAGISel::SelectAddrOperands64(SDValue Op, SDValue &Offset,
return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64, Op, Offset, Addr);
}
+bool WebAssemblyDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
+ SDValue &ShAmt) {
+
+ ShAmt = N;
+
+ if (ShAmt.getOpcode() == ISD::AND &&
+ isa<ConstantSDNode>(ShAmt.getOperand(1))) {
+ const APInt &AndMask = ShAmt.getConstantOperandAPInt(1);
+
+ // Since the max shift amount is a power of 2 we can subtract 1 to make a
+ // mask that covers the bits needed to represent all shift amounts.
+ assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
+ APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
+
+ if (ShMask.isSubsetOf(AndMask)) {
+ ShAmt = ShAmt.getOperand(0);
+ } else {
+ // SimplifyDemandedBits may have optimized the mask so try restoring any
+ // bits that are known zero.
+ KnownBits Known = CurDAG->computeKnownBits(ShAmt.getOperand(0));
+ if (ShMask.isSubsetOf(AndMask | Known.Zero))
+ ShAmt = ShAmt.getOperand(0);
+ }
+ return true;
+ }
+
+ // TODO: Port rest of riscv if applicable
+ return false;
+}
+
/// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
/// for instruction scheduling.
FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 3f80b2ab2bd6d..7df4e2590c212 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -3343,7 +3343,6 @@ static SDValue performAnyAllCombine(SDNode *N, SelectionDAG &DAG) {
Ret = DAG.getNOT(DL, Ret, MVT::i1);
return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
};
-
if (SDValue AnyTrueEQ = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETEQ,
Intrinsic::wasm_alltrue))
return AnyTrueEQ;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 13d048a98d6ea..ce4db2e112fa0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -460,8 +460,8 @@ def : Pat<(i64 (WebAssemblyWrapperREL texternalsym:$addr)),
include "WebAssemblyInstrMemory.td"
include "WebAssemblyInstrCall.td"
include "WebAssemblyInstrControl.td"
-include "WebAssemblyInstrInteger.td"
include "WebAssemblyInstrConv.td"
+include "WebAssemblyInstrInteger.td"
include "WebAssemblyInstrFloat.td"
include "WebAssemblyInstrAtomics.td"
include "WebAssemblyInstrSIMD.td"
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
index d4c8f92c883e7..8505608d42c4c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
@@ -44,6 +44,10 @@ multiclass ComparisonInt<CondCode cond, string name, bits<32> i32Inst, bits<32>
!strconcat("i64.", name), i64Inst>;
}
+// ComplexPattern
+def shiftMask64FromI32
+ : ComplexPattern<i32, 1, "selectShiftMask64FromI32", [], [], 0>;
+
// The spaces after the names are for aesthetic purposes only, to make
// operands line up vertically after tab expansion.
let isCommutable = 1 in
@@ -101,6 +105,9 @@ def : Pat<(shl I64:$lhs, (and I64:$rhs, 63)), (SHL_I64 I64:$lhs, I64:$rhs)>;
def : Pat<(sra I64:$lhs, (and I64:$rhs, 63)), (SHR_S_I64 I64:$lhs, I64:$rhs)>;
def : Pat<(srl I64:$lhs, (and I64:$rhs, 63)), (SHR_U_I64 I64:$lhs, I64:$rhs)>;
+def : Pat<(shl I64:$lhs, (zext(shiftMask64FromI32 I32:$rhs))),
+ (SHL_I64 I64:$lhs, (I64_EXTEND_U_I32 I32:$rhs))>;
+
// Optimize away an explicit mask on a rotate count.
def : Pat<(rotl I32:$lhs, (and I32:$rhs, 31)), (ROTL_I32 I32:$lhs, I32:$rhs)>;
def : Pat<(rotr I32:$lhs, (and I32:$rhs, 31)), (ROTR_I32 I32:$lhs, I32:$rhs)>;
diff --git a/llvm/test/CodeGen/WebAssembly/masked-shifts.ll b/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
index 47b3b5c9fdc0f..45c79df5f3f2b 100644
--- a/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
+++ b/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
@@ -24,8 +24,6 @@ define i64 @shl_i64_i32(i64 %v, i32 %x) {
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.const 63
-; CHECK-NEXT: i32.and
; CHECK-NEXT: i64.extend_i32_u
; CHECK-NEXT: i64.shl
; CHECK-NEXT: # fallthrough-return
>From 8f1cd06a0c9ffc7157f4d7d62d2085fd5ff7e2f2 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Thu, 27 Nov 2025 16:18:14 -0800
Subject: [PATCH 3/4] Simplify "Optimize away mask of 63 for shl ( zext (and
i32 63)))"
This reverts commit 40e9092ace4dec089eaea6c65d480c9bd79eafcd and replace
it with a simple constant 63 mask
---
.../WebAssembly/WebAssemblyISelDAGToDAG.cpp | 35 -------------------
.../WebAssembly/WebAssemblyISelLowering.cpp | 1 +
.../WebAssembly/WebAssemblyInstrInteger.td | 10 ++----
3 files changed, 4 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index 202c770bf8e8f..b03b35028c69c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -70,11 +70,6 @@ class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
bool SelectAddrOperands32(SDValue Op, SDValue &Offset, SDValue &Addr);
bool SelectAddrOperands64(SDValue Op, SDValue &Offset, SDValue &Addr);
- bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt);
-
- bool selectShiftMask64FromI32(SDValue N, SDValue &ShAmt) {
- return selectShiftMask(N, 64, ShAmt);
- }
// Include the pieces autogenerated from the target description.
#include "WebAssemblyGenDAGISel.inc"
@@ -544,36 +539,6 @@ bool WebAssemblyDAGToDAGISel::SelectAddrOperands64(SDValue Op, SDValue &Offset,
return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64, Op, Offset, Addr);
}
-bool WebAssemblyDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
- SDValue &ShAmt) {
-
- ShAmt = N;
-
- if (ShAmt.getOpcode() == ISD::AND &&
- isa<ConstantSDNode>(ShAmt.getOperand(1))) {
- const APInt &AndMask = ShAmt.getConstantOperandAPInt(1);
-
- // Since the max shift amount is a power of 2 we can subtract 1 to make a
- // mask that covers the bits needed to represent all shift amounts.
- assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
- APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
-
- if (ShMask.isSubsetOf(AndMask)) {
- ShAmt = ShAmt.getOperand(0);
- } else {
- // SimplifyDemandedBits may have optimized the mask so try restoring any
- // bits that are known zero.
- KnownBits Known = CurDAG->computeKnownBits(ShAmt.getOperand(0));
- if (ShMask.isSubsetOf(AndMask | Known.Zero))
- ShAmt = ShAmt.getOperand(0);
- }
- return true;
- }
-
- // TODO: Port rest of riscv if applicable
- return false;
-}
-
/// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
/// for instruction scheduling.
FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 7df4e2590c212..3f80b2ab2bd6d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -3343,6 +3343,7 @@ static SDValue performAnyAllCombine(SDNode *N, SelectionDAG &DAG) {
Ret = DAG.getNOT(DL, Ret, MVT::i1);
return DAG.getZExtOrTrunc(Ret, DL, N->getValueType(0));
};
+
if (SDValue AnyTrueEQ = CombineSetCC(Intrinsic::wasm_anytrue, ISD::SETEQ,
Intrinsic::wasm_alltrue))
return AnyTrueEQ;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
index 8505608d42c4c..eb692679f5971 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td
@@ -44,10 +44,6 @@ multiclass ComparisonInt<CondCode cond, string name, bits<32> i32Inst, bits<32>
!strconcat("i64.", name), i64Inst>;
}
-// ComplexPattern
-def shiftMask64FromI32
- : ComplexPattern<i32, 1, "selectShiftMask64FromI32", [], [], 0>;
-
// The spaces after the names are for aesthetic purposes only, to make
// operands line up vertically after tab expansion.
let isCommutable = 1 in
@@ -105,15 +101,15 @@ def : Pat<(shl I64:$lhs, (and I64:$rhs, 63)), (SHL_I64 I64:$lhs, I64:$rhs)>;
def : Pat<(sra I64:$lhs, (and I64:$rhs, 63)), (SHR_S_I64 I64:$lhs, I64:$rhs)>;
def : Pat<(srl I64:$lhs, (and I64:$rhs, 63)), (SHR_U_I64 I64:$lhs, I64:$rhs)>;
-def : Pat<(shl I64:$lhs, (zext(shiftMask64FromI32 I32:$rhs))),
- (SHL_I64 I64:$lhs, (I64_EXTEND_U_I32 I32:$rhs))>;
-
// Optimize away an explicit mask on a rotate count.
def : Pat<(rotl I32:$lhs, (and I32:$rhs, 31)), (ROTL_I32 I32:$lhs, I32:$rhs)>;
def : Pat<(rotr I32:$lhs, (and I32:$rhs, 31)), (ROTR_I32 I32:$lhs, I32:$rhs)>;
def : Pat<(rotl I64:$lhs, (and I64:$rhs, 63)), (ROTL_I64 I64:$lhs, I64:$rhs)>;
def : Pat<(rotr I64:$lhs, (and I64:$rhs, 63)), (ROTR_I64 I64:$lhs, I64:$rhs)>;
+def : Pat<(shl I64:$lhs, (zext (and I32:$rhs, 63))),
+ (SHL_I64 I64:$lhs, (I64_EXTEND_U_I32 I32:$rhs))>;
+
defm SELECT_I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs, I32:$cond),
(outs), (ins),
[(set I32:$dst, (select I32:$cond, I32:$lhs, I32:$rhs))],
>From cc4b02f07b16192a2b55db07a6884d4c21b19967 Mon Sep 17 00:00:00 2001
From: Jasmine Tang <jjasmine at igalia.com>
Date: Mon, 1 Dec 2025 03:01:47 -0800
Subject: [PATCH 4/4] Rename test case
---
llvm/test/CodeGen/WebAssembly/masked-shifts.ll | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/test/CodeGen/WebAssembly/masked-shifts.ll b/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
index 45c79df5f3f2b..368f30fd5d7ed 100644
--- a/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
+++ b/llvm/test/CodeGen/WebAssembly/masked-shifts.ll
@@ -18,9 +18,9 @@ define i32 @shl_i32(i32 %v, i32 %x) {
ret i32 %a
}
-define i64 @shl_i64_i32(i64 %v, i32 %x) {
-; CHECK-LABEL: shl_i64_i32:
-; CHECK: .functype shl_i64_i32 (i64, i32) -> (i64)
+define i64 @shl_i64_zext(i64 %v, i32 %x) {
+; CHECK-LABEL: shl_i64_zext:
+; CHECK: .functype shl_i64_zext (i64, i32) -> (i64)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 1
More information about the llvm-commits
mailing list