[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