-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[InstCombineCompares] Try to "strengthen" compares based on known bits. #79405
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
Changes from all commits
20e1c91
ec9315d
91b7eb1
be9c0c7
4488bcb
70fc18c
82ad843
fae6acc
67cc2a0
f5fef05
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -20,6 +20,7 @@ | |||||||||
#include "llvm/Analysis/ConstantFolding.h" | ||||||||||
#include "llvm/Analysis/InstructionSimplify.h" | ||||||||||
#include "llvm/Analysis/Utils/Local.h" | ||||||||||
#include "llvm/Analysis/ValueTracking.h" | ||||||||||
#include "llvm/Analysis/VectorUtils.h" | ||||||||||
#include "llvm/IR/ConstantRange.h" | ||||||||||
#include "llvm/IR/DataLayout.h" | ||||||||||
|
@@ -6100,6 +6101,91 @@ bool InstCombinerImpl::replacedSelectWithOperand(SelectInst *SI, | |||||||||
return false; | ||||||||||
} | ||||||||||
|
||||||||||
// Try to "strengthen" the RHS of compare based on known bits. | ||||||||||
// For example, replace `icmp ugt %x, 14` with `icmp ugt %x, 15` when | ||||||||||
// it is known that the two least significant bits of `%x` is zero. | ||||||||||
static Instruction *strengthenICmpUsingKnownBits(ICmpInst &I, | ||||||||||
KnownBits Op0Known, | ||||||||||
KnownBits Op1Known, | ||||||||||
unsigned BitWidth) { | ||||||||||
if (!BitWidth) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||
return nullptr; | ||||||||||
if (!(Op1Known.isConstant() && Op0Known.Zero.isMask())) | ||||||||||
return nullptr; | ||||||||||
|
||||||||||
Value *Op0 = I.getOperand(0); | ||||||||||
ICmpInst::Predicate Pred = I.getPredicate(); | ||||||||||
Type *Ty = Op0->getType(); | ||||||||||
APInt RHSConst = Op1Known.getConstant(); | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can add a check here to avoid breaking the SPF. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dtcxzyw Added a check not to break any select patterns. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Tests? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Emm, it seems like some regressions are still there :( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dtcxzyw I just added test for select patterns and sign-check pattern. Everything works as intended. I tried your specific example and the pattern's wasn't broken. There must be something else happening in that code. Can you double check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Baseline (-O3):
After this patch:
It looks like a phase ordering problem :( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After inlining the call
so the constant There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, the |
||||||||||
ConstantRange Op0PredRange = | ||||||||||
ConstantRange::makeExactICmpRegion(Pred, RHSConst); | ||||||||||
int KnownZeroMaskLength = BitWidth - Op0Known.Zero.countLeadingZeros(); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
if (KnownZeroMaskLength == 0) | ||||||||||
return nullptr; | ||||||||||
|
||||||||||
APInt PowOf2(BitWidth, 1 << KnownZeroMaskLength); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||||||||||
APInt Op0MinAccordingToPred(BitWidth, 0); | ||||||||||
APInt Op0MaxAccordingToPred(BitWidth, 0); | ||||||||||
APInt Op0MinRefinedByKnownBits(BitWidth, 0); | ||||||||||
APInt Op0MaxRefinedByKnownBits(BitWidth, 0); | ||||||||||
APInt NewLower(BitWidth, 0); | ||||||||||
APInt NewUpper(BitWidth, 0); | ||||||||||
bool ImprovedLower = false; | ||||||||||
bool ImprovedUpper = false; | ||||||||||
if (I.isSigned()) { | ||||||||||
Op0MinAccordingToPred = Op0PredRange.getSignedMin(); | ||||||||||
Op0MaxAccordingToPred = Op0PredRange.getSignedMax(); | ||||||||||
// Compute the smallest number satisfying the known-bits constrained | ||||||||||
// which is at greater or equal Op0MinAccordingToPred. | ||||||||||
Op0MinRefinedByKnownBits = | ||||||||||
PowOf2 * APIntOps::RoundingSDiv(Op0MinAccordingToPred, PowOf2, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the compile-time impact of this patch? |
||||||||||
APInt::Rounding::UP); | ||||||||||
// Compute the largest number satisfying the known-bits constrained | ||||||||||
// which is at less or equal Op0MaxAccordingToPred. | ||||||||||
Comment on lines
+6144
to
+6145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
Op0MaxRefinedByKnownBits = | ||||||||||
PowOf2 * APIntOps::RoundingSDiv(Op0MaxAccordingToPred, PowOf2, | ||||||||||
APInt::Rounding::DOWN); | ||||||||||
NewLower = APIntOps::smax(Op0MinRefinedByKnownBits, Op0MinAccordingToPred); | ||||||||||
NewUpper = APIntOps::smin(Op0MaxRefinedByKnownBits, Op0MaxAccordingToPred); | ||||||||||
ImprovedLower = NewLower.sgt(Op0MinAccordingToPred); | ||||||||||
ImprovedUpper = NewUpper.slt(Op0MaxAccordingToPred); | ||||||||||
} else { | ||||||||||
Op0MinAccordingToPred = Op0PredRange.getUnsignedMin(); | ||||||||||
Op0MaxAccordingToPred = Op0PredRange.getUnsignedMax(); | ||||||||||
Op0MinRefinedByKnownBits = | ||||||||||
PowOf2 * APIntOps::RoundingUDiv(Op0MinAccordingToPred, PowOf2, | ||||||||||
APInt::Rounding::UP); | ||||||||||
Comment on lines
+6157
to
+6158
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Can the multiplication overflow? |
||||||||||
Op0MaxRefinedByKnownBits = | ||||||||||
PowOf2 * APIntOps::RoundingUDiv(Op0MaxAccordingToPred, PowOf2, | ||||||||||
APInt::Rounding::DOWN); | ||||||||||
NewLower = APIntOps::umax(Op0MinRefinedByKnownBits, Op0MinAccordingToPred); | ||||||||||
NewUpper = APIntOps::umin(Op0MaxRefinedByKnownBits, Op0MaxAccordingToPred); | ||||||||||
ImprovedLower = NewLower.ugt(Op0MinAccordingToPred); | ||||||||||
ImprovedUpper = NewUpper.ult(Op0MaxAccordingToPred); | ||||||||||
} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of creating this custom bounds, why not use |
||||||||||
|
||||||||||
// Non-strict inequalities should have been canonicalized to strict ones | ||||||||||
// by now. | ||||||||||
switch (Pred) { | ||||||||||
default: | ||||||||||
break; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can early exit when the predicate is not signed. |
||||||||||
case ICmpInst::ICMP_ULT: | ||||||||||
case ICmpInst::ICMP_SLT: { | ||||||||||
if (ImprovedUpper) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we avoid refining lower when the predicate is |
||||||||||
return new ICmpInst(Pred, Op0, ConstantInt::get(Ty, NewUpper + 1)); | ||||||||||
break; | ||||||||||
} | ||||||||||
case ICmpInst::ICMP_UGT: | ||||||||||
case ICmpInst::ICMP_SGT: { | ||||||||||
if (ImprovedLower) | ||||||||||
return new ICmpInst(Pred, Op0, ConstantInt::get(Ty, NewLower - 1)); | ||||||||||
break; | ||||||||||
} | ||||||||||
} | ||||||||||
return nullptr; | ||||||||||
} | ||||||||||
|
||||||||||
/// Try to fold the comparison based on range information we can get by checking | ||||||||||
/// whether bits are known to be zero or one in the inputs. | ||||||||||
Instruction *InstCombinerImpl::foldICmpUsingKnownBits(ICmpInst &I) { | ||||||||||
|
@@ -6357,6 +6443,23 @@ Instruction *InstCombinerImpl::foldICmpUsingKnownBits(ICmpInst &I) { | |||||||||
(Op0Known.One.isNegative() && Op1Known.One.isNegative()))) | ||||||||||
return new ICmpInst(I.getUnsignedPredicate(), Op0, Op1); | ||||||||||
|
||||||||||
// if the result of compare is used only in conditional branches, try to | ||||||||||
// "strengthen" the compare. This may allow us to deduce stronger results | ||||||||||
// about the value involved in comparison in the blocks dominated by these branches. | ||||||||||
bool AllUsesAreInBranches = true; | ||||||||||
for (const Use &U : I.uses()) { | ||||||||||
const Instruction *UI = cast<Instruction>(U.getUser()); | ||||||||||
if (!dyn_cast<BranchInst>(UI)) { | ||||||||||
AllUsesAreInBranches = false; | ||||||||||
break; | ||||||||||
} | ||||||||||
} | ||||||||||
if (AllUsesAreInBranches) { | ||||||||||
if (Instruction *Res = | ||||||||||
strengthenICmpUsingKnownBits(I, Op0Known, Op1Known, BitWidth)) | ||||||||||
return Res; | ||||||||||
} | ||||||||||
|
||||||||||
return nullptr; | ||||||||||
} | ||||||||||
|
||||||||||
|
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.