diff --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp --- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp +++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp @@ -100,7 +100,22 @@ return I.mayHaveSideEffects() && !I.isDroppable(); })) return false; - return true; + + // The loop or any of its sub-loops looping infinitely is legal. The loop can + // only be considered dead if either the function or all loops are + // mustprogress. + bool FnMustProgress = L->getHeader()->getParent()->mustProgress(); + auto LoopFinite = [&SE, FnMustProgress](Loop *L) { + const SCEV *S = SE.getConstantMaxBackedgeTakenCount(L); + if (isa(S) && !FnMustProgress && !hasMustProgress(L)) { + LLVM_DEBUG( + dbgs() << "Could not compute SCEV MaxBackedgeTakenCount and was " + "not required to make progress.\n"); + return false; + } + return true; + }; + return LoopFinite(L) && all_of(*L, LoopFinite); } /// This function returns true if there is no viable path from the @@ -230,17 +245,6 @@ : LoopDeletionResult::Unmodified; } - // Don't remove loops for which we can't solve the trip count unless the loop - // was required to make progress but has been determined to be dead. - const SCEV *S = SE.getConstantMaxBackedgeTakenCount(L); - if (isa(S) && - !L->getHeader()->getParent()->mustProgress() && !hasMustProgress(L)) { - LLVM_DEBUG(dbgs() << "Could not compute SCEV MaxBackedgeTakenCount and was " - "not required to make progress.\n"); - return Changed ? LoopDeletionResult::Modified - : LoopDeletionResult::Unmodified; - } - LLVM_DEBUG(dbgs() << "Loop is invariant, delete it!"); ORE.emit([&]() { return OptimizationRemark(DEBUG_TYPE, "Invariant", L->getStartLoc(), diff --git a/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll b/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll --- a/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll +++ b/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll @@ -158,7 +158,19 @@ ; function/loop is mustprogress. Test case from PR50511. define void @inner_loop_may_be_infinite(i1 %c1, i1 %c2) { ; CHECK-LABEL: @inner_loop_may_be_infinite( -; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK-NEXT: br label [[LOOP1:%.*]] +; CHECK: loop1: +; CHECK-NEXT: br i1 [[C1:%.*]], label [[LOOP1_LATCH:%.*]], label [[LOOP2_PREHEADER:%.*]] +; CHECK: loop2.preheader: +; CHECK-NEXT: br label [[LOOP2:%.*]] +; CHECK: loop2: +; CHECK-NEXT: br i1 [[C2:%.*]], label [[LOOP1_LATCH_LOOPEXIT:%.*]], label [[LOOP2]] +; CHECK: loop1.latch.loopexit: +; CHECK-NEXT: br label [[LOOP1_LATCH]] +; CHECK: loop1.latch: +; CHECK-NEXT: br i1 false, label [[LOOP1_LATCH_LOOP1_CRIT_EDGE:%.*]], label [[EXIT:%.*]] +; CHECK: loop1.latch.loop1_crit_edge: +; CHECK-NEXT: unreachable ; CHECK: exit: ; CHECK-NEXT: ret void ; @@ -256,7 +268,21 @@ ; mustprogress and can be removed. define void @loop2_mustprogress_but_not_sibling_loop(i1 %c1, i1 %c2, i1 %c3) { ; CHECK-LABEL: @loop2_mustprogress_but_not_sibling_loop( -; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK-NEXT: br label [[LOOP1:%.*]] +; CHECK: loop1: +; CHECK-NEXT: br i1 [[C1:%.*]], label [[LOOP1_LATCH:%.*]], label [[LOOP2_PREHEADER:%.*]] +; CHECK: loop2.preheader: +; CHECK-NEXT: br label [[LOOP3_PREHEADER:%.*]] +; CHECK: loop3.preheader: +; CHECK-NEXT: br label [[LOOP3:%.*]] +; CHECK: loop3: +; CHECK-NEXT: br i1 [[C2:%.*]], label [[LOOP1_LATCH_LOOPEXIT:%.*]], label [[LOOP3]] +; CHECK: loop1.latch.loopexit: +; CHECK-NEXT: br label [[LOOP1_LATCH]] +; CHECK: loop1.latch: +; CHECK-NEXT: br i1 false, label [[LOOP1_LATCH_LOOP1_CRIT_EDGE:%.*]], label [[EXIT:%.*]] +; CHECK: loop1.latch.loop1_crit_edge: +; CHECK-NEXT: unreachable ; CHECK: exit: ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll b/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll --- a/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll +++ b/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll @@ -317,7 +317,21 @@ define void @test9(i64 %n) { ; CHECK-LABEL: @test9( ; CHECK-NEXT: entry: -; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK-NEXT: br label [[L1:%.*]] +; CHECK: L1.loopexit: +; CHECK-NEXT: br label [[L1_LOOPEXIT_SPLIT:%.*]] +; CHECK: L1.loopexit.split: +; CHECK-NEXT: unreachable +; CHECK: L1: +; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[L2_PREHEADER:%.*]] +; CHECK: L2.preheader: +; CHECK-NEXT: br label [[L3_PREHEADER:%.*]] +; CHECK: L3.preheader: +; CHECK-NEXT: [[Y_L2_LCSSA:%.*]] = phi i64 [ undef, [[L2_PREHEADER]] ] +; CHECK-NEXT: br label [[L3:%.*]] +; CHECK: L3: +; CHECK-NEXT: [[COND2:%.*]] = icmp slt i64 [[Y_L2_LCSSA]], [[N:%.*]] +; CHECK-NEXT: br i1 [[COND2]], label [[L3]], label [[L1_LOOPEXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret void ;