[llvm] [KnownBits] Add fast path for udiv by pow2 and overloads for shift ops by constant (PR #189779)

Max Graey via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 2 11:50:37 PDT 2026


https://github.com/MaxGraey updated https://github.com/llvm/llvm-project/pull/189779

>From bc71364b702b686d437e63bd8fb043ff3d001a6b Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Wed, 1 Apr 2026 03:48:37 +0300
Subject: [PATCH 01/17] add fast-path for KnownBits::udiv when RHS is contant

---
 llvm/lib/Support/KnownBits.cpp | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 07e7781d0839d..5809fff3ad6ab 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -1209,6 +1209,20 @@ KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS,
     return Known;
   }
 
+  if (RHS.isConstant()) {
+    const APInt Divisor = RHS.getConstant();
+    if (Divisor.isOne())
+      return LHS;
+
+    if (Divisor.isPowerOf2()) {
+      unsigned Shift = Divisor.logBase2();
+      KnownBits Known = LHS;
+      Known.One.lshrInPlace(Shift);
+      Known.Zero.lshrInPlace(Shift);
+      return Known;
+    }
+  }
+
   // We can figure out the minimum number of upper zero bits by doing
   // MaxNumerator / MinDenominator. If the Numerator gets smaller or Denominator
   // gets larger, the number of upper zero bits increases.

>From 98fbc0b1f97150ca44a9fe1b4ca9152665c75868 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Wed, 1 Apr 2026 03:56:48 +0300
Subject: [PATCH 02/17] refactor

---
 llvm/lib/Support/KnownBits.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 5809fff3ad6ab..25530d7e46727 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -1216,7 +1216,7 @@ KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS,
 
     if (Divisor.isPowerOf2()) {
       unsigned Shift = Divisor.logBase2();
-      KnownBits Known = LHS;
+      Known = LHS;
       Known.One.lshrInPlace(Shift);
       Known.Zero.lshrInPlace(Shift);
       return Known;

>From f326a707d239257f17684715800cb511c523dda9 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Wed, 1 Apr 2026 05:01:20 +0300
Subject: [PATCH 03/17] fix: preserve high bits of LHS

---
 llvm/lib/Support/KnownBits.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 25530d7e46727..56ec9de6af77e 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -1216,9 +1216,15 @@ KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS,
 
     if (Divisor.isPowerOf2()) {
       unsigned Shift = Divisor.logBase2();
+
+      APInt MaxRes = LHS.getMaxValue().lshr(Shift);
+      unsigned LeadZ = MaxRes.countLeadingZeros();
+
       Known = LHS;
       Known.One.lshrInPlace(Shift);
       Known.Zero.lshrInPlace(Shift);
+      Known.Zero.setHighBits(LeadZ);
+
       return Known;
     }
   }

>From 7c6b11aeec5d951c899adbae80635abd721540e9 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Wed, 1 Apr 2026 11:31:59 +0300
Subject: [PATCH 04/17] update mir tests

---
 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sdiv.mir | 4 ++--
 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-udiv.mir | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sdiv.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sdiv.mir
index 7b315205bc2e8..ae56e9097c99f 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sdiv.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sdiv.mir
@@ -8,7 +8,7 @@ body: |
   ; CHECK-LABEL: name: @Cst
   ; CHECK-NEXT: %0:_ KnownBits:01100100 SignBits:1
   ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5
-  ; CHECK-NEXT: %2:_ KnownBits:000????? SignBits:3
+  ; CHECK-NEXT: %2:_ KnownBits:00011001 SignBits:3
     %0:_(s8) = G_CONSTANT i8 100
     %1:_(s8) = G_CONSTANT i8 4
     %2:_(s8) = G_SDIV %0, %1
@@ -36,7 +36,7 @@ body: |
   ; CHECK-LABEL: name: @Exact
   ; CHECK-NEXT: %0:_ KnownBits:00001100 SignBits:4
   ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5
