From 77e165569e352bd095ac02e06c9d0c46f53c8094 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Mon, 27 Jun 2016 23:26:08 +0000 Subject: [PATCH] [PM] Improve the debugging and logging facilities of the CGSCC bits of the new pass manager. This adds operator<< overloads for the various bits of the LazyCallGraph, dump methods for use from the debugger, and debug logging using them to the CGSCC pass manager. Having this was essential for debugging the call graph update patch, and I've extracted what I could from that patch here to minimize the delta. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273961 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/CGSCCPassManager.h | 40 ++++++++++------ include/llvm/Analysis/LazyCallGraph.h | 61 ++++++++++++++++-------- lib/Analysis/LazyCallGraph.cpp | 53 ++++++++++++++++++++ lib/Passes/PassBuilder.cpp | 9 ++-- test/Other/new-pass-manager.ll | 1 + 5 files changed, 125 insertions(+), 39 deletions(-) diff --git a/include/llvm/Analysis/CGSCCPassManager.h b/include/llvm/Analysis/CGSCCPassManager.h index 989305ebb27..3263ecec4e2 100644 --- a/include/llvm/Analysis/CGSCCPassManager.h +++ b/include/llvm/Analysis/CGSCCPassManager.h @@ -67,19 +67,20 @@ template class ModuleToPostOrderCGSCCPassAdaptor : public PassInfoMixin> { public: - explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) - : Pass(std::move(Pass)) {} + explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) + : Pass(std::move(Pass)), DebugLogging(DebugLogging) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. ModuleToPostOrderCGSCCPassAdaptor( const ModuleToPostOrderCGSCCPassAdaptor &Arg) - : Pass(Arg.Pass) {} + : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {} ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)) {} + : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {} friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS, ModuleToPostOrderCGSCCPassAdaptor &RHS) { using std::swap; swap(LHS.Pass, RHS.Pass); + swap(LHS.DebugLogging, RHS.DebugLogging); } ModuleToPostOrderCGSCCPassAdaptor & operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) { @@ -97,8 +98,11 @@ public: LazyCallGraph &CG = AM.getResult(M); PreservedAnalyses PA = PreservedAnalyses::all(); - for (LazyCallGraph::RefSCC &OuterC : CG.postorder_ref_sccs()) - for (LazyCallGraph::SCC &C : OuterC) { + for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) { + if (DebugLogging) + dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n"; + + for (LazyCallGraph::SCC &C : RC) { PreservedAnalyses PassPA = Pass.run(C, CGAM); // We know that the CGSCC pass couldn't have invalidated any other @@ -115,6 +119,7 @@ public: // analyses will eventually occur when the module pass completes. PA.intersect(std::move(PassPA)); } + } // By definition we preserve the proxy. This precludes *any* invalidation // of CGSCC analyses by the proxy, but that's OK because we've taken @@ -126,14 +131,15 @@ public: private: CGSCCPassT Pass; + bool DebugLogging; }; /// \brief A function to deduce a function pass type and wrap it in the /// templated adaptor. template ModuleToPostOrderCGSCCPassAdaptor -createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) { - return ModuleToPostOrderCGSCCPassAdaptor(std::move(Pass)); +createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) { + return ModuleToPostOrderCGSCCPassAdaptor(std::move(Pass), DebugLogging); } extern template class InnerAnalysisManagerProxy class CGSCCToFunctionPassAdaptor : public PassInfoMixin> { public: - explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass) - : Pass(std::move(Pass)) {} + explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) + : Pass(std::move(Pass)), DebugLogging(DebugLogging) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg) - : Pass(Arg.Pass) {} + : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {} CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)) {} + : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {} friend void swap(CGSCCToFunctionPassAdaptor &LHS, CGSCCToFunctionPassAdaptor &RHS) { using std::swap; swap(LHS.Pass, RHS.Pass); + swap(LHS.DebugLogging, RHS.DebugLogging); } CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) { swap(*this, RHS); @@ -183,6 +190,9 @@ public: FunctionAnalysisManager &FAM = AM.getResult(C).getManager(); + if (DebugLogging) + dbgs() << "Running function passes across an SCC: " << C << "\n"; + PreservedAnalyses PA = PreservedAnalyses::all(); for (LazyCallGraph::Node &N : C) { PreservedAnalyses PassPA = Pass.run(N.getFunction(), FAM); @@ -211,14 +221,16 @@ public: private: FunctionPassT Pass; + bool DebugLogging; }; /// \brief A function to deduce a function pass type and wrap it in the /// templated adaptor. template CGSCCToFunctionPassAdaptor -createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) { - return CGSCCToFunctionPassAdaptor(std::move(Pass)); +createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) { + return CGSCCToFunctionPassAdaptor(std::move(Pass), + DebugLogging); } } diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h index 340ca491574..47cb3101ba3 100644 --- a/include/llvm/Analysis/LazyCallGraph.h +++ b/include/llvm/Analysis/LazyCallGraph.h @@ -48,6 +48,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -222,6 +223,12 @@ public: /// Internal helper to remove the edge to the given function. void removeEdgeInternal(Function &ChildF); + /// Print the name of this node's function. + friend raw_ostream &operator<<(raw_ostream &OS, const Node &N); + + /// Dump the name of this node's function to stderr. + void dump() const; + public: LazyCallGraph &getGraph() const { return *G; } @@ -353,6 +360,15 @@ public: Nodes.clear(); } + /// Print a short descrtiption useful for debugging or logging. + /// + /// We print the function names in the SCC wrapped in '()'s and skipping + /// the middle functions if there are a large number. + friend raw_ostream &operator<<(raw_ostream &OS, const SCC &C); + + /// Dump a short description of this SCC to stderr. + void dump() const; + #ifndef NDEBUG /// Verify invariants about the SCC. /// @@ -373,25 +389,15 @@ public: RefSCC &getOuterRefSCC() const { return *OuterRefSCC; } - /// Short name useful for debugging or logging. + /// Provide a short name by printing this SCC to a std::string. /// - /// We use the name of the first function in the SCC to name the SCC for - /// the purposes of debugging and logging. + /// This copes with the fact that we don't have a name per-se for an SCC + /// while still making the use of this in debugging and logging useful. std::string getName() const { std::string Name; - int i = 0; - for (Node &N : *this) { - if (i > 0) - Name += ", "; - // Elide the inner elements if there are too many. - if (i > 8) { - Name += "..., "; - Name += Nodes.back()->getFunction().getName().str(); - break; - } - Name += N.getFunction().getName().str(); - ++i; - } + raw_string_ostream OS(Name); + OS << *this; + OS.flush(); return Name; } }; @@ -426,6 +432,15 @@ public: /// formRefSCCFast on the graph itself. RefSCC(LazyCallGraph &G); + /// Print a short description useful for debugging or logging. + /// + /// We print the SCCs wrapped in '[]'s and skipping the middle SCCs if + /// there are a large number. + friend raw_ostream &operator<<(raw_ostream &OS, const RefSCC &RC); + + /// Dump a short description of this RefSCC to stderr. + void dump() const; + #ifndef NDEBUG /// Verify invariants about the RefSCC and all its SCCs. /// @@ -477,12 +492,16 @@ public: /// Test if this RefSCC is a descendant of \a C. bool isDescendantOf(const RefSCC &C) const; - /// Short name useful for debugging or logging. + /// Provide a short name by printing this SCC to a std::string. /// - /// We use the name of the first function in the SCC to name the SCC for - /// the purposes of debugging and logging. - StringRef getName() const { - return begin()->begin()->getFunction().getName(); + /// This copes with the fact that we don't have a name per-se for an SCC + /// while still making the use of this in debugging and logging useful. + std::string getName() const { + std::string Name; + raw_string_ostream OS(Name); + OS << *this; + OS.flush(); + return Name; } ///@{ diff --git a/lib/Analysis/LazyCallGraph.cpp b/lib/Analysis/LazyCallGraph.cpp index a153333e79a..2d34a243f47 100644 --- a/lib/Analysis/LazyCallGraph.cpp +++ b/lib/Analysis/LazyCallGraph.cpp @@ -120,6 +120,14 @@ void LazyCallGraph::Node::removeEdgeInternal(Function &Target) { EdgeIndexMap.erase(IndexMapI); } +raw_ostream &llvm::operator<<(raw_ostream &OS, const LazyCallGraph::Node &N) { + return OS << N.F.getName(); +} + +void LazyCallGraph::Node::dump() const { + dbgs() << *this << '\n'; +} + LazyCallGraph::LazyCallGraph(Module &M) : NextDFSNumber(0) { DEBUG(dbgs() << "Building CG for module: " << M.getModuleIdentifier() << "\n"); @@ -173,6 +181,28 @@ LazyCallGraph &LazyCallGraph::operator=(LazyCallGraph &&G) { return *this; } +raw_ostream &llvm::operator<<(raw_ostream &OS, const LazyCallGraph::SCC &C) { + OS << '('; + int i = 0; + for (LazyCallGraph::Node &N : C) { + if (i > 0) + OS << ", "; + // Elide the inner elements if there are too many. + if (i > 8) { + OS << "..., " << *C.Nodes.back(); + break; + } + OS << N; + ++i; + } + OS << ')'; + return OS; +} + +void LazyCallGraph::SCC::dump() const { + dbgs() << *this << '\n'; +} + #ifndef NDEBUG void LazyCallGraph::SCC::verify() { assert(OuterRefSCC && "Can't have a null RefSCC!"); @@ -194,6 +224,29 @@ void LazyCallGraph::SCC::verify() { LazyCallGraph::RefSCC::RefSCC(LazyCallGraph &G) : G(&G) {} +raw_ostream &llvm::operator<<(raw_ostream &OS, + const LazyCallGraph::RefSCC &RC) { + OS << '['; + int i = 0; + for (LazyCallGraph::SCC &C : RC) { + if (i > 0) + OS << ", "; + // Elide the inner elements if there are too many. + if (i > 4) { + OS << "..., " << *RC.SCCs.back(); + break; + } + OS << C; + ++i; + } + OS << ']'; + return OS; +} + +void LazyCallGraph::RefSCC::dump() const { + dbgs() << *this << '\n'; +} + #ifndef NDEBUG void LazyCallGraph::RefSCC::verify() { assert(G && "Can't have a null graph!"); diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index 362bd13d03d..5f617455022 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/lib/Passes/PassBuilder.cpp @@ -561,7 +561,8 @@ bool PassBuilder::parseCGSCCPassPipeline(CGSCCPassManager &CGPM, PipelineText = PipelineText.substr(1); // Add the nested pass manager with the appropriate adaptor. - CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(NestedFPM))); + CGPM.addPass( + createCGSCCToFunctionPassAdaptor(std::move(NestedFPM), DebugLogging)); } else { // Otherwise try to parse a pass name. size_t End = PipelineText.find_first_of(",)"); @@ -627,8 +628,8 @@ bool PassBuilder::parseModulePassPipeline(ModulePassManager &MPM, PipelineText = PipelineText.substr(1); // Add the nested pass manager with the appropriate adaptor. - MPM.addPass( - createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM))); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM), + DebugLogging)); } else if (PipelineText.startswith("function(")) { FunctionPassManager NestedFPM(DebugLogging); @@ -689,7 +690,7 @@ bool PassBuilder::parsePassPipeline(ModulePassManager &MPM, DebugLogging) || !PipelineText.empty()) return false; - MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM), DebugLogging)); return true; } diff --git a/test/Other/new-pass-manager.ll b/test/Other/new-pass-manager.ll index 1ffd422c6a2..cbb45928429 100644 --- a/test/Other/new-pass-manager.ll +++ b/test/Other/new-pass-manager.ll @@ -22,6 +22,7 @@ ; CHECK-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor ; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> ; CHECK-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis +; CHECK-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)] ; CHECK-CGSCC-PASS-NEXT: Starting llvm::LazyCallGraph::SCC pass manager run ; CHECK-CGSCC-PASS-NEXT: Running pass: NoOpCGSCCPass ; CHECK-CGSCC-PASS-NEXT: Finished llvm::LazyCallGraph::SCC pass manager run