[llvm] [DAG] Improved handling of ISD::ROTL and ISD::ROTR in isKnownToBeAPowerOfTwo (PR #182744)

Mir Immad via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 2 01:23:10 PST 2026


https://github.com/mirimmad updated https://github.com/llvm/llvm-project/pull/182744

>From afe98f3eca652bd4882d08d52e45e263de4bd397 Mon Sep 17 00:00:00 2001
From: Immad Mir <mirimmad17 at gmail.com>
Date: Sun, 22 Feb 2026 19:11:03 +0530
Subject: [PATCH 1/6] use 'OrZero' in 'isKnownToBeAPowerOfTwo'

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 581553d41cb6d..971c5f5674ecb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4733,8 +4733,7 @@ bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val,
 
   case ISD::ROTL:
   case ISD::ROTR:
-    return isKnownToBeAPowerOfTwo(Val.getOperand(0), /*OrZero=*/false,
-                                  Depth + 1);
+    return isKnownToBeAPowerOfTwo(Val.getOperand(0), false, Depth + 1);
 
   case ISD::SMIN:
   case ISD::SMAX:

>From 1659b7d6ef9e5aa7a98798f3e7820672096b01b1 Mon Sep 17 00:00:00 2001
From: Immad Mir <mirimmad17 at gmail.com>
Date: Sun, 22 Feb 2026 19:26:42 +0530
Subject: [PATCH 2/6] Add a test for ISD::ROTL and ISD::ROTR

---
 .../AArch64/AArch64SelectionDAGTest.cpp       | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index b2b8dfb0c21fc..33a3540f6b562 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1119,6 +1119,55 @@ TEST_F(AArch64SelectionDAGTest,
   EXPECT_EQ(SplatIdx, 0);
 }
 
+TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTL) {
+  SDLoc Loc;
+  auto IntVT = EVT::getIntegerVT(Context, 32);
+
+  // Power-of-two values
+  auto Pow2_4 = DAG->getConstant(4, Loc, IntVT);
+  auto Pow2_8 = DAG->getConstant(8, Loc, IntVT);
+
+  // Non-power-of-two values
+  auto NonPow2_5 = DAG->getConstant(5, Loc, IntVT);
+  auto NonPow2_0 = DAG->getConstant(0, Loc, IntVT);
+
+  auto RotAmount = DAG->getConstant(3, Loc, IntVT);
+
+  auto RotlPow2_4 = DAG->getNode(ISD::ROTL, Loc, IntVT, Pow2_4, RotAmount);
+  auto RotlPow2_8 = DAG->getNode(ISD::ROTL, Loc, IntVT, Pow2_8, RotAmount);
+  auto RotlNonPow2_5 =
+      DAG->getNode(ISD::ROTL, Loc, IntVT, NonPow2_5, RotAmount);
+  auto RotlZero = DAG->getNode(ISD::ROTL, Loc, IntVT, NonPow2_0, RotAmount);
+
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlPow2_4));
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlPow2_8));
+
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlNonPow2_5));
+
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlZero));
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlZero, /*OrZero=*/true));
+}
+
+TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTR) {
+  SDLoc Loc;
+  auto IntVT = EVT::getIntegerVT(Context, 32);
+
+  auto Pow2_16 = DAG->getConstant(16, Loc, IntVT);
+  auto NonPow2_6 = DAG->getConstant(6, Loc, IntVT);
+  auto Zero = DAG->getConstant(0, Loc, IntVT);
+
+  auto RotAmount = DAG->getConstant(5, Loc, IntVT);
+
+  auto RotrPow2 = DAG->getNode(ISD::ROTR, Loc, IntVT, Pow2_16, RotAmount);
+  auto RotrNonPow2 = DAG->getNode(ISD::ROTR, Loc, IntVT, NonPow2_6, RotAmount);
+  auto RotrZero = DAG->getNode(ISD::ROTR, Loc, IntVT, Zero, RotAmount);
+
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotrPow2));
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrNonPow2));
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrZero));
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotrZero, /*OrZero=*/true));
+}
+
 TEST_F(AArch64SelectionDAGTest, getRepeatedSequence_Patterns) {
   TargetLowering TL(*TM, *STI);
 

>From 38cd91eed0f8f4613807576a5e9f8fbfc083edeb Mon Sep 17 00:00:00 2001
From: Immad Mir <mirimmad17 at gmail.com>
Date: Sun, 22 Feb 2026 23:07:34 +0530
Subject: [PATCH 3/6] Add missing 'DemandedElts' and 'OrZero' arguments to
 'isKnownToBeAPowerOfTwo' and associated tests

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  2 +-
 .../AArch64/AArch64SelectionDAGTest.cpp       | 21 +++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 971c5f5674ecb..422f7cc7bde24 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4733,7 +4733,7 @@ bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val,
 
   case ISD::ROTL:
   case ISD::ROTR:
-    return isKnownToBeAPowerOfTwo(Val.getOperand(0), false, Depth + 1);
+    return isKnownToBeAPowerOfTwo(Val.getOperand(0), DemandedElts, OrZero, Depth + 1);
 
   case ISD::SMIN:
   case ISD::SMAX:
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 33a3540f6b562..3c610afeaa2da 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1146,6 +1146,17 @@ TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTL) {
 
   EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlZero));
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlZero, /*OrZero=*/true));
+
+    // Also verify DemandedElts is forwarded through ROTL for vector lanes.
+    auto VecVT = EVT::getVectorVT(Context, IntVT, 2, /*IsScalable=*/false);
+    auto PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_4, NonPow2_0});
+    auto RotAmountVec = DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
+    auto RotlPowAndZero =
+      DAG->getNode(ISD::ROTL, Loc, VecVT, PowAndZero, RotAmountVec);
+    APInt DemandAll(2, 3);
+    EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlPowAndZero, DemandAll));
+    EXPECT_TRUE(
+      DAG->isKnownToBeAPowerOfTwo(RotlPowAndZero, DemandAll, /*OrZero=*/true));
 }
 
 TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTR) {
@@ -1166,6 +1177,16 @@ TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTR) {
   EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrNonPow2));
   EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrZero));
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotrZero, /*OrZero=*/true));
+
+    auto VecVT = EVT::getVectorVT(Context, IntVT, 2, /*IsScalable=*/false);
+    auto PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_16, Zero});
+    auto RotAmountVec = DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
+    auto RotrPowAndZero =
+      DAG->getNode(ISD::ROTR, Loc, VecVT, PowAndZero, RotAmountVec);
+    APInt DemandAll(2, 3);
+    EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrPowAndZero, DemandAll));
+    EXPECT_TRUE(
+      DAG->isKnownToBeAPowerOfTwo(RotrPowAndZero, DemandAll, /*OrZero=*/true));
 }
 
 TEST_F(AArch64SelectionDAGTest, getRepeatedSequence_Patterns) {

>From 4bfd5a7c101135c379e2ceefba2b9dcd28f08495 Mon Sep 17 00:00:00 2001
From: Immad Mir <mirimmad17 at gmail.com>
Date: Tue, 24 Feb 2026 16:48:59 +0530
Subject: [PATCH 4/6] Remove 'auto' and add a test for vector case

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  3 +-
 llvm/test/CodeGen/X86/known-pow2.ll           | 31 ++++++++
 .../AArch64/AArch64SelectionDAGTest.cpp       | 73 ++++++++++---------
 3 files changed, 71 insertions(+), 36 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 422f7cc7bde24..3538091c19884 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -4733,7 +4733,8 @@ bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val,
 
   case ISD::ROTL:
   case ISD::ROTR:
-    return isKnownToBeAPowerOfTwo(Val.getOperand(0), DemandedElts, OrZero, Depth + 1);
+    return isKnownToBeAPowerOfTwo(Val.getOperand(0), DemandedElts, OrZero,
+                                  Depth + 1);
 
   case ISD::SMIN:
   case ISD::SMAX:
diff --git a/llvm/test/CodeGen/X86/known-pow2.ll b/llvm/test/CodeGen/X86/known-pow2.ll
index 2662767b9e2db..0cbf701cd3841 100644
--- a/llvm/test/CodeGen/X86/known-pow2.ll
+++ b/llvm/test/CodeGen/X86/known-pow2.ll
@@ -11,6 +11,8 @@ declare i32 @llvm.smin.i32(i32, i32)
 declare i32 @llvm.smax.i32(i32, i32)
 declare i32 @llvm.fshl.i32(i32, i32, i32)
 declare i32 @llvm.fshr.i32(i32, i32, i32)
+declare <2 x i32> @llvm.fshl.v2i32(<2 x i32>, <2 x i32>, <2 x i32>)
+declare <2 x i32> @llvm.fshr.v2i32(<2 x i32>, <2 x i32>, <2 x i32>)
 
 define <4 x i32> @pow2_non_splat_vec(<4 x i32> %x) {
 ; CHECK-LABEL: pow2_non_splat_vec:
@@ -889,3 +891,32 @@ define i1 @pow2_and_i128(i128 %num, i128 %shift) {
   %bool = icmp eq i128 %bit, 0
   ret i1 %bool
 }
+
+define <2 x i32> @pow2_rotl_vec() {
+; CHECK-LABEL: pow2_rotl_vec:
+; CHECK:       # %bb.0:
+; CHECK:       xmm0 = [32,0,0,0]
+; CHECK:       retq
+entry:
+  ; build vector <4,0>
+  %v0 = insertelement <2 x i32> undef, i32 4, i32 0
+  %v1 = insertelement <2 x i32> %v0, i32 0, i32 1
+  %amt0 = insertelement <2 x i32> undef, i32 3, i32 0
+  %amt1 = insertelement <2 x i32> %amt0, i32 3, i32 1
+  %r = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> %v1, <2 x i32> %v1, <2 x i32> %amt1)
+  ret <2 x i32> %r
+}
+
+define <2 x i32> @pow2_rotr_vec() {
+; CHECK-LABEL: pow2_rotr_vec:
+; CHECK:       # %bb.0:
+; CHECK:       xmm0 = [2147483648,0,0,0]
+; CHECK:       retq
+entry:
+  %v0 = insertelement <2 x i32> undef, i32 16, i32 0
+  %v1 = insertelement <2 x i32> %v0, i32 0, i32 1
+  %amt0 = insertelement <2 x i32> undef, i32 5, i32 0
+  %amt1 = insertelement <2 x i32> %amt0, i32 5, i32 1
+  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %v1, <2 x i32> %v1, <2 x i32> %amt1)
+  ret <2 x i32> %r
+}
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 3c610afeaa2da..267609c7c0367 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1121,23 +1121,24 @@ TEST_F(AArch64SelectionDAGTest,
 
 TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTL) {
   SDLoc Loc;
-  auto IntVT = EVT::getIntegerVT(Context, 32);
-
   // Power-of-two values
-  auto Pow2_4 = DAG->getConstant(4, Loc, IntVT);
-  auto Pow2_8 = DAG->getConstant(8, Loc, IntVT);
+  SDValue Pow2_4 = DAG->getConstant(4, Loc, MVT::i32);
+  SDValue Pow2_8 = DAG->getConstant(8, Loc, MVT::i32);
 
   // Non-power-of-two values
-  auto NonPow2_5 = DAG->getConstant(5, Loc, IntVT);
-  auto NonPow2_0 = DAG->getConstant(0, Loc, IntVT);
+  SDValue NonPow2_5 = DAG->getConstant(5, Loc, MVT::i32);
+  SDValue NonPow2_0 = DAG->getConstant(0, Loc, MVT::i32);
 
-  auto RotAmount = DAG->getConstant(3, Loc, IntVT);
+  SDValue RotAmount = DAG->getConstant(3, Loc, MVT::i32);
 
-  auto RotlPow2_4 = DAG->getNode(ISD::ROTL, Loc, IntVT, Pow2_4, RotAmount);
-  auto RotlPow2_8 = DAG->getNode(ISD::ROTL, Loc, IntVT, Pow2_8, RotAmount);
-  auto RotlNonPow2_5 =
-      DAG->getNode(ISD::ROTL, Loc, IntVT, NonPow2_5, RotAmount);
-  auto RotlZero = DAG->getNode(ISD::ROTL, Loc, IntVT, NonPow2_0, RotAmount);
+  SDValue RotlPow2_4 =
+      DAG->getNode(ISD::ROTL, Loc, MVT::i32, Pow2_4, RotAmount);
+  SDValue RotlPow2_8 =
+      DAG->getNode(ISD::ROTL, Loc, MVT::i32, Pow2_8, RotAmount);
+  SDValue RotlNonPow2_5 =
+      DAG->getNode(ISD::ROTL, Loc, MVT::i32, NonPow2_5, RotAmount);
+  SDValue RotlZero =
+      DAG->getNode(ISD::ROTL, Loc, MVT::i32, NonPow2_0, RotAmount);
 
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlPow2_4));
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlPow2_8));
@@ -1147,45 +1148,47 @@ TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTL) {
   EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlZero));
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlZero, /*OrZero=*/true));
 
