[llvm] [ConstantRange] Bail out early in unsignedMulMayOverflow for wide integer types (PR #192275)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 15 08:30:36 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-ir
Author: Firebear (Firebear518)
<details>
<summary>Changes</summary>
Problem
ConstantRange::unsignedMulMayOverflow calls APInt::umul_ov on the range bounds to determine overflow. APInt multiplication is O(n²) in the word
count, so integer types wider than ~1024 bits cause multi-second hangs in InstCombine.
Minimal reproducer:
define i5754496 @<!-- -->test(i5754496 %arg) {
%add1 = add i5754496 %arg, %arg
%add2 = add i5754496 %arg, %add1
ret i5754496 %add2
}
# Before this patch
$ time opt -passes=instcombine repro.ll -o /dev/null
real 0m30.2s
# After this patch
$ time opt -passes=instcombine repro.ll -o /dev/null
real 0m0.5s
Discovered via llvm-opt-fuzzer.
Solution
Return a conservative MayOverflow early when getBitWidth() > 1024. MayOverflow is always a valid upper bound — callers that receive it simply forgo
adding nuw to the folded instruction, which is safe.
The threshold 1024 covers all integer types that appear in real-world IR (≤512 bit) and matches the practical limit above which APInt word-count
growth causes quadratic cost.
The sibling functions (unsignedAddMayOverflow, signedAddMayOverflow, unsignedSubMayOverflow, signedSubMayOverflow) rely only on O(n) APInt
addition/subtraction and do not require this guard.
Testing
[ RUN ] ConstantRangeTest.UnsignedMulOverflowExhaustive OK (182 ms)
[ RUN ] ConstantRangeTest.UnsignedMulOverflowWideTypeBailout OK (0 ms)
UnsignedMulOverflowWideTypeBailout is a new regression test that completes in 0 ms with the fix and would hang >30 s without it.
cc @<!-- -->nikic @<!-- -->RKSimon @<!-- -->LebedevRI
---
Full diff: https://github.com/llvm/llvm-project/pull/192275.diff
2 Files Affected:
- (modified) llvm/lib/IR/ConstantRange.cpp (+6)
- (modified) llvm/unittests/IR/ConstantRangeTest.cpp (+23)
``````````diff
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 4c10dfb140cbe..9e12ac0c03f3e 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -2261,6 +2261,12 @@ ConstantRange::OverflowResult ConstantRange::unsignedMulMayOverflow(
if (isEmptySet() || Other.isEmptySet())
return OverflowResult::MayOverflow;
+ // Bail out for very wide integer types: APInt multiplication is O(n^2) in
+ // the number of words, so types wider than ~1024 bits can cause multi-second
+ // hangs. Return a conservative result instead.
+ if (getBitWidth() > 1024)
+ return OverflowResult::MayOverflow;
+
APInt Min = getUnsignedMin(), Max = getUnsignedMax();
APInt OtherMin = Other.getUnsignedMin(), OtherMax = Other.getUnsignedMax();
bool Overflow;
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 13712a76d3edf..8c774d522b122 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -2506,6 +2506,29 @@ TEST_F(ConstantRangeTest, UnsignedMulOverflowExhaustive) {
});
}
+// Regression test: very wide integer types (>1024 bits) triggered an O(n^2)
+// APInt multiplication inside unsignedMulMayOverflow via APInt::umul_ov,
+// causing multi-second hangs in InstCombine (discovered via llvm-opt-fuzzer
+// with i5754496). The fix returns a conservative MayOverflow early for bit
+// widths above 1024.
+TEST_F(ConstantRangeTest, UnsignedMulOverflowWideTypeBailout) {
+ // 2048 bits is above the 1024-bit bailout threshold.
+ const unsigned W = 2048;
+ ConstantRange WFull = ConstantRange::getFull(W);
+ ConstantRange WOne(APInt(W, 1));
+ ConstantRange WMax(APInt::getMaxValue(W));
+ ConstantRange WEmpty = ConstantRange::getEmpty(W);
+
+ // For types wider than 1024 bits all non-empty pairs return MayOverflow
+ // (conservative but always correct).
+ EXPECT_MAY_OVERFLOW(WFull.unsignedMulMayOverflow(WFull));
+ EXPECT_MAY_OVERFLOW(WOne.unsignedMulMayOverflow(WMax));
+ EXPECT_MAY_OVERFLOW(WMax.unsignedMulMayOverflow(WOne));
+ // Empty-set cases are still handled before the width check.
+ EXPECT_MAY_OVERFLOW(WEmpty.unsignedMulMayOverflow(WFull));
+ EXPECT_MAY_OVERFLOW(WFull.unsignedMulMayOverflow(WEmpty));
+}
+
TEST_F(ConstantRangeTest, SignedAddOverflowExhaustive) {
TestOverflowExhaustive(
[](bool &IsOverflowHigh, const APInt &N1, const APInt &N2) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/192275
More information about the llvm-commits
mailing list