summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Analysis/ScalarEvolutionExpander.cpp90
-rw-r--r--llvm/test/Analysis/ScalarEvolution/expander-replace-congruent-ivs.ll70
2 files changed, 117 insertions, 43 deletions
diff --git a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp
index c71f1a51382..0f07d3f57e2 100644
--- a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp
+++ b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp
@@ -1794,51 +1794,55 @@ unsigned SCEVExpander::replaceCongruentIVs(Loop *L, const DominatorTree *DT,
continue;
if (BasicBlock *LatchBlock = L->getLoopLatch()) {
- Instruction *OrigInc =
- cast<Instruction>(OrigPhiRef->getIncomingValueForBlock(LatchBlock));
+ Instruction *OrigInc = dyn_cast<Instruction>(
+ OrigPhiRef->getIncomingValueForBlock(LatchBlock));
Instruction *IsomorphicInc =
- cast<Instruction>(Phi->getIncomingValueForBlock(LatchBlock));
-
- // 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.
- 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)) {
- DEBUG_WITH_TYPE(DebugType,
- dbgs() << "INDVARS: Eliminated congruent iv.inc: "
- << *IsomorphicInc << '\n');
- Value *NewInc = OrigInc;
- if (OrigInc->getType() != IsomorphicInc->getType()) {
- Instruction *IP = nullptr;
- if (PHINode *PN = dyn_cast<PHINode>(OrigInc))
- IP = &*PN->getParent()->getFirstInsertionPt();
- else
- IP = OrigInc->getNextNode();
-
- IRBuilder<> Builder(IP);
- Builder.SetCurrentDebugLocation(IsomorphicInc->getDebugLoc());
- NewInc = Builder.
- CreateTruncOrBitCast(OrigInc, IsomorphicInc->getType(), IVName);
+ 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.
+ 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)) {
+ DEBUG_WITH_TYPE(DebugType,
+ dbgs() << "INDVARS: Eliminated congruent iv.inc: "
+ << *IsomorphicInc << '\n');
+ Value *NewInc = OrigInc;
+ if (OrigInc->getType() != IsomorphicInc->getType()) {
+ Instruction *IP = nullptr;
+ if (PHINode *PN = dyn_cast<PHINode>(OrigInc))
+ IP = &*PN->getParent()->getFirstInsertionPt();
+ else
+ IP = OrigInc->getNextNode();
+
+ IRBuilder<> Builder(IP);
+ Builder.SetCurrentDebugLocation(IsomorphicInc->getDebugLoc());
+ NewInc = Builder.CreateTruncOrBitCast(
+ OrigInc, IsomorphicInc->getType(), IVName);
+ }
+ IsomorphicInc->replaceAllUsesWith(NewInc);
+ DeadInsts.emplace_back(IsomorphicInc);
}
- IsomorphicInc->replaceAllUsesWith(NewInc);
- DeadInsts.emplace_back(IsomorphicInc);
}
}
DEBUG_WITH_TYPE(DebugType, dbgs() << "INDVARS: Eliminated congruent iv: "
diff --git a/llvm/test/Analysis/ScalarEvolution/expander-replace-congruent-ivs.ll b/llvm/test/Analysis/ScalarEvolution/expander-replace-congruent-ivs.ll
index 887b9db7f25..0adb92d671b 100644
--- a/llvm/test/Analysis/ScalarEvolution/expander-replace-congruent-ivs.ll
+++ b/llvm/test/Analysis/ScalarEvolution/expander-replace-congruent-ivs.ll
@@ -39,3 +39,73 @@ loop_1:
leave:
ret void
}
+
+
+; @ReplaceArg_0 and @ReplaceArg_1 used to trigger a failed cast<>
+; assertion in SCEVExpander.
+
+define void @ReplaceArg_0(i32 %val) {
+; CHECK-LABEL: @ReplaceArg_0(
+entry:
+ br i1 undef, label %loop_0.cond, label %for.body.us
+
+for.body.us:
+ br label %loop_0.cond
+
+loop_0.cond:
+ br i1 true, label %loop_0.ph, label %loop_1.ph
+
+loop_0.ph:
+ br label %loop_0
+
+loop_1.exit:
+ br label %loop_1.ph
+
+loop_1.ph:
+ %c.lcssa = phi i32 [ 0, %loop_0.cond ], [ %val, %loop_1.exit ]
+ br label %loop_1
+
+loop_0:
+ br i1 undef, label %loop_0, label %loop_1.exit
+
+loop_1:
+ %d.1 = phi i32 [ %c.lcssa, %loop_1 ], [ %val, %loop_1.ph ]
+ %t.1 = phi i32 [ %val, %loop_1 ], [ %c.lcssa, %loop_1.ph ]
+ br i1 undef, label %leave, label %loop_1
+
+leave:
+ ret void
+}
+
+define void @ReplaceArg_1(i32 %val) {
+; CHECK-LABEL: @ReplaceArg_1(
+entry:
+ br i1 undef, label %loop_0.cond, label %for.body.us
+
+for.body.us:
+ br label %loop_0.cond
+
+loop_0.cond:
+ br i1 true, label %loop_0.ph, label %loop_1.ph
+
+loop_0.ph:
+ br label %loop_0
+
+loop_1.exit:
+ br label %loop_1.ph
+
+loop_1.ph:
+ %c.lcssa = phi i32 [ 0, %loop_0.cond ], [ %val, %loop_1.exit ]
+ br label %loop_1
+
+loop_0:
+ br i1 undef, label %loop_0, label %loop_1.exit
+
+loop_1:
+ %t.1 = phi i32 [ %val, %loop_1 ], [ %c.lcssa, %loop_1.ph ]
+ %d.1 = phi i32 [ %c.lcssa, %loop_1 ], [ %val, %loop_1.ph ]
+ br i1 undef, label %leave, label %loop_1
+
+leave:
+ ret void
+}
OpenPOWER on IntegriCloud