Skip to content

Commit

Permalink
[SCEVExp] Move logic to replace congruent IV increments to helper (NFC).
Browse files Browse the repository at this point in the history
Move logic to replace congruent IV increments to helper function, to
reduce the indentation by using early returns. This is in preparation
for a follow-up patch.
  • Loading branch information
fhahn committed Jan 25, 2024
1 parent 3b76289 commit d88e365
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 54 deletions.
7 changes: 7 additions & 0 deletions llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,13 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> {
/// Create LCSSA PHIs for \p V, if it is required for uses at the Builder's
/// current insertion point.
Value *fixupLCSSAFormFor(Value *V);

/// Replace congruent phi increments with their most canonical representative.
/// May swap \p Phi and \p OrigPhi, if \p Phi is more canonical, due to its
/// increment.
void replaceCongruentIVInc(PHINode *&Phi, PHINode *&OrigPhi, Loop *L,
const DominatorTree *DT,
SmallVectorImpl<WeakTrackingVH> &DeadInsts);
};

/// Helper to remove instructions inserted during SCEV expansion, unless they
Expand Down
118 changes: 64 additions & 54 deletions llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1569,6 +1569,69 @@ void SCEVExpander::rememberInstruction(Value *I) {
DoInsert(I);
}

void SCEVExpander::replaceCongruentIVInc(
PHINode *&Phi, PHINode *&OrigPhi, Loop *L, const DominatorTree *DT,
SmallVectorImpl<WeakTrackingVH> &DeadInsts) {
BasicBlock *LatchBlock = L->getLoopLatch();
if (!LatchBlock)
return;

Instruction *OrigInc =
dyn_cast<Instruction>(OrigPhi->getIncomingValueForBlock(LatchBlock));
Instruction *IsomorphicInc =
dyn_cast<Instruction>(Phi->getIncomingValueForBlock(LatchBlock));
if (!OrigInc || !IsomorphicInc)
return;

// If this phi has the same width but is more canonical, replace the
// original with it. As part of the "more canonical" determination,
// respect a prior decision to use an IV chain.
if (OrigPhi->getType() == Phi->getType() &&
!(ChainedPhis.count(Phi) ||
isExpandedAddRecExprPHI(OrigPhi, OrigInc, L)) &&
(ChainedPhis.count(Phi) ||
isExpandedAddRecExprPHI(Phi, IsomorphicInc, L))) {
std::swap(OrigPhi, Phi);
std::swap(OrigInc, IsomorphicInc);
}

// Replacing the congruent phi is sufficient because acyclic
// redundancy elimination, CSE/GVN, should handle the
// rest. However, once SCEV proves that a phi is congruent,
// it's often the head of an IV user cycle that is isomorphic
// with the original phi. It's worth eagerly cleaning up the
// common case of a single IV increment so that DeleteDeadPHIs
// can remove cycles that had postinc uses.
// Because we may potentially introduce a new use of OrigIV that didn't
// exist before at this point, its poison flags need readjustment.
const SCEV *TruncExpr =
SE.getTruncateOrNoop(SE.getSCEV(OrigInc), IsomorphicInc->getType());
if (OrigInc == IsomorphicInc || TruncExpr != SE.getSCEV(IsomorphicInc) ||
!SE.LI.replacementPreservesLCSSAForm(IsomorphicInc, OrigInc) ||
!hoistIVInc(OrigInc, IsomorphicInc,
/*RecomputePoisonFlags*/ true))
return;

SCEV_DEBUG_WITH_TYPE(DebugType,
dbgs() << "INDVARS: Eliminated congruent iv.inc: "
<< *IsomorphicInc << '\n');
Value *NewInc = OrigInc;
if (OrigInc->getType() != IsomorphicInc->getType()) {
BasicBlock::iterator IP;
if (PHINode *PN = dyn_cast<PHINode>(OrigInc))
IP = PN->getParent()->getFirstInsertionPt();
else
IP = OrigInc->getNextNonDebugInstruction()->getIterator();

IRBuilder<> Builder(IP->getParent(), IP);
Builder.SetCurrentDebugLocation(IsomorphicInc->getDebugLoc());
NewInc =
Builder.CreateTruncOrBitCast(OrigInc, IsomorphicInc->getType(), IVName);
}
IsomorphicInc->replaceAllUsesWith(NewInc);
DeadInsts.emplace_back(IsomorphicInc);
}

