mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-11 21:45:16 +00:00
[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:
parent
dae9803e4d
commit
a210f22919
@ -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);
|
||||
|
37
test/Transforms/LoopDeletion/basic-remark.ll
Normal file
37
test/Transforms/LoopDeletion/basic-remark.ll
Normal 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)
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user