-    // Also verify DemandedElts is forwarded through ROTL for vector lanes.
-    auto VecVT = EVT::getVectorVT(Context, IntVT, 2, /*IsScalable=*/false);
-    auto PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_4, NonPow2_0});
-    auto RotAmountVec = DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
-    auto RotlPowAndZero =
+  // Also verify DemandedElts is forwarded through ROTL for vector lanes.
+  MVT::SimpleValueType VecVT = MVT::v2i32;
+  SDValue PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_4, NonPow2_0});
+  SDValue RotAmountVec =
+      DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
+  SDValue RotlPowAndZero =
       DAG->getNode(ISD::ROTL, Loc, VecVT, PowAndZero, RotAmountVec);
-    APInt DemandAll(2, 3);
-    EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlPowAndZero, DemandAll));
-    EXPECT_TRUE(
+  APInt DemandAll(2, 3);
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlPowAndZero, DemandAll));
+  EXPECT_TRUE(
       DAG->isKnownToBeAPowerOfTwo(RotlPowAndZero, DemandAll, /*OrZero=*/true));
 }
 
 TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTR) {
   SDLoc Loc;
-  auto IntVT = EVT::getIntegerVT(Context, 32);
 
-  auto Pow2_16 = DAG->getConstant(16, Loc, IntVT);
-  auto NonPow2_6 = DAG->getConstant(6, Loc, IntVT);
-  auto Zero = DAG->getConstant(0, Loc, IntVT);
+  SDValue Pow2_16 = DAG->getConstant(16, Loc, MVT::i32);
+  SDValue NonPow2_6 = DAG->getConstant(6, Loc, MVT::i32);
+  SDValue Zero = DAG->getConstant(0, Loc, MVT::i32);
 
-  auto RotAmount = DAG->getConstant(5, Loc, IntVT);
+  SDValue RotAmount = DAG->getConstant(5, Loc, MVT::i32);
 
-  auto RotrPow2 = DAG->getNode(ISD::ROTR, Loc, IntVT, Pow2_16, RotAmount);
-  auto RotrNonPow2 = DAG->getNode(ISD::ROTR, Loc, IntVT, NonPow2_6, RotAmount);
-  auto RotrZero = DAG->getNode(ISD::ROTR, Loc, IntVT, Zero, RotAmount);
+  SDValue RotrPow2 = DAG->getNode(ISD::ROTR, Loc, MVT::i32, Pow2_16, RotAmount);
+  SDValue RotrNonPow2 =
+      DAG->getNode(ISD::ROTR, Loc, MVT::i32, NonPow2_6, RotAmount);
+  SDValue RotrZero = DAG->getNode(ISD::ROTR, Loc, MVT::i32, Zero, RotAmount);
 
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotrPow2));
   EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrNonPow2));
   EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrZero));
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotrZero, /*OrZero=*/true));
 