-  ; CHECK-NEXT: %2:_ KnownBits:000000?1 SignBits:6
+  ; CHECK-NEXT: %2:_ KnownBits:00000011 SignBits:6
     %0:_(s8) = G_CONSTANT i8 12
     %1:_(s8) = G_CONSTANT i8 4
     %2:_(s8) = exact G_SDIV %0, %1
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-udiv.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-udiv.mir
index dfbcd3f3c6188..0a0a00ce456ae 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-udiv.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-udiv.mir
@@ -8,7 +8,7 @@ body: |
   ; CHECK-LABEL: name: @Cst
   ; CHECK-NEXT: %0:_ KnownBits:01100100 SignBits:1
   ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5
-  ; CHECK-NEXT: %2:_ KnownBits:000????? SignBits:3
+  ; CHECK-NEXT: %2:_ KnownBits:00011001 SignBits:3
     %0:_(s8) = G_CONSTANT i8 100
     %1:_(s8) = G_CONSTANT i8 4
     %2:_(s8) = G_UDIV %0, %1
@@ -36,7 +36,7 @@ body: |
   ; CHECK-LABEL: name: @Exact
   ; CHECK-NEXT: %0:_ KnownBits:00001100 SignBits:4
   ; CHECK-NEXT: %1:_ KnownBits:00000100 SignBits:5
-  ; CHECK-NEXT: %2:_ KnownBits:000000?1 SignBits:6
+  ; CHECK-NEXT: %2:_ KnownBits:00000011 SignBits:6
     %0:_(s8) = G_CONSTANT i8 12
     %1:_(s8) = G_CONSTANT i8 4
     %2:_(s8) = exact G_UDIV %0, %1

>From c223b1f1b92bc4d0c4b90e6e7c9b55fe9b7031e0 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Wed, 1 Apr 2026 13:36:25 +0300
Subject: [PATCH 05/17] simplify

---
 llvm/lib/Support/KnownBits.cpp | 24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 56ec9de6af77e..97ae3138356ee 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -1209,24 +1209,12 @@ KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS,
     return Known;
   }
 
