[ConstantRange] Expand makeAllowedICmpRegion to use samesign to give tighter range#174355
[ConstantRange] Expand makeAllowedICmpRegion to use samesign to give tighter range#174355Adar-Dagan wants to merge 8 commits intollvm:mainfrom
Conversation
|
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-ir Author: Adar Dagan (Adar-Dagan) ChangesFull diff: https://github.com/llvm/llvm-project/pull/174355.diff 2 Files Affected:
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index f4d4f1f555fa4..47b9b60b64b2e 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -41,6 +41,7 @@ namespace llvm {
class MDNode;
class raw_ostream;
+class CmpPredicate;
struct KnownBits;
/// This class represents a range of values.
@@ -106,7 +107,7 @@ class [[nodiscard]] ConstantRange {
///
/// Example: Pred = ult and Other = i8 [2, 5) returns Result = [0, 4)
LLVM_ABI static ConstantRange
- makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other);
+ makeAllowedICmpRegion(CmpPredicate Pred, const ConstantRange &Other);
/// Produce the largest range such that all values in the returned range
/// satisfy the given predicate with all values contained within Other.
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 9beaee60d0bc1..87d180f19470e 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -23,6 +23,7 @@
#include "llvm/IR/ConstantRange.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/CmpPredicate.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
@@ -106,7 +107,7 @@ std::pair<ConstantRange, ConstantRange> ConstantRange::splitPosNeg() const {
return {intersectWith(PosFilter), intersectWith(NegFilter)};
}
-ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
+ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
const ConstantRange &CR) {
if (CR.isEmptySet())
return CR;
@@ -141,6 +142,8 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
+ if (Pred.hasSameSign() && CR.isAllNonNegative())
+ return ConstantRange(std::move(UMin) + 1, APInt::getSignedMinValue(W));
return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
}
case CmpInst::ICMP_SGT: {
@@ -150,6 +153,8 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
}
case CmpInst::ICMP_UGE:
+ if (Pred.hasSameSign() && CR.isAllNonNegative())
+ return getNonEmpty(CR.getUnsignedMin(), APInt::getSignedMinValue(W));
return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
case CmpInst::ICMP_SGE:
return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
|
|
@nikic Hey, I see you were added as a reviewer. Could you review this? or point me to who I should get a review from? |
1599826 to
4154699
Compare
|
@nikic ping? |
nikic
left a comment
There was a problem hiding this comment.
Missing PR description, motivation and tests?
0f57fca to
74e72d5
Compare
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
74e72d5 to
94734c3
Compare
| ret i1 %q | ||
| } | ||
|
|
||
| define i8 @remove_for_samesign(i8 %x) { |
There was a problem hiding this comment.
This test doesn't change with your patch: https://godbolt.org/z/84YPE5Kq4
There was a problem hiding this comment.
Yes, I meant to show here that instcombine does an optimization that leads to loss of information in computeConstantRange without this patch. I'll remove it and add to the description instead
| /// Example: Pred = ult and Other = i8 [2, 5) returns Result = [0, 4) | ||
| LLVM_ABI static ConstantRange | ||
| makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other); | ||
| makeAllowedICmpRegion(CmpPredicate Pred, const ConstantRange &Other); |
There was a problem hiding this comment.
I'd expect this to simplify isImpliedCondCommonOperandWithCR:
llvm-project/llvm/lib/Analysis/ValueTracking.cpp
Lines 9456 to 9467 in d5a5678
There was a problem hiding this comment.
Unfortunately no, we need to do the same to ConstantRange::icmp to simplify this
| EXPECT_EQ(10, CR2.getUpper()); | ||
| } | ||
|
|
||
| { |
There was a problem hiding this comment.
Please also add an exhaustive test in ConstantRangeTest.cpp to make sure the result is optimal. I also doubt the correctness of Boolean constant ranges.
There was a problem hiding this comment.
Nice catch, there is an edge case for booleans
Added tests to check my changes
There was a problem hiding this comment.
For exhaustive tests, I mean you can use EnumerateInterestingConstantRanges to enumerate all possible ranges from i1 to i4. Then you use TestRange to check for correctness and optimality. If the optimality is infeasible, please make sure it is always smaller than the result without samesign.
There was a problem hiding this comment.
I printed out the elements I create for each test to validate the correct elements are created, attached file with that print
res.txt
|
@dtcxzyw I answered your comments, any followups or something else? or could you approve? |
artagnon
left a comment
There was a problem hiding this comment.
Thanks, this is looking pretty good.
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
dtcxzyw
left a comment
There was a problem hiding this comment.
LGTM. I guess there is still much room for further simplifying the implementation. But I don't have any ideas for now. Please wait for additional approval from other reviewers.
e94c036 to
004eb60
Compare
artagnon
left a comment
There was a problem hiding this comment.
Hm, there's quite a bit of subtle complexity here. I wonder why this has such a small impact on llvm-opt-benchmark?
I guess it will become more useful after we let |
|
@artagnon Could you take another look? |
|
@nikic ping |
antoniofrighetto
left a comment
There was a problem hiding this comment.
I guess there is still much room for further simplifying the implementation.
Second this concern, implementation looks quite bespoke (and sort of getting harder to follow). Just wondering, don't intend to block this, would it be possible to leverage samesign semantics, thus splitting the input range in positive and negative ones, reuse existing SGT/SLT logic, and union the twos? Or would that still lead to a suboptimal range?
llvm/lib/IR/ConstantRange.cpp
Outdated
There was a problem hiding this comment.
May be worth elaborating on the edge cases?
llvm/lib/IR/ConstantRange.cpp
Outdated
There was a problem hiding this comment.
Maybe add a comment explaining that can never be satisfied for i1?
There was a problem hiding this comment.
I imagine there could be other users in the codebase that may start benefiting from using the whole CmpPredicate, so may be worth postponing this change in a follow-up?
reusing the signed logic and using intersect works |
Looks like this introduces significant compile-time overhead (+0.00349118% -> +0.13571089%) :( |
After the addition of samesign then instcombine correctly transforms unsigned greater than to use it if it can prove that value is greater than zero and then removes the assume that allowed it to prove that. For example:
Is optimized to:
This leads to a wrong range being returned from computeConstantRange because it doesn't look at samesign when constructing a range from assumes, this patch fixes that.