[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
This commit is contained in:
Chandler Carruth 2016-06-27 23:26:08 +00:00
parent 5e49c0d4a2
commit 77e165569e
5 changed files with 125 additions and 39 deletions

View File

@ -67,19 +67,20 @@ template <typename CGSCCPassT>
class ModuleToPostOrderCGSCCPassAdaptor
: public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>> {
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<LazyCallGraphAnalysis>(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 <typename CGSCCPassT>
ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>
createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) {
return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass));
createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) {
return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass), DebugLogging);
}
extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
@ -159,18 +165,19 @@ template <typename FunctionPassT>
class CGSCCToFunctionPassAdaptor
: public PassInfoMixin<CGSCCToFunctionPassAdaptor<FunctionPassT>> {
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<FunctionAnalysisManagerCGSCCProxy>(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 <typename FunctionPassT>
CGSCCToFunctionPassAdaptor<FunctionPassT>
createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) {
return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass));
createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) {
return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass),
DebugLogging);
}
}

View File

@ -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 <iterator>
#include <utility>
@ -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;
}
///@{

View File

@ -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!");

View File

@ -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;
}

View File

@ -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