-  if (RHS.isConstant()) {
-    const APInt Divisor = RHS.getConstant();
-    if (Divisor.isOne())
-      return LHS;
-
-    if (Divisor.isPowerOf2()) {
-      unsigned Shift = Divisor.logBase2();
-
-      APInt MaxRes = LHS.getMaxValue().lshr(Shift);
-      unsigned LeadZ = MaxRes.countLeadingZeros();
-
-      Known = LHS;
-      Known.One.lshrInPlace(Shift);
-      Known.Zero.lshrInPlace(Shift);
-      Known.Zero.setHighBits(LeadZ);
-
-      return Known;
-    }
+  if (RHS.isConstant() && RHS.getConstant().isPowerOf2()) {
+    unsigned Shift = RHS.getConstant().logBase2();
+    Known = LHS;
+    Known >>= Shift;
+    Known.Zero.setHighBits(Shift);
+    return Known;
   }
 
   // We can figure out the minimum number of upper zero bits by doing

>From 185302411f5ea48bc3d5c4c48b90566a9da8cb76 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 03:15:09 +0300
Subject: [PATCH 06/17] refactor: intoduce shifted by const KnownBits::lshr and
 KnownBits::ashr versions and reuse it

---
 llvm/include/llvm/Support/KnownBits.h |  8 ++++++
 llvm/lib/Support/KnownBits.cpp        | 38 +++++++++++++--------------
 2 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index d99817dc43e5b..d773339d679cf 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -460,11 +460,19 @@ struct KnownBits {
                                 bool NUW = false, bool NSW = false,
                                 bool ShAmtNonZero = false);
 
+  /// Compute known bits for lshr(LHS, ShiftAmt).
+  /// This is shift by constant variant of lshr(LHS, RHS).
+  LLVM_ABI static KnownBits lshr(const KnownBits &LHS, unsigned ShiftAmt);
+
   /// Compute known bits for lshr(LHS, RHS).
   /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
   LLVM_ABI static KnownBits lshr(const KnownBits &LHS, const KnownBits &RHS,
                                  bool ShAmtNonZero = false, bool Exact = false);
 
+  /// Compute known bits for ashr(LHS, ShiftAmt).
+  /// This is shift by constant variant of ashr(LHS, RHS).
+  LLVM_ABI static KnownBits ashr(const KnownBits &LHS, unsigned ShiftAmt);
+
   /// Compute known bits for ashr(LHS, RHS).
   /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
   LLVM_ABI static KnownBits ashr(const KnownBits &LHS, const KnownBits &RHS,
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 97ae3138356ee..fb1a9f8638639 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -488,16 +488,17 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
   return Known;
 }
 
+KnownBits KnownBits::lshr(const KnownBits &LHS, unsigned ShiftAmt) {
+  KnownBits Known = LHS;
+  Known >>= ShiftAmt;
+  // High bits are known zero.
+  Known.Zero.setHighBits(ShiftAmt);
+  return Known;
+}
+
 KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS,
                           bool ShAmtNonZero, bool Exact) {
   unsigned BitWidth = LHS.getBitWidth();
-  auto ShiftByConst = [&](const KnownBits &LHS, unsigned ShiftAmt) {
-    KnownBits Known = LHS;
-    Known >>= ShiftAmt;
-    // High bits are known zero.
-    Known.Zero.setHighBits(ShiftAmt);
-    return Known;
-  };
 
   // Fast path for a common case when LHS is completely unknown.
   KnownBits Known(BitWidth);
@@ -533,7 +534,7 @@ KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS,
     if ((ShiftAmtZeroMask & ShiftAmt) != 0 ||
         (ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
       continue;
-    Known = Known.intersectWith(ShiftByConst(LHS, ShiftAmt));
+    Known = Known.intersectWith(lshr(LHS, ShiftAmt));
     if (Known.isUnknown())
       break;
   }
@@ -544,15 +545,16 @@ KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS,
   return Known;
 }
 
+KnownBits KnownBits::ashr(const KnownBits &LHS, unsigned ShiftAmt) {
+  KnownBits Known = LHS;
+  Known.Zero.ashrInPlace(ShiftAmt);
+  Known.One.ashrInPlace(ShiftAmt);
+  return Known;
+}
+
 KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS,
                           bool ShAmtNonZero, bool Exact) {
   unsigned BitWidth = LHS.getBitWidth();
-  auto ShiftByConst = [&](const KnownBits &LHS, unsigned ShiftAmt) {
-    KnownBits Known = LHS;
-    Known.Zero.ashrInPlace(ShiftAmt);
-    Known.One.ashrInPlace(ShiftAmt);
-    return Known;
-  };
 
   // Fast path for a common case when LHS is completely unknown.
   KnownBits Known(BitWidth);
@@ -592,7 +594,7 @@ KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS,
     if ((ShiftAmtZeroMask & ShiftAmt) != 0 ||
         (ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
       continue;
-    Known = Known.intersectWith(ShiftByConst(LHS, ShiftAmt));
+    Known = Known.intersectWith(ashr(LHS, ShiftAmt));
     if (Known.isUnknown())
       break;
   }
@@ -1210,11 +1212,7 @@ KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS,
   }
 
   if (RHS.isConstant() && RHS.getConstant().isPowerOf2()) {
-    unsigned Shift = RHS.getConstant().logBase2();
-    Known = LHS;
-    Known >>= Shift;
-    Known.Zero.setHighBits(Shift);
-    return Known;
+    return lshr(LHS, RHS.getConstant().logBase2());
   }
 
   // We can figure out the minimum number of upper zero bits by doing

>From a045228f606745445eab57adde4dd3730fb992e1 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 14:39:13 +0300
Subject: [PATCH 07/17] add KnownBits::shl with immidiate shift overload

---
 llvm/include/llvm/Support/KnownBits.h |  5 +++
 llvm/lib/Support/KnownBits.cpp        | 44 ++++++++++++++-------------
 2 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index d773339d679cf..131908d205ddf 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -454,6 +454,11 @@ struct KnownBits {
   /// Compute known bits for abds(LHS, RHS).
   LLVM_ABI static KnownBits abds(KnownBits LHS, KnownBits RHS);
 
+  /// Compute known bits for shl(LHS, ShiftAmt).
+  /// This is shift by constant variant of shl(LHS, RHS).
+  LLVM_ABI static KnownBits shl(const KnownBits &LHS, unsigned ShiftAmt,
+                                bool NUW = false, bool NSW = false);
+
   /// Compute known bits for shl(LHS, RHS).
   /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
   LLVM_ABI static KnownBits shl(const KnownBits &LHS, const KnownBits &RHS,
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index fb1a9f8638639..82bf6c1229960 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -404,29 +404,31 @@ static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
   return MaxValue.getLimitedValue(BitWidth - 1);
 }
 
+KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
+                         bool NSW) {
+  KnownBits Known;
+  bool ShiftedOutZero, ShiftedOutOne;
+  Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
+  Known.Zero.setLowBits(ShiftAmt);
+  Known.One = LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne);
+
+  // All cases returning poison have been handled by MaxShiftAmount already.
+  if (NSW) {
+    if (NUW && ShiftAmt != 0)
+      // NUW means we can assume anything shifted out was a zero.
+      ShiftedOutZero = true;
+
+    if (ShiftedOutZero)
+      Known.makeNonNegative();
+    else if (ShiftedOutOne)
+      Known.makeNegative();
+  }
+  return Known;
+}
+
 KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
                          bool NSW, bool ShAmtNonZero) {
   unsigned BitWidth = LHS.getBitWidth();
-  auto ShiftByConst = [&](const KnownBits &LHS, unsigned ShiftAmt) {
-    KnownBits Known;
-    bool ShiftedOutZero, ShiftedOutOne;
-    Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
-    Known.Zero.setLowBits(ShiftAmt);
-    Known.One = LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne);
-
-    // All cases returning poison have been handled by MaxShiftAmount already.
-    if (NSW) {
-      if (NUW && ShiftAmt != 0)
-        // NUW means we can assume anything shifted out was a zero.
-        ShiftedOutZero = true;
-
-      if (ShiftedOutZero)
-        Known.makeNonNegative();
-      else if (ShiftedOutOne)
-        Known.makeNegative();
-    }
-    return Known;
-  };
 
   // Fast path for a common case when LHS is completely unknown.
   KnownBits Known(BitWidth);
