[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
Sat Apr 4 09:46:41 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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;
}
>From a28cb3e78fad37859fdff0046ceef2a4e1fe7ffe Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Thu, 2 Apr 2026 21:54:34 +0300
Subject: [PATCH 18/24] fix
---
llvm/include/llvm/Support/KnownBits.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index b31ae60ff5800..34b978a189686 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -368,7 +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");
- return KnownBits::shl(LHS, 1, NUW, NSW);
+ return KnownBits::shl(LHS, 1, NUW, NSW, /*ShAmtNonZero=*/true);
}
return computeForAddSub(/*Add=*/true, NSW, NUW, LHS, RHS);
}
>From d8e2f5e80fc3dcb7924116de021468b5c094215e Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Fri, 3 Apr 2026 10:44:20 +0300
Subject: [PATCH 19/24] fix
---
llvm/include/llvm/Support/KnownBits.h | 2 +-
llvm/lib/Support/KnownBits.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index 34b978a189686..b31ae60ff5800 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -368,7 +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");
- return KnownBits::shl(LHS, 1, 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 53fdd2435825e..61999b56e2cdf 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -409,7 +409,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
// 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);
+ return shl(LHS, RHS, NUW, NSW, ShiftAmt != 0);
}
KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
>From dcf1bbd802fc535e96c305ce9d16f5d2f8eb0171 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Fri, 3 Apr 2026 17:17:40 +0300
Subject: [PATCH 20/24] New attempt of proper implantation specialised shl with
const RHS
---
llvm/lib/Support/KnownBits.cpp | 40 ++++++++++++++++++++++++++++++----
1 file changed, 36 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 61999b56e2cdf..1e1e208085116 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -406,10 +406,42 @@ static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
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, ShiftAmt != 0);
+ if (ShiftAmt == 0)
+ return LHS;
+
+ unsigned BitWidth = LHS.getBitWidth();
+ KnownBits Known(BitWidth);
+
+ if (ShiftAmt >= BitWidth)
+ return Known;
+
+ if (LHS.isUnknown()) {
+ Known.Zero.setLowBits(ShiftAmt);
+ if (NUW && NSW)
+ Known.makeNonNegative();
+ return Known;
+ }
+
+ bool ShiftedOutZero, ShiftedOutOne;
+ Known.One = LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne);
+ if (NUW && ShiftedOutOne) {
+ // ones shifted out means this is always poison.
+ Known.setAllZero();
+ return Known;
+ }
+ Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
+ Known.Zero.setLowBits(ShiftAmt);
+
+ if (NSW) {
+ if (NUW)
+ ShiftedOutZero = true;
+ if (ShiftedOutZero)
+ Known.makeNonNegative();
+ else if (ShiftedOutOne)
+ Known.makeNegative();
+ }
+
+ return Known;
}
KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
>From 1c1b635867dcfb4c67f6606ee210562af1e5cc4c Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Fri, 3 Apr 2026 18:10:10 +0300
Subject: [PATCH 21/24] fix
---
llvm/lib/Support/KnownBits.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 1e1e208085116..ae5155a4a4b60 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -412,9 +412,6 @@ KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
unsigned BitWidth = LHS.getBitWidth();
KnownBits Known(BitWidth);
- if (ShiftAmt >= BitWidth)
- return Known;
-
if (LHS.isUnknown()) {
Known.Zero.setLowBits(ShiftAmt);
if (NUW && NSW)
@@ -430,7 +427,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
return Known;
}
Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
- Known.Zero.setLowBits(ShiftAmt);
+ Known.Zero.setLowBits(std::min(ShiftAmt, BitWidth));
if (NSW) {
if (NUW)
>From b082a1adaa57efebc4d3ce389c585505a5b642d2 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Fri, 3 Apr 2026 19:30:05 +0300
Subject: [PATCH 22/24] specialize ashr is similar way
---
llvm/lib/Support/KnownBits.cpp | 44 ++++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index ae5155a4a4b60..d1cd2c475bf21 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -526,6 +526,17 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
}
KnownBits KnownBits::lshr(const KnownBits &LHS, unsigned ShiftAmt) {
+ if (ShiftAmt == 0)
+ return LHS;
+
+ unsigned BitWidth = LHS.getBitWidth();
+
+ if (ShiftAmt >= BitWidth) {
+ KnownBits Known(BitWidth);
+ Known.setAllZero();
+ return Known;
+ }
+
KnownBits Known = LHS;
Known >>= ShiftAmt;
// High bits are known zero.
@@ -586,8 +597,37 @@ 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 RHS = KnownBits::makeConstant(APInt(LHS.getBitWidth(), ShiftAmt));
+ // return ashr(LHS, RHS, ShAmtNonZero, Exact);
+
+ unsigned BitWidth = LHS.getBitWidth();
+ KnownBits Known(BitWidth);
+
+ if (ShiftAmt == 0) {
+ if (!ShAmtNonZero)
+ return LHS;
+
+ Known.setAllZero();
+ return Known;
+ }
+
+ if (ShiftAmt >= BitWidth) {
+ Known.setAllZero();
+ return Known;
+ }
+
+ if (LHS.isUnknown())
+ return Known;
+
+ if (Exact && LHS.countMaxTrailingZeros() < ShiftAmt) {
+ Known.setAllZero();
+ return Known;
+ }
+
+ Known = LHS;
+ Known.Zero.ashrInPlace(ShiftAmt);
+ Known.One.ashrInPlace(ShiftAmt);
+ return Known;
}
KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS,
>From 8237c151b4d3e087db5c7fa4780e8754b245fd47 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Fri, 3 Apr 2026 21:11:35 +0300
Subject: [PATCH 23/24] cleanups
---
llvm/include/llvm/Support/KnownBits.h | 5 ++-
llvm/lib/Support/KnownBits.cpp | 34 ++++---------------
.../InstCombineSimplifyDemanded.cpp | 2 +-
3 files changed, 9 insertions(+), 32 deletions(-)
diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index b31ae60ff5800..4041e82c04f97 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -474,9 +474,8 @@ struct KnownBits {
bool ShAmtNonZero = false, bool Exact = false);
/// Compute known bits for ashr(LHS, 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);
+ /// 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.
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index d1cd2c475bf21..b8d88bf469dcb 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -526,7 +526,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW,
}
KnownBits KnownBits::lshr(const KnownBits &LHS, unsigned ShiftAmt) {
- if (ShiftAmt == 0)
+ if (ShiftAmt == 0)
return LHS;
unsigned BitWidth = LHS.getBitWidth();
@@ -593,23 +593,13 @@ KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS,
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, unsigned ShiftAmt) {
unsigned BitWidth = LHS.getBitWidth();
- KnownBits Known(BitWidth);
- if (ShiftAmt == 0) {
- if (!ShAmtNonZero)
- return LHS;
+ if (ShiftAmt == 0)
+ return LHS;
- Known.setAllZero();
- return Known;
- }
+ KnownBits Known(BitWidth);
if (ShiftAmt >= BitWidth) {
Known.setAllZero();
@@ -619,11 +609,6 @@ KnownBits KnownBits::ashr(const KnownBits &LHS, unsigned ShiftAmt,
if (LHS.isUnknown())
return Known;
- if (Exact && LHS.countMaxTrailingZeros() < ShiftAmt) {
- Known.setAllZero();
- return Known;
- }
-
Known = LHS;
Known.Zero.ashrInPlace(ShiftAmt);
Known.One.ashrInPlace(ShiftAmt);
@@ -633,13 +618,6 @@ 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);
unsigned MinShiftAmount = RHS.getMinValue().getLimitedValue(BitWidth);
@@ -678,7 +656,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;
}
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 8ea869fbe410acd21bfeb808332371504de6447b Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Sat, 4 Apr 2026 19:46:16 +0300
Subject: [PATCH 24/24] add unit tests and minor fixes
---
llvm/lib/Support/KnownBits.cpp | 19 ++++-
llvm/unittests/Support/KnownBitsTest.cpp | 102 +++++++++++++++++++++++
2 files changed, 118 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index b8d88bf469dcb..00bc14c2c1fc0 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -412,6 +412,13 @@ KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
unsigned BitWidth = LHS.getBitWidth();
KnownBits Known(BitWidth);
+ if (ShiftAmt >= BitWidth) {
+ Known.setAllZero();
+ if (NUW && NSW)
+ Known.makeNonNegative();
+ return Known;
+ }
+
if (LHS.isUnknown()) {
Known.Zero.setLowBits(ShiftAmt);
if (NUW && NSW)
@@ -428,6 +435,11 @@ KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
}
Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero);
Known.Zero.setLowBits(std::min(ShiftAmt, BitWidth));
+ if (NSW && ShiftedOutZero && ShiftedOutOne) {
+ // mixed shifted out means this is always poison.
+ Known.setAllZero();
+ return Known;
+ }
if (NSW) {
if (NUW)
@@ -438,6 +450,9 @@ KnownBits KnownBits::shl(const KnownBits &LHS, unsigned ShiftAmt, bool NUW,
Known.makeNegative();
}
+ if (Known.hasConflict())
+ Known.setAllZero();
+
return Known;
}
@@ -530,7 +545,6 @@ KnownBits KnownBits::lshr(const KnownBits &LHS, unsigned ShiftAmt) {
return LHS;
unsigned BitWidth = LHS.getBitWidth();
-
if (ShiftAmt >= BitWidth) {
KnownBits Known(BitWidth);
Known.setAllZero();
@@ -594,11 +608,10 @@ KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS,
}
KnownBits KnownBits::ashr(const KnownBits &LHS, unsigned ShiftAmt) {
- unsigned BitWidth = LHS.getBitWidth();
-
if (ShiftAmt == 0)
return LHS;
+ unsigned BitWidth = LHS.getBitWidth();
KnownBits Known(BitWidth);
if (ShiftAmt >= BitWidth) {
diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp
index dc4a47d7cc562..4651a56d5d9e7 100644
--- a/llvm/unittests/Support/KnownBitsTest.cpp
+++ b/llvm/unittests/Support/KnownBitsTest.cpp
@@ -517,6 +517,30 @@ TEST(KnownBitsTest, BinaryExhaustive) {
return N1.shl(N2);
},
/*CheckOptimality=*/true, /*RefinePoisonToZero=*/true);
+ testBinaryOpExhaustive(
+ "shl const",
+ [](const KnownBits &Known1, const KnownBits &Known2) {
+ KnownBits Generic = KnownBits::shl(Known1, Known2);
+
+ if (!Known2.isConstant() || Known1.hasConflict() || Known2.hasConflict())
+ return Generic;
+
+ unsigned ShiftAmt = Known2.getConstant().getLimitedValue();
+ KnownBits Const = KnownBits::shl(Known1, ShiftAmt);
+
+ EXPECT_EQ(Generic, Const) << "shl const mismatch for\n"
+ << "Known1 = " << Known1 << "\n"
+ << "Known2 = " << Known2
+ << " (" << ShiftAmt << ")\n\n";
+
+ return Const;
+ },
+ [](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
+ if (N2.uge(N2.getBitWidth()))
+ return std::nullopt;
+ return N1.shl(N2);
+ },
+ /*CheckOptimality=*/true, /*RefinePoisonToZero=*/true);
testBinaryOpExhaustive(
"ushl_ov",
[](const KnownBits &Known1, const KnownBits &Known2) {
@@ -543,6 +567,34 @@ TEST(KnownBitsTest, BinaryExhaustive) {
return Res;
},
/*CheckOptimality=*/true, /*RefinePoisonToZero=*/true);
+ testBinaryOpExhaustive(
+ "shl nsw const",
+ [](const KnownBits &Known1, const KnownBits &Known2) {
+ KnownBits Generic =
+ KnownBits::shl(Known1, Known2, /*NUW=*/false, /*NSW=*/true);
+
+ if (!Known2.isConstant() || Known1.hasConflict() || Known2.hasConflict())
+ return Generic;
+
+ unsigned ShiftAmt = Known2.getConstant().getLimitedValue();
+ KnownBits Const =
+ KnownBits::shl(Known1, ShiftAmt, /*NUW=*/false, /*NSW=*/true);
+
+ EXPECT_EQ(Generic, Const) << "shl const mismatch for\n"
+ << "Known1 = " << Known1 << "\n"
+ << "Known2 = " << Known2
+ << " (" << ShiftAmt << ")\n\n";
+
+ return Const;
+ },
+ [](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
+ bool Overflow;
+ APInt Res = N1.sshl_ov(N2, Overflow);
+ if (Overflow)
+ return std::nullopt;
+ return Res;
+ },
+ /*CheckOptimality=*/true, /*RefinePoisonToZero=*/true);
testBinaryOpExhaustive(
"shl nuw",
[](const KnownBits &Known1, const KnownBits &Known2) {
@@ -583,6 +635,31 @@ TEST(KnownBitsTest, BinaryExhaustive) {
return N1.lshr(N2);
},
/*CheckOptimality=*/true, /*RefinePoisonToZero=*/true);
+ testBinaryOpExhaustive(
+ "lshr const",
+ [](const KnownBits &Known1, const KnownBits &Known2) {
+ KnownBits Generic = KnownBits::lshr(Known1, Known2);
+
+ if (!Known2.isConstant() || Known1.hasConflict() || Known2.hasConflict())
+ return Generic;
+
+ unsigned ShiftAmt = Known2.getConstant().getLimitedValue();
+ KnownBits Const = KnownBits::lshr(Known1, ShiftAmt);
+
+ EXPECT_EQ(Generic, Const) << "lshr const mismatch for\n"
+ << "Known1 = " << Known1 << "\n"
+ << "Known2 = " << Known2
+ << " (" << ShiftAmt << ")\n\n";
+
+ return Const;
+ },
+ [](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
+ if (N2.uge(N2.getBitWidth()))
+ return std::nullopt;
+ return N1.lshr(N2);
+ },
+ /*CheckOptimality=*/false,
+ /*RefinePoisonToZero=*/true);
testBinaryOpExhaustive(
"ashr",
[](const KnownBits &Known1, const KnownBits &Known2) {
@@ -608,6 +685,31 @@ TEST(KnownBitsTest, BinaryExhaustive) {
return N1.ashr(N2);
},
/*CheckOptimality=*/true, /*RefinePoisonToZero=*/true);
+ testBinaryOpExhaustive(
+ "ashr const",
+ [](const KnownBits &Known1, const KnownBits &Known2) {
+ KnownBits Generic = KnownBits::ashr(Known1, Known2);
+
+ if (!Known2.isConstant() || Known1.hasConflict() || Known2.hasConflict())
+ return Generic;
+
+ unsigned ShiftAmt = Known2.getConstant().getLimitedValue();
+ KnownBits Const = KnownBits::ashr(Known1, ShiftAmt);
+
+ EXPECT_EQ(Generic, Const) << "ashr const mismatch for\n"
+ << "Known1 = " << Known1 << "\n"
+ << "Known2 = " << Known2
+ << " (" << ShiftAmt << ")\n\n";
+
+ return Const;
+ },
+ [](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
+ if (N2.uge(N2.getBitWidth()))
+ return std::nullopt;
+ return N1.ashr(N2);
+ },
+ /*CheckOptimality=*/false,
+ /*RefinePoisonToZero=*/true);
testBinaryOpExhaustive(
"mul",
[](const KnownBits &Known1, const KnownBits &Known2) {
More information about the llvm-commits
mailing list