diff --git a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp index c71f1a513823..0f07d3f57e2f 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(OrigPhiRef->getIncomingValueForBlock(LatchBlock)); + Instruction *OrigInc = dyn_cast( + OrigPhiRef->getIncomingValueForBlock(LatchBlock)); Instruction *IsomorphicInc = - cast(Phi->getIncomingValueForBlock(LatchBlock)); + dyn_cast(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(OrigInc)) - IP = &*PN->getParent()->getFirstInsertionPt(); - else - IP = OrigInc->getNextNode(); - - IRBuilder<> Builder(IP); - Builder.SetCurrentDebugLocation(IsomorphicInc->getDebugLoc()); - NewInc = Builder. - CreateTruncOrBitCast(OrigInc, IsomorphicInc->getType(), IVName); + 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(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 887b9db7f258..0adb92d671b1 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 +}