-    auto VecVT = EVT::getVectorVT(Context, IntVT, 2, /*IsScalable=*/false);
-    auto PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_16, Zero});
-    auto RotAmountVec = DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
-    auto RotrPowAndZero =
+  MVT::SimpleValueType VecVT = MVT::v2i32;
+  SDValue PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_16, Zero});
+  SDValue RotAmountVec =
+      DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
+  SDValue RotrPowAndZero =
       DAG->getNode(ISD::ROTR, Loc, VecVT, PowAndZero, RotAmountVec);
-    APInt DemandAll(2, 3);
-    EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrPowAndZero, DemandAll));
-    EXPECT_TRUE(
+  APInt DemandAll(2, 3);
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrPowAndZero, DemandAll));
+  EXPECT_TRUE(
       DAG->isKnownToBeAPowerOfTwo(RotrPowAndZero, DemandAll, /*OrZero=*/true));
 }
 

>From cc0b29c7a040746773f863d181d0b5aecc6ca7d1 Mon Sep 17 00:00:00 2001
From: Immad Mir <mirimmad17 at gmail.com>
Date: Wed, 25 Feb 2026 16:04:34 +0530
Subject: [PATCH 5/6] Use 'SELECT' when creating ROTL/ROTR nodes Use
 zeroinitializer instead of undef.

