[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