From 94dca7c7eacd363041d747fa1dd2393a5109c67f Mon Sep 17 00:00:00 2001 From: Fedor Sergeev Date: Fri, 1 Dec 2017 17:42:46 +0000 Subject: [PATCH] IR printing improvement for function passes - introducing -print-module-scope Summary: When debugging function passes it happens to be rather useful to dump the whole module before the transformation and then use this dump to analyze this single transformation by running it separately on that particular module state. Introducing -print-module-scope debugging option that forces all the function-level IR dumps to become whole-module dumps. This option builds on top of normal dumping controls like -print-before/after -filter-print-funcs The plan is to eventually extend this option to cover other local passes (at least loop passes) but that should go as a separate change. Reviewers: sanjoy, weimingz, silvas, fedor.sergeev Reviewed By: weimingz Subscribers: apilipenko, skatkov, llvm-commits, mehdi_amini Differential Revision: https://reviews.llvm.org/D40245 llvm-svn: 319561 --- llvm/include/llvm/Pass.h | 6 +++ llvm/lib/IR/IRPrintingPasses.cpp | 5 ++- llvm/lib/IR/LegacyPassManager.cpp | 8 ++++ llvm/test/Other/print-module-scope.ll | 55 +++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Other/print-module-scope.ll diff --git a/llvm/include/llvm/Pass.h b/llvm/include/llvm/Pass.h index ff64117035091..a29b3771abb46 100644 --- a/llvm/include/llvm/Pass.h +++ b/llvm/include/llvm/Pass.h @@ -361,6 +361,12 @@ extern bool TimePassesIsEnabled; // @brief Tells if the function IR should be printed by PrinterPass. extern bool isFunctionInPrintList(StringRef FunctionName); +/// forcePrintModuleIR - returns true if IR printing passes should +// be printing module IR (even for local-pass printers e.g. function-pass) +// to provide more context, as enabled by debugging option -print-module-scope +// @brief Tells if IR printer should be printing module IR +extern bool forcePrintModuleIR(); + } // end namespace llvm // Include support files that contain important APIs commonly used by Passes, diff --git a/llvm/lib/IR/IRPrintingPasses.cpp b/llvm/lib/IR/IRPrintingPasses.cpp index 4c8afda18b711..3308ef4c249ce 100644 --- a/llvm/lib/IR/IRPrintingPasses.cpp +++ b/llvm/lib/IR/IRPrintingPasses.cpp @@ -45,7 +45,10 @@ PrintFunctionPass::PrintFunctionPass(raw_ostream &OS, const std::string &Banner) PreservedAnalyses PrintFunctionPass::run(Function &F, FunctionAnalysisManager &) { if (isFunctionInPrintList(F.getName())) - OS << Banner << static_cast(F); + if (forcePrintModuleIR()) + OS << Banner << " (function: " << F.getName() << ")\n" << *F.getParent(); + else + OS << Banner << static_cast(F); return PreservedAnalyses::all(); } diff --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp index c13893d1a9edf..8bd9ed6ef0faa 100644 --- a/llvm/lib/IR/LegacyPassManager.cpp +++ b/llvm/lib/IR/LegacyPassManager.cpp @@ -82,6 +82,12 @@ static cl::opt PrintAfterAll("print-after-all", llvm::cl::desc("Print IR after each pass"), cl::init(false), cl::Hidden); +static cl::opt + PrintModuleScope("print-module-scope", + cl::desc("When printing IR for print-[before|after]{-all} " + "always print a module IR"), + cl::init(false)); + static cl::list PrintFuncsList("filter-print-funcs", cl::value_desc("function names"), cl::desc("Only print IR for functions whose name " @@ -115,6 +121,8 @@ static bool ShouldPrintAfterPass(const PassInfo *PI) { return PrintAfterAll || ShouldPrintBeforeOrAfterPass(PI, PrintAfter); } +bool llvm::forcePrintModuleIR() { return PrintModuleScope; } + bool llvm::isFunctionInPrintList(StringRef FunctionName) { static std::unordered_set PrintFuncNames(PrintFuncsList.begin(), PrintFuncsList.end()); diff --git a/llvm/test/Other/print-module-scope.ll b/llvm/test/Other/print-module-scope.ll new file mode 100644 index 0000000000000..0e9c4d59cc3b3 --- /dev/null +++ b/llvm/test/Other/print-module-scope.ll @@ -0,0 +1,55 @@ +; This test is checking basic properties of -print-module-scope options: +; - dumps all the module IR at once +; - all the function attributes are shown, including those of declarations +; - works on top of -print-after and -filter-print-funcs +; +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -simplifycfg -print-after=simplifycfg -print-module-scope \ +; RUN: | FileCheck %s -check-prefix=CFG +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -simplifycfg -print-after=simplifycfg -filter-print-funcs=foo -print-module-scope \ +; RUN: | FileCheck %s -check-prefix=FOO + +; CFG: IR Dump After +; CFG-SAME: function: foo +; CFG-NEXT: ModuleID = +; CFG: define void @foo +; CFG: define void @bar +; CFG: declare void @baz +; CFG: IR Dump After +; CFG-SAME: function: bar +; CFG-NEXT: ModuleID = +; CFG: define void @foo +; CFG: define void @bar +; CFG: declare void @baz + +; FOO: IR Dump After +; FOO-NOT: function: bar +; FOO-SAME: function: foo +; FOO-NEXT: ModuleID = +; FOO: Function Attrs: nounwind ssp +; FOO: define void @foo +; FOO: Function Attrs: nounwind +; FOO: define void @bar +; FOO: Function Attrs: nounwind readnone ssp +; FOO: declare void @baz + +define void @foo() nounwind ssp { + call void @baz() + ret void +} + +define void @bar() #0 { + ret void +} + +declare void @baz() #1 + +attributes #0 = { nounwind "no-frame-pointer-elim"="true" } + +attributes #1 = { nounwind readnone ssp "use-soft-float"="false" } +; FOO: attributes #{{[0-9]}} = { nounwind "no-frame-pointer-elim"="true" } + +; FOO: attributes #{{[0-9]}} = { nounwind readnone ssp "use-soft-float"="false" } + +; FOO-NOT: IR Dump