---
 llvm/test/CodeGen/X86/known-pow2.ll           |  8 +-
 .../AArch64/AArch64SelectionDAGTest.cpp       | 91 ++++++++++++++-----
 2 files changed, 70 insertions(+), 29 deletions(-)

diff --git a/llvm/test/CodeGen/X86/known-pow2.ll b/llvm/test/CodeGen/X86/known-pow2.ll
index 0cbf701cd3841..9d101abd020b1 100644
--- a/llvm/test/CodeGen/X86/known-pow2.ll
+++ b/llvm/test/CodeGen/X86/known-pow2.ll
@@ -899,9 +899,9 @@ define <2 x i32> @pow2_rotl_vec() {
 ; CHECK:       retq
 entry:
   ; build vector <4,0>
-  %v0 = insertelement <2 x i32> undef, i32 4, i32 0
+  %v0 = insertelement <2 x i32> zeroinitializer, i32 4, i32 0
   %v1 = insertelement <2 x i32> %v0, i32 0, i32 1
-  %amt0 = insertelement <2 x i32> undef, i32 3, i32 0
+  %amt0 = insertelement <2 x i32> zeroinitializer, i32 3, i32 0
   %amt1 = insertelement <2 x i32> %amt0, i32 3, i32 1
   %r = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> %v1, <2 x i32> %v1, <2 x i32> %amt1)
   ret <2 x i32> %r
