/// Determine the insertion point for this user. By default, insert immediately
/// before the user. SCEVExpander or LICM will hoist loop invariants out of the
/// loop. For PHI nodes, there may be multiple uses, so compute the nearest
-/// common dominator for the incoming blocks.
+/// common dominator for the incoming blocks. A nullptr can be returned if no
+/// viable location is found: it may happen if User is a PHI and Def only comes
+/// to this PHI from unreachable blocks.
static Instruction *getInsertPointForUses(Instruction *User, Value *Def,
DominatorTree *DT, LoopInfo *LI) {
PHINode *PHI = dyn_cast<PHINode>(User);
continue;
BasicBlock *InsertBB = PHI->getIncomingBlock(i);
+
+ if (!DT->isReachableFromEntry(InsertBB))
+ continue;
+
if (!InsertPt) {
InsertPt = InsertBB->getTerminator();
continue;
InsertBB = DT->findNearestCommonDominator(InsertPt->getParent(), InsertBB);
InsertPt = InsertBB->getTerminator();
}
- assert(InsertPt && "Missing phi operand");
+
+ // If we have skipped all inputs, it means that Def only comes to Phi from
+ // unreachable blocks.
+ if (!InsertPt)
+ return nullptr;
auto *DefI = dyn_cast<Instruction>(Def);
if (!DefI)
/// This IV user cannot be widen. Replace this use of the original narrow IV
/// with a truncation of the new wide IV to isolate and eliminate the narrow IV.
static void truncateIVUse(NarrowIVDefUse DU, DominatorTree *DT, LoopInfo *LI) {
+ auto *InsertPt = getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI);
+ if (!InsertPt)
+ return;
LLVM_DEBUG(dbgs() << "INDVARS: Truncate IV " << *DU.WideDef << " for user "
<< *DU.NarrowUse << "\n");
- IRBuilder<> Builder(
- getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI));
+ IRBuilder<> Builder(InsertPt);
Value *Trunc = Builder.CreateTrunc(DU.WideDef, DU.NarrowDef->getType());
DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, Trunc);
}
assert(CastWidth <= IVWidth && "Unexpected width while widening compare.");
// Widen the compare instruction.
- IRBuilder<> Builder(
- getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI));
+ auto *InsertPt = getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI);
+ if (!InsertPt)
+ return false;
+ IRBuilder<> Builder(InsertPt);
DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, DU.WideDef);
// Widen the other operand of the compare, if necessary.
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -indvars < %s | FileCheck %s
-; REQUIRES: asserts
-; XFAIL: *
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @test() {
-; CHECK-LABEL: @test
+; CHECK-LABEL: @test(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: br label [[BB2:%.*]]
+; CHECK: bb1:
+; CHECK-NEXT: br label [[BB2]]
+; CHECK: bb2:
+; CHECK-NEXT: [[TMP:%.*]] = phi i32 [ -9, [[BB:%.*]] ], [ [[TMP6:%.*]], [[BB1:%.*]] ]
+; CHECK-NEXT: br label [[BB3:%.*]]
+; CHECK: bb3:
+; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ -9, [[BB2]] ], [ [[TMP6]], [[BB10:%.*]] ]
+; CHECK-NEXT: br i1 false, label [[BB5:%.*]], label [[BB12:%.*]]
+; CHECK: bb5:
+; CHECK-NEXT: [[TMP6]] = add nsw i32 [[TMP4]], -1
+; CHECK-NEXT: br i1 undef, label [[BB8:%.*]], label [[BB9:%.*]]
+; CHECK: bb8:
+; CHECK-NEXT: br label [[BB10]]
+; CHECK: bb9:
+; CHECK-NEXT: br label [[BB10]]
+; CHECK: bb10:
+; CHECK-NEXT: br label [[BB3]]
+; CHECK: bb12:
+; CHECK-NEXT: ret void
+;
bb:
br label %bb2