/// replaceCongruentIVs - Check for congruent phis in this loop header and
/// replace them with their most canonical representative. Return the number of
/// phis eliminated.
Expand Down Expand Up @@ -1654,60 +1717,7 @@ SCEVExpander::replaceCongruentIVs(Loop *L, const DominatorTree *DT,
if (OrigPhiRef->getType()->isPointerTy() != Phi->getType()->isPointerTy())
continue;

if (BasicBlock *LatchBlock = L->getLoopLatch()) {
Instruction *OrigInc = dyn_cast<Instruction>(
OrigPhiRef->getIncomingValueForBlock(LatchBlock));
Instruction *IsomorphicInc =
dyn_cast<Instruction>(Phi->getIncomingValueForBlock(LatchBlock));

if (OrigInc && IsomorphicInc) {
// If this phi has the same width but is more canonical, replace the
// original with it. As part of the "more canonical" determination,
// respect a prior decision to use an IV chain.
if (OrigPhiRef->getType() == Phi->getType() &&
!(ChainedPhis.count(Phi) ||
isExpandedAddRecExprPHI(OrigPhiRef, OrigInc, L)) &&
(ChainedPhis.count(Phi) ||
isExpandedAddRecExprPHI(Phi, IsomorphicInc, L))) {
std::swap(OrigPhiRef, Phi);
std::swap(OrigInc, IsomorphicInc);
}
// Replacing the congruent phi is sufficient because acyclic
// redundancy elimination, CSE/GVN, should handle the
// rest. However, once SCEV proves that a phi is congruent,
// it's often the head of an IV user cycle that is isomorphic
// with the original phi. It's worth eagerly cleaning up the
// common case of a single IV increment so that DeleteDeadPHIs
// can remove cycles that had postinc uses.
// Because we may potentially introduce a new use of OrigIV that didn't
// exist before at this point, its poison flags need readjustment.
const SCEV *TruncExpr =
SE.getTruncateOrNoop(SE.getSCEV(OrigInc), IsomorphicInc->getType());
if (OrigInc != IsomorphicInc &&
TruncExpr == SE.getSCEV(IsomorphicInc) &&
SE.LI.replacementPreservesLCSSAForm(IsomorphicInc, OrigInc) &&
hoistIVInc(OrigInc, IsomorphicInc, /*RecomputePoisonFlags*/ true)) {
SCEV_DEBUG_WITH_TYPE(
DebugType, dbgs() << "INDVARS: Eliminated congruent iv.inc: "
<< *IsomorphicInc << '\n');
Value *NewInc = OrigInc;
if (OrigInc->getType() != IsomorphicInc->getType()) {
BasicBlock::iterator IP;
if (PHINode *PN = dyn_cast<PHINode>(OrigInc))
IP = PN->getParent()->getFirstInsertionPt();
else
IP = OrigInc->getNextNonDebugInstruction()->getIterator();

IRBuilder<> Builder(IP->getParent(), IP);
Builder.SetCurrentDebugLocation(IsomorphicInc->getDebugLoc());
NewInc = Builder.CreateTruncOrBitCast(
OrigInc, IsomorphicInc->getType(), IVName);
}
IsomorphicInc->replaceAllUsesWith(NewInc);
DeadInsts.emplace_back(IsomorphicInc);
}
}
}
replaceCongruentIVInc(Phi, OrigPhiRef, L, DT, DeadInsts);
SCEV_DEBUG_WITH_TYPE(DebugType,
dbgs() << "INDVARS: Eliminated congruent iv: " << *Phi
<< '\n');
Expand Down

0 comments on commit d88e365

Please sign in to comment.