Index: llvm/include/llvm/Transforms/Utils/LoopUtils.h =================================================================== --- llvm/include/llvm/Transforms/Utils/LoopUtils.h +++ llvm/include/llvm/Transforms/Utils/LoopUtils.h @@ -227,6 +227,9 @@ /// Look for the loop attribute that disables the LICM transformation heuristics. bool hasDisableLICMTransformsHint(const Loop *L); +/// Look for the loop attribute that requires progress within the loop. +bool hasMustProgress(const Loop *L); + /// The mode sets how eager a transformation should be applied. enum TransformationMode { /// The pass can use heuristics to determine whether a transformation should Index: llvm/lib/Transforms/Scalar/LoopDeletion.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LoopDeletion.cpp +++ llvm/lib/Transforms/Scalar/LoopDeletion.cpp @@ -87,7 +87,11 @@ for (auto &I : L->blocks()) if (any_of(*I, [](Instruction &I) { return I.mayHaveSideEffects(); })) return false; - return true; + + // If this loop was explicitly required to make progress, or if the function + // is required to make progress, or if the function is known to return, we + // can remove this loop. + return hasMustProgress(L) || L->getHeader()->getParent()->hasMustProgress(); } /// This function returns true if there is no viable path from the @@ -202,7 +206,8 @@ // Don't remove loops for which we can't solve the trip count. // They could be infinite, in which case we'd be changing program behavior. const SCEV *S = SE.getConstantMaxBackedgeTakenCount(L); - if (isa(S)) { + if (isa(S) && + !L->getHeader()->getParent()->hasMustProgress()) { LLVM_DEBUG(dbgs() << "Could not compute SCEV MaxBackedgeTakenCount.\n"); return Changed ? LoopDeletionResult::Modified : LoopDeletionResult::Unmodified; Index: llvm/lib/Transforms/Utils/LoopUtils.cpp =================================================================== --- llvm/lib/Transforms/Utils/LoopUtils.cpp +++ llvm/lib/Transforms/Utils/LoopUtils.cpp @@ -63,6 +63,7 @@ static const char *LLVMLoopDisableNonforced = "llvm.loop.disable_nonforced"; static const char *LLVMLoopDisableLICM = "llvm.licm.disable"; +static const char *LLVMLoopMustProgress = "llvm.loop.mustprogress"; bool llvm::formDedicatedExitBlocks(Loop *L, DominatorTree *DT, LoopInfo *LI, MemorySSAUpdater *MSSAU, @@ -404,6 +405,10 @@ return getBooleanLoopAttribute(L, LLVMLoopDisableLICM); } +bool llvm::hasMustProgress(const Loop *L) { + return getBooleanLoopAttribute(L, LLVMLoopMustProgress); +} + TransformationMode llvm::hasUnrollTransformation(Loop *L) { if (getBooleanLoopAttribute(L, "llvm.loop.unroll.disable")) return TM_SuppressedByUser; Index: llvm/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll +++ llvm/test/Analysis/ScalarEvolution/2012-03-26-LoadConstant.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -basic-aa -globalopt -instcombine -loop-rotate -licm -instcombine -indvars -loop-deletion -constmerge -S | FileCheck %s +; RUN: opt < %s -basic-aa -globalopt -instcombine -loop-rotate -licm -instcombine -indvars -loop-deletion -constmerge -simplifycfg -S | FileCheck %s ; PR11882: ComputeLoadConstantCompareExitLimit crash. ; ; for.body is deleted leaving a loop-invariant load. Index: llvm/test/Other/loop-deletion-printer.ll =================================================================== --- llvm/test/Other/loop-deletion-printer.ll +++ llvm/test/Other/loop-deletion-printer.ll @@ -14,7 +14,7 @@ ; DELETED-BUT-PRINTED: IR Dump {{.*}}LoopDeletionPass {{.*invalidated:}} ; DELETED-BUT-PRINTED-NOT: IR Dump {{.*}}LoopInstSimplifyPass -define void @deleteme() { +define void @deleteme() willreturn { entry: br label %loop loop: Index: llvm/test/Other/loop-pm-invalidation.ll =================================================================== --- llvm/test/Other/loop-pm-invalidation.ll +++ llvm/test/Other/loop-pm-invalidation.ll @@ -227,7 +227,7 @@ ret void } -define void @dead_loop() { +define void @dead_loop() willreturn { ; CHECK-LOOP-INV: Starting {{.*}}Function pass manager run ; CHECK-LOOP-INV-NEXT: Starting {{.*}}Function pass manager run ; CHECK-LOOP-INV-NEXT: Running pass: LoopSimplifyPass Index: llvm/test/Transforms/IndVarSimplify/exit_value_tests.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/exit_value_tests.ll +++ llvm/test/Transforms/IndVarSimplify/exit_value_tests.ll @@ -8,7 +8,8 @@ define i32 @polynomial_constant() { ;