[PM] Push the debug option for the new pass manager into the opt tool

and expose the necessary hooks in the API directly.

This makes it much cleaner for example to log the usage of a pass
manager from a library. It also makes it more obvious that this
functionality isn't "optional" or "asserts-only" for the pass manager.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225841 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth 2015-01-13 22:42:38 +00:00
parent f38f71d8a0
commit 3c95d9ccc0
5 changed files with 70 additions and 52 deletions

View File

@ -56,13 +56,6 @@ namespace llvm {
class Module; class Module;
class Function; class Function;
namespace detail {
// Declare our debug option here so we can refer to it from templates.
extern cl::opt<bool> DebugPM;
} // End detail namespace
/// \brief An abstract set of preserved analyses following a transformation pass /// \brief An abstract set of preserved analyses following a transformation pass
/// run. /// run.
/// ///
@ -185,12 +178,18 @@ template <typename IRUnitT> class AnalysisManager;
/// runs. /// runs.
template <typename IRUnitT> class PassManager { template <typename IRUnitT> class PassManager {
public: public:
/// \brief Construct a pass manager.
///
/// It can be passed a flag to get debug logging as the passes are run.
PassManager(bool DebugLogging = false) : DebugLogging(DebugLogging) {}
// We have to explicitly define all the special member functions because MSVC // We have to explicitly define all the special member functions because MSVC
// refuses to generate them. // refuses to generate them.
PassManager() {} PassManager(PassManager &&Arg)
PassManager(PassManager &&Arg) : Passes(std::move(Arg.Passes)) {} : Passes(std::move(Arg.Passes)),
DebugLogging(std::move(Arg.DebugLogging)) {}
PassManager &operator=(PassManager &&RHS) { PassManager &operator=(PassManager &&RHS) {
Passes = std::move(RHS.Passes); Passes = std::move(RHS.Passes);
DebugLogging = std::move(RHS.DebugLogging);
return *this; return *this;
} }
@ -198,11 +197,11 @@ public:
PreservedAnalyses run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM = nullptr) { PreservedAnalyses run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM = nullptr) {
PreservedAnalyses PA = PreservedAnalyses::all(); PreservedAnalyses PA = PreservedAnalyses::all();
if (detail::DebugPM) if (DebugLogging)
dbgs() << "Starting pass manager run.\n"; dbgs() << "Starting pass manager run.\n";
for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) {
if (detail::DebugPM) if (DebugLogging)
dbgs() << "Running pass: " << Passes[Idx]->name() << "\n"; dbgs() << "Running pass: " << Passes[Idx]->name() << "\n";
PreservedAnalyses PassPA = Passes[Idx]->run(IR, AM); PreservedAnalyses PassPA = Passes[Idx]->run(IR, AM);
@ -226,7 +225,7 @@ public:
//IR.getContext().yield(); //IR.getContext().yield();
} }
if (detail::DebugPM) if (DebugLogging)
dbgs() << "Finished pass manager run.\n"; dbgs() << "Finished pass manager run.\n";
return PA; return PA;
@ -246,6 +245,9 @@ private:
PassManager &operator=(const PassManager &) LLVM_DELETED_FUNCTION; PassManager &operator=(const PassManager &) LLVM_DELETED_FUNCTION;
std::vector<std::unique_ptr<PassConceptT>> Passes; std::vector<std::unique_ptr<PassConceptT>> Passes;
/// \brief Flag indicating whether we should do debug logging.
bool DebugLogging;
}; };
/// \brief Convenience typedef for a pass manager over modules. /// \brief Convenience typedef for a pass manager over modules.
@ -412,15 +414,22 @@ class AnalysisManager
public: public:
// Most public APIs are inherited from the CRTP base class. // Most public APIs are inherited from the CRTP base class.
/// \brief Construct an empty analysis manager.
///
/// A flag can be passed to indicate that the manager should perform debug
/// logging.
AnalysisManager(bool DebugLogging = false) : DebugLogging(DebugLogging) {}
// We have to explicitly define all the special member functions because MSVC // We have to explicitly define all the special member functions because MSVC
// refuses to generate them. // refuses to generate them.
AnalysisManager() {}
AnalysisManager(AnalysisManager &&Arg) AnalysisManager(AnalysisManager &&Arg)
: BaseT(std::move(static_cast<BaseT &>(Arg))), : BaseT(std::move(static_cast<BaseT &>(Arg))),
AnalysisResults(std::move(Arg.AnalysisResults)) {} AnalysisResults(std::move(Arg.AnalysisResults)),
DebugLogging(std::move(Arg.DebugLogging)) {}
AnalysisManager &operator=(AnalysisManager &&RHS) { AnalysisManager &operator=(AnalysisManager &&RHS) {
BaseT::operator=(std::move(static_cast<BaseT &>(RHS))); BaseT::operator=(std::move(static_cast<BaseT &>(RHS)));
AnalysisResults = std::move(RHS.AnalysisResults); AnalysisResults = std::move(RHS.AnalysisResults);
DebugLogging = std::move(RHS.DebugLogging);
return *this; return *this;
} }
@ -458,7 +467,7 @@ private:
// run it to produce a result, which we then add to the cache. // run it to produce a result, which we then add to the cache.
if (Inserted) { if (Inserted) {
auto &P = this->lookupPass(PassID); auto &P = this->lookupPass(PassID);
if (detail::DebugPM) if (DebugLogging)
dbgs() << "Running analysis: " << P.name() << "\n"; dbgs() << "Running analysis: " << P.name() << "\n";
AnalysisResultListT &ResultList = AnalysisResultLists[&IR]; AnalysisResultListT &ResultList = AnalysisResultLists[&IR];
ResultList.emplace_back(PassID, P.run(IR, this)); ResultList.emplace_back(PassID, P.run(IR, this));
@ -482,7 +491,7 @@ private:
if (RI == AnalysisResults.end()) if (RI == AnalysisResults.end())
return; return;
if (detail::DebugPM) if (DebugLogging)
dbgs() << "Invalidating analysis: " << this->lookupPass(PassID).name() dbgs() << "Invalidating analysis: " << this->lookupPass(PassID).name()
<< "\n"; << "\n";
AnalysisResultLists[&IR].erase(RI->second); AnalysisResultLists[&IR].erase(RI->second);
@ -495,7 +504,7 @@ private:
if (PA.areAllPreserved()) if (PA.areAllPreserved())
return std::move(PA); return std::move(PA);
if (detail::DebugPM) if (DebugLogging)
dbgs() << "Invalidating all non-preserved analyses for: " dbgs() << "Invalidating all non-preserved analyses for: "
<< IR.getName() << "\n"; << IR.getName() << "\n";
@ -512,7 +521,7 @@ private:
// necessary. The analysis pass can return false if no action on the part // necessary. The analysis pass can return false if no action on the part
// of the analysis manager is required for this invalidation event. // of the analysis manager is required for this invalidation event.
if (I->second->invalidate(IR, PA)) { if (I->second->invalidate(IR, PA)) {
if (detail::DebugPM) if (DebugLogging)
dbgs() << "Invalidating analysis: " << this->lookupPass(PassID).name() dbgs() << "Invalidating analysis: " << this->lookupPass(PassID).name()
<< "\n"; << "\n";
@ -562,6 +571,9 @@ private:
/// \brief Map from an analysis ID and function to a particular cached /// \brief Map from an analysis ID and function to a particular cached
/// analysis result. /// analysis result.
AnalysisResultMapT AnalysisResults; AnalysisResultMapT AnalysisResults;
/// \brief A flag indicating whether debug logging is enabled.
bool DebugLogging;
}; };
/// \brief Convenience typedef for the Module analysis manager. /// \brief Convenience typedef for the Module analysis manager.

View File

@ -12,11 +12,6 @@
#include "llvm/IR/PassManager.h" #include "llvm/IR/PassManager.h"
using namespace llvm; using namespace llvm;
using llvm::detail::DebugPM;
cl::opt<bool> llvm::detail::DebugPM(
"debug-pass-manager", cl::Hidden,
cl::desc("Print pass management debugging information"));
char FunctionAnalysisManagerModuleProxy::PassID; char FunctionAnalysisManagerModuleProxy::PassID;

View File

@ -30,12 +30,16 @@
using namespace llvm; using namespace llvm;
using namespace opt_tool; using namespace opt_tool;
static cl::opt<bool>
DebugPM("debug-pass-manager", cl::Hidden,
cl::desc("Print pass management debugging information"));
bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
tool_output_file *Out, StringRef PassPipeline, tool_output_file *Out, StringRef PassPipeline,
OutputKind OK, VerifierKind VK) { OutputKind OK, VerifierKind VK) {
FunctionAnalysisManager FAM; FunctionAnalysisManager FAM(DebugPM);
CGSCCAnalysisManager CGAM; CGSCCAnalysisManager CGAM(DebugPM);
ModuleAnalysisManager MAM; ModuleAnalysisManager MAM(DebugPM);
// Register all the basic analyses with the managers. // Register all the basic analyses with the managers.
registerModuleAnalyses(MAM); registerModuleAnalyses(MAM);
@ -50,11 +54,11 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
FAM.registerPass(CGSCCAnalysisManagerFunctionProxy(CGAM)); FAM.registerPass(CGSCCAnalysisManagerFunctionProxy(CGAM));
FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM)); FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM));
ModulePassManager MPM; ModulePassManager MPM(DebugPM);
if (VK > VK_NoVerifier) if (VK > VK_NoVerifier)
MPM.addPass(VerifierPass()); MPM.addPass(VerifierPass());
if (!parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass)) { if (!parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass, DebugPM)) {
errs() << Arg0 << ": unable to parse pass pipeline description.\n"; errs() << Arg0 << ": unable to parse pass pipeline description.\n";
return false; return false;
} }

