From 2a184af221854262d713b82ea014cfbcc0004b48 Mon Sep 17 00:00:00 2001 From: Max Kazantsev Date: Tue, 12 Feb 2019 09:59:44 +0000 Subject: [PATCH] [IndVars] Fix corner case with unreachable Phi inputs. PR40454 Logic in `getInsertPointForUses` doesn't account for a corner case when `Def` only comes to a Phi user from unreachable blocks. In this case, the incoming value may be arbitrary (and not even available in the input block) and break the loop-related invariants that are asserted below. In fact, if we encounter this situation, no IR modification is needed. This Phi will be simplified away with nearest cleanup. Differential Revision: https://reviews.llvm.org/D58045 Reviewed By: spatel llvm-svn: 353816 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 26 +++++++++++++----- .../test/Transforms/IndVarSimplify/pr40454.ll | 27 ++++++++++++++++--- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 0ffe0102c105..ecf0bef13df2 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -217,7 +217,9 @@ bool IndVarSimplify::isValidRewrite(Value *FromVal, Value *ToVal) { /// 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(User); @@ -230,6 +232,10 @@ static Instruction *getInsertPointForUses(Instruction *User, Value *Def, continue; BasicBlock *InsertBB = PHI->getIncomingBlock(i); + + if (!DT->isReachableFromEntry(InsertBB)) + continue; + if (!InsertPt) { InsertPt = InsertBB->getTerminator(); continue; @@ -237,7 +243,11 @@ static Instruction *getInsertPointForUses(Instruction *User, Value *Def, 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(Def); if (!DefI) @@ -1307,10 +1317,12 @@ WidenIV::WidenedRecTy WidenIV::getWideRecurrence(NarrowIVDefUse DU) { /// 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); } @@ -1347,8 +1359,10 @@ bool WidenIV::widenLoopCompare(NarrowIVDefUse DU) { 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. diff --git a/llvm/test/Transforms/IndVarSimplify/pr40454.ll b/llvm/test/Transforms/IndVarSimplify/pr40454.ll index a2c569d5901e..c0ad01e4a7f9 100644 --- a/llvm/test/Transforms/IndVarSimplify/pr40454.ll +++ b/llvm/test/Transforms/IndVarSimplify/pr40454.ll @@ -1,11 +1,32 @@ +; 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