diff --git a/llvm/include/llvm/Analysis/CallGraph.h b/llvm/include/llvm/Analysis/CallGraph.h --- a/llvm/include/llvm/Analysis/CallGraph.h +++ b/llvm/include/llvm/Analysis/CallGraph.h @@ -326,6 +326,17 @@ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +/// Printer pass for the summarized \c CallGraphAnalysis results. +class CallGraphSCCsPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit CallGraphSCCsPrinterPass(raw_ostream &OS) : OS(OS) {} + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + /// The \c ModulePass which wraps up a \c CallGraph and the logic to /// build it. /// diff --git a/llvm/lib/Analysis/CallGraph.cpp b/llvm/lib/Analysis/CallGraph.cpp --- a/llvm/lib/Analysis/CallGraph.cpp +++ b/llvm/lib/Analysis/CallGraph.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/CallGraph.h" +#include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Config/llvm-config.h" @@ -312,6 +313,34 @@ return PreservedAnalyses::all(); } +PreservedAnalyses CallGraphSCCsPrinterPass::run(Module &M, + ModuleAnalysisManager &AM) { + auto &CG = AM.getResult(M); + unsigned sccNum = 0; + OS << "SCCs for the program in PostOrder:"; + for (scc_iterator SCCI = scc_begin(&CG); !SCCI.isAtEnd(); + ++SCCI) { + const std::vector &nextSCC = *SCCI; + OS << "\nSCC #" << ++sccNum << ": "; + bool First = true; + for (std::vector::const_iterator I = nextSCC.begin(), + E = nextSCC.end(); + I != E; ++I) { + if (First) + First = false; + else + OS << ", "; + OS << ((*I)->getFunction() ? (*I)->getFunction()->getName() + : "external node"); + } + + if (nextSCC.size() == 1 && SCCI.hasCycle()) + OS << " (Has self-loop)."; + } + OS << "\n"; + return PreservedAnalyses::all(); +} + //===----------------------------------------------------------------------===// // Out-of-line definitions of CallGraphAnalysis class members. // diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -92,6 +92,7 @@ MODULE_PASS("pgo-instr-use", PGOInstrumentationUse()) MODULE_PASS("print-profile-summary", ProfileSummaryPrinterPass(dbgs())) MODULE_PASS("print-callgraph", CallGraphPrinterPass(dbgs())) +MODULE_PASS("print-callgraph-sccs", CallGraphSCCsPrinterPass(dbgs())) MODULE_PASS("print", PrintModulePass(dbgs())) MODULE_PASS("print-lcg", LazyCallGraphPrinterPass(dbgs())) MODULE_PASS("print-lcg-dot", LazyCallGraphDOTPrinterPass(dbgs())) diff --git a/llvm/test/Analysis/CallGraph/printer.ll b/llvm/test/Analysis/CallGraph/printer.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/CallGraph/printer.ll @@ -0,0 +1,19 @@ +; RUN: opt -S -passes=print-callgraph-sccs -disable-output < %s 2>&1 | FileCheck %s +; CHECK: SCC #1: g, f +; CHECK: SCC #2: h +; CHECK: SCC #3: external node + +define void @f() { + call void @g() + ret void +} + +define void @g() { + call void @f() + ret void +} + +define void @h() { + call void @f() + ret void +} diff --git a/llvm/tools/opt/PrintSCC.cpp b/llvm/tools/opt/PrintSCC.cpp --- a/llvm/tools/opt/PrintSCC.cpp +++ b/llvm/tools/opt/PrintSCC.cpp @@ -25,7 +25,6 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/SCCIterator.h" -#include "llvm/Analysis/CallGraph.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" @@ -44,32 +43,12 @@ AU.setPreservesAll(); } }; - - struct CallGraphSCC : public ModulePass { - static char ID; // Pass identification, replacement for typeid - CallGraphSCC() : ModulePass(ID) {} - - // run - Print out SCCs in the call graph for the specified module. - bool runOnModule(Module &M) override; - - void print(raw_ostream &O, const Module* = nullptr) const override { } - - // getAnalysisUsage - This pass requires the CallGraph. - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - AU.addRequired(); - } - }; } char CFGSCC::ID = 0; static RegisterPass Y("print-cfg-sccs", "Print SCCs of each function CFG"); -char CallGraphSCC::ID = 0; -static RegisterPass -Z("print-callgraph-sccs", "Print SCCs of the Call Graph"); - bool CFGSCC::runOnFunction(Function &F) { unsigned sccNum = 0; errs() << "SCCs for Function " << F.getName() << " in PostOrder:"; @@ -87,25 +66,3 @@ return true; } - - -// run - Print out SCCs in the call graph for the specified module. -bool CallGraphSCC::runOnModule(Module &M) { - CallGraph &CG = getAnalysis().getCallGraph(); - unsigned sccNum = 0; - errs() << "SCCs for the program in PostOrder:"; - for (scc_iterator SCCI = scc_begin(&CG); !SCCI.isAtEnd(); - ++SCCI) { - const std::vector &nextSCC = *SCCI; - errs() << "\nSCC #" << ++sccNum << " : "; - for (std::vector::const_iterator I = nextSCC.begin(), - E = nextSCC.end(); I != E; ++I) - errs() << ((*I)->getFunction() ? (*I)->getFunction()->getName() - : "external node") << ", "; - if (nextSCC.size() == 1 && SCCI.hasCycle()) - errs() << " (Has self-loop)."; - } - errs() << "\n"; - - return true; -}