-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[SCEV] Collect and merge loop guards through PHI nodes with multiple incoming values #113915
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 1 commit
b595b8c
b5d72e3
8d38196
bda368d
e4d5a76
59da748
772fc50
3320956
36f5626
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 |
---|---|---|
|
@@ -10648,7 +10648,7 @@ ScalarEvolution::getPredecessorWithUniqueSuccessorForBB(const BasicBlock *BB) | |
if (const Loop *L = LI.getLoopFor(BB)) | ||
return {L->getLoopPredecessor(), L->getHeader()}; | ||
|
||
return {nullptr, nullptr}; | ||
return {nullptr, BB}; | ||
} | ||
|
||
/// SCEV structural equivalence is usually sufficient for testing whether two | ||
|
@@ -15217,7 +15217,16 @@ bool ScalarEvolution::matchURem(const SCEV *Expr, const SCEV *&LHS, | |
|
||
ScalarEvolution::LoopGuards | ||
ScalarEvolution::LoopGuards::collect(const Loop *L, ScalarEvolution &SE) { | ||
BasicBlock *Header = L->getHeader(); | ||
BasicBlock *Pred = L->getLoopPredecessor(); | ||
LoopGuards Guards(SE); | ||
return collectFromBlock(SE, Guards, Header, Pred, {}); | ||
} | ||
|
||
ScalarEvolution::LoopGuards ScalarEvolution::LoopGuards::collectFromBlock( | ||
ScalarEvolution &SE, ScalarEvolution::LoopGuards &Guards, | ||
const BasicBlock *Block, const BasicBlock *Pred, | ||
SmallPtrSet<const BasicBlock *, 8> VisitedBlocks) { | ||
SmallVector<const SCEV *> ExprsToRewrite; | ||
auto CollectCondition = [&](ICmpInst::Predicate Predicate, const SCEV *LHS, | ||
const SCEV *RHS, | ||
|
@@ -15556,14 +15565,13 @@ ScalarEvolution::LoopGuards::collect(const Loop *L, ScalarEvolution &SE) { | |
} | ||
}; | ||
|
||
BasicBlock *Header = L->getHeader(); | ||
SmallVector<PointerIntPair<Value *, 1, bool>> Terms; | ||
// First, collect information from assumptions dominating the loop. | ||
for (auto &AssumeVH : SE.AC.assumptions()) { | ||
if (!AssumeVH) | ||
continue; | ||
auto *AssumeI = cast<CallInst>(AssumeVH); | ||
if (!SE.DT.dominates(AssumeI, Header)) | ||
if (!SE.DT.dominates(AssumeI, Block)) | ||
continue; | ||
Terms.emplace_back(AssumeI->getOperand(0), true); | ||
} | ||
|
@@ -15574,20 +15582,19 @@ ScalarEvolution::LoopGuards::collect(const Loop *L, ScalarEvolution &SE) { | |
if (GuardDecl) | ||
for (const auto *GU : GuardDecl->users()) | ||
if (const auto *Guard = dyn_cast<IntrinsicInst>(GU)) | ||
if (Guard->getFunction() == Header->getParent() && | ||
SE.DT.dominates(Guard, Header)) | ||
if (Guard->getFunction() == Block->getParent() && | ||
SE.DT.dominates(Guard, Block)) | ||
Terms.emplace_back(Guard->getArgOperand(0), true); | ||
|
||
// Third, collect conditions from dominating branches. Starting at the loop | ||
// predecessor, climb up the predecessor chain, as long as there are | ||
// predecessors that can be found that have unique successors leading to the | ||
// original header. | ||
// TODO: share this logic with isLoopEntryGuardedByCond. | ||
for (std::pair<const BasicBlock *, const BasicBlock *> Pair( | ||
L->getLoopPredecessor(), Header); | ||
Pair.first; | ||
std::pair<const BasicBlock *, const BasicBlock *> Pair(Pred, Block); | ||
for (; Pair.first; | ||
Pair = SE.getPredecessorWithUniqueSuccessorForBB(Pair.first)) { | ||
|
||
VisitedBlocks.insert(Pair.second); | ||
const BranchInst *LoopEntryPredicate = | ||
dyn_cast<BranchInst>(Pair.first->getTerminator()); | ||
if (!LoopEntryPredicate || LoopEntryPredicate->isUnconditional()) | ||
|
@@ -15596,6 +15603,66 @@ ScalarEvolution::LoopGuards::collect(const Loop *L, ScalarEvolution &SE) { | |
Terms.emplace_back(LoopEntryPredicate->getCondition(), | ||
LoopEntryPredicate->getSuccessor(0) == Pair.second); | ||
} | ||
// Finally, if we stopped climbing the predecessor chain because | ||
// there wasn't a unique one to continue, try to collect conditions | ||
// for PHINodes by recursively following all of their incoming | ||
// blocks and try to merge the found conditions to build a new one | ||
// for the Phi. | ||
if (Pair.second->hasNPredecessorsOrMore(2)) { | ||
for (auto &Phi : Pair.second->phis()) { | ||
juliannagele marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!SE.isSCEVable(Phi.getType())) | ||
continue; | ||
|
||
using MinMaxPattern = std::pair<const SCEVConstant *, SCEVTypes>; | ||
auto GetMinMaxConst = [&SE, &VisitedBlocks, &Pair, | ||
&Phi](unsigned int In) -> MinMaxPattern { | ||
juliannagele marked this conversation as resolved.
Show resolved
Hide resolved
|
||
LoopGuards G(SE); | ||
if (VisitedBlocks.insert(Phi.getIncomingBlock(In)).second) | ||
juliannagele marked this conversation as resolved.
Show resolved
Hide resolved
|
||
collectFromBlock(SE, G, Pair.second, Phi.getIncomingBlock(In), | ||
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 should probably only allow a single level of recursion to start with, i.e. don't allow multiple predecessors after recursing here the first time 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. done, added |
||
VisitedBlocks); | ||
const SCEV *S = G.RewriteMap[SE.getSCEV(Phi.getIncomingValue(In))]; | ||
auto *SM = dyn_cast_if_present<SCEVMinMaxExpr>(S); | ||
if (!SM) | ||
return {nullptr, scCouldNotCompute}; | ||
if (const SCEVConstant *C0 = dyn_cast<SCEVConstant>(SM->getOperand(0))) | ||
return {C0, SM->getSCEVType()}; | ||
if (const SCEVConstant *C1 = dyn_cast<SCEVConstant>(SM->getOperand(1))) | ||
return {C1, SM->getSCEVType()}; | ||
return {nullptr, scCouldNotCompute}; | ||
}; | ||
auto MergeMinMaxConst = [](MinMaxPattern P1, | ||
MinMaxPattern P2) -> MinMaxPattern { | ||
auto [C1, T1] = P1; | ||
auto [C2, T2] = P2; | ||
if (!C1 || !C2 || T1 != T2) | ||
return {nullptr, scCouldNotCompute}; | ||
switch (T1) { | ||
case scUMaxExpr: | ||
return {C1->getAPInt().ult(C2->getAPInt()) ? C1 : C2, T1}; | ||
case scSMaxExpr: | ||
return {C1->getAPInt().slt(C2->getAPInt()) ? C1 : C2, T1}; | ||
case scUMinExpr: | ||
return {C1->getAPInt().ugt(C2->getAPInt()) ? C1 : C2, T1}; | ||
case scSMinExpr: | ||
return {C1->getAPInt().sgt(C2->getAPInt()) ? C1 : C2, T1}; | ||
juliannagele marked this conversation as resolved.
Show resolved
Hide resolved
|
||
default: | ||
llvm_unreachable("Trying to merge non-MinMaxExpr SCEVs."); | ||
} | ||
}; | ||
auto P = GetMinMaxConst(0); | ||
for (unsigned int In = 1; In < Phi.getNumIncomingValues(); In++) { | ||
if (!P.first) | ||
break; | ||
P = MergeMinMaxConst(P, GetMinMaxConst(In)); | ||
} | ||
if (P.first) { | ||
const SCEV *LHS = SE.getSCEV(const_cast<PHINode *>(&Phi)); | ||
SmallVector<const SCEV *, 2> Ops({P.first, LHS}); | ||
const SCEV *RHS = SE.getMinMaxExpr(P.second, Ops); | ||
Guards.RewriteMap.insert({LHS, RHS}); | ||
} | ||
} | ||
} | ||
|
||
// Now apply the information from the collected conditions to | ||
// Guards.RewriteMap. Conditions are processed in reverse order, so the | ||
|
Uh oh!
There was an error while loading. Please reload this page.