-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[SimplifyCFG] Fix the compile crash for invalid upper bound value #71351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Allen (vfdff) ChangesFor '%add = add nuw i32 %x', we can only infer the LowerBound is 1, and keep the UpperBound is initialized 0 in computeConstantRange. so we can't assume the UpperBound is valid bound when its value is 0. Fix #71329. Full diff: https://github.com/llvm/llvm-project/pull/71351.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index b58bcd35f940f96..1f068309b61ff57 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6639,13 +6639,16 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
// WouldFitInRegister.
// TODO: Consider growing the table also when it doesn't fit in a register
// if no optsize is specified.
- if (all_of(ResultTypes, [&](const auto &KV) {
+ // Check the UpperBound is updated with a valid value.
+ const APInt &UpperBound = CR.getUpper();
+ if (UpperBound.getZExtValue() != 0 &&
+ all_of(ResultTypes, [&](const auto &KV) {
return SwitchLookupTable::WouldFitInRegister(
- DL, CR.getUpper().getLimitedValue(), KV.second /* ResultType */);
+ DL, UpperBound.getLimitedValue(), KV.second /* ResultType */);
})) {
// The default branch is unreachable after we enlarge the lookup table.
// Adjust DefaultIsReachable to reuse code path.
- TableSize = CR.getUpper().getZExtValue();
+ TableSize = UpperBound.getZExtValue();
DefaultIsReachable = false;
}
}
diff --git a/llvm/test/Transforms/SimplifyCFG/switch_mask.ll b/llvm/test/Transforms/SimplifyCFG/switch_mask.ll
index 53ee21eae223c6a..efb8ea507ee63ae 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch_mask.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch_mask.ll
@@ -173,3 +173,35 @@ lor.end: ; preds = %entry, %entry, %ent
%0 = phi i1 [ true, %entry ], [ %call, %default ], [ true, %entry ], [ true, %entry ]
ret i1 %0
}
+
+; Negative test: The result in default reachable, but its value is not const.
+define void @switch_lookup_with_nonconst_range(i32 %x, i1 %cond) {
+; CHECK-LABEL: @switch_lookup_with_nonconst_range(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[FOR_PREHEADER:%.*]]
+; CHECK: for.preheader:
+; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR_PREHEADER]], label [[LOR_END:%.*]]
+; CHECK: lor.end:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %for.preheader
+
+for.preheader: ; preds = %for.preheader, %entry
+ %add = add nuw i32 %x, 1 ; the UpperBound is unconfirmed
+ br i1 %cond, label %for.preheader, label %for.end
+
+for.end: ; preds = %for.preheader
+ switch i32 %add, label %default [
+ i32 0, label %lor.end
+ i32 1, label %lor.end
+ i32 5, label %lor.end
+ ]
+
+default: ; preds = %for.end
+ br label %lor.end
+
+lor.end: ; preds = %default, %for.end, %for.end, %for.end
+ %retval.0.i.i = phi i32 [ 0, %default ], [ 0, %for.end ], [ 0, %for.end ], [ 0, %for.end ]
+ ret void
+}
|
I didn't find an API, which check whether the Upper of return value of computeConstantRange is updated, so I test it with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since @nikic is the ConstantRange expert, I'd like his input here.
Please let me know if I've got this right. In the test we have:
%add = add nuw i32 %x, 1 ; the UpperBound is unconfirmed
It seems the upper bound for %add
would be 2^32-1. However, since the upper end of ConstantRange
is exclusive, it means ConstantRange::Upper
becomes 2^32 which wraps to zero? That's pretty subtle.
Instead of checking for zero, I think this would be clearer:
// Check that the constant range hasn't wrapped.
if (CR.getUpper() > CR.getLower() && ...
It's probably best to use getUnsignedMax() and then do +1 when assigning TableSize. getUnsignedMax() is the inclusive unsigned upper bound (UINT_MAX for a wrapped range). |
Update and use |
if (UpperBound.getZExtValue() > CR.getLower().getZExtValue() && | ||
all_of(ResultTypes, [&](const auto &KV) { | ||
return SwitchLookupTable::WouldFitInRegister( | ||
DL, UpperBound.getLimitedValue(), KV.second /* ResultType */); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why getLimitedValue()
here but getZextValue()
everywhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, thanks, I'll unify the update to getLimitedValue()
// if no optsize is specified. | ||
// Check that the constant range hasn't wrapped. | ||
const APInt &UpperBound = CR.getUpper(); | ||
if (UpperBound.getZExtValue() > CR.getLower().getZExtValue() && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (UpperBound.getZExtValue() > CR.getLower().getZExtValue() && | |
if (!CR.isUpperWrapped() && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apply your comment, thanks
…tion When the small mask value little than 64, we can eliminate the checking for upper limit of the range by enlarge the lookup table size to the maximum index value. (Then the final table size grows to the next pow2 value) ``` bool f(unsigned x) { switch (x % 8) { case 0: return 1; case 1: return 0; case 2: return 0; case 3: return 1; case 4: return 1; case 5: return 0; case 6: return 1; // This would remove the range check: case 7: return 0; } return 0; } ``` Use WouldFitInRegister instead of fitsInLegalInteger to support more result type beside bool. Fixes llvm#65120 Note: For '%add = add nuw i32 %x, 1', we can infer the LowerBound is 1, but the UpperBound is wrapped to 0 in computeConstantRange. so we can't assume the UpperBound is valid bound when its value is 0. Fix llvm#71329.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as well.
For '%add = add nuw i32 %x, 1', we can only infer the LowerBound is 1, and keep the UpperBound is initialized 0 in computeConstantRange. so we can't assume the UpperBound is valid bound when its value is 0.
Fix #71329.