@@ -913,9 +913,9 @@ define <2 x i32> @pow2_rotr_vec() {
 ; CHECK:       xmm0 = [2147483648,0,0,0]
 ; CHECK:       retq
 entry:
-  %v0 = insertelement <2 x i32> undef, i32 16, i32 0
+  %v0 = insertelement <2 x i32> zeroinitializer, i32 16, i32 0
   %v1 = insertelement <2 x i32> %v0, i32 0, i32 1
-  %amt0 = insertelement <2 x i32> undef, i32 5, i32 0
+  %amt0 = insertelement <2 x i32> zeroinitializer, i32 5, i32 0
   %amt1 = insertelement <2 x i32> %amt0, i32 5, i32 1
   %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %v1, <2 x i32> %v1, <2 x i32> %amt1)
   ret <2 x i32> %r
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 267609c7c0367..91562796d0081 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1124,55 +1124,83 @@ TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTL) {
   // Power-of-two values
   SDValue Pow2_4 = DAG->getConstant(4, Loc, MVT::i32);
   SDValue Pow2_8 = DAG->getConstant(8, Loc, MVT::i32);
-
   // Non-power-of-two values
-  SDValue NonPow2_5 = DAG->getConstant(5, Loc, MVT::i32);
+  SDValue NonPow2_3 = DAG->getConstant(3, Loc, MVT::i32);
+  SDValue NonPow2_9 = DAG->getConstant(9, Loc, MVT::i32);
+
+  // Zero value
   SDValue NonPow2_0 = DAG->getConstant(0, Loc, MVT::i32);
 
   SDValue RotAmount = DAG->getConstant(3, Loc, MVT::i32);
 
-  SDValue RotlPow2_4 =
-      DAG->getNode(ISD::ROTL, Loc, MVT::i32, Pow2_4, RotAmount);
-  SDValue RotlPow2_8 =
-      DAG->getNode(ISD::ROTL, Loc, MVT::i32, Pow2_8, RotAmount);
-  SDValue RotlNonPow2_5 =
-      DAG->getNode(ISD::ROTL, Loc, MVT::i32, NonPow2_5, RotAmount);
-  SDValue RotlZero =
-      DAG->getNode(ISD::ROTL, Loc, MVT::i32, NonPow2_0, RotAmount);
+  SDValue Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 1, MVT::i1);
 
