diff --git a/llvm/include/llvm/IR/PrintPasses.h b/llvm/include/llvm/IR/PrintPasses.h index 95b97e76c867c..0aa1b379c35cf 100644 --- a/llvm/include/llvm/IR/PrintPasses.h +++ b/llvm/include/llvm/IR/PrintPasses.h @@ -51,6 +51,9 @@ std::vector printAfterPasses(); // Returns true if we should always print the entire module. bool forcePrintModuleIR(); +// Returns true if we should print the entire function for loop passes. +bool forcePrintFuncIR(); + // Return true if -filter-passes is empty or contains the pass name. bool isPassInPrintList(StringRef PassName); bool isFilterPassesEmpty(); diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp index 6bb5f001e9bd1..7bd5e1e0cfac8 100644 --- a/llvm/lib/Analysis/LoopInfo.cpp +++ b/llvm/lib/Analysis/LoopInfo.cpp @@ -999,6 +999,18 @@ void llvm::printLoop(Loop &L, raw_ostream &OS, const std::string &Banner) { return; } + if (forcePrintFuncIR()) { + // handling -print-loop-func-scope. + // -print-module-scope overrides this. + OS << Banner << " (loop: "; + L.getHeader()->printAsOperand(OS, false); + OS << ")\n"; + + // printing whole function. + OS << *L.getHeader()->getParent(); + return; + } + OS << Banner; auto *PreHeader = L.getLoopPreheader(); diff --git a/llvm/lib/IR/PrintPasses.cpp b/llvm/lib/IR/PrintPasses.cpp index e2ef20bb81ba7..610411a3cf978 100644 --- a/llvm/lib/IR/PrintPasses.cpp +++ b/llvm/lib/IR/PrintPasses.cpp @@ -88,6 +88,12 @@ static cl::opt "always print a module IR"), cl::init(false), cl::Hidden); +static cl::opt LoopPrintFuncScope( + "print-loop-func-scope", + cl::desc("When printing IR for print-[before|after]{-all} " + "for a loop pass, always print function IR"), + cl::init(false), cl::Hidden); + // See the description for -print-changed for an explanation of the use // of this option. static cl::list FilterPasses( @@ -141,6 +147,8 @@ std::vector llvm::printAfterPasses() { bool llvm::forcePrintModuleIR() { return PrintModuleScope; } +bool llvm::forcePrintFuncIR() { return LoopPrintFuncScope; } + bool llvm::isPassInPrintList(StringRef PassName) { static std::unordered_set Set(FilterPasses.begin(), FilterPasses.end()); diff --git a/llvm/test/Other/print-loop-func-scope.ll b/llvm/test/Other/print-loop-func-scope.ll new file mode 100644 index 0000000000000..507ff70a5fd96 --- /dev/null +++ b/llvm/test/Other/print-loop-func-scope.ll @@ -0,0 +1,75 @@ +; This test documents how the IR dumped for loop passes differs with -print-loop-func-scope +; and -print-module-scope +; - Without -print-loop-func-scope, dumps only the loop, with 3 sections- preheader, +; loop, and exit blocks +; - With -print-loop-func-scope, dumps only the function which contains the loop +; - With -print-module-scope, dumps the entire module containing the loop, and disregards +; the -print-loop-func-scope flag. + +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=licm -print-after=licm \ +; RUN: | FileCheck %s -check-prefix=VANILLA +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=licm -print-after=licm -print-loop-func-scope \ +; RUN: | FileCheck %s -check-prefix=LOOPFUNC +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=licm -print-after=licm -print-module-scope \ +; RUN: | FileCheck %s -check-prefix=MODULE +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=licm -print-after=licm -print-module-scope -print-loop-func-scope\ +; RUN: | FileCheck %s -check-prefix=MODULEWITHLOOP + +; VANILLA: IR Dump After LICMPass +; VANILLA-NOT: define void @foo +; VANILLA: Preheader: +; VANILLA: Loop: +; VANILLA: Exit blocks + +; LOOPFUNC: IR Dump After LICMPass +; LOOPFUNC: (loop: +; LOOPFUNC: define void @foo +; LOOPFUNC-NOT: Preheader: +; LOOPFUNC-NOT: Loop: +; LOOPFUNC-NOT: Exit blocks + +; MODULE: IR Dump After LICMPass +; MODULE: ModuleID = +; MODULE: define void @foo +; MODULE-NOT: Preheader: +; MODULE-NOT: Loop: +; MODULE-NOT: Exit blocks +; MODULE: define void @bar +; MODULE: declare void @baz(i32) + +; MODULEWITHLOOP: IR Dump After LICMPass +; MODULEWITHLOOP: ModuleID = +; MODULEWITHLOOP: define void @foo +; MODULEWITHLOOP-NOT: Preheader: +; MODULEWITHLOOP-NOT: Loop: +; MODULEWITHLOOP-NOT: Exit blocks +; MODULEWITHLOOP: define void @bar +; MODULEWITHLOOP: declare void @baz(i32) + +define void @foo(i32 %n) { +entry: + br label %loop_cond + +loop_cond: + %i = phi i32 [ 0, %entry ], [ %i_next, %loop_body ] + %cmp = icmp slt i32 %i, %n + br i1 %cmp, label %loop_body, label %loop_end + +loop_body: + call void @baz(i32 %i) + %i_next = add i32 %i, 1 + br label %loop_cond + +loop_end: + ret void +} + +define void @bar() { + ret void +} + +declare void @baz(i32)