[llvm] 494db38 - [LoopDeletion] Also consider loops with subloops for deletion.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 6 06:52:42 PST 2021


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.
 


        


More information about the llvm-commits mailing list