Index: include/llvm/Pass.h =================================================================== --- include/llvm/Pass.h +++ include/llvm/Pass.h @@ -361,6 +361,12 @@ // @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, Index: lib/IR/IRPrintingPasses.cpp =================================================================== --- lib/IR/IRPrintingPasses.cpp +++ lib/IR/IRPrintingPasses.cpp @@ -45,7 +45,10 @@ 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(); } Index: lib/IR/LegacyPassManager.cpp =================================================================== --- lib/IR/LegacyPassManager.cpp +++ lib/IR/LegacyPassManager.cpp @@ -84,6 +84,12 @@ llvm::cl::desc("Print IR after each pass"), cl::init(false)); +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 " @@ -117,6 +123,8 @@ return PrintAfterAll || ShouldPrintBeforeOrAfterPass(PI, PrintAfter); } +bool llvm::forcePrintModuleIR() { return PrintModuleScope; } + bool llvm::isFunctionInPrintList(StringRef FunctionName) { static std::unordered_set PrintFuncNames(PrintFuncsList.begin(), PrintFuncsList.end()); Index: test/Other/print-module-scope.ll =================================================================== --- /dev/null +++ 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