[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
This commit is contained in:
Francis Visoiu Mistrih 2020-07-02 22:09:01 -07:00
parent dae9803e4d
commit a210f22919
3 changed files with 84 additions and 4 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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