-  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlPow2_4));
-  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlPow2_8));
+  SDValue Sel_pow2 =
+      DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Pow2_4, Pow2_8);
+  SDValue Sel_non_pow2 =
+      DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, NonPow2_3, NonPow2_9);
 
-  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlNonPow2_5));
+  SDValue RotlPow2 =
+      DAG->getNode(ISD::ROTL, Loc, MVT::i32, Sel_pow2, RotAmount);
+  SDValue RotlNonPow2 =
+      DAG->getNode(ISD::ROTL, Loc, MVT::i32, Sel_non_pow2, RotAmount);
+  SDValue RotlZero =
+      DAG->getNode(ISD::ROTL, Loc, MVT::i32, NonPow2_0, RotAmount);
 
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlPow2));
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlNonPow2));
   EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlZero));
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotlZero, /*OrZero=*/true));
 
   // Also verify DemandedElts is forwarded through ROTL for vector lanes.
   MVT::SimpleValueType VecVT = MVT::v2i32;
   SDValue PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_4, NonPow2_0});
+  SDValue PowAndNonPow = DAG->getBuildVector(VecVT, Loc, {Pow2_8, NonPow2_0});
+
   SDValue RotAmountVec =
       DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
-  SDValue RotlPowAndZero =
-      DAG->getNode(ISD::ROTL, Loc, VecVT, PowAndZero, RotAmountVec);
+
+  SDValue VecCond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 2, MVT::v2i1);
+  SDValue Sel_pow2_vec =
+      DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, PowAndZero, PowAndNonPow);
+
+  SDValue Rotl =
+      DAG->getNode(ISD::ROTL, Loc, VecVT, Sel_pow2_vec, RotAmountVec);
+
   APInt DemandAll(2, 3);
-  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotlPowAndZero, DemandAll));
-  EXPECT_TRUE(
-      DAG->isKnownToBeAPowerOfTwo(RotlPowAndZero, DemandAll, /*OrZero=*/true));
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Rotl, DemandAll));
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Rotl, DemandAll, /*OrZero=*/true));
+
+  APInt DemandLo(2, 1);
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Rotl, DemandLo));
+
+  APInt DemandHi(2, 2);
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Rotl, DemandHi));
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Rotl, DemandHi, /*OrZero=*/true));
 }
 
 TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTR) {
   SDLoc Loc;
 
   SDValue Pow2_16 = DAG->getConstant(16, Loc, MVT::i32);
+  SDValue Pow2_8 = DAG->getConstant(8, Loc, MVT::i32);
   SDValue NonPow2_6 = DAG->getConstant(6, Loc, MVT::i32);
+  SDValue NonPow2_9 = DAG->getConstant(9, Loc, MVT::i32);
   SDValue Zero = DAG->getConstant(0, Loc, MVT::i32);
 
   SDValue RotAmount = DAG->getConstant(5, Loc, MVT::i32);
 
-  SDValue RotrPow2 = DAG->getNode(ISD::ROTR, Loc, MVT::i32, Pow2_16, RotAmount);
+  SDValue Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 3, MVT::i1);
+
+  SDValue Sel_pow2 =
+      DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Pow2_16, Pow2_8);
+  SDValue Sel_non_pow2 =
+      DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, NonPow2_6, NonPow2_9);
+
+  SDValue RotrPow2 =
+      DAG->getNode(ISD::ROTR, Loc, MVT::i32, Sel_pow2, RotAmount);
   SDValue RotrNonPow2 =
