1193323Sed//===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// 2193323Sed// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6193323Sed// 7193323Sed//===----------------------------------------------------------------------===// 8193323Sed// 9344779Sdim// This file defines a `-dot-cfg` analysis pass, which emits the 10344779Sdim// `<prefix>.<fnname>.dot` file for each function in the program, with a graph 11344779Sdim// of the CFG for that function. The default value for `<prefix>` is `cfg` but 12344779Sdim// can be customized as needed. 13193323Sed// 14193323Sed// The other main feature of this file is that it implements the 15193323Sed// Function::viewCFG method, which is useful for debugging passes which operate 16193323Sed// on the CFG. 17193323Sed// 18193323Sed//===----------------------------------------------------------------------===// 19193323Sed 20198396Srdivacky#include "llvm/Analysis/CFGPrinter.h" 21360784Sdim#include "llvm/InitializePasses.h" 22193323Sed#include "llvm/Pass.h" 23360784Sdim#include "llvm/Support/CommandLine.h" 24276479Sdim#include "llvm/Support/FileSystem.h" 25193323Sedusing namespace llvm; 26193323Sed 27341825Sdimstatic cl::opt<std::string> CFGFuncName( 28341825Sdim "cfg-func-name", cl::Hidden, 29341825Sdim cl::desc("The name of a function (or its substring)" 30341825Sdim " whose CFG is viewed/printed.")); 31341825Sdim 32344779Sdimstatic cl::opt<std::string> CFGDotFilenamePrefix( 33344779Sdim "cfg-dot-filename-prefix", cl::Hidden, 34344779Sdim cl::desc("The prefix used for the CFG dot file names.")); 35344779Sdim 36193323Sednamespace { 37314564Sdim struct CFGViewerLegacyPass : public FunctionPass { 38193323Sed static char ID; // Pass identifcation, replacement for typeid 39314564Sdim CFGViewerLegacyPass() : FunctionPass(ID) { 40314564Sdim initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry()); 41218893Sdim } 42193323Sed 43276479Sdim bool runOnFunction(Function &F) override { 44193323Sed F.viewCFG(); 45193323Sed return false; 46193323Sed } 47193323Sed 48276479Sdim void print(raw_ostream &OS, const Module* = nullptr) const override {} 49193323Sed 50276479Sdim void getAnalysisUsage(AnalysisUsage &AU) const override { 51193323Sed AU.setPreservesAll(); 52193323Sed } 53193323Sed }; 54193323Sed} 55193323Sed 56314564Sdimchar CFGViewerLegacyPass::ID = 0; 57314564SdimINITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true) 58193323Sed 59314564SdimPreservedAnalyses CFGViewerPass::run(Function &F, 60314564Sdim FunctionAnalysisManager &AM) { 61314564Sdim F.viewCFG(); 62314564Sdim return PreservedAnalyses::all(); 63314564Sdim} 64314564Sdim 65314564Sdim 66193323Sednamespace { 67314564Sdim struct CFGOnlyViewerLegacyPass : public FunctionPass { 68193323Sed static char ID; // Pass identifcation, replacement for typeid 69314564Sdim CFGOnlyViewerLegacyPass() : FunctionPass(ID) { 70314564Sdim initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry()); 71218893Sdim } 72193323Sed 73276479Sdim bool runOnFunction(Function &F) override { 74198090Srdivacky F.viewCFGOnly(); 75193323Sed return false; 76193323Sed } 77193323Sed 78276479Sdim void print(raw_ostream &OS, const Module* = nullptr) const override {} 79193323Sed 80276479Sdim void getAnalysisUsage(AnalysisUsage &AU) const override { 81193323Sed AU.setPreservesAll(); 82193323Sed } 83193323Sed }; 84193323Sed} 85193323Sed 86314564Sdimchar CFGOnlyViewerLegacyPass::ID = 0; 87314564SdimINITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only", 88218893Sdim "View CFG of function (with no function bodies)", false, true) 89193323Sed 90314564SdimPreservedAnalyses CFGOnlyViewerPass::run(Function &F, 91314564Sdim FunctionAnalysisManager &AM) { 92314564Sdim F.viewCFGOnly(); 93314564Sdim return PreservedAnalyses::all(); 94314564Sdim} 95314564Sdim 96327952Sdimstatic void writeCFGToDotFile(Function &F, bool CFGOnly = false) { 97341825Sdim if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) 98341825Sdim return; 99344779Sdim std::string Filename = 100344779Sdim (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str(); 101314564Sdim errs() << "Writing '" << Filename << "'..."; 102314564Sdim 103314564Sdim std::error_code EC; 104360784Sdim raw_fd_ostream File(Filename, EC, sys::fs::OF_Text); 105314564Sdim 106314564Sdim if (!EC) 107327952Sdim WriteGraph(File, (const Function*)&F, CFGOnly); 108314564Sdim else 109314564Sdim errs() << " error opening file for writing!"; 110314564Sdim errs() << "\n"; 111314564Sdim} 112314564Sdim 113193323Sednamespace { 114314564Sdim struct CFGPrinterLegacyPass : public FunctionPass { 115193323Sed static char ID; // Pass identification, replacement for typeid 116314564Sdim CFGPrinterLegacyPass() : FunctionPass(ID) { 117314564Sdim initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); 118218893Sdim } 119193323Sed 120276479Sdim bool runOnFunction(Function &F) override { 121314564Sdim writeCFGToDotFile(F); 122193323Sed return false; 123193323Sed } 124193323Sed 125276479Sdim void print(raw_ostream &OS, const Module* = nullptr) const override {} 126193323Sed 127276479Sdim void getAnalysisUsage(AnalysisUsage &AU) const override { 128193323Sed AU.setPreservesAll(); 129193323Sed } 130193323Sed }; 131193323Sed} 132193323Sed 133314564Sdimchar CFGPrinterLegacyPass::ID = 0; 134341825SdimINITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file", 135218893Sdim false, true) 136193323Sed 137314564SdimPreservedAnalyses CFGPrinterPass::run(Function &F, 138314564Sdim FunctionAnalysisManager &AM) { 139314564Sdim writeCFGToDotFile(F); 140314564Sdim return PreservedAnalyses::all(); 141314564Sdim} 142314564Sdim 143193323Sednamespace { 144314564Sdim struct CFGOnlyPrinterLegacyPass : public FunctionPass { 145193323Sed static char ID; // Pass identification, replacement for typeid 146314564Sdim CFGOnlyPrinterLegacyPass() : FunctionPass(ID) { 147314564Sdim initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); 148218893Sdim } 149276479Sdim 150276479Sdim bool runOnFunction(Function &F) override { 151327952Sdim writeCFGToDotFile(F, /*CFGOnly=*/true); 152193323Sed return false; 153193323Sed } 154276479Sdim void print(raw_ostream &OS, const Module* = nullptr) const override {} 155193323Sed 156276479Sdim void getAnalysisUsage(AnalysisUsage &AU) const override { 157193323Sed AU.setPreservesAll(); 158193323Sed } 159193323Sed }; 160193323Sed} 161193323Sed 162314564Sdimchar CFGOnlyPrinterLegacyPass::ID = 0; 163314564SdimINITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only", 164212904Sdim "Print CFG of function to 'dot' file (with no function bodies)", 165218893Sdim false, true) 166193323Sed 167314564SdimPreservedAnalyses CFGOnlyPrinterPass::run(Function &F, 168314564Sdim FunctionAnalysisManager &AM) { 169327952Sdim writeCFGToDotFile(F, /*CFGOnly=*/true); 170314564Sdim return PreservedAnalyses::all(); 171314564Sdim} 172314564Sdim 173193323Sed/// viewCFG - This function is meant for use from the debugger. You can just 174193323Sed/// say 'call F->viewCFG()' and a ghostview window should pop up from the 175193323Sed/// program, displaying the CFG of the current function. This depends on there 176193323Sed/// being a 'dot' and 'gv' program in your path. 177193323Sed/// 178193323Sedvoid Function::viewCFG() const { 179341825Sdim if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) 180341825Sdim return; 181234353Sdim ViewGraph(this, "cfg" + getName()); 182193323Sed} 183193323Sed 184193323Sed/// viewCFGOnly - This function is meant for use from the debugger. It works 185193323Sed/// just like viewCFG, but it does not include the contents of basic blocks 186276479Sdim/// into the nodes, just the label. If you are only interested in the CFG 187276479Sdim/// this can make the graph smaller. 188193323Sed/// 189193323Sedvoid Function::viewCFGOnly() const { 190341825Sdim if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) 191341825Sdim return; 192234353Sdim ViewGraph(this, "cfg" + getName(), true); 193193323Sed} 194193323Sed 195314564SdimFunctionPass *llvm::createCFGPrinterLegacyPassPass () { 196314564Sdim return new CFGPrinterLegacyPass(); 197193323Sed} 198193323Sed 199314564SdimFunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () { 200314564Sdim return new CFGOnlyPrinterLegacyPass(); 201193323Sed} 202193323Sed 203