@@ -477,7 +479,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
     if ((ShiftAmtZeroMask & ShiftAmt) != 0 ||
         (ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
       continue;
-    Known = Known.intersectWith(ShiftByConst(LHS, ShiftAmt));
+    Known = Known.intersectWith(shl(LHS, ShiftAmt, NUW, NSW));
     if (Known.isUnknown())
       break;
   }

>From d0314c064c6a1ee0df252ca61331fd4654deac9d Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 15:37:33 +0300
Subject: [PATCH 08/17] fix?

---
 llvm/lib/Support/KnownBits.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 82bf6c1229960..5df6123a9b59b 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -406,7 +406,7 @@ static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
 
 KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
                          bool NSW) {
-  KnownBits Known;
+  KnownBits Known(LHS.getBitWidth());
   bool ShiftedOutZero, ShiftedOutOne;
   Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
   Known.Zero.setLowBits(ShiftAmt);

>From a8f161def7554c3d7ba2cff26982464d4bc741a5 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 16:51:39 +0300
Subject: [PATCH 09/17] refactor KnownBits::shl. Address review comments

---
 llvm/lib/Support/KnownBits.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 5df6123a9b59b..15483f00c5b21 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -406,13 +406,13 @@ static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
 
 KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
                          bool NSW) {
-  KnownBits Known(LHS.getBitWidth());
   bool ShiftedOutZero, ShiftedOutOne;
-  Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
+  KnownBits Known(LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero),
+                  LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne));
   Known.Zero.setLowBits(ShiftAmt);
-  Known.One = LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne);
 
-  // All cases returning poison have been handled by MaxShiftAmount already.
+  // This part assumes a valid shift amount and does not check for
+  // cases that would result in poison.
   if (NSW) {
     if (NUW && ShiftAmt != 0)
       // NUW means we can assume anything shifted out was a zero.

>From 4069ae9ff0d4d66f48b56f398acab41cc28a06a3 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 17:35:07 +0300
Subject: [PATCH 10/17] simplify KnownBits add self add path by reusing new
 overloaded KnownBits::shl

---
 llvm/include/llvm/Support/KnownBits.h | 3 +--
 llvm/lib/Support/KnownBits.cpp        | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index 131908d205ddf..4041e82c04f97 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -368,8 +368,7 @@ struct KnownBits {
       // Shift amount bitwidth is independent of src bitwidth (and we're
       // just shifting by one so don't have any bounds issues).
       assert(LHS == RHS && "Expected matching knownbits");
-      KnownBits Amt = KnownBits::makeConstant(APInt(8, 1));
-      return KnownBits::shl(LHS, Amt, NUW, NSW, /*ShAmtNonZero=*/true);
+      return KnownBits::shl(LHS, 1, NUW, NSW);
     }
     return computeForAddSub(/*Add=*/true, NSW, NUW, LHS, RHS);
   }
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 15483f00c5b21..5e283758cade3 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -1213,9 +1213,8 @@ KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS,
     return Known;
   }
 
-  if (RHS.isConstant() && RHS.getConstant().isPowerOf2()) {
+  if (RHS.isConstant() && RHS.getConstant().isPowerOf2())
     return lshr(LHS, RHS.getConstant().logBase2());
-  }
 
   // We can figure out the minimum number of upper zero bits by doing
   // MaxNumerator / MinDenominator. If the Numerator gets smaller or Denominator

>From ad7223a3b843cc3c12da7fdeff307eb20cb0b78e Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 17:40:50 +0300
Subject: [PATCH 11/17] add more usages for new overloaded shift ops

---
 .../Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 28cfa55b968dc..d25e9e3a8c7da 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -787,8 +787,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Instruction *I,
       if (SimplifyDemandedBits(I, 0, DemandedMaskIn, Known, Q, Depth + 1))
         return I;
 
-      Known = KnownBits::shl(Known,
-                             KnownBits::makeConstant(APInt(BitWidth, ShiftAmt)),
+      Known = KnownBits::shl(Known, ShiftAmt,
                              /* NUW */ IOp->hasNoUnsignedWrap(),
                              /* NSW */ IOp->hasNoSignedWrap());
     } else {
@@ -931,9 +930,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Instruction *I,
         return InsertNewInstWith(LShr, I->getIterator());
       }
 
-      Known = KnownBits::ashr(
-          Known, KnownBits::makeConstant(APInt(BitWidth, ShiftAmt)),
-          ShiftAmt != 0, I->isExact());
+      Known = KnownBits::ashr(Known, ShiftAmt, ShiftAmt != 0, I->isExact());
     } else {
       llvm::computeKnownBits(I, Known, Q, Depth);
     }

>From 56fda86c855ca111f87d82ea42ca065c6472b10f Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 17:46:23 +0300
Subject: [PATCH 12/17] fix

---
 llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index d25e9e3a8c7da..7be7c2f12e355 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -930,7 +930,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Instruction *I,
         return InsertNewInstWith(LShr, I->getIterator());
       }
 
-      Known = KnownBits::ashr(Known, ShiftAmt, ShiftAmt != 0, I->isExact());
+      Known = KnownBits::ashr(Known, ShiftAmt);
     } else {
       llvm::computeKnownBits(I, Known, Q, Depth);
     }

>From c6e05d3ae9194ad660019e52d83df5e608cef54e Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 21:01:52 +0300
Subject: [PATCH 13/17] use fallback to general version for overloaded

---
 llvm/lib/Support/KnownBits.cpp | 50 +++++++++++++++++++---------------
 1 file changed, 28 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 5e283758cade3..5748dfb21e7c0 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -404,31 +404,37 @@ static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
   return MaxValue.getLimitedValue(BitWidth - 1);
 }
 
-KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
-                         bool NSW) {
-  bool ShiftedOutZero, ShiftedOutOne;
-  KnownBits Known(LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero),
-                  LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne));
-  Known.Zero.setLowBits(ShiftAmt);
-
-  // This part assumes a valid shift amount and does not check for
-  // cases that would result in poison.
-  if (NSW) {
-    if (NUW && ShiftAmt != 0)
-      // NUW means we can assume anything shifted out was a zero.
-      ShiftedOutZero = true;
-
-    if (ShiftedOutZero)
-      Known.makeNonNegative();
-    else if (ShiftedOutOne)
-      Known.makeNegative();
-  }
-  return Known;
+KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt,
+                         bool NUW, bool NSW) {
+  // TODO: This is simple fallback to generic RHS-based shl.
+  // Add a specialized constant-shift implementation with identical semantics.
+  KnownBits RHS = KnownBits::makeConstant(APInt(LHS.getBitWidth(), ShiftAmt));
+  return shl(LHS, RHS, NUW, NSW);
 }
 
 KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
                          bool NSW, bool ShAmtNonZero) {
   unsigned BitWidth = LHS.getBitWidth();
+  auto ShiftByConst = [&](const KnownBits &LHS, unsigned ShiftAmt) {
+    KnownBits Known;
+    bool ShiftedOutZero, ShiftedOutOne;
+    Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
+    Known.Zero.setLowBits(ShiftAmt);
+    Known.One = LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne);
+
+    // All cases returning poison have been handled by MaxShiftAmount already.
+    if (NSW) {
+      if (NUW && ShiftAmt != 0)
+        // NUW means we can assume anything shifted out was a zero.
+        ShiftedOutZero = true;
+
+      if (ShiftedOutZero)
+        Known.makeNonNegative();
+      else if (ShiftedOutOne)
+        Known.makeNegative();
+    }
+    return Known;
+  };
 
   // Fast path for a common case when LHS is completely unknown.
   KnownBits Known(BitWidth);
@@ -454,7 +460,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
         MaxShiftAmount,
         std::max(LHS.countMaxLeadingZeros(), LHS.countMaxLeadingOnes()) - 1);
 
-  // Fast path for common case where the shift amount is unknown.
+   // Fast path for common case where the shift amount is unknown.
   if (MinShiftAmount == 0 && MaxShiftAmount == BitWidth - 1 &&
       isPowerOf2_32(BitWidth)) {
     Known.Zero.setLowBits(LHS.countMinTrailingZeros());
@@ -479,7 +485,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
     if ((ShiftAmtZeroMask & ShiftAmt) != 0 ||
         (ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
       continue;
-    Known = Known.intersectWith(shl(LHS, ShiftAmt, NUW, NSW));
+    Known = Known.intersectWith(ShiftByConst(LHS, ShiftAmt));
     if (Known.isUnknown())
       break;
   }

>From 1a099f1280bb6526cf5e8943f04bdf364718b55d Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 21:06:14 +0300
Subject: [PATCH 14/17] format fix

---
 llvm/lib/Support/KnownBits.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 5748dfb21e7c0..f4eb5fb946475 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -460,7 +460,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
         MaxShiftAmount,
         std::max(LHS.countMaxLeadingZeros(), LHS.countMaxLeadingOnes()) - 1);
 
-   // Fast path for common case where the shift amount is unknown.
+  // Fast path for common case where the shift amount is unknown.
   if (MinShiftAmount == 0 && MaxShiftAmount == BitWidth - 1 &&
       isPowerOf2_32(BitWidth)) {
     Known.Zero.setLowBits(LHS.countMinTrailingZeros());

>From a1897b0f9bed0b2e2b1bd4a4d71274e9c9efd414 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 21:06:54 +0300
Subject: [PATCH 15/17] format fix

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

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index f4eb5fb946475..8c58ef1db8af3 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -404,8 +404,8 @@ static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
   return MaxValue.getLimitedValue(BitWidth - 1);
 }
 
-KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt,
-                         bool NUW, bool NSW) {
+KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
+                         bool NSW) {
   // TODO: This is simple fallback to generic RHS-based shl.
   // Add a specialized constant-shift implementation with identical semantics.
   KnownBits RHS = KnownBits::makeConstant(APInt(LHS.getBitWidth(), ShiftAmt));

>From 083641d56fd2c12450fad7e6d57f952145e34787 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 21:22:33 +0300
Subject: [PATCH 16/17] do the same for KnownBits::ashr

---
 llvm/include/llvm/Support/KnownBits.h                 |  5 +++--
 llvm/lib/Support/KnownBits.cpp                        | 11 ++++++-----
 .../InstCombine/InstCombineSimplifyDemanded.cpp       |  2 +-
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index 4041e82c04f97..b31ae60ff5800 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -474,8 +474,9 @@ struct KnownBits {
                                  bool ShAmtNonZero = false, bool Exact = false);
 
   /// Compute known bits for ashr(LHS, ShiftAmt).
-  /// This is shift by constant variant of ashr(LHS, RHS).
-  LLVM_ABI static KnownBits ashr(const KnownBits &LHS, unsigned ShiftAmt);
+  /// This is shift by constant variant of ashr(LHS, ShiftAmt).
+  LLVM_ABI static KnownBits ashr(const KnownBits &LHS, unsigned ShiftAmt,
+                                 bool ShAmtNonZero = false, bool Exact = false);
 
   /// Compute known bits for ashr(LHS, RHS).
   /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 8c58ef1db8af3..b71e24a0eaec7 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -553,11 +553,12 @@ KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS,
   return Known;
 }
 
-KnownBits KnownBits::ashr(const KnownBits &LHS, unsigned ShiftAmt) {
-  KnownBits Known = LHS;
-  Known.Zero.ashrInPlace(ShiftAmt);
-  Known.One.ashrInPlace(ShiftAmt);
-  return Known;
+KnownBits KnownBits::ashr(const KnownBits &LHS, unsigned ShiftAmt,
+                          bool ShAmtNonZero, bool Exact) {
+  // TODO: This is simple fallback to generic RHS-based ashr.
+  // Add a specialized constant-shift implementation with identical semantics.
+  KnownBits RHS = KnownBits::makeConstant(APInt(LHS.getBitWidth(), ShiftAmt));
+  return ashr(LHS, RHS, ShAmtNonZero, Exact);
 }
 
 KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS,
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 7be7c2f12e355..d25e9e3a8c7da 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -930,7 +930,7 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Instruction *I,
         return InsertNewInstWith(LShr, I->getIterator());
       }
 
-      Known = KnownBits::ashr(Known, ShiftAmt);
+      Known = KnownBits::ashr(Known, ShiftAmt, ShiftAmt != 0, I->isExact());
     } else {
       llvm::computeKnownBits(I, Known, Q, Depth);
     }

>From 74e50ef4c55fe80ad830ee97b028500e5ed7031c Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 21:50:15 +0300
Subject: [PATCH 17/17] fix ashr

---
 llvm/lib/Support/KnownBits.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index b71e24a0eaec7..53fdd2435825e 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -564,6 +564,12 @@ KnownBits KnownBits::ashr(const KnownBits &LHS, unsigned ShiftAmt,
 KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS,
                           bool ShAmtNonZero, bool Exact) {
   unsigned BitWidth = LHS.getBitWidth();
+  auto ShiftByConst = [&](const KnownBits &LHS, unsigned ShiftAmt) {
+    KnownBits Known = LHS;
+    Known.Zero.ashrInPlace(ShiftAmt);
+    Known.One.ashrInPlace(ShiftAmt);
+    return Known;
+  };
 
   // Fast path for a common case when LHS is completely unknown.
   KnownBits Known(BitWidth);
@@ -603,7 +609,7 @@ KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS,
     if ((ShiftAmtZeroMask & ShiftAmt) != 0 ||
         (ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
       continue;
-    Known = Known.intersectWith(ashr(LHS, ShiftAmt));
+    Known = Known.intersectWith(ShiftByConst(LHS, ShiftAmt));
     if (Known.isUnknown())
       break;
   }



More information about the llvm-commits mailing list