-      DAG->getNode(ISD::ROTR, Loc, MVT::i32, NonPow2_6, RotAmount);
+      DAG->getNode(ISD::ROTR, Loc, MVT::i32, Sel_non_pow2, RotAmount);
   SDValue RotrZero = DAG->getNode(ISD::ROTR, Loc, MVT::i32, Zero, RotAmount);
 
   EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(RotrPow2));
@@ -1182,14 +1210,27 @@ TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_ROTR) {
 
   MVT::SimpleValueType VecVT = MVT::v2i32;
   SDValue PowAndZero = DAG->getBuildVector(VecVT, Loc, {Pow2_16, Zero});
+  SDValue PowAndNonPow = DAG->getBuildVector(VecVT, Loc, {Pow2_8, Zero});
+
   SDValue RotAmountVec =
       DAG->getBuildVector(VecVT, Loc, {RotAmount, RotAmount});
-  SDValue RotrPowAndZero =
-      DAG->getNode(ISD::ROTR, Loc, VecVT, PowAndZero, RotAmountVec);
+
+  SDValue VecCond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 4, MVT::v2i1);
+  SDValue Sel_pow2_vec =
+      DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, PowAndZero, PowAndNonPow);
+
+  SDValue Rotr =
+      DAG->getNode(ISD::ROTR, Loc, VecVT, Sel_pow2_vec, RotAmountVec);
   APInt DemandAll(2, 3);
