1 //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines a `-dot-cfg` analysis pass, which emits the 10 // `<prefix>.<fnname>.dot` file for each function in the program, with a graph 11 // of the CFG for that function. The default value for `<prefix>` is `cfg` but 12 // can be customized as needed. 13 // 14 // The other main feature of this file is that it implements the 15 // Function::viewCFG method, which is useful for debugging passes which operate 16 // on the CFG. 17 // 18 //===----------------------------------------------------------------------===// 19 20 #include "llvm/ADT/PostOrderIterator.h" 21 #include "llvm/Analysis/CFGPrinter.h" 22 #include "llvm/InitializePasses.h" 23 #include "llvm/Pass.h" 24 #include "llvm/Support/CommandLine.h" 25 #include "llvm/Support/FileSystem.h" 26 #include <algorithm> 27 28 using namespace llvm; 29 30 static cl::opt<std::string> CFGFuncName( 31 "cfg-func-name", cl::Hidden, 32 cl::desc("The name of a function (or its substring)" 33 " whose CFG is viewed/printed.")); 34 35 static cl::opt<std::string> CFGDotFilenamePrefix( 36 "cfg-dot-filename-prefix", cl::Hidden, 37 cl::desc("The prefix used for the CFG dot file names.")); 38 39 static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths", 40 cl::init(false)); 41 42 static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths", 43 cl::init(false)); 44 45 static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI, 46 BranchProbabilityInfo *BPI, 47 bool isSimple) { 48 std::string Filename = 49 (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str(); 50 errs() << "Writing '" << Filename << "'..."; 51 52 std::error_code EC; 53 raw_fd_ostream File(Filename, EC, sys::fs::F_Text); 54 55 DOTFuncInfo CFGInfo(&F, BFI, BPI); 56 if (!EC) 57 WriteGraph(File, &CFGInfo, isSimple); 58 else 59 errs() << " error opening file for writing!"; 60 errs() << "\n"; 61 } 62 63 static void viewCFG(Function &F, BlockFrequencyInfo *BFI, 64 BranchProbabilityInfo *BPI, 65 bool isSimple) { 66 DOTFuncInfo CFGInfo(&F, BFI, BPI); 67 ViewGraph(&CFGInfo, "cfg." + F.getName(), isSimple); 68 } 69 70 namespace { 71 struct CFGViewerLegacyPass : public FunctionPass { 72 static char ID; // Pass identifcation, replacement for typeid 73 CFGViewerLegacyPass() : FunctionPass(ID) { 74 initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry()); 75 } 76 77 bool runOnFunction(Function &F) override { 78 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI(); 79 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI(); 80 viewCFG(F, BFI, BPI, /*isSimple=*/false); 81 return false; 82 } 83 84 void print(raw_ostream &OS, const Module* = nullptr) const override {} 85 86 void getAnalysisUsage(AnalysisUsage &AU) const override { 87 FunctionPass::getAnalysisUsage(AU); // Maybe Change to FunctionPass::... 88 AU.addRequired<BlockFrequencyInfoWrapperPass>(); 89 AU.addRequired<BranchProbabilityInfoWrapperPass>(); 90 AU.setPreservesAll(); 91 } 92 }; 93 } 94 95 char CFGViewerLegacyPass::ID = 0; 96 INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true) 97 98 PreservedAnalyses CFGViewerPass::run(Function &F, 99 FunctionAnalysisManager &AM) { 100 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F); 101 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F); 102 viewCFG(F, BFI, BPI, /*isSimple=*/false); 103 return PreservedAnalyses::all(); 104 } 105 106 107 namespace { 108 struct CFGOnlyViewerLegacyPass : public FunctionPass { 109 static char ID; // Pass identifcation, replacement for typeid 110 CFGOnlyViewerLegacyPass() : FunctionPass(ID) { 111 initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry()); 112 } 113 114 bool runOnFunction(Function &F) override { 115 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI(); 116 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI(); 117 viewCFG(F, BFI, BPI, /*isSimple=*/false); 118 return false; 119 } 120 121 void print(raw_ostream &OS, const Module* = nullptr) const override {} 122 123 void getAnalysisUsage(AnalysisUsage &AU) const override { 124 FunctionPass::getAnalysisUsage(AU); 125 AU.addRequired<BlockFrequencyInfoWrapperPass>(); 126 AU.addRequired<BranchProbabilityInfoWrapperPass>(); 127 AU.setPreservesAll(); 128 } 129 }; 130 } 131 132 char CFGOnlyViewerLegacyPass::ID = 0; 133 INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only", 134 "View CFG of function (with no function bodies)", false, true) 135 136 PreservedAnalyses CFGOnlyViewerPass::run(Function &F, 137 FunctionAnalysisManager &AM) { 138 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F); 139 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F); 140 viewCFG(F, BFI, BPI, /*isSimple=*/false); 141 return PreservedAnalyses::all(); 142 } 143 144 namespace { 145 struct CFGPrinterLegacyPass : public FunctionPass { 146 static char ID; // Pass identification, replacement for typeid 147 CFGPrinterLegacyPass() : FunctionPass(ID) { 148 initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); 149 } 150 151 bool runOnFunction(Function &F) override { 152 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI(); 153 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI(); 154 writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false); 155 return false; 156 } 157 158 void print(raw_ostream &OS, const Module* = nullptr) const override {} 159 160 void getAnalysisUsage(AnalysisUsage &AU) const override { 161 FunctionPass::getAnalysisUsage(AU); 162 AU.addRequired<BlockFrequencyInfoWrapperPass>(); 163 AU.addRequired<BranchProbabilityInfoWrapperPass>(); 164 AU.setPreservesAll(); 165 } 166 }; 167 } 168 169 char CFGPrinterLegacyPass::ID = 0; 170 INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file", 171 false, true) 172 173 PreservedAnalyses CFGPrinterPass::run(Function &F, 174 FunctionAnalysisManager &AM) { 175 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F); 176 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F); 177 writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false); 178 return PreservedAnalyses::all(); 179 } 180 181 namespace { 182 struct CFGOnlyPrinterLegacyPass : public FunctionPass { 183 static char ID; // Pass identification, replacement for typeid 184 CFGOnlyPrinterLegacyPass() : FunctionPass(ID) { 185 initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); 186 } 187 188 bool runOnFunction(Function &F) override { 189 auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI(); 190 auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI(); 191 writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false); 192 return false; 193 } 194 void print(raw_ostream &OS, const Module* = nullptr) const override {} 195 196 void getAnalysisUsage(AnalysisUsage &AU) const override { 197 FunctionPass::getAnalysisUsage(AU); 198 AU.addRequired<BlockFrequencyInfoWrapperPass>(); 199 AU.addRequired<BranchProbabilityInfoWrapperPass>(); 200 AU.setPreservesAll(); 201 } 202 }; 203 } 204 205 char CFGOnlyPrinterLegacyPass::ID = 0; 206 INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only", 207 "Print CFG of function to 'dot' file (with no function bodies)", 208 false, true) 209 210 PreservedAnalyses CFGOnlyPrinterPass::run(Function &F, 211 FunctionAnalysisManager &AM) { 212 auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F); 213 auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F); 214 writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false); 215 return PreservedAnalyses::all(); 216 } 217 218 /// viewCFG - This function is meant for use from the debugger. You can just 219 /// say 'call F->viewCFG()' and a ghostview window should pop up from the 220 /// program, displaying the CFG of the current function. This depends on there 221 /// being a 'dot' and 'gv' program in your path. 222 /// 223 void Function::viewCFG() const { 224 if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) 225 return; 226 DOTFuncInfo CFGInfo(this); 227 ViewGraph(&CFGInfo, "cfg" + getName()); 228 } 229 230 /// viewCFGOnly - This function is meant for use from the debugger. It works 231 /// just like viewCFG, but it does not include the contents of basic blocks 232 /// into the nodes, just the label. If you are only interested in the CFG 233 /// this can make the graph smaller. 234 /// 235 void Function::viewCFGOnly() const { 236 if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) 237 return; 238 DOTFuncInfo CFGInfo(this); 239 ViewGraph(&CFGInfo, "cfg" + getName(), true); 240 } 241 242 FunctionPass *llvm::createCFGPrinterLegacyPassPass () { 243 return new CFGPrinterLegacyPass(); 244 } 245 246 FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () { 247 return new CFGOnlyPrinterLegacyPass(); 248 } 249 250 void DOTGraphTraits<DOTFuncInfo *>::computeHiddenNodes(const Function *F) { 251 auto evaluateBB = [&](const BasicBlock *Node) { 252 if (succ_begin(Node) == succ_end(Node)) { 253 const Instruction *TI = Node->getTerminator(); 254 isHiddenBasicBlock[Node] = 255 (HideUnreachablePaths && isa<UnreachableInst>(TI)) || 256 (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall()); 257 return; 258 } 259 isHiddenBasicBlock[Node] = std::all_of( 260 succ_begin(Node), succ_end(Node), 261 [this](const BasicBlock *BB) { return isHiddenBasicBlock[BB]; }); 262 }; 263 /// The post order traversal iteration is done to know the status of 264 /// isHiddenBasicBlock for all the successors on the current BB. 265 for_each(po_begin(&F->getEntryBlock()), po_end(&F->getEntryBlock()), 266 evaluateBB); 267 } 268 269 bool DOTGraphTraits<DOTFuncInfo *>::isNodeHidden(const BasicBlock *Node) { 270 // If both restricting flags are false, all nodes are displayed. 271 if (!HideUnreachablePaths && !HideDeoptimizePaths) 272 return false; 273 if (isHiddenBasicBlock.find(Node) == isHiddenBasicBlock.end()) 274 computeHiddenNodes(Node->getParent()); 275 return isHiddenBasicBlock[Node]; 276 } 277