[llvm] r292332 - [PM] Teach LoopDeletion to correctly update the LPM when loops are

Chandler Carruth via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 17 18:41:26 PST 2017


Author: chandlerc
Date: Tue Jan 17 20:41:26 2017
New Revision: 292332

URL: http://llvm.org/viewvc/llvm-project?rev=292332&view=rev
Log:
[PM] Teach LoopDeletion to correctly update the LPM when loops are
deleted.

I've expanded its test coverage a bit including adding one test that
will crash clearly without this change.

Added:
    llvm/trunk/test/Transforms/LoopDeletion/invalidation.ll
Modified:
    llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp
    llvm/trunk/test/Transforms/LoopDeletion/multiple-exit-conditions.ll
    llvm/trunk/test/Transforms/LoopDeletion/multiple-exits.ll

Modified: llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp?rev=292332&r1=292331&r2=292332&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/LoopDeletion.cpp Tue Jan 17 20:41:26 2017
@@ -100,12 +100,16 @@ static bool isLoopDead(Loop *L, ScalarEv
 /// This entire process relies pretty heavily on LoopSimplify form and LCSSA in
 /// order to make various safety checks work.
 ///
-/// \returns true if any changes are made, even if the loop is not deleted.
+/// \returns true if the loop is deleted.
+///
+/// This also sets the \p Changed output parameter to `true` if any changes
+/// were made. This may mutate the loop even if it is unable to delete it due
+/// to hoisting trivially loop invariant instructions out of the loop.
 ///
 /// This also updates the relevant analysis information in \p DT, \p SE, and \p
 /// LI.
 static bool deleteLoopIfDead(Loop *L, DominatorTree &DT, ScalarEvolution &SE,
-                             LoopInfo &LI) {
+                             LoopInfo &LI, bool &Changed) {
   assert(L->isLCSSAForm(DT) && "Expected LCSSA!");
 
   // We can only remove the loop if there is a preheader that we can
@@ -135,15 +139,14 @@ static bool deleteLoopIfDead(Loop *L, Do
     return false;
 
   // Finally, we have to check that the loop really is dead.
-  bool Changed = false;
   if (!isLoopDead(L, SE, ExitingBlocks, ExitBlock, Changed, Preheader))
-    return Changed;
+    return false;
 
   // 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.getMaxBackedgeTakenCount(L);
   if (isa<SCEVCouldNotCompute>(S))
-    return Changed;
+    return false;
 
   // Now that we know the removal is safe, remove the loop by changing the
   // branch from the preheader to go to the single exit block.
@@ -215,15 +218,21 @@ static bool deleteLoopIfDead(Loop *L, Do
 
   ++NumDeleted;
 
-  return Changed;
+  return true;
 }
 
 PreservedAnalyses LoopDeletionPass::run(Loop &L, LoopAnalysisManager &AM,
                                         LoopStandardAnalysisResults &AR,
-                                        LPMUpdater &) {
-  bool Changed = deleteLoopIfDead(&L, AR.DT, AR.SE, AR.LI);
-  if (!Changed)
+                                        LPMUpdater &Updater) {
+  bool Changed = false;
+
+  if (deleteLoopIfDead(&L, AR.DT, AR.SE, AR.LI, Changed)) {
+    assert(Changed && "Cannot delete a loop without changing something!");
+    // Need to update the LPM about this loop going away.
+    Updater.markLoopAsDeleted(L);
+  } else if (!Changed) {
     return PreservedAnalyses::all();
+  }
 
   return getLoopPassPreservedAnalyses();
 }
@@ -262,5 +271,6 @@ bool LoopDeletionLegacyPass::runOnLoop(L
   ScalarEvolution &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
   LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
 
-  return deleteLoopIfDead(L, DT, SE, LI);
+  bool Changed = false;
+  return deleteLoopIfDead(L, DT, SE, LI, Changed) || Changed;
 }

Added: llvm/trunk/test/Transforms/LoopDeletion/invalidation.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopDeletion/invalidation.ll?rev=292332&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/LoopDeletion/invalidation.ll (added)
+++ llvm/trunk/test/Transforms/LoopDeletion/invalidation.ll Tue Jan 17 20:41:26 2017
@@ -0,0 +1,42 @@
+; Ensure we don't run analyses over loops after they've been deleted. We run
+; one version with a no-op loop pass to make sure that the loop doesn't get
+; simplified away.
+;
+; RUN: opt < %s -passes='require<ivusers>,no-op-loop,require<ivusers>' -S \
+; RUN:     | FileCheck %s --check-prefixes=CHECK,BEFORE
+; RUN: opt < %s -passes='require<ivusers>,loop-deletion,require<ivusers>' -S \
+; RUN:     | FileCheck %s --check-prefixes=CHECK,AFTER
+
+
+define void @foo(i64 %n, i64 %m) nounwind {
+; CHECK-LABEL: @foo(
+
+entry:
+  br label %bb
+; CHECK:       entry:
+; BEFORE-NEXT:   br label %bb
+; AFTER-NEXT:    br label %return
+
+bb:
+  %x.0 = phi i64 [ 0, %entry ], [ %t0, %bb2 ]
+  %t0 = add i64 %x.0, 1
+  %t1 = icmp slt i64 %x.0, %n
+  br i1 %t1, label %bb2, label %return
+; BEFORE:      bb:
+; BEFORE:        br i1 {{.*}}, label %bb2, label %return
+; AFTER-NOT:   bb:
+; AFTER-NOT:     br
+
+bb2:
+  %t2 = icmp slt i64 %x.0, %m
+  br i1 %t1, label %bb, label %return
+; BEFORE:      bb2:
+; BEFORE:        br i1 {{.*}}, label %bb, label %return
+; AFTER-NOT:   bb2:
+; AFTER-NOT:     br
+
+return:
+  ret void
+; CHECK:       return:
+; CHECK-NEXT:    ret void
+}

Modified: llvm/trunk/test/Transforms/LoopDeletion/multiple-exit-conditions.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopDeletion/multiple-exit-conditions.ll?rev=292332&r1=292331&r2=292332&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopDeletion/multiple-exit-conditions.ll (original)
+++ llvm/trunk/test/Transforms/LoopDeletion/multiple-exit-conditions.ll Tue Jan 17 20:41:26 2017
@@ -1,5 +1,5 @@
 ; RUN: opt < %s -loop-deletion -S | FileCheck %s
-; RUN: opt < %s -passes='require<scalar-evolution>,loop(loop-deletion)' -S | FileCheck %s
+; RUN: opt < %s -passes='loop(loop-deletion)' -S | FileCheck %s
 
 ; ScalarEvolution can prove the loop iteration is finite, even though
 ; it can't represent the exact trip count as an expression. That's

Modified: llvm/trunk/test/Transforms/LoopDeletion/multiple-exits.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopDeletion/multiple-exits.ll?rev=292332&r1=292331&r2=292332&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopDeletion/multiple-exits.ll (original)
+++ llvm/trunk/test/Transforms/LoopDeletion/multiple-exits.ll Tue Jan 17 20:41:26 2017
@@ -5,6 +5,9 @@
 ;
 ; RUN: opt < %s -loop-simplify -lcssa -S | FileCheck %s --check-prefixes=CHECK,BEFORE
 ; RUN: opt < %s -loop-deletion -S | FileCheck %s --check-prefixes=CHECK,AFTER
+;
+; RUN: opt < %s -passes=no-op-loop -S | FileCheck %s --check-prefixes=CHECK,BEFORE
+; RUN: opt < %s -passes=loop-deletion -S | FileCheck %s --check-prefixes=CHECK,AFTER
 
 
 define void @foo(i64 %n, i64 %m) nounwind {




More information about the llvm-commits mailing list