-  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(RotrPowAndZero, DemandAll));
-  EXPECT_TRUE(
-      DAG->isKnownToBeAPowerOfTwo(RotrPowAndZero, DemandAll, /*OrZero=*/true));
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Rotr, DemandAll));
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Rotr, DemandAll, /*OrZero=*/true));
+
+  APInt DemandLo(2, 1);
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Rotr, DemandLo));
+
+  APInt DemandHi(2, 2);
+  EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Rotr, DemandHi));
+  EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Rotr, DemandHi, /*OrZero=*/true));
 }
 
 TEST_F(AArch64SelectionDAGTest, getRepeatedSequence_Patterns) {

>From 468330e18b9d8a0929aa566872600e5eae746191 Mon Sep 17 00:00:00 2001
From: Immad Mir <mirimmad17 at gmail.com>
Date: Mon, 2 Mar 2026 14:52:24 +0530
Subject: [PATCH 6/6] Add test for handling DemndElts for vectors in ROTL and
 ROTR

---
 llvm/test/CodeGen/X86/known-pow2.ll | 91 +++++++++++++++++++++--------
 1 file changed, 68 insertions(+), 23 deletions(-)

diff --git a/llvm/test/CodeGen/X86/known-pow2.ll b/llvm/test/CodeGen/X86/known-pow2.ll
index 9d101abd020b1..bc2ebffb07d22 100644
--- a/llvm/test/CodeGen/X86/known-pow2.ll
+++ b/llvm/test/CodeGen/X86/known-pow2.ll
@@ -892,31 +892,76 @@ define i1 @pow2_and_i128(i128 %num, i128 %shift) {
   ret i1 %bool
 }
 
-define <2 x i32> @pow2_rotl_vec() {
-; CHECK-LABEL: pow2_rotl_vec:
-; CHECK:       # %bb.0:
-; CHECK:       xmm0 = [32,0,0,0]
-; CHECK:       retq
+
+
+define i1 @pow2_rotl_extract_vec(<2 x i32> %a0, i32 %rotamt, i32 %x) {
+; CHECK-LABEL: pow2_rotl_extract_vec:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movl %edi, %ecx
+; CHECK-NEXT:    pxor %xmm1, %xmm1
+; CHECK-NEXT:    pcmpgtd %xmm0, %xmm1
+; CHECK-NEXT:    movdqa %xmm1, %xmm0
+; CHECK-NEXT:    pandn {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-NEXT:    pand {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; CHECK-NEXT:    por %xmm0, %xmm1
+; CHECK-NEXT:    movd %xmm1, %eax
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    roll %cl, %eax
+; CHECK-NEXT:    notl %esi
+; CHECK-NEXT:    testl %esi, %eax
+; CHECK-NEXT:    sete %al
+; CHECK-NEXT:    retq
 entry:
-  ; build vector <4,0>
-  %v0 = insertelement <2 x i32> zeroinitializer, i32 4, i32 0
-  %v1 = insertelement <2 x i32> %v0, i32 0, i32 1
-  %amt0 = insertelement <2 x i32> zeroinitializer, i32 3, i32 0
-  %amt1 = insertelement <2 x i32> %amt0, i32 3, i32 1
-  %r = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> %v1, <2 x i32> %v1, <2 x i32> %amt1)
-  ret <2 x i32> %r
+  %cmp = icmp sgt <2 x i32> zeroinitializer, %a0
+
+  %powvec = select <2 x i1> %cmp,
+                     <2 x i32> <i32 1024, i32 1024>,
+                     <2 x i32> <i32 4096, i32 4096>
+
+  %base = extractelement <2 x i32> %powvec, i32 0
+
+  %d = call i32 @llvm.fshl.i32(i32 %base,
+                               i32 %base,
+                               i32 %rotamt)
+
+  %and = and i32 %x, %d
+  %r = icmp eq i32 %and, %d
+
+  ret i1 %r
 }
 
-define <2 x i32> @pow2_rotr_vec() {
-; CHECK-LABEL: pow2_rotr_vec:
-; CHECK:       # %bb.0:
-; CHECK:       xmm0 = [2147483648,0,0,0]
-; CHECK:       retq
+define i1 @pow2_rotr_extract_vec(<2 x i32> %a0, i32 %rotamt, i32 %x) {
+; CHECK-LABEL: pow2_rotr_extract_vec:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movl %edi, %ecx
+; CHECK-NEXT:    pxor %xmm1, %xmm1
+; CHECK-NEXT:    pcmpgtd %xmm0, %xmm1
+; CHECK-NEXT:    movdqa %xmm1, %xmm0
+; CHECK-NEXT:    pandn {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; CHECK-NEXT:    pand {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; CHECK-NEXT:    por %xmm0, %xmm1
+; CHECK-NEXT:    movd %xmm1, %eax
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    rorl %cl, %eax
+; CHECK-NEXT:    notl %esi
+; CHECK-NEXT:    testl %esi, %eax
+; CHECK-NEXT:    sete %al
+; CHECK-NEXT:    retq
 entry:
-  %v0 = insertelement <2 x i32> zeroinitializer, i32 16, i32 0
-  %v1 = insertelement <2 x i32> %v0, i32 0, i32 1
-  %amt0 = insertelement <2 x i32> zeroinitializer, i32 5, i32 0
-  %amt1 = insertelement <2 x i32> %amt0, i32 5, i32 1
-  %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %v1, <2 x i32> %v1, <2 x i32> %amt1)
-  ret <2 x i32> %r
+
+  %cmp = icmp sgt <2 x i32> zeroinitializer, %a0
+  %powvec = select <2 x i1> %cmp,
+                     <2 x i32> <i32 1024, i32 1024>,
+                     <2 x i32> <i32 4096, i32 4096>
+
+  %base = extractelement <2 x i32> %powvec, i32 0
+
+  %d = call i32 @llvm.fshr.i32(i32 %base,
+                               i32 %base,
+                               i32 %rotamt)
+
+  %and = and i32 %x, %d
+  %r = icmp eq i32 %and, %d
+
+  ret i1 %r
 }



More information about the llvm-commits mailing list