[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