[llvm] [DemandedBits] Support non-constant shift amounts for funnel shifts (PR #180569)

Panagiotis Karouzakis via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 7 18:59:28 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 01/11] 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 02/11] 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 03/11] [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 04/11] 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 05/11] 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 06/11] 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;
           }

>From 6836e0eec2121003d4d923855d91248eb93faa5f Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Mon, 9 Feb 2026 20:58:50 +0200
Subject: [PATCH 07/11] removed getLimitedValue, added getZExtValue

---
 llvm/lib/Analysis/DemandedBits.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index 3061f126a584e..09eca868f86c8 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -159,8 +159,8 @@ void DemandedBits::determineLiveOperandBits(
             AB = APInt::getAllOnes(BitWidth);
             return;
           }
-          uint64_t Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
-          uint64_t Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
+          uint64_t Min = Known.getMinValue().getZExtValue();
+          uint64_t Max = Known.getMaxValue().getZExtValue();
           bool IsFShr = II->getIntrinsicID() == Intrinsic::fshr;
           bool ShiftLeft = false;
           uint64_t SMin = Min, SMax = Max;

>From f60dcdfed44de37eb8b2a32da81dbc34a70bc5bb Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Sun, 15 Feb 2026 16:56:55 +0200
Subject: [PATCH 08/11] added extra cases and simplified logic

---
 llvm/lib/Analysis/DemandedBits.cpp | 43 +++++++++++++++++++-----------
 1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp
