-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
[InstCombine] Simplify select using KnownBits of condition #95923
Changes from all commits
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 |
---|---|---|
|
@@ -3519,6 +3519,33 @@ static bool matchFMulByZeroIfResultEqZero(InstCombinerImpl &IC, Value *Cmp0, | |
return false; | ||
} | ||
|
||
/// Check whether the KnownBits of a select arm may be affected by the | ||
/// select condition. | ||
static bool hasAffectedValue(Value *V, SmallPtrSetImpl<Value *> &Affected, | ||
unsigned Depth) { | ||
if (Depth == MaxAnalysisRecursionDepth) | ||
return false; | ||
|
||
// Ignore the case where the select arm itself is affected. These cases | ||
// are handled more efficiently by other optimizations. | ||
if (Depth != 0 && Affected.contains(V)) | ||
return true; | ||
|
||
if (auto *I = dyn_cast<Instruction>(V)) { | ||
if (isa<PHINode>(I)) { | ||
if (Depth == MaxAnalysisRecursionDepth - 1) | ||
return false; | ||
Depth = MaxAnalysisRecursionDepth - 2; | ||
} | ||
return any_of(I->operands(), [&](Value *Op) { | ||
return Op->getType()->isIntOrIntVectorTy() && | ||
hasAffectedValue(Op, Affected, Depth + 1); | ||
}); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { | ||
Value *CondVal = SI.getCondition(); | ||
Value *TrueVal = SI.getTrueValue(); | ||
|
@@ -4016,5 +4043,33 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { | |
if (CondVal->getType() == SI.getType() && isKnownInversion(FalseVal, TrueVal)) | ||
return BinaryOperator::CreateXor(CondVal, FalseVal); | ||
|
||
if (SelType->isIntOrIntVectorTy() && | ||
(!isa<Constant>(TrueVal) || !isa<Constant>(FalseVal))) { | ||
// Try to simplify select arms based on KnownBits implied by the condition. | ||
CondContext CC(CondVal); | ||
findValuesAffectedByCondition(CondVal, /*IsAssume=*/false, [&](Value *V) { | ||
CC.AffectedValues.insert(V); | ||
}); | ||
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. Maybe aggressive inst combine is the right place for this? Also, think for select you can at least limit You might also try early out of Finally, maybe try simplifying both 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. Actually, think you really should only add 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. As mentioned in the PR description, most of the overhead comes from simply adding a member to SimplifyQuery rather than anything happening in InstCombine. These are the numbers just for adding a dummy member: https://llvm-compile-time-tracker.com/compare.php?from=3ca17443ef4af21bdb1f3b4fbcfff672cbc6176c&to=e7a64d837a061d6afeac9c0f06c4827998d43561&stat=instructions:u As such, I don't think we'll get any substantial improvement out of changing how exactly the KnownBits calculation is done.
This would prevent extending this to use SimplifyDemandedBits, which enabled simplifying the expression without folding to constants (nikic@1b8edbd). This will allow us to subsume special cases like #92658.
I think managing invalidation for this would be quite tricky, and this approach would be inherently limited to one-use chains to the select only.
Why? V may be used by TrueArm/FalseArm recursively. 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, although a bit more ugly, what about adding an additional optional argument to 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.
Also, esp for ThinLTO, seems to be substantial enough difference to justify saving an iteration of InstCombine IMO. Don't think it will really affect code complexity much. 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 didn't get what you refer to with "saving an iteration of InstCombine" -- how can we save an InstCombine iteration? For the record, this is the impact of the KnownBits calculation (as opposed to the extra member and the affected value calculation): http://llvm-compile-time-tracker.com/compare.php?from=c9edd08d49137e47fe3acda3ea5b2bae563cb3ac&to=db730283063dff0dc72338413f346bd0174dafdd&stat=instructions:u 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 mean do the full transform in a single shot as opposed to going through the work list twice. Iteration was wrong word to us there given it's other meaning. 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.
Do you mean the case where it's possible to simplify both select operands? If so, this should be very rare, and as such not worth optimizing. |
||
SimplifyQuery Q = SQ.getWithInstruction(&SI).getWithCondContext(CC); | ||
if (!CC.AffectedValues.empty()) { | ||
if (!isa<Constant>(TrueVal) && | ||
hasAffectedValue(TrueVal, CC.AffectedValues, /*Depth=*/0)) { | ||
KnownBits Known = llvm::computeKnownBits(TrueVal, /*Depth=*/0, Q); | ||
if (Known.isConstant()) | ||
return replaceOperand(SI, 1, | ||
ConstantInt::get(SelType, Known.getConstant())); | ||
} | ||
|
||
CC.Invert = true; | ||
if (!isa<Constant>(FalseVal) && | ||
hasAffectedValue(FalseVal, CC.AffectedValues, /*Depth=*/0)) { | ||
KnownBits Known = llvm::computeKnownBits(FalseVal, /*Depth=*/0, Q); | ||
if (Known.isConstant()) | ||
return replaceOperand(SI, 2, | ||
ConstantInt::get(SelType, Known.getConstant())); | ||
} | ||
} | ||
} | ||
|
||
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.
SInce you are essentially only going to being able to do
computeKnownBitsFromCond
up to a depth of two, can you get away with changing yourcomputeKnownBits
calls to useMaxAnalysisRecursionDepth - 2
? Or does not having the additional bits matter?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 do you say that computeKnownBitsFromCond() will only work up to a depth of two? Or do you mean in the phi case? (The phi case is going to pass MaxAnalysisRecursionDepth - 1 as the new depth.)
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.
As in, in
computeKnownBits
, by a depth of two, you will no longer hit any values in "Affected" (or at least rarely, if you hit any they will not be by-chance from multi-use). So it will be similiar to a normalcomputeKnownBits
call which is not what this patch is really after.I'm not sure if, however, if you need to normal
computeKnownBits
to provide some extra bits to fill in the constants.