From 8457adc4c1079036c2cce416b70f3dc836162583 Mon Sep 17 00:00:00 2001 From: Sean Silva Date: Sat, 18 Jun 2016 09:17:32 +0000 Subject: [PATCH] Add a super basic LazyCallGraph DOT printer. Access it through -passes=print-lcg-dot Let me know any suggestions for changing the rendering; I'm not particularly attached to what is implemented here. llvm-svn: 273082 --- include/llvm/Analysis/LazyCallGraph.h | 12 ++++++++++ lib/Analysis/LazyCallGraph.cpp | 32 +++++++++++++++++++++++++++ lib/Passes/PassRegistry.def | 1 + 3 files changed, 45 insertions(+) diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h index 3e63bf59f6c..34d854c78fe 100644 --- a/include/llvm/Analysis/LazyCallGraph.h +++ b/include/llvm/Analysis/LazyCallGraph.h @@ -925,6 +925,18 @@ public: PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +/// A pass which prints the call graph as a DOT file to a \c raw_ostream. +/// +/// This is primarily useful for visualization purposes. +class LazyCallGraphDOTPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit LazyCallGraphDOTPrinterPass(raw_ostream &OS); + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; } #endif diff --git a/lib/Analysis/LazyCallGraph.cpp b/lib/Analysis/LazyCallGraph.cpp index 36425c99adc..a153333e79a 100644 --- a/lib/Analysis/LazyCallGraph.cpp +++ b/lib/Analysis/LazyCallGraph.cpp @@ -14,6 +14,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/GraphWriter.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -1545,3 +1546,34 @@ PreservedAnalyses LazyCallGraphPrinterPass::run(Module &M, return PreservedAnalyses::all(); } + +LazyCallGraphDOTPrinterPass::LazyCallGraphDOTPrinterPass(raw_ostream &OS) + : OS(OS) {} + +static void printNodeDOT(raw_ostream &OS, LazyCallGraph::Node &N) { + std::string Name = "\"" + DOT::EscapeString(N.getFunction().getName()) + "\""; + + for (const LazyCallGraph::Edge &E : N) { + OS << " " << Name << " -> \"" + << DOT::EscapeString(E.getFunction().getName()) << "\""; + if (!E.isCall()) // It is a ref edge. + OS << " [style=dashed,label=\"ref\"]"; + OS << ";\n"; + } + + OS << "\n"; +} + +PreservedAnalyses LazyCallGraphDOTPrinterPass::run(Module &M, + ModuleAnalysisManager &AM) { + LazyCallGraph &G = AM.getResult(M); + + OS << "digraph \"" << DOT::EscapeString(M.getModuleIdentifier()) << "\" {\n"; + + for (Function &F : M) + printNodeDOT(OS, G.get(F)); + + OS << "}\n"; + + return PreservedAnalyses::all(); +} diff --git a/lib/Passes/PassRegistry.def b/lib/Passes/PassRegistry.def index e84f3933db8..18b50ddcc20 100644 --- a/lib/Passes/PassRegistry.def +++ b/lib/Passes/PassRegistry.def @@ -57,6 +57,7 @@ MODULE_PASS("print-profile-summary", ProfileSummaryPrinterPass(dbgs())) MODULE_PASS("print-callgraph", CallGraphPrinterPass(dbgs())) MODULE_PASS("print", PrintModulePass(dbgs())) MODULE_PASS("print-lcg", LazyCallGraphPrinterPass(dbgs())) +MODULE_PASS("print-lcg-dot", LazyCallGraphDOTPrinterPass(dbgs())) MODULE_PASS("rpo-functionattrs", ReversePostOrderFunctionAttrsPass()) MODULE_PASS("sample-profile", SampleProfileLoaderPass()) MODULE_PASS("strip-dead-prototypes", StripDeadPrototypesPass())