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) {
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
// 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
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,
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);
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);
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);
}
}
#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>
/// 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; }
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.
///
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;
}
};
/// 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.
///
/// 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;
}
///@{
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");
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!");
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!");
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(",)");
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);
DebugLogging) ||
!PipelineText.empty())
return false;
- MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
+ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM), DebugLogging));
return true;
}
; 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