[llvm] 625538f - [KnownBits] Fix add() SelfAdd assertion for bitwidths >= 512 (#202769)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 05:07:47 PDT 2026
Author: Paweł Bylica
Date: 2026-06-11T14:07:42+02:00
New Revision: 625538f44601b906a3db03b2b110f50915ca3ecd
URL: https://github.com/llvm/llvm-project/commit/625538f44601b906a3db03b2b110f50915ca3ecd
DIFF: https://github.com/llvm/llvm-project/commit/625538f44601b906a3db03b2b110f50915ca3ecd.diff
LOG: [KnownBits] Fix add() SelfAdd assertion for bitwidths >= 512 (#202769)
`KnownBits::add()` with `SelfAdd=true` lowers `X+X` to `shl(X, 1)` using
a fixed 8-bit shift amount:
```cpp
KnownBits Amt = KnownBits::makeConstant(APInt(8, 1));
return KnownBits::shl(LHS, Amt, NUW, NSW, /*ShAmtNonZero=*/true);
```
The comment there claims the shift-amount bitwidth is independent of the
source bitwidth, but that is not true: `shl()`'s `getMaxShiftAmount()`
extracts `Log2_32(BitWidth)` bits from the shift amount's max value when
`BitWidth` is a power of two:
```cpp
static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
if (isPowerOf2_32(BitWidth))
return MaxValue.extractBitsAsZExtValue(Log2_32(BitWidth), 0);
...
}
```
For source widths `>= 512`, `Log2_32(BitWidth) >= 9`, so extracting that
many bits from the 8-bit shift amount trips the assertion in
`APInt::extractBitsAsZExtValue`:
```
Assertion `bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth && "Illegal bit extraction"' failed.
#9 llvm::APInt::extractBitsAsZExtValue(unsigned int, unsigned int) const
#10 llvm::KnownBits::shl(...)
#11 llvm::KnownBits::add(...)
```
(256 is the boundary that still works: `Log2_32(256) == 8`, extracting
exactly 8 bits from the 8-bit amount.)
Fix: make the shift-amount bitwidth match the source bitwidth so the
extraction is always in bounds. The `SelfAdd` path was introduced in
#188078.
Found via fuzzing. Adds a `SelfAddWide` regression test covering widths
256/512/1024.
Added:
Modified:
llvm/lib/Support/KnownBits.cpp
llvm/unittests/Support/KnownBitsTest.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index b1b985b80cffd..5becdac89fcaa 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -399,7 +399,10 @@ KnownBits KnownBits::abds(KnownBits LHS, KnownBits RHS) {
static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) {
if (isPowerOf2_32(BitWidth))
- return MaxValue.extractBitsAsZExtValue(Log2_32(BitWidth), 0);
+ // Clamp to the shift amount's width: a narrower amount is already
+ // < BitWidth, so this stays a valid upper bound.
+ return MaxValue.extractBitsAsZExtValue(
+ std::min(Log2_32(BitWidth), MaxValue.getBitWidth()), 0);
// This is only an approximate upper bound.
return MaxValue.getLimitedValue(BitWidth - 1);
}
diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp
index 0303b2f121c3b..581efad2aee8b 100644
--- a/llvm/unittests/Support/KnownBitsTest.cpp
+++ b/llvm/unittests/Support/KnownBitsTest.cpp
@@ -179,6 +179,25 @@ TEST(KnownBitsTest, SelfAddExhaustive) {
});
}
+TEST(KnownBitsTest, SelfAddWide) {
+ // SelfAdd lowers to shl(X, 1), whose getMaxShiftAmount extracts
+ // Log2_32(BitWidth) bits from the shift amount. For source widths >= 512 that
+ // is more than the 8-bit shift amount used by the lowering, which used to
+ // assert in APInt::extractBitsAsZExtValue.
+ // 1 << 23 is IntegerType::MAX_INT_BITS, the widest integer IR can produce.
+ for (unsigned Bits : {256u, 512u, 1024u, 1u << 23}) {
+ for (const APInt &X : {APInt(Bits, 1), APInt::getMaxValue(Bits)}) {
+ KnownBits Known = KnownBits::makeConstant(X);
+ KnownBits Computed = KnownBits::add(Known, Known, /*NSW=*/false,
+ /*NUW=*/false, /*SelfAdd=*/true);
+ // X + X == X << 1 (truncated to Bits); the result is fully known.
+ APInt Doubled = X << 1;
+ EXPECT_EQ(Computed.One, Doubled);
+ EXPECT_EQ(Computed.Zero, ~Doubled);
+ }
+ }
+}
+
TEST(KnownBitsTest, AddCarryExhaustive) {
unsigned Bits = 4;
ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
More information about the llvm-commits
mailing list