[llvm] [DemandedBits] Support non-constant shift amounts for funnel shifts (PR #180569)
Panagiotis Karouzakis via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 9 10:48:10 PST 2026
https://github.com/karouzakisp updated https://github.com/llvm/llvm-project/pull/180569
>From e7a3c3da10dfe2141807a36067dde30b446c5e6a Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Sat, 27 Dec 2025 14:11:18 +0200
Subject: [PATCH 1/6] in progress fshr
---
llvm/lib/Analysis/DemandedBits.cpp | 42 ++++
llvm/test/Analysis/DemandedBits/fshr-fshl.ll | 201 +++++++++++++++++++
2 files changed, 243 insertions(+)
create mode 100644 llvm/test/Analysis/DemandedBits/fshr-fshl.ll
diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index e0881751aef7e..f3de058299292 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -153,6 +153,48 @@ void DemandedBits::determineLiveOperandBits(
AB = AOut.lshr(ShiftAmt);
else if (OperandNo == 1)
AB = AOut.shl(BitWidth - ShiftAmt);
+ } else {
+ ComputeKnownBits(BitWidth, UserI->getOperand(2), nullptr);
+ if (!Known.getMaxValue().ult(BitWidth)) {
+ AB = APInt::getAllOnes(BitWidth);
+ return;
+ }
+ uint64_t Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
+ uint64_t Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
+ bool IsFShl = II->getIntrinsicID() == Intrinsic::fshl;
+ bool ShiftLeft;
+ uint64_t SMin = Min, SMax = Max;
+ // fshl(a, b, k ) is defined by concatenating a . b
+ // then doing a left shift by k and then extracting the upper bits.
+ // For BW = 4, k = 2 we have
+ // a4 a3 a2 a1 b4 b3 b2 b1, shift by k = 2 we get
+ // a2 a1 b4 b3.
+ // fshl(a,b,k) = (a << k) | (b >> (BW - k))
+ //
+ // Suppose AOut == 0b0000 0001
+ // [min, max] = [1, 3]
+ // iteration 1 shift by 1 mask is 0b0000 0011
+ // iteration 2 shift by 2 mask is 0b0000 1111
+ // iteration 3, shiftAmnt = 4 > max - min, we stop.
+ //
+ // fshr is defined in a similar way from fshl.
+ // a16 a15 .. a2 a1 b16 b15 ... b2 b1
+ //
+ // doing a right shift by (bw - k) and then extracting the lower bits.
+ // a4 a3 a2 a1 b4 b3 b2 b1, shift right by k = 2 we get
+ // a4 a3 a2 a1 b4 b3, then exracting the lower bits
+ // a2 a1 b4 b3
+ // fshr(a,b,k) = (a >> k) | (b << (BW - k))
+ //
+ if (OperandNo == 0) {
+ // We shift left for a only for fshr
+ ShiftLeft = !IsFShl;
+ } else {
+ SMin = BitWidth - Max;
+ SMax = BitWidth - Min;
+ ShiftLeft = IsFShl;
+ }
+ GetShiftedRange(SMin, SMax, ShiftLeft);
}
break;
}
diff --git a/llvm/test/Analysis/DemandedBits/fshr-fshl.ll b/llvm/test/Analysis/DemandedBits/fshr-fshl.ll
new file mode 100644
index 0000000000000..a8c9aba4d7bab
--- /dev/null
+++ b/llvm/test/Analysis/DemandedBits/fshr-fshl.ll
@@ -0,0 +1,201 @@
+; RUN: opt -S -disable-output -passes="print<demanded-bits>" < %s 2>&1 | FileCheck %s
+declare i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+declare i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+
+
+define i8 @test_lshr_const_amount_4(i32 %a) {
+; CHECK-LABEL: 'test_lshr_const_amount_4'
+; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 4
+; CHECK-DAG: DemandedBits: 0xff0 for %a in %lshr = lshr i32 %a, 4
+; CHECK-DAG: DemandedBits: 0xffffffff for 4 in %lshr = lshr i32 %a, 4
+;
+ %lshr = lshr i32 %a, 4
+ %lshr.t = trunc i32 %lshr to i8
+ ret i8 %lshr.t
+}
+
+define i8 @test_lshr_const_amount_5(i32 %a) {
+; CHECK-LABEL: 'test_lshr_const_amount_5'
+; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 5
+; CHECK-DAG: DemandedBits: 0x1fe0 for %a in %lshr = lshr i32 %a, 5
+; CHECK-DAG: DemandedBits: 0xffffffff for 5 in %lshr = lshr i32 %a, 5
+; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
+;
+ %lshr = lshr i32 %a, 5
+ %lshr.t = trunc i32 %lshr to i8
+ ret i8 %lshr.t
+}
+define i8 @test_lshr_const_amount_8(i32 %a) {
+; CHECK-LABEL: 'test_lshr_const_amount_8'
+; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 8
+; CHECK-DAG: DemandedBits: 0xff00 for %a in %lshr = lshr i32 %a, 8
+; CHECK-DAG: DemandedBits: 0xffffffff for 8 in %lshr = lshr i32 %a, 8
+;
+ %lshr = lshr i32 %a, 8
+ %lshr.t = trunc i32 %lshr to i8
+ ret i8 %lshr.t
+}
+
+define i8 @test_lshr_const_amount_9(i32 %a) {
+; CHECK-LABEL: 'test_lshr_const_amount_9'
+; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 9
+; CHECK-DAG: DemandedBits: 0x1fe00 for %a in %lshr = lshr i32 %a, 9
+; CHECK-DAG: DemandedBits: 0xffffffff for 9 in %lshr = lshr i32 %a, 9
+;
+ %lshr = lshr i32 %a, 9
+ %lshr.t = trunc i32 %lshr to i8
+ ret i8 %lshr.t
+}
+
+define i8 @test_lshr(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr'
+; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
+;
+ %lshr = lshr i32 %a, %b
+ %lshr.t = trunc i32 %lshr to i8
+ ret i8 %lshr.t
+}
+
+define i8 @test_lshr_range_1(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr_range_1'
+; CHECK-DAG: DemandedBits: 0xff for %shl.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr in %shl.t = trunc i32 %lshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, %b2
+; CHECK-DAG: DemandedBits: 0x7ff for %a in %lshr = lshr i32 %a, %b2
+; CHECK-DAG: DemandedBits: 0xffffffff for %b2 in %lshr = lshr i32 %a, %b2
+; CHECK-DAG: DemandedBits: 0xffffffff for %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x3 for %b in %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0xffffffff for 3 in %b2 = and i32 %b, 3
+;
+ %b2 = and i32 %b, 3
+ %lshr = lshr i32 %a, %b2
+ %shl.t = trunc i32 %lshr to i8
+ ret i8 %shl.t
+}
+
+define i32 @test_lshr_range_2(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr_range_2'
+; CHECK-DAG: DemandedBits: 0xffffffff for %lshr = lshr i32 %a, %b2
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in %lshr = lshr i32 %a, %b2
+; CHECK-DAG: DemandedBits: 0xffffffff for %b2 in %lshr = lshr i32 %a, %b2
+; CHECK-DAG: DemandedBits: 0xffffffff for %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x3 for %b in %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0xffffffff for 3 in %b2 = and i32 %b, 3
+;
+ %b2 = and i32 %b, 3
+ %lshr = lshr i32 %a, %b2
+ ret i32 %lshr
+}
+
+define i32 @test_lshr_range_3(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr_range_3'
+; CHECK-DAG: DemandedBits: 0xffff for %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %shl = shl i32 %lshr, 16
+; CHECK-DAG: DemandedBits: 0xffff for %lshr in %shl = shl i32 %lshr, 16
+; CHECK-DAG: DemandedBits: 0xffffffff for 16 in %shl = shl i32 %lshr, 16
+;
+ %lshr = lshr i32 %a, %b
+ %shl = shl i32 %lshr, 16
+ ret i32 %shl
+}
+
+define i32 @test_lshr_range_4(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr_range_4'
+; CHECK-DAG: DemandedBits: 0xffffff00 for %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffff00 for %a in %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %shr = ashr i32 %lshr, 8
+; CHECK-DAG: DemandedBits: 0xffffff00 for %lshr in %shr = ashr i32 %lshr, 8
+; CHECK-DAG: DemandedBits: 0xffffffff for 8 in %shr = ashr i32 %lshr, 8
+ %lshr = lshr i32 %a, %b
+ %shr = ashr i32 %lshr, 8
+ ret i32 %shr
+}
+
+define i32 @test_lshr_range_5(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr_range_5'
+; CHECK-DAG: DemandedBits: 0xff for %1 = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %2 = and i32 %1, 255
+; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = and i32 %1, 255
+; CHECK-DAG: DemandedBits: 0xffffffff for 255 in %2 = and i32 %1, 255
+;
+ %1 = lshr i32 %a, %b
+ %2 = and i32 %1, 255
+ ret i32 %2
+}
+
+define i32 @test_lshr_range_6(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr_range_6'
+; CHECK-DAG: DemandedBits: 0xffff0000 for %lshr.1 = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffff0000 for %a in %lshr.1 = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr.1 = lshr i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %lshr.2 = lshr i32 %lshr.1, 16
+; CHECK-DAG: DemandedBits: 0xffff0000 for %lshr.1 in %lshr.2 = lshr i32 %lshr.1, 16
+; CHECK-DAG: DemandedBits: 0xffffffff for 16 in %lshr.2 = lshr i32 %lshr.1, 16
+;
+ %lshr.1 = lshr i32 %a, %b
+ %lshr.2 = lshr i32 %lshr.1, 16
+ ret i32 %lshr.2
+}
+
+
+define i8 @test_lshr_var_amount(i32 %a, i32 %b){
+; CHECK-LABEL: 'test_lshr_var_amount'
+; CHECK-DAG: DemandedBits: 0xff for %4 = lshr i32 %1, %3
+; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = lshr i32 %1, %3
+; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = lshr i32 %1, %3
+; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
+; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
+; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
+; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
+;
+ %1 = add nsw i32 %a, %b
+ %2 = trunc i32 %1 to i8
+ %3 = zext i8 %2 to i32
+ %4 = lshr i32 %1, %3
+ %5 = trunc i32 %4 to i8
+ ret i8 %5
+}
+
+define i8 @test_lshr_var_amount_exact(i32 %a, i32 %b){
+ ; CHECK-LABEL 'test_lshr_var_amount_nsw'
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b
+ ; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
+ ; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
+ ; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
+ ; CHECK-DAG: DemandedBits: 0xff for %4 = lshr exact i32 %1, %3
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = lshr exact i32 %1, %3
+ ; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = lshr exact i32 %1, %3
+ ; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
+ ; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
+ ;
+ %1 = add nsw i32 %a, %b
+ %2 = trunc i32 %1 to i8
+ %3 = zext i8 %2 to i32
+ %4 = lshr exact i32 %1, %3
+ %5 = trunc i32 %4 to i8
+ ret i8 %5
+}
>From 9684d973e74b3ddda93cd921fee0b433c1032ace Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Sun, 8 Feb 2026 18:02:52 +0200
Subject: [PATCH 2/6] funnel shift, needs checks
---
llvm/lib/Analysis/DemandedBits.cpp | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index f3de058299292..3b7365f9a3086 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -162,6 +162,7 @@ void DemandedBits::determineLiveOperandBits(
uint64_t Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
uint64_t Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
bool IsFShl = II->getIntrinsicID() == Intrinsic::fshl;
+ bool IsFShr = II->getIntrinsicID() == Intrinsic::fshr;
bool ShiftLeft;
uint64_t SMin = Min, SMax = Max;
// fshl(a, b, k ) is defined by concatenating a . b
@@ -185,14 +186,20 @@ void DemandedBits::determineLiveOperandBits(
// a4 a3 a2 a1 b4 b3, then exracting the lower bits
// a2 a1 b4 b3
// fshr(a,b,k) = (a >> k) | (b << (BW - k))
- //
- if (OperandNo == 0) {
- // We shift left for a only for fshr
- ShiftLeft = !IsFShl;
- } else {
+
+ // Normalize to funnel shift left.
+ if (IsFShr) {
SMin = BitWidth - Max;
SMax = BitWidth - Min;
- ShiftLeft = IsFShl;
+ }
+ if (OperandNo == 0) {
+ ShiftLeft = false;
+ } else if (OperandNo == 1) {
+ ShiftLeft = true;
+ auto NewSMin = BitWidth - SMax;
+ auto NewSMax = BitWidth - SMin;
+ SMin = NewSMin;
+ SMax = NewSMax;
}
GetShiftedRange(SMin, SMax, ShiftLeft);
}
>From 60c43e15dcff90c5f70fdf28ed6c6a9ea0827735 Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Mon, 9 Feb 2026 18:32:38 +0200
Subject: [PATCH 3/6] [DemandedBits] Support non constant shift amounts for
fshl/fshr
---
llvm/lib/Analysis/DemandedBits.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index 3b7365f9a3086..0f56032b4cd68 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -161,7 +161,6 @@ void DemandedBits::determineLiveOperandBits(
}
uint64_t Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
uint64_t Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
- bool IsFShl = II->getIntrinsicID() == Intrinsic::fshl;
bool IsFShr = II->getIntrinsicID() == Intrinsic::fshr;
bool ShiftLeft;
uint64_t SMin = Min, SMax = Max;
>From 6db59f64aff2aa394cc78767b9f1f3b35ec51b12 Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Mon, 9 Feb 2026 19:18:50 +0200
Subject: [PATCH 4/6] removed wrong tests
---
llvm/test/Analysis/DemandedBits/fshr-fshl.ll | 201 -------------------
1 file changed, 201 deletions(-)
delete mode 100644 llvm/test/Analysis/DemandedBits/fshr-fshl.ll
diff --git a/llvm/test/Analysis/DemandedBits/fshr-fshl.ll b/llvm/test/Analysis/DemandedBits/fshr-fshl.ll
deleted file mode 100644
index a8c9aba4d7bab..0000000000000
--- a/llvm/test/Analysis/DemandedBits/fshr-fshl.ll
+++ /dev/null
@@ -1,201 +0,0 @@
-; RUN: opt -S -disable-output -passes="print<demanded-bits>" < %s 2>&1 | FileCheck %s
-declare i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
-declare i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
-
-
-define i8 @test_lshr_const_amount_4(i32 %a) {
-; CHECK-LABEL: 'test_lshr_const_amount_4'
-; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 4
-; CHECK-DAG: DemandedBits: 0xff0 for %a in %lshr = lshr i32 %a, 4
-; CHECK-DAG: DemandedBits: 0xffffffff for 4 in %lshr = lshr i32 %a, 4
-;
- %lshr = lshr i32 %a, 4
- %lshr.t = trunc i32 %lshr to i8
- ret i8 %lshr.t
-}
-
-define i8 @test_lshr_const_amount_5(i32 %a) {
-; CHECK-LABEL: 'test_lshr_const_amount_5'
-; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 5
-; CHECK-DAG: DemandedBits: 0x1fe0 for %a in %lshr = lshr i32 %a, 5
-; CHECK-DAG: DemandedBits: 0xffffffff for 5 in %lshr = lshr i32 %a, 5
-; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
-;
- %lshr = lshr i32 %a, 5
- %lshr.t = trunc i32 %lshr to i8
- ret i8 %lshr.t
-}
-define i8 @test_lshr_const_amount_8(i32 %a) {
-; CHECK-LABEL: 'test_lshr_const_amount_8'
-; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 8
-; CHECK-DAG: DemandedBits: 0xff00 for %a in %lshr = lshr i32 %a, 8
-; CHECK-DAG: DemandedBits: 0xffffffff for 8 in %lshr = lshr i32 %a, 8
-;
- %lshr = lshr i32 %a, 8
- %lshr.t = trunc i32 %lshr to i8
- ret i8 %lshr.t
-}
-
-define i8 @test_lshr_const_amount_9(i32 %a) {
-; CHECK-LABEL: 'test_lshr_const_amount_9'
-; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, 9
-; CHECK-DAG: DemandedBits: 0x1fe00 for %a in %lshr = lshr i32 %a, 9
-; CHECK-DAG: DemandedBits: 0xffffffff for 9 in %lshr = lshr i32 %a, 9
-;
- %lshr = lshr i32 %a, 9
- %lshr.t = trunc i32 %lshr to i8
- ret i8 %lshr.t
-}
-
-define i8 @test_lshr(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr'
-; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %a in %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xff for %lshr.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr in %lshr.t = trunc i32 %lshr to i8
-;
- %lshr = lshr i32 %a, %b
- %lshr.t = trunc i32 %lshr to i8
- ret i8 %lshr.t
-}
-
-define i8 @test_lshr_range_1(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr_range_1'
-; CHECK-DAG: DemandedBits: 0xff for %shl.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr in %shl.t = trunc i32 %lshr to i8
-; CHECK-DAG: DemandedBits: 0xff for %lshr = lshr i32 %a, %b2
-; CHECK-DAG: DemandedBits: 0x7ff for %a in %lshr = lshr i32 %a, %b2
-; CHECK-DAG: DemandedBits: 0xffffffff for %b2 in %lshr = lshr i32 %a, %b2
-; CHECK-DAG: DemandedBits: 0xffffffff for %b2 = and i32 %b, 3
-; CHECK-DAG: DemandedBits: 0x3 for %b in %b2 = and i32 %b, 3
-; CHECK-DAG: DemandedBits: 0xffffffff for 3 in %b2 = and i32 %b, 3
-;
- %b2 = and i32 %b, 3
- %lshr = lshr i32 %a, %b2
- %shl.t = trunc i32 %lshr to i8
- ret i8 %shl.t
-}
-
-define i32 @test_lshr_range_2(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr_range_2'
-; CHECK-DAG: DemandedBits: 0xffffffff for %lshr = lshr i32 %a, %b2
-; CHECK-DAG: DemandedBits: 0xffffffff for %a in %lshr = lshr i32 %a, %b2
-; CHECK-DAG: DemandedBits: 0xffffffff for %b2 in %lshr = lshr i32 %a, %b2
-; CHECK-DAG: DemandedBits: 0xffffffff for %b2 = and i32 %b, 3
-; CHECK-DAG: DemandedBits: 0x3 for %b in %b2 = and i32 %b, 3
-; CHECK-DAG: DemandedBits: 0xffffffff for 3 in %b2 = and i32 %b, 3
-;
- %b2 = and i32 %b, 3
- %lshr = lshr i32 %a, %b2
- ret i32 %lshr
-}
-
-define i32 @test_lshr_range_3(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr_range_3'
-; CHECK-DAG: DemandedBits: 0xffff for %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %a in %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %shl = shl i32 %lshr, 16
-; CHECK-DAG: DemandedBits: 0xffff for %lshr in %shl = shl i32 %lshr, 16
-; CHECK-DAG: DemandedBits: 0xffffffff for 16 in %shl = shl i32 %lshr, 16
-;
- %lshr = lshr i32 %a, %b
- %shl = shl i32 %lshr, 16
- ret i32 %shl
-}
-
-define i32 @test_lshr_range_4(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr_range_4'
-; CHECK-DAG: DemandedBits: 0xffffff00 for %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffff00 for %a in %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %shr = ashr i32 %lshr, 8
-; CHECK-DAG: DemandedBits: 0xffffff00 for %lshr in %shr = ashr i32 %lshr, 8
-; CHECK-DAG: DemandedBits: 0xffffffff for 8 in %shr = ashr i32 %lshr, 8
- %lshr = lshr i32 %a, %b
- %shr = ashr i32 %lshr, 8
- ret i32 %shr
-}
-
-define i32 @test_lshr_range_5(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr_range_5'
-; CHECK-DAG: DemandedBits: 0xff for %1 = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %2 = and i32 %1, 255
-; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = and i32 %1, 255
-; CHECK-DAG: DemandedBits: 0xffffffff for 255 in %2 = and i32 %1, 255
-;
- %1 = lshr i32 %a, %b
- %2 = and i32 %1, 255
- ret i32 %2
-}
-
-define i32 @test_lshr_range_6(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr_range_6'
-; CHECK-DAG: DemandedBits: 0xffff0000 for %lshr.1 = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffff0000 for %a in %lshr.1 = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %b in %lshr.1 = lshr i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %lshr.2 = lshr i32 %lshr.1, 16
-; CHECK-DAG: DemandedBits: 0xffff0000 for %lshr.1 in %lshr.2 = lshr i32 %lshr.1, 16
-; CHECK-DAG: DemandedBits: 0xffffffff for 16 in %lshr.2 = lshr i32 %lshr.1, 16
-;
- %lshr.1 = lshr i32 %a, %b
- %lshr.2 = lshr i32 %lshr.1, 16
- ret i32 %lshr.2
-}
-
-
-define i8 @test_lshr_var_amount(i32 %a, i32 %b){
-; CHECK-LABEL: 'test_lshr_var_amount'
-; CHECK-DAG: DemandedBits: 0xff for %4 = lshr i32 %1, %3
-; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = lshr i32 %1, %3
-; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = lshr i32 %1, %3
-; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
-; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
-; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
-; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
-; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b
-; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
-; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
-;
- %1 = add nsw i32 %a, %b
- %2 = trunc i32 %1 to i8
- %3 = zext i8 %2 to i32
- %4 = lshr i32 %1, %3
- %5 = trunc i32 %4 to i8
- ret i8 %5
-}
-
-define i8 @test_lshr_var_amount_exact(i32 %a, i32 %b){
- ; CHECK-LABEL 'test_lshr_var_amount_nsw'
- ; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b
- ; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b
- ; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b
- ; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
- ; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
- ; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
- ; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
- ; CHECK-DAG: DemandedBits: 0xff for %4 = lshr exact i32 %1, %3
- ; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = lshr exact i32 %1, %3
- ; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = lshr exact i32 %1, %3
- ; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
- ; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
- ;
- %1 = add nsw i32 %a, %b
- %2 = trunc i32 %1 to i8
- %3 = zext i8 %2 to i32
- %4 = lshr exact i32 %1, %3
- %5 = trunc i32 %4 to i8
- ret i8 %5
-}
>From 85b1e728e5a270c62ed03b5c6938118eca0fa381 Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Mon, 9 Feb 2026 20:05:33 +0200
Subject: [PATCH 5/6] fixed non-initialized variable
---
llvm/lib/Analysis/DemandedBits.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index 0f56032b4cd68..3d14d3b21ef74 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -162,7 +162,7 @@ void DemandedBits::determineLiveOperandBits(
uint64_t Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
uint64_t Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
bool IsFShr = II->getIntrinsicID() == Intrinsic::fshr;
- bool ShiftLeft;
+ bool ShiftLeft = false;
uint64_t SMin = Min, SMax = Max;
// fshl(a, b, k ) is defined by concatenating a . b
// then doing a left shift by k and then extracting the upper bits.
>From fa8d43ae1684e9a86847a2345d07712cc7be0850 Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Mon, 9 Feb 2026 20:47:52 +0200
Subject: [PATCH 6/6] fixed wrong smin, smax calculations
---
llvm/lib/Analysis/DemandedBits.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index 3d14d3b21ef74..3061f126a584e 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -188,15 +188,15 @@ void DemandedBits::determineLiveOperandBits(
// Normalize to funnel shift left.
if (IsFShr) {
- SMin = BitWidth - Max;
- SMax = BitWidth - Min;
+ SMin = BitWidth - Max - 1;
+ SMax = BitWidth - Min - 1;
}
if (OperandNo == 0) {
ShiftLeft = false;
} else if (OperandNo == 1) {
ShiftLeft = true;
- auto NewSMin = BitWidth - SMax;
- auto NewSMax = BitWidth - SMin;
+ auto NewSMin = BitWidth - SMax - 1;
+ auto NewSMax = BitWidth - SMin - 1;
SMin = NewSMin;
SMax = NewSMax;
}
More information about the llvm-commits
mailing list