[llvm] aa5ec34 - [LoopDeletion] Emit a remark when a dead loop is deleted

Francis Visoiu Mistrih via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 3 15:41:44 PDT 2020


Author: Francis Visoiu Mistrih
Date: 2020-07-03T15:20:23-07:00
New Revision: aa5ec34e312699a2fe5263133129a1e103ac91ee

URL: https://github.com/llvm/llvm-project/commit/aa5ec34e312699a2fe5263133129a1e103ac91ee
DIFF: https://github.com/llvm/llvm-project/commit/aa5ec34e312699a2fe5263133129a1e103ac91ee.diff

LOG: [LoopDeletion] Emit a remark when a dead loop is deleted

This emits a remark when LoopDeletion deletes a dead loop, using the
source location of the loop's header. There are currently two reasons
for removing the loop: invariant loop or loop that never executes.

Differential Revision: https://reviews.llvm.org/D83113

Added: 
    llvm/test/Transforms/LoopDeletion/basic-remark.ll

Modified: 
    llvm/lib/Transforms/Scalar/LoopDeletion.cpp
    llvm/test/Transforms/LoopDeletion/unreachable-loops.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
index 19493405c41c..be209d34be42 100644
--- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
@@ -19,6 +19,7 @@
 #include "llvm/Analysis/GlobalsModRef.h"
 #include "llvm/Analysis/LoopPass.h"
 #include "llvm/Analysis/MemorySSA.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/InitializePasses.h"
@@ -136,7 +137,8 @@ static bool isLoopNeverExecuted(Loop *L) {
 /// instructions out of the loop.
 static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT,
                                            ScalarEvolution &SE, LoopInfo &LI,
-                                           MemorySSA *MSSA) {
+                                           MemorySSA *MSSA,
+                                           OptimizationRemarkEmitter &ORE) {
   assert(L->isLCSSAForm(DT) && "Expected LCSSA!");
 
   // We can only remove the loop if there is a preheader that we can branch from
@@ -166,6 +168,11 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT,
       std::fill(P.incoming_values().begin(), P.incoming_values().end(),
                 UndefValue::get(P.getType()));
     }
+    ORE.emit([&]() {
+      return OptimizationRemark(DEBUG_TYPE, "NeverExecutes", L->getStartLoc(),
+                                L->getHeader())
+             << "Loop deleted because it never executes";
+    });
     deleteDeadLoop(L, &DT, &SE, &LI, MSSA);
     ++NumDeleted;
     return LoopDeletionResult::Deleted;
@@ -202,6 +209,11 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT,
   }
 
   LLVM_DEBUG(dbgs() << "Loop is invariant, delete it!");
+  ORE.emit([&]() {
+    return OptimizationRemark(DEBUG_TYPE, "Invariant", L->getStartLoc(),
+                              L->getHeader())
+           << "Loop deleted because it is invariant";
+  });
   deleteDeadLoop(L, &DT, &SE, &LI, MSSA);
   ++NumDeleted;
 
@@ -215,7 +227,11 @@ PreservedAnalyses LoopDeletionPass::run(Loop &L, LoopAnalysisManager &AM,
   LLVM_DEBUG(dbgs() << "Analyzing Loop for deletion: ");
   LLVM_DEBUG(L.dump());
   std::string LoopName = std::string(L.getName());
-  auto Result = deleteLoopIfDead(&L, AR.DT, AR.SE, AR.LI, AR.MSSA);
+  // For the new PM, we can't use OptimizationRemarkEmitter as an analysis
+  // pass. Function analyses need to be preserved across loop transformations
+  // but ORE cannot be preserved (see comment before the pass definition).
+  OptimizationRemarkEmitter ORE(L.getHeader()->getParent());
+  auto Result = deleteLoopIfDead(&L, AR.DT, AR.SE, AR.LI, AR.MSSA, ORE);
   if (Result == LoopDeletionResult::Unmodified)
     return PreservedAnalyses::all();
 
@@ -265,11 +281,15 @@ bool LoopDeletionLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) {
   MemorySSA *MSSA = nullptr;
   if (MSSAAnalysis)
     MSSA = &MSSAAnalysis->getMSSA();
+  // For the old PM, we can't use OptimizationRemarkEmitter as an analysis
+  // pass.  Function analyses need to be preserved across loop transformations
+  // but ORE cannot be preserved (see comment before the pass definition).
+  OptimizationRemarkEmitter ORE(L->getHeader()->getParent());
 
   LLVM_DEBUG(dbgs() << "Analyzing Loop for deletion: ");
   LLVM_DEBUG(L->dump());
 
-  LoopDeletionResult Result = deleteLoopIfDead(L, DT, SE, LI, MSSA);
+  LoopDeletionResult Result = deleteLoopIfDead(L, DT, SE, LI, MSSA, ORE);
 
   if (Result == LoopDeletionResult::Deleted)
     LPM.markLoopAsDeleted(*L);

diff  --git a/llvm/test/Transforms/LoopDeletion/basic-remark.ll b/llvm/test/Transforms/LoopDeletion/basic-remark.ll
new file mode 100644
index 000000000000..c56ae9dcb03e
--- /dev/null
+++ b/llvm/test/Transforms/LoopDeletion/basic-remark.ll
@@ -0,0 +1,37 @@
+; RUN: opt -loop-deletion %s -o /dev/null --pass-remarks-output=%t --pass-remarks-filter=loop-delete
+; RUN: cat %t | FileCheck %s
+
+; Check that we use the right debug location: the loop header.
+; CHECK:      --- !Passed
+; CHECK-NEXT: Pass:            loop-delete
+; CHECK-NEXT: Name:            Invariant
+; CHECK-NEXT: DebugLoc:        { File: loop.c, Line: 2, Column: 3 }
+; CHECK-NEXT: Function:        main
+; CHECK-NEXT: Args:
+; CHECK-NEXT:   - String:          Loop deleted because it is invariant
+; CHECK-NEXT: ...
+define i32 @main() local_unnamed_addr #0 {
+entry:
+  br label %for.cond, !dbg !9
+
+for.cond:
+  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.cond ]
+  %cmp = icmp ult i32 %i.0, 1000
+  %inc = add nuw nsw i32 %i.0, 1
+  br i1 %cmp, label %for.cond, label %for.cond.cleanup
+
+for.cond.cleanup:
+  ret i32 0
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "", isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug, enums: !2, nameTableKind: None, sysroot: "/")
+!1 = !DIFile(filename: "loop.c", directory: "")
+!2 = !{}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 1, type: !8, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+!7 = !DIFile(filename: "loop.c", directory: "")
+!8 = !DISubroutineType(types: !2)
+!9 = !DILocation(line: 2, column: 3, scope: !6)

