[llvm] [DAG] Improved ISD::SHL handling in isKnownToBeAPowerOfTwo (PR #181882)
Aadarsh Keshri via llvm-commits
llvm-commits at lists.llvm.org
Sat Feb 21 01:24:00 PST 2026
https://github.com/Aadarsh-Keshri updated https://github.com/llvm/llvm-project/pull/181882
>From 699e9ac367afb27b9358fc72f8c64561b0939cda Mon Sep 17 00:00:00 2001
From: Aadarsh-Keshri <keshri.aadarsh123 at gmail.com>
Date: Tue, 17 Feb 2026 23:44:57 +0530
Subject: [PATCH 1/5] [DAG] Improved ISD::SHL handling in
isKnownToBeAPowerOfTwo
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 581553d41cb6d..707e24120514c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4712,10 +4712,12 @@ bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val,
case ISD::SHL: {
// A left-shift of a constant one will have exactly one bit set because
// shifting the bit off the end is undefined.
- auto *C = isConstOrConstSplat(Val.getOperand(0));
+ auto *C = isConstOrConstSplat(Val.getOperand(0), DemandedElts);
if (C && C->getAPIntValue() == 1)
return true;
- return isKnownToBeAPowerOfTwo(Val.getOperand(0), /*OrZero=*/false,
+ if (!(OrZero || isKnownNeverZero(Val, Depth)))
+ return false;
+ return isKnownToBeAPowerOfTwo(Val.getOperand(0), DemandedElts, OrZero,
Depth + 1) &&
isKnownNeverZero(Val, Depth);
}
>From bbb2156291611f7029da3c7f70c2a1cdfe80f0e9 Mon Sep 17 00:00:00 2001
From: Aadarsh Keshri <120744385+Aadarsh-Keshri at users.noreply.github.com>
Date: Wed, 18 Feb 2026 16:23:54 +0530
Subject: [PATCH 2/5] Apply suggestion from @RKSimon
Co-authored-by: Simon Pilgrim <git at redking.me.uk>
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 707e24120514c..5938cc9c19137 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4715,11 +4715,9 @@ bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val,
auto *C = isConstOrConstSplat(Val.getOperand(0), DemandedElts);
if (C && C->getAPIntValue() == 1)
return true;
- if (!(OrZero || isKnownNeverZero(Val, Depth)))
- return false;
- return isKnownToBeAPowerOfTwo(Val.getOperand(0), DemandedElts, OrZero,
- Depth + 1) &&
- isKnownNeverZero(Val, Depth);
+ return (OrZero || isKnownNeverZero(Val, Depth)) &&
+ isKnownToBeAPowerOfTwo(Val.getOperand(0), DemandedElts, OrZero,
+ Depth + 1);
}
case ISD::SRL: {
>From 81310147a742d00567c933fd3b96bc06edc9f9e1 Mon Sep 17 00:00:00 2001
From: Aadarsh-Keshri <keshri.aadarsh123 at gmail.com>
Date: Thu, 19 Feb 2026 00:39:28 +0530
Subject: [PATCH 3/5] Added DAG tests
---
.../AArch64/AArch64SelectionDAGTest.cpp | 54 +++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index b2b8dfb0c21fc..3033a6cab35be 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -6,12 +6,16 @@
//===----------------------------------------------------------------------===//
#include "AArch64SelectionDAGInfo.h"
+#include "llvm/ADT/APInt.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/AsmParser/Parser.h"
+#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGenTypes/MachineValueType.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
@@ -914,6 +918,56 @@ TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_Constants) {
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(SplatBig, /*OrZero=*/true));
}
+TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_SHL) {
+ SDLoc Loc;
+ auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
+ auto Cst1 = DAG->getConstant(1, Loc, MVT::i32);
+ auto Cst3 = DAG->getConstant(3, Loc, MVT::i32);
+ auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
+ auto Cst16 = DAG->getConstant(16, Loc, MVT::i32);
+
+ auto Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 1, MVT::i32);
+ auto ShlConst1 = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cst1, Cond);
+
+ EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlConst1));
+ EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlConst1, /*OrZero=*/true));
+
+ auto And16 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cond, Cst16);
+ auto ShlMaybeZero = DAG->getNode(ISD::SHL, Loc, MVT::i32, And16, Cst1);
+
+ EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlMaybeZero));
+ EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlMaybeZero, /*OrZero=*/true));
+
+ auto ShlUnknown = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cond, Cst1);
+ EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlUnknown));
+
+ auto Neg3 = DAG->getNode(ISD::SUB, Loc, MVT::i32, Cst0, Cst3);
+ auto AndPow2 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cst3, Neg3);
+ auto ShlPow2 = DAG->getNode(ISD::SHL, Loc, MVT::i32, AndPow2, Cst1);
+
+ EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlPow2));
+
+ auto VecVT = MVT::v2i32;
+ auto Vec13 = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst3});
+ auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
+ auto VecShift = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst1});
+ auto VecShl13 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec13, VecShift);
+ auto VecShl04 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec04, VecShift);
+
+ APInt DemandLo(2, 1);
+ APInt DemandHi(2, 2);
+ APInt DemandAll(2, 3);
+
+ EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(VecShl13, DemandLo));
+ EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VecShl13, DemandHi));
+ EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VecShl13, DemandAll));
+
+ EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VecShl04, DemandAll));
+ EXPECT_TRUE(
+ DAG->isKnownToBeAPowerOfTwo(VecShl04, DemandAll, /*OrZero=*/true));
+ EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(VecShl04, DemandHi));
+}
+
TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_Select) {
SDLoc Loc;
auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
>From 3001ded8d61cd041f03ef94ece7f996a634d5535 Mon Sep 17 00:00:00 2001
From: Aadarsh-Keshri <keshri.aadarsh123 at gmail.com>
Date: Fri, 20 Feb 2026 01:16:18 +0530
Subject: [PATCH 4/5] Specified Explict Types in isKnownToBeAPowerOfZero_SHL
unit tests
---
.../AArch64/AArch64SelectionDAGTest.cpp | 38 +++++++++----------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 3033a6cab35be..0099cf2d67d47 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -920,39 +920,39 @@ TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_Constants) {
TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_SHL) {
SDLoc Loc;
- auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
- auto Cst1 = DAG->getConstant(1, Loc, MVT::i32);
- auto Cst3 = DAG->getConstant(3, Loc, MVT::i32);
- auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
- auto Cst16 = DAG->getConstant(16, Loc, MVT::i32);
+ SDValue Cst0 = DAG->getConstant(0, Loc, MVT::i32);
+ SDValue Cst1 = DAG->getConstant(1, Loc, MVT::i32);
+ SDValue Cst3 = DAG->getConstant(3, Loc, MVT::i32);
+ SDValue Cst4 = DAG->getConstant(4, Loc, MVT::i32);
+ SDValue Cst16 = DAG->getConstant(16, Loc, MVT::i32);
- auto Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 1, MVT::i32);
- auto ShlConst1 = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cst1, Cond);
+ SDValue Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 1, MVT::i32);
+ SDValue ShlConst1 = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cst1, Cond);
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlConst1));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlConst1, /*OrZero=*/true));
- auto And16 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cond, Cst16);
- auto ShlMaybeZero = DAG->getNode(ISD::SHL, Loc, MVT::i32, And16, Cst1);
+ SDValue And16 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cond, Cst16);
+ SDValue ShlMaybeZero = DAG->getNode(ISD::SHL, Loc, MVT::i32, And16, Cst1);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlMaybeZero));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlMaybeZero, /*OrZero=*/true));
- auto ShlUnknown = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cond, Cst1);
+ SDValue ShlUnknown = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cond, Cst1);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlUnknown));
- auto Neg3 = DAG->getNode(ISD::SUB, Loc, MVT::i32, Cst0, Cst3);
- auto AndPow2 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cst3, Neg3);
- auto ShlPow2 = DAG->getNode(ISD::SHL, Loc, MVT::i32, AndPow2, Cst1);
+ SDValue Neg3 = DAG->getNode(ISD::SUB, Loc, MVT::i32, Cst0, Cst3);
+ SDValue AndPow2 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cst3, Neg3);
+ SDValue ShlPow2 = DAG->getNode(ISD::SHL, Loc, MVT::i32, AndPow2, Cst1);
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlPow2));
- auto VecVT = MVT::v2i32;
- auto Vec13 = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst3});
- auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
- auto VecShift = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst1});
- auto VecShl13 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec13, VecShift);
- auto VecShl04 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec04, VecShift);
+ MVT::SimpleValueType VecVT = MVT::v2i32;
+ SDValue Vec13 = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst3});
+ SDValue Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
+ SDValue VecShift = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst1});
+ SDValue VecShl13 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec13, VecShift);
+ SDValue VecShl04 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec04, VecShift);
APInt DemandLo(2, 1);
APInt DemandHi(2, 2);
>From 427dd0afa88f8a5ead3e70d7db690b3f24e4d677 Mon Sep 17 00:00:00 2001
From: Aadarsh-Keshri <keshri.aadarsh123 at gmail.com>
Date: Sat, 21 Feb 2026 14:03:50 +0530
Subject: [PATCH 5/5] Regenerated known-pow2.ll and removed unnecessary
includes
---
llvm/test/CodeGen/X86/known-pow2.ll | 10 +++-------
.../Target/AArch64/AArch64SelectionDAGTest.cpp | 4 ----
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/llvm/test/CodeGen/X86/known-pow2.ll b/llvm/test/CodeGen/X86/known-pow2.ll
index b4dd00125aab5..ac76524de7c33 100644
--- a/llvm/test/CodeGen/X86/known-pow2.ll
+++ b/llvm/test/CodeGen/X86/known-pow2.ll
@@ -779,14 +779,10 @@ define i1 @pow2_and_fail0(i32 %x, i32 %y) {
; CHECK-LABEL: pow2_and_fail0:
; CHECK: # %bb.0:
; CHECK-NEXT: movl %esi, %ecx
-; CHECK-NEXT: movl $4, %eax
-; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
-; CHECK-NEXT: shll %cl, %eax
-; CHECK-NEXT: movl %eax, %ecx
-; CHECK-NEXT: negl %ecx
-; CHECK-NEXT: andl %eax, %ecx
; CHECK-NEXT: notl %edi
-; CHECK-NEXT: testl %edi, %ecx
+; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT: shrl %cl, %edi
+; CHECK-NEXT: testb $4, %dil
; CHECK-NEXT: sete %al
; CHECK-NEXT: retq
%yy = shl i32 4, %y
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 0099cf2d67d47..bc2bb24f6e4fa 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -6,16 +6,12 @@
//===----------------------------------------------------------------------===//
#include "AArch64SelectionDAGInfo.h"
-#include "llvm/ADT/APInt.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/AsmParser/Parser.h"
-#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
-#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/TargetLowering.h"
-#include "llvm/CodeGenTypes/MachineValueType.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
More information about the llvm-commits
mailing list