Index: llvm/lib/Transforms/Scalar/LICM.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LICM.cpp +++ llvm/lib/Transforms/Scalar/LICM.cpp @@ -140,7 +140,7 @@ static bool isNotUsedOrFreeInLoop(const Instruction &I, const Loop *CurLoop, const LoopSafetyInfo *SafetyInfo, TargetTransformInfo *TTI, bool &FreeInLoop, - bool LoopNestMode); + const Loop *LoopNestCurLoop); static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop, BasicBlock *Dest, ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater *MSSAU, ScalarEvolution *SE, @@ -549,9 +549,10 @@ bool LoopNestMode = OutermostLoop != nullptr; if (!I.mayHaveSideEffects() && isNotUsedOrFreeInLoop(I, LoopNestMode ? OutermostLoop : CurLoop, - SafetyInfo, TTI, FreeInLoop, LoopNestMode) && - canSinkOrHoistInst(I, AA, DT, CurLoop, /*CurAST*/nullptr, MSSAU, true, - &Flags, ORE)) { + SafetyInfo, TTI, FreeInLoop, + LoopNestMode ? CurLoop : nullptr) && + canSinkOrHoistInst(I, AA, DT, CurLoop, /*CurAST*/ nullptr, MSSAU, + true, &Flags, ORE)) { if (sink(I, LI, DT, BFI, CurLoop, SafetyInfo, MSSAU, ORE)) { if (!FreeInLoop) { ++II; @@ -1380,7 +1381,7 @@ static bool isNotUsedOrFreeInLoop(const Instruction &I, const Loop *CurLoop, const LoopSafetyInfo *SafetyInfo, TargetTransformInfo *TTI, bool &FreeInLoop, - bool LoopNestMode) { + const Loop *LoopNestCurLoop) { const auto &BlockColors = SafetyInfo->getBlockColors(); bool IsFree = isFreeInLoop(I, CurLoop, TTI); for (const User *U : I.users()) { @@ -1398,13 +1399,24 @@ BlockColors.find(const_cast(BB))->second.size() != 1) return false; - if (LoopNestMode) { + // In loop nest mode, CurLoop is always the outermost loop. + // So the actual current loop is given as LoopNestCurLoop. + if (LoopNestCurLoop) { + // Skip PHI chain inside the loop nest that may have been created by + // lcssa pass. while (isa(UI) && UI->hasOneUser() && UI->getNumOperands() == 1) { + // If UI is inside the current loop, return false. + if (LoopNestCurLoop->contains(UI)) + return false; + // If UI is outside the loop nest, stop skipping. if (!CurLoop->contains(UI)) break; UI = cast(UI->user_back()); } + // If UI is a PHI that prevents sinking, return false. + if (isa(UI) && (!UI->hasOneUser() || UI->getNumOperands() > 1)) + return false; } } Index: llvm/test/Transforms/LICM/lnicm-crash.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LICM/lnicm-crash.ll @@ -0,0 +1,30 @@ +; RUN: opt -passes='loop-mssa(licm)' -S %s | FileCheck %s --check-prefixes CHECK +; RUN: opt -passes='loop-mssa(lnicm)' -S %s | FileCheck %s --check-prefixes CHECK + +define void @main() { +entry: + br label %for.body + +for.body: + %0 = select i1 undef, i40 undef, i40 253841517325 + br i1 true, label %for.end, label %for.body2 + +for.body2: + %v_299.017 = phi i40 [ %0, %for.body ] + br i1 true, label %for.end2, label %for.body + +; CHECK: for.end: +; CHECK-NEXT: [[SPLIT:%.*]] = phi i40 [ undef, %for.body ] +for.end: + %split = phi i40 [ %0, %for.body ] + br label %end + +; CHECK: for.end2: +; CHECK-NEXT: [[SPLIT1:%.*]] = phi i40 [ undef, %for.body2 ] +for.end2: + %split1 = phi i40 [ %v_299.017, %for.body2 ] + br label %end + +end: + ret void +} Index: llvm/test/Transforms/LICM/lnicm-crash2.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LICM/lnicm-crash2.ll @@ -0,0 +1,48 @@ +; RUN: opt -passes='function(loop-mssa(licm,loop-rotate,loop-deletion,lnicm))' -S %s | FileCheck %s --check-prefixes CHECK + +target datalayout = "n16:32" + +@f.a = external dso_local global i32, align 1 +@f.c = external dso_local global i16*, align 1 + +define void @f() { +entry: + br label %for.cond + +for.cond: + br label %lbl1 + +; CHECK-LABEL: lbl1 +; CHECK: [[LOAD:%.*]] = load i32, i32* @f.a, align 1 +; CHECK: [[CONV:%.*]] = trunc i32 [[LOAD]] to i16 +lbl1: + %0 = load i16*, i16** @f.c, align 1 + store i16 0, i16* %0, align 1 + br label %lbl2 + +lbl2: + br label %for.cond1 + +for.cond1: + %tobool = icmp ne i16 undef, 0 + br i1 %tobool, label %for.body, label %for.cond3 + +for.body: + br i1 undef, label %lbl1, label %if.end + +if.end: + br label %for.cond1 + +for.cond3: + br i1 false, label %for.body4, label %for.end5 + +for.body4: + %1 = load i32, i32* @f.a, align 1 + %conv = trunc i32 %1 to i16 + store i16 %conv, i16* undef, align 1 + br label %lbl2 + +for.end5: + br label %for.cond +} +