diff  --git a/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll b/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll
index 5bdaeb11232a..a74ddf99285e 100644
--- a/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll
+++ b/llvm/test/Transforms/LoopDeletion/unreachable-loops.ll
@@ -1,4 +1,5 @@
-; RUN: opt < %s -loop-deletion -verify-dom-info -S | FileCheck %s
+; RUN: opt < %s -loop-deletion -verify-dom-info --pass-remarks-output=%t --pass-remarks-filter=loop-delete -S | FileCheck %s
+; RUN: cat %t | FileCheck %s --check-prefix=REMARKS
 
 ; Checking that we can delete loops that are never executed.
 ; We do not change the constant conditional branch statement (where the not-taken target
@@ -10,6 +11,8 @@ define void @test1(i64 %n, i64 %m) nounwind {
 ; CHECK-LABEL: entry:
 ; CHECK-NEXT: br i1 true, label %return, label %bb.preheader
 ; CHECK-NOT: bb:
+; REMARKS-LABEL: Function: test1
+; REMARKS: Loop deleted because it never executes
 entry:
   br i1 true, label %return, label %bb
 
@@ -63,6 +66,8 @@ define i64 @test3(i64 %n, i64 %m, i64 %maybe_zero) nounwind {
 ; CHECK-LABEL: return:
 ; CHECK-NEXT: %x.lcssa = phi i64 [ 20, %entry ], [ %x.lcssa.ph, %return.loopexit ]
 ; CHECK-NEXT: ret i64 %x.lcssa
+; REMARKS-LABEL: Function: test3
+; REMARKS: Loop deleted because it never executes
 entry:
   br i1 false, label %bb, label %return
 
@@ -121,6 +126,8 @@ define void @test5(i64 %n, i64 %m, i1 %cond) nounwind {
 ; CHECK-LABEL: looppred2:
 ; CHECK-NEXT: br i1 true, label %return, label %bb.preheader
 ; CHECK-NOT: bb:
+; REMARKS-LABEL: Function: test5
+; REMARKS: Loop deleted because it never executes
 entry:
   br i1 %cond, label %looppred1, label %looppred2
 
@@ -179,6 +186,8 @@ define i64 @test7(i64 %n) {
 ; CHECK-LABEL: L1Latch:
 ; CHECK-NEXT: %y = phi i64 [ %y.next, %L1 ], [ %y.L2.lcssa, %L1Latch.loopexit ]
 ; CHECK: br i1 %cond2, label %exit, label %L1
+; REMARKS-LABEL: Function: test7
+; REMARKS: Loop deleted because it never executes
 entry: 
   br label %L1
 
@@ -213,6 +222,8 @@ define void @test8(i64 %n) {
 ; CHECK-NEXT: br label %exit
 ; CHECK-LABEL: exit:
 ; CHECK-NEXT: ret void
+; REMARKS-LABEL: Function: test8
+; REMARKS: Loop deleted because it never executes
 entry: 
   br label %L1
 
@@ -246,6 +257,8 @@ define void @test9(i64 %n) {
 ; CHECK-NEXT: br label %L3
 ; CHECK-LABEL: L3:
 ; CHECK: br i1 %cond2, label %L3, label %L1.loopexit
+; REMARKS-LABEL: Function: test9
+; REMARKS: Loop deleted because it never executes
 entry: 
   br label %L1
 
@@ -311,6 +324,12 @@ define void @test11(i64 %n) {
 ; CHECK-NEXT: br label %exit
 ; CHECK-LABEL: exit:
 ; CHECK-NEXT: ret void
+; REMARKS-LABEL: Function: test11
+; REMARKS: Loop deleted because it is invariant
+; REMARKS-LABEL: Function: test11
+; REMARKS: Loop deleted because it never executes
+; REMARKS-LABEL: Function: test11
+; REMARKS: Loop deleted because it is invariant
 entry: 
   br label %L1
 
@@ -345,6 +364,8 @@ define i64 @test12(i64 %n){
 ; CHECK-LABEL: exit:
 ; CHECK-NEXT:    %y.phi = phi i64 [ undef, %L1.preheader ]
 ; CHECK-NEXT:    ret i64 %y.phi
+; REMARKS-LABEL: Function: test12
+; REMARKS: Loop deleted because it never executes
 
 entry:
   br i1 true, label %exit1, label %L1
@@ -380,6 +401,8 @@ define i64 @test13(i64 %n) {
 ; CHECK-LABEL: exit:
 ; CHECK-NEXT:    %y.phi = phi i64 [ undef, %L1.preheader ]
 ; CHECK-NEXT:    ret i64 %y.phi
+; REMARKS-LABEL: Function: test13
+; REMARKS: Loop deleted because it never executes
 
 entry:
   br i1 true, label %exit1, label %L1


        


More information about the llvm-commits mailing list