index 09eca868f86c8..2282004c5ae2a 100644
--- a/llvm/lib/Analysis/DemandedBits.cpp
+++ b/llvm/lib/Analysis/DemandedBits.cpp
@@ -155,12 +155,13 @@ void DemandedBits::determineLiveOperandBits(
             AB = AOut.shl(BitWidth - ShiftAmt);
         } else {
           ComputeKnownBits(BitWidth, UserI->getOperand(2), nullptr);
-          if (!Known.getMaxValue().ult(BitWidth)) {
+          APInt APIntMax = Known.getMaxValue();
+          if (!APIntMax.ult(BitWidth)) {
             AB = APInt::getAllOnes(BitWidth);
             return;
           }
           uint64_t Min = Known.getMinValue().getZExtValue();
-          uint64_t Max = Known.getMaxValue().getZExtValue();
+          uint64_t Max = APIntMax.getZExtValue();
           bool IsFShr = II->getIntrinsicID() == Intrinsic::fshr;
           bool ShiftLeft = false;
           uint64_t SMin = Min, SMax = Max;
@@ -186,21 +187,33 @@ void DemandedBits::determineLiveOperandBits(
           // a2 a1 b4 b3
           // fshr(a,b,k) = (a >> k) | (b << (BW - k))
 
-          // Normalize to funnel shift left.
-          if (IsFShr) {
-            SMin = BitWidth - Max - 1;
-            SMax = BitWidth - Min - 1;
+          // Skip poison shifts.
+          if (((IsFShr && OperandNo == 0) || (!IsFShr && OperandNo == 1)) &&
+              Min == 0) {
+            AB = APInt::getAllOnes(BitWidth);
+            return;
           }
-          if (OperandNo == 0) {
-            ShiftLeft = false;
-          } else if (OperandNo == 1) {
-            ShiftLeft = true;
-            auto NewSMin = BitWidth - SMax - 1;
-            auto NewSMax = BitWidth - SMin - 1;
-            SMin = NewSMin;
-            SMax = NewSMax;
+
+          // IsFSHR and Op1 == ShiftLeft: true
+          // IsFSHR and Op0 == ShiftLeft: false
+          // !IsFSHR and Op0 == ShiftLeft: false
+          // !IsFShr and Op1 == ShiftLeft: true;
+          ShiftLeft = OperandNo == 1;
+
+          // ComplementShit
+          // ISFSHR and Op0 == True.
+          // ISFSHR and Op1 == False.
+          // !ISFSHR and Op0 == False.
+          // !ISFSHR and Op1 == true;
+          bool ComplementShift = IsFShr ^ (OperandNo == 1);
+
+          if (ComplementShift) {
+            SMin = BitWidth - Max;
+            SMax = BitWidth - Min;
+            Min = SMin;
+            Max = SMax;
           }
-          GetShiftedRange(SMin, SMax, ShiftLeft);
+          GetShiftedRange(Min, Max, ShiftLeft);
         }
         break;
       }

>From 94b3e423e3a5338580eac2540a92513968c2bb8e Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Sat, 7 Mar 2026 07:23:00 +0200
Subject: [PATCH 09/11] added missing tests on fshl and fshr

---
 llvm/test/Analysis/DemandedBits/fshl.ll | 206 ++++++++++++++++++++++++
 llvm/test/Analysis/DemandedBits/fshr.ll | 203 +++++++++++++++++++++++
 2 files changed, 409 insertions(+)
 create mode 100644 llvm/test/Analysis/DemandedBits/fshl.ll
 create mode 100644 llvm/test/Analysis/DemandedBits/fshr.ll

diff --git a/llvm/test/Analysis/DemandedBits/fshl.ll b/llvm/test/Analysis/DemandedBits/fshl.ll
new file mode 100644
index 0000000000000..6daa9b8b3be42
--- /dev/null
+++ b/llvm/test/Analysis/DemandedBits/fshl.ll
@@ -0,0 +1,206 @@
+; RUN: opt -S -disable-output -passes="print<demanded-bits>" < %s 2>&1 | FileCheck %s
+
+declare i32  @llvm.fshl.i32 (i32 %a, i32 %b, i32 %c)
+
+
+define i8 @test_fshl_const_amount_4(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshl_const_amount_4'
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshl in   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0xf for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0xf0000000 for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0x1f for 4 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 4)
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 4)
+  %tr = trunc i32 %fshl to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshl_const_amount_5(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshl_const_amount_5'
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshl in   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0x7 for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0xf8000000 for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0x1f for 5 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 5)
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 5)
+  %tr = trunc i32 %fshl to i8
+  ret i8 %tr
+
+
+}
+
+define i8 @test_fshl_const_amount_8(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshl_const_amount_8'
+;
+; CHECK-DAG: DemandedBits: 0xff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0x0 for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xff000000 for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0x1f for 8 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshl in   %tr = trunc i32 %fshl to i8
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 8)
+  %tr = trunc i32 %fshl to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshl_const_amount_9(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshl_const_amount_9'
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshl in   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 9)
+; CHECK-DAG: DemandedBits: 0x0 for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 9)
+; CHECK-DAG: DemandedBits: 0x7f800000 for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 9)
+; CHECK-DAG: DemandedBits: 0x1f for 9 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 9)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 9)
+
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 9)
+  %tr = trunc i32 %fshl to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshl(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshl'
+;
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshl in   %tr = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+  %tr = trunc i32 %fshl to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshl_range_1(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshl_range_1'
+; CHECK-DAG: DemandedBits: 0xff for   %shl.t = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshl in   %shl.t = trunc i32 %fshl to i8
+; CHECK-DAG: DemandedBits: 0x1f for   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x3 for %b in   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x1f for 3 in   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0xff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xff for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0x1f for %b2 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+;
+  %b2 = and i32 %b, 3
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+  %shl.t = trunc i32 %fshl to i8
+  ret i8 %shl.t
+}
+
+define i32 @test_fshl_range_2(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshl_range_2'
+; CHECK-DAG: DemandedBits: 0xffffffff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0x1f for %b2 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0x1f for   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x3 for %b in   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x1f for 3 in   %b2 = and i32 %b, 3
+;
+  %b2 = and i32 %b, 3
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %b2)
+  ret i32 %fshl
+}
+
+define i32 @test_fshl_range_3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshl_range_3'
+; CHECK-DAG: DemandedBits: 0xffff for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for   %shl = shl i32 %fshl, 16
+; CHECK-DAG: DemandedBits: 0xffff for %fshl in   %shl = shl i32 %fshl, 16
+; CHECK-DAG: DemandedBits: 0xffffffff for 16 in   %shl = shl i32 %fshl, 16
+;
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+  %shl = shl i32 %fshl, 16
+  ret i32 %shl
+}
+
+define i32 @test_fshl_range_4(i32 %a, i32 %b, i32 %c) {
+; CHECK-DAG: DemandedBits: 0xffffff00 for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for   %shr = ashr i32 %fshl, 8
+; CHECK-DAG: DemandedBits: 0xffffff00 for %fshl in   %shr = ashr i32 %fshl, 8
+; CHECK-DAG: DemandedBits: 0xffffffff for 8 in   %shr = ashr i32 %fshl, 8
+
+
+; CHECK-LABEL: 'test_fshl_range_4'
+  %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+  %shr = ashr i32 %fshl, 8
+  ret i32 %shr
+}
+
+define i32 @test_fshl_range_5(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshl_range_5'
+; CHECK-DAG: DemandedBits: 0xff for   %1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; 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 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+  %2 = and i32 %1, 255
+  ret i32 %2
+}
+
+define i32 @test_fshl_range_6(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshl_range_6'
+; CHECK-DAG: DemandedBits: 0xffff for   %fshl.1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshl.1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshl.1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshl.1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl.1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for   %fshl.2 = call i32 @llvm.fshl.i32(i32 %fshl.1, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0xffff for %fshl.1 in   %fshl.2 = call i32 @llvm.fshl.i32(i32 %fshl.1, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0xffff0000 for %b in   %fshl.2 = call i32 @llvm.fshl.i32(i32 %fshl.1, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0x1f for 16 in   %fshl.2 = call i32 @llvm.fshl.i32(i32 %fshl.1, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl.2 = call i32 @llvm.fshl.i32(i32 %fshl.1, i32 %b, i32 16)
+;
+  %fshl.1 = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
+  %fshl.2 = call i32 @llvm.fshl.i32(i32 %fshl.1, i32 %b, i32 16)
+
+  ret i32 %fshl.2
+}
+
+define i8 @test_fshl_var_amount(i32 %a, i32 %b, i32 %c){
+; CHECK-LABEL: 'test_fshl_var_amount'
+; 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: 0xff for   %4 = call i32 @llvm.fshl.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %4 = call i32 @llvm.fshl.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0xffffffff for %c in   %4 = call i32 @llvm.fshl.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0x1f for %3 in   %4 = call i32 @llvm.fshl.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %4 = call i32 @llvm.fshl.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0x1f for   %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0x1f for %a in   %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0x1f for %b in   %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0x1f for   %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0x1f for %2 in   %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0x1f for   %2 = trunc i32 %1 to i8
+; CHECK-DAG: DemandedBits: 0x1f 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 = call i32 @llvm.fshl.i32(i32 %a, i32 %c, i32 %3)
+  %5 = trunc i32 %4 to i8
+  ret i8 %5
+}
diff --git a/llvm/test/Analysis/DemandedBits/fshr.ll b/llvm/test/Analysis/DemandedBits/fshr.ll
new file mode 100644
index 0000000000000..9a2b4509f0bd8
--- /dev/null
+++ b/llvm/test/Analysis/DemandedBits/fshr.ll
@@ -0,0 +1,203 @@
+; RUN: opt -S -disable-output -passes="print<demanded-bits>" < %s 2>&1 | FileCheck %s
+
+declare i32  @llvm.fshl.i32 (i32 %a, i32 %b, i32 %c)
+
+declare i32  @llvm.fshr.i32 (i32 %a, i32 %b, i32 %c)
+
+
+define i8 @test_fshr_const_amount_4(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshr_const_amount_4'
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshr in   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0x0 for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0xff0 for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0x1f for 4 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 4)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 4)
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 4)
+  %tr = trunc i32 %fshr to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshr_const_amount_5(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshr_const_amount_5'
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshr in   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0x0 for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0x1fe0 for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0x1f for 5 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 5)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 5)
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 5)
+  %tr = trunc i32 %fshr to i8
+  ret i8 %tr
+
+
+}
+
+define i8 @test_fshr_const_amount_8(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshr_const_amount_8'
+; CHECK-DAG: DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0x0 for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xff00 for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0x1f for 8 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshr in   %tr = trunc i32 %fshr to i8
+;
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+  %tr = trunc i32 %fshr to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshr_const_amount_9(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_fshr_const_amount_9'
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshr in   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0x0 for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xff00 for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0x1f for 8 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+;
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 8)
+  %tr = trunc i32 %fshr to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshr(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshr'
+; CHECK-DAG: DemandedBits: 0xff for   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshr in   %tr = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+;
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+  %tr = trunc i32 %fshr to i8
+  ret i8 %tr
+}
+
+define i8 @test_fshr_range_1(i32 %a, i32 %b) {
+; CHECK-LABEL: 'test_lshr_range_1'
+; CHECK-DAG:  DemandedBits: 0xff for   %shl.t = trunc i32 %fshr to i8
+; CHECK-DAG:  DemandedBits: 0xff for %fshr in   %shl.t = trunc i32 %fshr to i8
+; CHECK-DAG:  DemandedBits: 0x1f for   %b2 = and i32 %b, 3
+; CHECK-DAG:  DemandedBits: 0x3 for %b in   %b2 = and i32 %b, 3
+; CHECK-DAG:  DemandedBits: 0x1f for 3 in   %b2 = and i32 %b, 3
+; CHECK-DAG:  DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG:  DemandedBits: 0xffffffff for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG:  DemandedBits: 0x7ff for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG:  DemandedBits: 0x1f for %b2 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG:  DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+;
+  %b2 = and i32 %b, 3
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+  %shl.t = trunc i32 %fshr 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:  0x1f for   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x3 for %b in   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x1f for 3 in   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0xffffffff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0x1f for %b2 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+;
+  %b2 = and i32 %b, 3
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+  ret i32 %fshr
+}
+
+define i32 @test_fshr_range_3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshr_range_3'
+; CHECK-DAG: DemandedBits: 0xffff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for   %shl = shl i32 %fshr, 16
+; CHECK-DAG: DemandedBits: 0xffff for %fshr in   %shl = shl i32 %fshr, 16
+; CHECK-DAG: DemandedBits: 0xffffffff for 16 in   %shl = shl i32 %fshr, 16
+;
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+  %shl = shl i32 %fshr, 16
+  ret i32 %shl
+}
+
+define i32 @test_fshr_range_4(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshr_range_4'
+; CHECK-DAG: DemandedBits: 0xffffff00 for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG: DemandedBits: 0xffffffff for   %shr = ashr i32 %fshr, 8
+; CHECK-DAG: DemandedBits: 0xffffff00 for %fshr in   %shr = ashr i32 %fshr, 8
+; CHECK-DAG: DemandedBits: 0xffffffff for 8 in   %shr = ashr i32 %fshr, 8
+
+  %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+  %shr = ashr i32 %fshr, 8
+  ret i32 %shr
+}
+
+define i32 @test_lshr_range_5(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_lshr_range_5'
+; CHECK-DAG:  DemandedBits: 0xff for   %1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG:  DemandedBits: 0xffffffff for %a in   %1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG:  DemandedBits: 0xffffffff for %b in   %1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG:  DemandedBits: 0x1f for %c in   %1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; CHECK-DAG:  DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+; 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 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+  %2 = and i32 %1, 255
+  ret i32 %2
+}
+
+define i32 @test_fshr_range_6(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshr_range_6'
+; CHECK-DAG: DemandedBits: 0xffffffff for   %fshr.2 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0xffff for %a in   %fshr.2 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0xffff0000 for %b in   %fshr.2 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0x1f for 16 in   %fshr.2 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 16)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr.2 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 16)
+;
+  %fshr.1 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %c)
+  %fshr.2 = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 16)
+
+  ret i32 %fshr.2
+}
+
+define i8 @test_lshr_var_amount(i32 %a, i32 %b, i32 %c){
+; CHECK-LABEL: 'test_lshr_var_amount'
+; CHECK-DAG: DemandedBits: 0x1f for   %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0x1f for %a in   %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0x1f for %b in   %1 = add nsw i32 %a, %b
+; CHECK-DAG: DemandedBits: 0x1f for   %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0x1f for %2 in   %3 = zext i8 %2 to i32
+; CHECK-DAG: DemandedBits: 0x1f for   %2 = trunc i32 %1 to i8
+; CHECK-DAG: DemandedBits: 0x1f for %1 in   %2 = trunc i32 %1 to i8
+; 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: 0xff for   %4 = call i32 @llvm.fshr.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %4 = call i32 @llvm.fshr.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0xffffffff for %c in   %4 = call i32 @llvm.fshr.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0x1f for %3 in   %4 = call i32 @llvm.fshr.i32(i32 %a, i32 %c, i32 %3)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %4 = call i32 @llvm.fshr.i32(i32 %a, i32 %c, i32 %3)
+;
+  %1 = add nsw i32 %a, %b
+  %2 = trunc i32 %1 to i8
+  %3 = zext i8 %2 to i32
+  %4 = call i32 @llvm.fshr.i32(i32 %a, i32 %c, i32 %3)
+  %5 = trunc i32 %4 to i8
+  ret i8 %5
+}