View File

@ -196,15 +196,16 @@ static bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) {
static bool parseFunctionPassPipeline(FunctionPassManager &FPM, static bool parseFunctionPassPipeline(FunctionPassManager &FPM,
StringRef &PipelineText, StringRef &PipelineText,
bool VerifyEachPass) { bool VerifyEachPass, bool DebugLogging) {
for (;;) { for (;;) {
// Parse nested pass managers by recursing. // Parse nested pass managers by recursing.
if (PipelineText.startswith("function(")) { if (PipelineText.startswith("function(")) {
FunctionPassManager NestedFPM; FunctionPassManager NestedFPM(DebugLogging);
// Parse the inner pipeline inte the nested manager. // Parse the inner pipeline inte the nested manager.
PipelineText = PipelineText.substr(strlen("function(")); PipelineText = PipelineText.substr(strlen("function("));
if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass,
DebugLogging) ||
PipelineText.empty()) PipelineText.empty())
return false; return false;
assert(PipelineText[0] == ')'); assert(PipelineText[0] == ')');
@ -232,16 +233,17 @@ static bool parseFunctionPassPipeline(FunctionPassManager &FPM,
} }
static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM,
StringRef &PipelineText, StringRef &PipelineText, bool VerifyEachPass,
bool VerifyEachPass) { bool DebugLogging) {
for (;;) { for (;;) {
// Parse nested pass managers by recursing. // Parse nested pass managers by recursing.
if (PipelineText.startswith("cgscc(")) { if (PipelineText.startswith("cgscc(")) {
CGSCCPassManager NestedCGPM; CGSCCPassManager NestedCGPM(DebugLogging);
// Parse the inner pipeline into the nested manager. // Parse the inner pipeline into the nested manager.
PipelineText = PipelineText.substr(strlen("cgscc(")); PipelineText = PipelineText.substr(strlen("cgscc("));
if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass) || if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass,
DebugLogging) ||
PipelineText.empty()) PipelineText.empty())
return false; return false;
assert(PipelineText[0] == ')'); assert(PipelineText[0] == ')');
@ -250,11 +252,12 @@ static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM,
// Add the nested pass manager with the appropriate adaptor. // Add the nested pass manager with the appropriate adaptor.
CGPM.addPass(std::move(NestedCGPM)); CGPM.addPass(std::move(NestedCGPM));
} else if (PipelineText.startswith("function(")) { } else if (PipelineText.startswith("function(")) {
FunctionPassManager NestedFPM; FunctionPassManager NestedFPM(DebugLogging);
// Parse the inner pipeline inte the nested manager. // Parse the inner pipeline inte the nested manager.
PipelineText = PipelineText.substr(strlen("function(")); PipelineText = PipelineText.substr(strlen("function("));
if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass,
DebugLogging) ||
PipelineText.empty()) PipelineText.empty())
return false; return false;
assert(PipelineText[0] == ')'); assert(PipelineText[0] == ')');
@ -282,15 +285,16 @@ static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM,
static bool parseModulePassPipeline(ModulePassManager &MPM, static bool parseModulePassPipeline(ModulePassManager &MPM,
StringRef &PipelineText, StringRef &PipelineText,
bool VerifyEachPass) { bool VerifyEachPass, bool DebugLogging) {
for (;;) { for (;;) {
// Parse nested pass managers by recursing. // Parse nested pass managers by recursing.
if (PipelineText.startswith("module(")) { if (PipelineText.startswith("module(")) {
ModulePassManager NestedMPM; ModulePassManager NestedMPM(DebugLogging);
// Parse the inner pipeline into the nested manager. // Parse the inner pipeline into the nested manager.
PipelineText = PipelineText.substr(strlen("module(")); PipelineText = PipelineText.substr(strlen("module("));
if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass) || if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass,
DebugLogging) ||
PipelineText.empty()) PipelineText.empty())
return false; return false;
assert(PipelineText[0] == ')'); assert(PipelineText[0] == ')');
@ -299,11 +303,12 @@ static bool parseModulePassPipeline(ModulePassManager &MPM,
// Now add the nested manager as a module pass. // Now add the nested manager as a module pass.
MPM.addPass(std::move(NestedMPM)); MPM.addPass(std::move(NestedMPM));
} else if (PipelineText.startswith("cgscc(")) { } else if (PipelineText.startswith("cgscc(")) {
CGSCCPassManager NestedCGPM; CGSCCPassManager NestedCGPM(DebugLogging);
// Parse the inner pipeline inte the nested manager. // Parse the inner pipeline inte the nested manager.
PipelineText = PipelineText.substr(strlen("cgscc(")); PipelineText = PipelineText.substr(strlen("cgscc("));
if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass) || if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass,
DebugLogging) ||
PipelineText.empty()) PipelineText.empty())
return false; return false;
assert(PipelineText[0] == ')'); assert(PipelineText[0] == ')');
@ -313,11 +318,12 @@ static bool parseModulePassPipeline(ModulePassManager &MPM,
MPM.addPass( MPM.addPass(
createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM))); createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM)));
} else if (PipelineText.startswith("function(")) { } else if (PipelineText.startswith("function(")) {
FunctionPassManager NestedFPM; FunctionPassManager NestedFPM(DebugLogging);
// Parse the inner pipeline inte the nested manager. // Parse the inner pipeline inte the nested manager.
PipelineText = PipelineText.substr(strlen("function(")); PipelineText = PipelineText.substr(strlen("function("));
if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass,
DebugLogging) ||
PipelineText.empty()) PipelineText.empty())
return false; return false;
assert(PipelineText[0] == ')'); assert(PipelineText[0] == ')');
@ -348,11 +354,11 @@ static bool parseModulePassPipeline(ModulePassManager &MPM,
// FIXME: Should this routine accept a TargetMachine or require the caller to // FIXME: Should this routine accept a TargetMachine or require the caller to
// pre-populate the analysis managers with target-specific stuff? // pre-populate the analysis managers with target-specific stuff?
bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
bool VerifyEachPass) { bool VerifyEachPass, bool DebugLogging) {
// By default, try to parse the pipeline as-if it were within an implicit // By default, try to parse the pipeline as-if it were within an implicit
// 'module(...)' pass pipeline. If this will parse at all, it needs to // 'module(...)' pass pipeline. If this will parse at all, it needs to
// consume the entire string. // consume the entire string.
if (parseModulePassPipeline(MPM, PipelineText, VerifyEachPass)) if (parseModulePassPipeline(MPM, PipelineText, VerifyEachPass, DebugLogging))
return PipelineText.empty(); return PipelineText.empty();
// This isn't parsable as a module pipeline, look for the end of a pass name // This isn't parsable as a module pipeline, look for the end of a pass name
@ -365,8 +371,9 @@ bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
// If this looks like a CGSCC pass, parse the whole thing as a CGSCC // If this looks like a CGSCC pass, parse the whole thing as a CGSCC
// pipeline. // pipeline.
if (isCGSCCPassName(FirstName)) { if (isCGSCCPassName(FirstName)) {
CGSCCPassManager CGPM; CGSCCPassManager CGPM(DebugLogging);
if (!parseCGSCCPassPipeline(CGPM, PipelineText, VerifyEachPass) || if (!parseCGSCCPassPipeline(CGPM, PipelineText, VerifyEachPass,
DebugLogging) ||
!PipelineText.empty()) !PipelineText.empty())
return false; return false;
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
@ -376,8 +383,9 @@ bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
// Similarly, if this looks like a Function pass, parse the whole thing as // Similarly, if this looks like a Function pass, parse the whole thing as
// a Function pipelien. // a Function pipelien.
if (isFunctionPassName(FirstName)) { if (isFunctionPassName(FirstName)) {
FunctionPassManager FPM; FunctionPassManager FPM(DebugLogging);
if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass) || if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass,
DebugLogging) ||
!PipelineText.empty()) !PipelineText.empty())
return false; return false;
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));

View File

@ -72,8 +72,7 @@ void registerFunctionAnalyses(FunctionAnalysisManager &FAM);
/// an error. You cannot mix different levels implicitly, you must explicitly /// an error. You cannot mix different levels implicitly, you must explicitly
/// form a pass manager in which to nest passes. /// form a pass manager in which to nest passes.
bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
bool VerifyEachPass = true); bool VerifyEachPass = true, bool DebugLogging = false);
} }
#endif #endif