[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