>From ccd0b529c8fd74470cf8aa211d3cf6dbcefabfa9 Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Sun, 8 Mar 2026 03:53:59 +0200
Subject: [PATCH 10/11] fixed test errors

---
 llvm/test/Analysis/DemandedBits/fshl.ll |  9 +++++----
 llvm/test/Analysis/DemandedBits/fshr.ll | 23 ++++++++++++-----------
 2 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/llvm/test/Analysis/DemandedBits/fshl.ll b/llvm/test/Analysis/DemandedBits/fshl.ll
index 6daa9b8b3be42..34ee3ebafd478 100644
--- a/llvm/test/Analysis/DemandedBits/fshl.ll
+++ b/llvm/test/Analysis/DemandedBits/fshl.ll
@@ -129,16 +129,17 @@ define i32 @test_fshl_range_3(i32 %a, i32 %b, i32 %c) {
   ret i32 %shl
 }
 
+
+
 define i32 @test_fshl_range_4(i32 %a, i32 %b, i32 %c) {
+; CHECK-DAG: DemandedBits: 0xffffffff for   %shr = ashr i32 %fshl, 8
+; CHECK-DAG: DemandedBits: 0xffffff00 for %fshl in   %shr = ashr i32 %fshl, 8
+; CHECK-DAG: DemandedBits: 0xffffffff for 8 in   %shr = ashr i32 %fshl, 8
 ; CHECK-DAG: DemandedBits: 0xffffff00 for   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
 ; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
 ; CHECK-DAG: DemandedBits: 0xffffffff for %b in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
 ; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
 ; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
-; CHECK-DAG: DemandedBits: 0xffffffff for   %shr = ashr i32 %fshl, 8
-; CHECK-DAG: DemandedBits: 0xffffff00 for %fshl in   %shr = ashr i32 %fshl, 8
-; CHECK-DAG: DemandedBits: 0xffffffff for 8 in   %shr = ashr i32 %fshl, 8
-
 
 ; CHECK-LABEL: 'test_fshl_range_4'
   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
diff --git a/llvm/test/Analysis/DemandedBits/fshr.ll b/llvm/test/Analysis/DemandedBits/fshr.ll
index 9a2b4509f0bd8..ba311ee4082eb 100644
--- a/llvm/test/Analysis/DemandedBits/fshr.ll
+++ b/llvm/test/Analysis/DemandedBits/fshr.ll
@@ -81,17 +81,18 @@ define i8 @test_fshr(i32 %a, i32 %b, i32 %c) {
 }
 
 define i8 @test_fshr_range_1(i32 %a, i32 %b) {
-; CHECK-LABEL: 'test_lshr_range_1'
-; CHECK-DAG:  DemandedBits: 0xff for   %shl.t = trunc i32 %fshr to i8
-; CHECK-DAG:  DemandedBits: 0xff for %fshr in   %shl.t = trunc i32 %fshr to i8
-; CHECK-DAG:  DemandedBits: 0x1f for   %b2 = and i32 %b, 3
-; CHECK-DAG:  DemandedBits: 0x3 for %b in   %b2 = and i32 %b, 3
-; CHECK-DAG:  DemandedBits: 0x1f for 3 in   %b2 = and i32 %b, 3
-; CHECK-DAG:  DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
-; CHECK-DAG:  DemandedBits: 0xffffffff for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
-; CHECK-DAG:  DemandedBits: 0x7ff for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
-; CHECK-DAG:  DemandedBits: 0x1f for %b2 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
-; CHECK-DAG:  DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-LABEL: 'test_fshr_range_1'
+; CHECK-DAG: DemandedBits: 0xff for   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffff for %a in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0x7ff for %b in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0x1f for %b2 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshr.i32 in   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)
+; CHECK-DAG: DemandedBits: 0x1f for   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x3 for %b in   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0x1f for 3 in   %b2 = and i32 %b, 3
+; CHECK-DAG: DemandedBits: 0xff for   %shl.t = trunc i32 %fshr to i8
+; CHECK-DAG: DemandedBits: 0xff for %fshr in   %shl.t = trunc i32 %fshr to i8
+
 ;
   %b2 = and i32 %b, 3
   %fshr = call i32 @llvm.fshr.i32(i32 %a, i32 %b, i32 %b2)

>From 65cc5610bac847181c9157120ca152fc3fdfc3c3 Mon Sep 17 00:00:00 2001
From: Panagiotis Karouzakis <karouzakispan at gmail.com>
Date: Sun, 8 Mar 2026 04:59:09 +0200
Subject: [PATCH 11/11] small test fixes

---
 llvm/test/Analysis/DemandedBits/fshl.ll | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/test/Analysis/DemandedBits/fshl.ll b/llvm/test/Analysis/DemandedBits/fshl.ll
index 34ee3ebafd478..5abfd15bf62b6 100644
--- a/llvm/test/Analysis/DemandedBits/fshl.ll
+++ b/llvm/test/Analysis/DemandedBits/fshl.ll
@@ -132,6 +132,7 @@ define i32 @test_fshl_range_3(i32 %a, i32 %b, i32 %c) {
 
 
 define i32 @test_fshl_range_4(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: 'test_fshl_range_4'
 ; CHECK-DAG: DemandedBits: 0xffffffff for   %shr = ashr i32 %fshl, 8
 ; CHECK-DAG: DemandedBits: 0xffffff00 for %fshl in   %shr = ashr i32 %fshl, 8
 ; CHECK-DAG: DemandedBits: 0xffffffff for 8 in   %shr = ashr i32 %fshl, 8
@@ -141,7 +142,7 @@ define i32 @test_fshl_range_4(i32 %a, i32 %b, i32 %c) {
 ; CHECK-DAG: DemandedBits: 0x1f for %c in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
 ; CHECK-DAG: DemandedBits: 0xffffffffffffffff for @llvm.fshl.i32 in   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
 
-; CHECK-LABEL: 'test_fshl_range_4'
+
   %fshl = call i32 @llvm.fshl.i32(i32 %a, i32 %b, i32 %c)
   %shr = ashr i32 %fshl, 8
   ret i32 %shr



More information about the llvm-commits mailing list