diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1179,6 +1179,7 @@ StandardInstrumentations SI(CodeGenOpts.DebugPassManager); SI.registerCallbacks(PIC); PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC); + SI.translatePassNamesToClassNames(PB); // Attempt to load pass plugins and register their callbacks with PB. for (auto &PluginFN : CodeGenOpts.PassPlugins) { diff --git a/llvm/include/llvm/IR/PrintPasses.h b/llvm/include/llvm/IR/PrintPasses.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/IR/PrintPasses.h @@ -0,0 +1,35 @@ +//===- PrintPasses.h - Utilities for printing IR ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_PRINTPASSES_H +#define LLVM_IR_PRINTPASSES_H + +#include "llvm/ADT/StringRef.h" +#include + +namespace llvm { + +bool shouldPrintBeforePass(); +bool shouldPrintAfterPass(); + +bool shouldPrintBeforePass(StringRef PassID); +bool shouldPrintAfterPass(StringRef PassID); + +bool shouldPrintBeforeAll(); +bool shouldPrintAfterAll(); + +std::vector printBeforePasses(); +std::vector printAfterPasses(); + +bool forcePrintModuleIR(); + +bool isFunctionInPrintList(StringRef FunctionName); + +} // namespace llvm + +#endif // LLVM_IR_PRINTPASSES_H diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h --- a/llvm/include/llvm/Passes/PassBuilder.h +++ b/llvm/include/llvm/Passes/PassBuilder.h @@ -532,6 +532,9 @@ /// Returns true if the pass name is the name of a (non-alias) analysis pass. bool isAnalysisPassName(StringRef PassName); + /// Translates a pass name to the corresponding class name. + StringRef translatePassNameToClassName(StringRef PassName); + /// Register a callback for a default optimizer pipeline extension /// point /// @@ -832,6 +835,6 @@ return false; } -} +} // namespace llvm #endif diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h --- a/llvm/include/llvm/Passes/StandardInstrumentations.h +++ b/llvm/include/llvm/Passes/StandardInstrumentations.h @@ -19,6 +19,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/PassInstrumentation.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/Passes/PassBuilder.h" #include #include @@ -37,12 +38,16 @@ ~PrintIRInstrumentation(); void registerCallbacks(PassInstrumentationCallbacks &PIC); + void translatePassNamesToClassNames(PassBuilder &PB); private: void printBeforePass(StringRef PassID, Any IR); void printAfterPass(StringRef PassID, Any IR); void printAfterPassInvalidated(StringRef PassID); + bool shouldPrintBeforePass(StringRef PassID); + bool shouldPrintAfterPass(StringRef PassID); + using PrintModuleDesc = std::tuple; void pushModuleDesc(StringRef PassID, Any IR); @@ -51,6 +56,8 @@ /// Stack of Module description, enough to print the module after a given /// pass. SmallVector ModuleDescStack; + SmallVector PrintBeforeClassNames; + SmallVector PrintAfterClassNames; bool StoreModuleDesc = false; }; @@ -85,6 +92,7 @@ StandardInstrumentations(bool DebugLogging) : PrintPass(DebugLogging) {} void registerCallbacks(PassInstrumentationCallbacks &PIC); + void translatePassNamesToClassNames(PassBuilder &PB); TimePassesHandler &getTimePasses() { return TimePasses; } }; diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt --- a/llvm/lib/IR/CMakeLists.txt +++ b/llvm/lib/IR/CMakeLists.txt @@ -44,6 +44,7 @@ PassManager.cpp PassRegistry.cpp PassTimingInfo.cpp + PrintPasses.cpp SafepointIRVerifier.cpp ProfileSummary.cpp Statepoint.cpp diff --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp --- a/llvm/lib/IR/LegacyPassManager.cpp +++ b/llvm/lib/IR/LegacyPassManager.cpp @@ -49,7 +49,7 @@ enum PassDebugLevel { Disabled, Arguments, Structure, Executions, Details }; -} +} // namespace static cl::opt PassDebugging("debug-pass", cl::Hidden, @@ -61,80 +61,6 @@ clEnumVal(Executions, "print pass name before it is executed"), clEnumVal(Details , "print pass details when it is executed"))); -namespace { -typedef llvm::cl::list -PassOptionList; -} - -// Print IR out before/after specified passes. -static PassOptionList -PrintBefore("print-before", - llvm::cl::desc("Print IR before specified passes"), - cl::Hidden); - -static PassOptionList -PrintAfter("print-after", - llvm::cl::desc("Print IR after specified passes"), - cl::Hidden); - -static cl::opt PrintBeforeAll("print-before-all", - llvm::cl::desc("Print IR before each pass"), - cl::init(false), cl::Hidden); -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), cl::Hidden); - -static cl::list - PrintFuncsList("filter-print-funcs", cl::value_desc("function names"), - cl::desc("Only print IR for functions whose name " - "match this for all print-[before|after][-all] " - "options"), - cl::CommaSeparated, cl::Hidden); - -/// This is a helper to determine whether to print IR before or -/// after a pass. - -bool llvm::shouldPrintBeforePass() { - return PrintBeforeAll || !PrintBefore.empty(); -} - -bool llvm::shouldPrintAfterPass() { - return PrintAfterAll || !PrintAfter.empty(); -} - -static bool ShouldPrintBeforeOrAfterPass(StringRef PassID, - PassOptionList &PassesToPrint) { - for (auto *PassInf : PassesToPrint) { - if (PassInf) - if (PassInf->getPassArgument() == PassID) { - return true; - } - } - return false; -} - -bool llvm::shouldPrintBeforePass(StringRef PassID) { - return PrintBeforeAll || ShouldPrintBeforeOrAfterPass(PassID, PrintBefore); -} - -bool llvm::shouldPrintAfterPass(StringRef PassID) { - return PrintAfterAll || ShouldPrintBeforeOrAfterPass(PassID, PrintAfter); -} - -bool llvm::forcePrintModuleIR() { return PrintModuleScope; } - -bool llvm::isFunctionInPrintList(StringRef FunctionName) { - static std::unordered_set PrintFuncNames(PrintFuncsList.begin(), - PrintFuncsList.end()); - return PrintFuncNames.empty() || - PrintFuncNames.count(std::string(FunctionName)); -} /// isPassDebuggingExecutionsOrMore - Return true if -debug-pass=Executions /// or higher is specified. bool PMDataManager::isPassDebuggingExecutionsOrMore() const { diff --git a/llvm/lib/IR/PrintPasses.cpp b/llvm/lib/IR/PrintPasses.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/IR/PrintPasses.cpp @@ -0,0 +1,92 @@ +//===- PrintPasses.cpp ----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/PrintPasses.h" +#include "llvm/Support/CommandLine.h" +#include + +using namespace llvm; + +// Print IR out before/after specified passes. +static cl::list + PrintBefore("print-before", + llvm::cl::desc("Print IR before specified passes"), + cl::CommaSeparated, cl::Hidden); + +static cl::list + PrintAfter("print-after", llvm::cl::desc("Print IR after specified passes"), + cl::CommaSeparated, cl::Hidden); + +static cl::opt PrintBeforeAll("print-before-all", + llvm::cl::desc("Print IR before each pass"), + cl::init(false), cl::Hidden); +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), cl::Hidden); + +static cl::list + PrintFuncsList("filter-print-funcs", cl::value_desc("function names"), + cl::desc("Only print IR for functions whose name " + "match this for all print-[before|after][-all] " + "options"), + cl::CommaSeparated, cl::Hidden); + +/// This is a helper to determine whether to print IR before or +/// after a pass. + +bool llvm::shouldPrintBeforePass() { + return PrintBeforeAll || !PrintBefore.empty(); +} + +bool llvm::shouldPrintAfterPass() { + return PrintAfterAll || !PrintAfter.empty(); +} + +static bool shouldPrintBeforeOrAfterPass(StringRef PassID, + ArrayRef PassesToPrint) { + for (auto &Pass : PassesToPrint) { + if (Pass == PassID) + return true; + } + return false; +} + +bool llvm::shouldPrintBeforeAll() { return PrintBeforeAll; } + +bool llvm::shouldPrintAfterAll() { return PrintAfterAll; } + +bool llvm::shouldPrintBeforePass(StringRef PassID) { + return PrintBeforeAll || shouldPrintBeforeOrAfterPass(PassID, PrintBefore); +} + +bool llvm::shouldPrintAfterPass(StringRef PassID) { + return PrintAfterAll || shouldPrintBeforeOrAfterPass(PassID, PrintAfter); +} + +std::vector llvm::printBeforePasses() { + return std::vector(PrintBefore); +} + +std::vector llvm::printAfterPasses() { + return std::vector(PrintAfter); +} + +bool llvm::forcePrintModuleIR() { return PrintModuleScope; } + +bool llvm::isFunctionInPrintList(StringRef FunctionName) { + static std::unordered_set PrintFuncNames(PrintFuncsList.begin(), + PrintFuncsList.end()); + return PrintFuncNames.empty() || + PrintFuncNames.count(std::string(FunctionName)); +} diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -200,8 +200,9 @@ StandardInstrumentations SI(Conf.DebugPassManager); SI.registerCallbacks(PIC); PassBuilder PB(TM, Conf.PTO, PGOOpt, &PIC); - AAManager AA; + SI.translatePassNamesToClassNames(PB); + AAManager AA; // Parse a custom AA pipeline if asked to. if (auto Err = PB.parseAAPipeline(AA, "default")) report_fatal_error("Error parsing default AA pipeline"); diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -67,6 +67,7 @@ #include "llvm/IR/Verifier.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetMachine.h" @@ -2806,3 +2807,21 @@ #include "PassRegistry.def" return false; } + +StringRef PassBuilder::translatePassNameToClassName(StringRef PassName) { + bool DebugLogging = false; +#define MODULE_PASS(NAME, CREATE_PASS) \ + if (PassName == NAME) \ + return decltype(CREATE_PASS)::name(); +#define FUNCTION_PASS(NAME, CREATE_PASS) \ + if (PassName == NAME) \ + return decltype(CREATE_PASS)::name(); +#define LOOP_PASS(NAME, CREATE_PASS) \ + if (PassName == NAME) \ + return decltype(CREATE_PASS)::name(); +#define CGSSC_PASS(NAME, CREATE_PASS) \ + if (PassName == NAME) \ + return decltype(CREATE_PASS)::name(); +#include "PassRegistry.def" + report_fatal_error("unrecognized pass name: " + PassName); +} diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -19,9 +19,9 @@ #include "llvm/Analysis/LazyCallGraph.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/Function.h" -#include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassInstrumentation.h" +#include "llvm/IR/PrintPasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormatVariadic.h" @@ -220,10 +220,10 @@ // Note: here we rely on a fact that we do not change modules while // traversing the pipeline, so the latest captured module is good // for all print operations that has not happen yet. - if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID)) + if (StoreModuleDesc && shouldPrintAfterPass(PassID)) pushModuleDesc(PassID, IR); - if (!llvm::shouldPrintBeforePass(PassID)) + if (!shouldPrintBeforePass(PassID)) return; SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); @@ -235,7 +235,7 @@ if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) return; - if (!llvm::shouldPrintAfterPass(PassID)) + if (!shouldPrintAfterPass(PassID)) return; if (StoreModuleDesc) @@ -246,7 +246,7 @@ } void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { - if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID)) + if (!StoreModuleDesc || !shouldPrintAfterPass(PassID)) return; if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) @@ -266,6 +266,26 @@ printIR(dbgs(), M, Banner, Extra); } +bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) { + if (llvm::shouldPrintBeforeAll()) + return true; + for (const auto &P : PrintBeforeClassNames) { + if (PassID == P) + return true; + } + return false; +} + +bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) { + if (llvm::shouldPrintAfterAll()) + return true; + for (const auto &P : PrintAfterClassNames) { + if (PassID == P) + return true; + } + return false; +} + void PrintIRInstrumentation::registerCallbacks( PassInstrumentationCallbacks &PIC) { // BeforePass callback is not just for printing, it also saves a Module @@ -287,6 +307,13 @@ } } +void PrintIRInstrumentation::translatePassNamesToClassNames(PassBuilder &PB) { + for (const auto &PassName : printBeforePasses()) + PrintBeforeClassNames.push_back(PB.translatePassNameToClassName(PassName)); + for (const auto &PassName : printAfterPasses()) + PrintAfterClassNames.push_back(PB.translatePassNameToClassName(PassName)); +} + void OptNoneInstrumentation::registerCallbacks( PassInstrumentationCallbacks &PIC) { PIC.registerBeforePassCallback( @@ -345,3 +372,7 @@ TimePasses.registerCallbacks(PIC); OptNone.registerCallbacks(PIC); } + +void StandardInstrumentations::translatePassNamesToClassNames(PassBuilder &PB) { + PrintIR.translatePassNamesToClassNames(PB); +} diff --git a/llvm/test/CodeGen/Generic/print-after.ll b/llvm/test/CodeGen/Generic/print-after.ll --- a/llvm/test/CodeGen/Generic/print-after.ll +++ b/llvm/test/CodeGen/Generic/print-after.ll @@ -1,6 +1,4 @@ ; RUN: llc --help-hidden 2>&1 | FileCheck %s ; CHECK: -print-after -; CHECK-NOT: -print-after-all -; CHECK: =simple-register-coalescing ; CHECK: -print-after-all diff --git a/llvm/test/Other/loop-pass-printer.ll b/llvm/test/Other/loop-pass-printer.ll --- a/llvm/test/Other/loop-pass-printer.ll +++ b/llvm/test/Other/loop-pass-printer.ll @@ -1,23 +1,23 @@ ; This test checks -print-after/before on loop passes ; Besides of the loop itself it should be dumping loop pre-header and exits. ; -; RUN: opt -enable-new-pm=0 < %s 2>&1 -disable-output \ +; RUN: opt < %s 2>&1 -disable-output \ ; RUN: -loop-deletion -print-before=loop-deletion \ ; RUN: | FileCheck %s -check-prefix=DEL ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes='loop(loop-deletion)' -print-before-all \ +; RUN: -passes='loop(loop-deletion)' -print-before=loop-deletion \ ; RUN: | FileCheck %s -check-prefix=DEL ; RUN: opt -enable-new-pm=0 < %s 2>&1 -disable-output \ ; RUN: -loop-unroll -print-after=loop-unroll -filter-print-funcs=bar \ ; RUN: | FileCheck %s -check-prefix=BAR -check-prefix=BAR-OLD ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes='require,loop(loop-unroll-full)' -print-after-all -filter-print-funcs=bar \ +; RUN: -passes='require,loop(loop-unroll-full)' -print-after=loop-unroll-full -filter-print-funcs=bar \ ; RUN: | FileCheck %s -check-prefix=BAR ; RUN: opt -enable-new-pm=0 < %s 2>&1 -disable-output \ ; RUN: -loop-unroll -print-after=loop-unroll -filter-print-funcs=foo -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=FOO-MODULE -check-prefix=FOO-MODULE-OLD ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes='require,loop(loop-unroll-full)' -print-after-all -filter-print-funcs=foo -print-module-scope \ +; RUN: -passes='require,loop(loop-unroll-full)' -print-after=loop-unroll-full -filter-print-funcs=foo -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=FOO-MODULE ; DEL: IR Dump Before {{Delete dead loops|LoopDeletionPass}} diff --git a/llvm/test/Other/print-before-after.ll b/llvm/test/Other/print-before-after.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/print-before-after.ll @@ -0,0 +1,33 @@ +; RUN: not --crash opt < %s -disable-output -passes='no-op-module' -print-before=bleh 2>&1 | FileCheck %s --check-prefix=NONE --allow-empty +; RUN: not --crash opt < %s -disable-output -passes='no-op-module' -print-after=bleh 2>&1 | FileCheck %s --check-prefix=NONE --allow-empty +; RUN: opt < %s -disable-output -passes='no-op-module' -print-before=no-op-function 2>&1 | FileCheck %s --check-prefix=NONE --allow-empty +; RUN: opt < %s -disable-output -passes='no-op-module' -print-after=no-op-function 2>&1 | FileCheck %s --check-prefix=NONE --allow-empty +; RUN: opt < %s -disable-output -passes='no-op-module,no-op-function' -print-before=no-op-module 2>&1 | FileCheck %s --check-prefix=ONCE +; RUN: opt < %s -disable-output -passes='no-op-module,no-op-function' -print-after=no-op-module 2>&1 | FileCheck %s --check-prefix=ONCE +; RUN: opt < %s -disable-output -passes='no-op-function' -print-before=no-op-function 2>&1 | FileCheck %s --check-prefix=ONCE +; RUN: opt < %s -disable-output -passes='no-op-function' -print-after=no-op-function 2>&1 | FileCheck %s --check-prefix=ONCE +; RUN: opt < %s -disable-output -passes='no-op-module,no-op-function' -print-before=no-op-function --print-module-scope 2>&1 | FileCheck %s --check-prefix=TWICE +; RUN: opt < %s -disable-output -passes='no-op-module,no-op-function' -print-after=no-op-function --print-module-scope 2>&1 | FileCheck %s --check-prefix=TWICE + +; NONE-NOT: @foo +; NONE-NOT: @bar + +; ONCE: @foo +; ONCE: @bar +; ONCE-NOT: @foo +; ONCE-NOT: @bar + +; TWICE: @foo +; TWICE: @bar +; TWICE: @foo +; TWICE: @bar +; TWICE-NOT: @foo +; TWICE-NOT: @bar + +define void @foo() { + ret void +} + +define void @bar() { + ret void +} diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -272,6 +272,7 @@ PTO.LoopUnrolling = !DisableLoopUnrolling; PTO.Coroutines = Coroutines; PassBuilder PB(TM, PTO, P, &PIC); + SI.translatePassNamesToClassNames(PB); registerEPCallbacks(PB, VerifyEachPass, DebugPM); // Load requested pass plugins and let them register pass builder callbacks diff --git a/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn @@ -59,6 +59,7 @@ "PassManager.cpp", "PassRegistry.cpp", "PassTimingInfo.cpp", + "PrintPasses.cpp", "ProfileSummary.cpp", "SafepointIRVerifier.cpp", "Statepoint.cpp",