Author: Florian Hahn Date: 2021-01-06T14:49:00Z New Revision: 494db3816b0ece5b6722054f75cc2622ae1b840a
URL: https://github.com/llvm/llvm-project/commit/494db3816b0ece5b6722054f75cc2622ae1b840a DIFF: https://github.com/llvm/llvm-project/commit/494db3816b0ece5b6722054f75cc2622ae1b840a.diff LOG: [LoopDeletion] Also consider loops with subloops for deletion. Currently, LoopDeletion does skip loops that have sub-loops, but this means we currently fail to remove some no-op loops. One example are inner loops with live-out values. Those cannot be removed by itself. But the containing loop may itself be a no-op and the whole loop-nest can be deleted. The legality checks do not seem to rely on analyzing inner-loops only for correctness. With LoopDeletion being a LoopPass, the change means that we now unfortunately need to do some extra work in parent loops, by checking some conditions we already checked. But there appears to be no noticeable compile time impact: http://llvm-compile-time-tracker.com/compare.php?from=02d11f3cda2ab5b8bf4fc02639fd1f4b8c45963e&to=843201e9cf3b6871e18c52aede5897a22994c36c&stat=instructions This changes patch leads to ~10 more loops being deleted on MultiSource, SPEC2000, SPEC2006 with -O3 & LTO This patch is also required (together with a few others) to eliminate a no-op loop in omnetpp as discussed on llvm-dev 'LoopDeletion / removal of empty loops.' (http://lists.llvm.org/pipermail/llvm-dev/2020-December/147462.html) This change becomes relevant after removing potentially infinite loops is made possible in 'must-progress' loops (D86844). Note that I added a function call with side-effects to an outer loop in `llvm/test/Transforms/LoopDeletion/update-scev.ll` to preserve the original spirit of the test. Reviewed By: reames Differential Revision: https://reviews.llvm.org/D93716 Added: Modified: llvm/lib/Transforms/Scalar/LoopDeletion.cpp llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll llvm/test/Transforms/LoopDeletion/unreachable-loops.ll llvm/test/Transforms/LoopDeletion/update-scev.ll Removed: ################################################################################ diff --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp index 814cfc7ac6a9..a94676eadeab 100644 --- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp +++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp @@ -156,13 +156,6 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT, << "Deletion requires Loop with preheader and dedicated exits.\n"); return LoopDeletionResult::Unmodified; } - // We can't remove loops that contain subloops. If the subloops were dead, - // they would already have been removed in earlier executions of this pass. - if (L->begin() != L->end()) { - LLVM_DEBUG(dbgs() << "Loop contains subloops.\n"); - return LoopDeletionResult::Unmodified; - } - BasicBlock *ExitBlock = L->getUniqueExitBlock(); diff --git a/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll b/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll index 464c12f453a7..b7a921a8dd51 100644 --- a/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll +++ b/llvm/test/Transforms/LoopDeletion/noop-loops-with-subloops.ll @@ -10,24 +10,7 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3 define void @test1(i64 %N, i64 %M, %pair_t* %ptr) willreturn { ; CHECK-LABEL: @test1( ; CHECK-NEXT: entry: -; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] -; CHECK: outer.header: -; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[OUTER_IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ] -; CHECK-NEXT: br label [[INNER:%.*]] -; CHECK: inner: -; CHECK-NEXT: [[INNER_IV:%.*]] = phi i64 [ 0, [[OUTER_HEADER]] ], [ [[INNER_IV_NEXT:%.*]], [[INNER]] ] -; CHECK-NEXT: [[GEP:%.*]] = getelementptr [[PAIR_T:%.*]], %pair_t* [[PTR:%.*]], i64 [[INNER_IV]] -; CHECK-NEXT: [[P:%.*]] = load [[PAIR_T]], %pair_t* [[GEP]], align 4 -; CHECK-NEXT: [[V_0:%.*]] = extractvalue [[PAIR_T]] [[P]], 0 -; CHECK-NEXT: [[V_1:%.*]] = extractvalue [[PAIR_T]] [[P]], 1 -; CHECK-NEXT: [[INNER_EC:%.*]] = icmp ult i64 [[V_0]], [[V_1]] -; CHECK-NEXT: [[INNER_IV_NEXT]] = add i64 [[INNER_IV]], 1 -; CHECK-NEXT: br i1 [[INNER_EC]], label [[OUTER_LATCH]], label [[INNER]] -; CHECK: outer.latch: -; CHECK-NEXT: [[LCSSA:%.*]] = phi i64 [ [[V_1]], [[INNER]] ] -; CHECK-NEXT: [[OUTER_EC:%.*]] = icmp ult i64 [[OUTER_IV]], [[LCSSA]] -; CHECK-NEXT: [[OUTER_IV_NEXT]] = add i64 [[OUTER_IV]], 1 -; CHECK-NEXT: br i1 [[OUTER_EC]], label [[EXIT:%.*]], label [[OUTER_HEADER]] +; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll b/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll index a74ddf99285e..c9e178fbf586 100644 --- a/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll +++ b/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll @@ -244,22 +244,15 @@ exit: ; Delete a loop (L2) which has subloop (L3). ; Here we delete loop L2, but leave L3 as is. -; FIXME: Can delete L3 as well, by iteratively going backward through the single -; predecessor of L3 until we reach L1's block that guarantees L3 is never -; executed. define void @test9(i64 %n) { ; CHECK-LABEL: test9 -; CHECK-LABEL: L2.preheader: -; CHECK-NEXT: br label %L3.preheader -; CHECK-NOT: L2: -; CHECK-LABEL: L3.preheader: -; CHECK-NEXT: %y.L2.lcssa = phi i64 [ undef, %L2.preheader ] -; CHECK-NEXT: br label %L3 -; CHECK-LABEL: L3: -; CHECK: br i1 %cond2, label %L3, label %L1.loopexit +; CHECK-LABEL: entry: +; CHECK-NEXT: br label %exit +; CHECK-LABEL: exit: +; CHECK-NEXT: ret void ; REMARKS-LABEL: Function: test9 ; REMARKS: Loop deleted because it never executes -entry: +entry: br label %L1 L1: @@ -283,12 +276,12 @@ exit: ; We cannot delete L3 because of call within it. ; Since L3 is not deleted, and entirely contained within L2, L2 is also not ; deleted. -; FIXME: We can delete unexecutable loops having -; subloops contained entirely within them. define void @test10(i64 %n) { ; CHECK-LABEL: test10 -; CHECK: L2: -; CHECK: L3: +; CHECK-LABEL: entry: +; CHECK-NEXT: br label %exit +; CHECK-LABEL: exit: +; CHECK-NEXT: ret void entry: br label %L1 diff --git a/llvm/test/Transforms/LoopDeletion/update-scev.ll b/llvm/test/Transforms/LoopDeletion/update-scev.ll index 44d23aa4060d..16a553021917 100644 --- a/llvm/test/Transforms/LoopDeletion/update-scev.ll +++ b/llvm/test/Transforms/LoopDeletion/update-scev.ll @@ -48,6 +48,7 @@ for.body6: ; preds = %for.body6, %for.bod for.inc11: ; preds = %for.body6 %and.lcssa = phi i32 [ %and, %for.body6 ] + call void @sideeffect(i32 %and.lcssa) %inc12 = add nsw i32 %val, 1 %tobool = icmp eq i32 %inc12, 0 br i1 %tobool, label %for.cond14, label %for.body @@ -56,6 +57,8 @@ for.cond14: ; preds = %for.cond14, %for.in br i1 undef, label %for.cond, label %for.cond14 } +declare void @sideeffect(i32) + ; LoopDeletion removes the loop %for.body7.1. Make sure %inc.lcssa.1 in the loop ; exit block is correctly invalidated. _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits