summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSanjoy Das <sanjoy@playingwithpointers.com>2016-05-11 17:41:41 +0000
committerSanjoy Das <sanjoy@playingwithpointers.com>2016-05-11 17:41:41 +0000
commit4e8c80382ff29c0e1dddfed5f497d9a1d7d36263 (patch)
treeb7c3ce2bdc47162a56c8ba6781759d8f917567a3
parentabb7b93eb9e21ea55a566b4f2c29b4fbd500906a (diff)
downloadbcm5719-llvm-4e8c80382ff29c0e1dddfed5f497d9a1d7d36263.tar.gz
bcm5719-llvm-4e8c80382ff29c0e1dddfed5f497d9a1d7d36263.zip
[SCEVExpander] Fix a failed cast<> assertion
SCEVExpander::replaceCongruentIVs assumes the backedge value of an SCEV-analysable PHI to always be an instruction, when this is not necessarily true. For now address this by bailing out of the optimization if the backedge value of the PHI is a non-Instruction. llvm-svn: 269213
-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