1 //===-- CFGPrinter.h - CFG printer external interface -----------*- C++ -*-===// 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 // cfg.<fnname>.dot file for each function in the program, with a graph of the 11 // CFG for that function. 12 // 13 // This file defines external functions that can be called to explicitly 14 // instantiate the CFG printer. 15 // 16 //===----------------------------------------------------------------------===// 17 18 #ifndef LLVM_ANALYSIS_CFGPRINTER_H 19 #define LLVM_ANALYSIS_CFGPRINTER_H 20 21 #include "llvm/IR/CFG.h" 22 #include "llvm/IR/Constants.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/Instructions.h" 25 #include "llvm/IR/PassManager.h" 26 #include "llvm/Support/GraphWriter.h" 27 28 namespace llvm { 29 class CFGViewerPass 30 : public PassInfoMixin<CFGViewerPass> { 31 public: 32 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 33 }; 34 35 class CFGOnlyViewerPass 36 : public PassInfoMixin<CFGOnlyViewerPass> { 37 public: 38 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 39 }; 40 41 class CFGPrinterPass 42 : public PassInfoMixin<CFGPrinterPass> { 43 public: 44 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 45 }; 46 47 class CFGOnlyPrinterPass 48 : public PassInfoMixin<CFGOnlyPrinterPass> { 49 public: 50 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 51 }; 52 53 template<> 54 struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { 55 56 DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} 57 58 static std::string getGraphName(const Function *F) { 59 return "CFG for '" + F->getName().str() + "' function"; 60 } 61 62 static std::string getSimpleNodeLabel(const BasicBlock *Node, 63 const Function *) { 64 if (!Node->getName().empty()) 65 return Node->getName().str(); 66 67 std::string Str; 68 raw_string_ostream OS(Str); 69 70 Node->printAsOperand(OS, false); 71 return OS.str(); 72 } 73 74 static std::string getCompleteNodeLabel(const BasicBlock *Node, 75 const Function *) { 76 enum { MaxColumns = 80 }; 77 std::string Str; 78 raw_string_ostream OS(Str); 79 80 if (Node->getName().empty()) { 81 Node->printAsOperand(OS, false); 82 OS << ":"; 83 } 84 85 OS << *Node; 86 std::string OutStr = OS.str(); 87 if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); 88 89 // Process string output to make it nicer... 90 unsigned ColNum = 0; 91 unsigned LastSpace = 0; 92 for (unsigned i = 0; i != OutStr.length(); ++i) { 93 if (OutStr[i] == '\n') { // Left justify 94 OutStr[i] = '\\'; 95 OutStr.insert(OutStr.begin()+i+1, 'l'); 96 ColNum = 0; 97 LastSpace = 0; 98 } else if (OutStr[i] == ';') { // Delete comments! 99 unsigned Idx = OutStr.find('\n', i+1); // Find end of line 100 OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx); 101 --i; 102 } else if (ColNum == MaxColumns) { // Wrap lines. 103 // Wrap very long names even though we can't find a space. 104 if (!LastSpace) 105 LastSpace = i; 106 OutStr.insert(LastSpace, "\\l..."); 107 ColNum = i - LastSpace; 108 LastSpace = 0; 109 i += 3; // The loop will advance 'i' again. 110 } 111 else 112 ++ColNum; 113 if (OutStr[i] == ' ') 114 LastSpace = i; 115 } 116 return OutStr; 117 } 118 119 std::string getNodeLabel(const BasicBlock *Node, 120 const Function *Graph) { 121 if (isSimple()) 122 return getSimpleNodeLabel(Node, Graph); 123 else 124 return getCompleteNodeLabel(Node, Graph); 125 } 126 127 static std::string getEdgeSourceLabel(const BasicBlock *Node, 128 succ_const_iterator I) { 129 // Label source of conditional branches with "T" or "F" 130 if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator())) 131 if (BI->isConditional()) 132 return (I == succ_begin(Node)) ? "T" : "F"; 133 134 // Label source of switch edges with the associated value. 135 if (const SwitchInst *SI = dyn_cast<SwitchInst>(Node->getTerminator())) { 136 unsigned SuccNo = I.getSuccessorIndex(); 137 138 if (SuccNo == 0) return "def"; 139 140 std::string Str; 141 raw_string_ostream OS(Str); 142 auto Case = *SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo); 143 OS << Case.getCaseValue()->getValue(); 144 return OS.str(); 145 } 146 return ""; 147 } 148 149 /// Display the raw branch weights from PGO. 150 std::string getEdgeAttributes(const BasicBlock *Node, succ_const_iterator I, 151 const Function *F) { 152 const Instruction *TI = Node->getTerminator(); 153 if (TI->getNumSuccessors() == 1) 154 return ""; 155 156 MDNode *WeightsNode = TI->getMetadata(LLVMContext::MD_prof); 157 if (!WeightsNode) 158 return ""; 159 160 MDString *MDName = cast<MDString>(WeightsNode->getOperand(0)); 161 if (MDName->getString() != "branch_weights") 162 return ""; 163 164 unsigned OpNo = I.getSuccessorIndex() + 1; 165 if (OpNo >= WeightsNode->getNumOperands()) 166 return ""; 167 ConstantInt *Weight = 168 mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(OpNo)); 169 if (!Weight) 170 return ""; 171 172 // Prepend a 'W' to indicate that this is a weight rather than the actual 173 // profile count (due to scaling). 174 return ("label=\"W:" + Twine(Weight->getZExtValue()) + "\"").str(); 175 } 176 }; 177 } // End llvm namespace 178 179 namespace llvm { 180 class FunctionPass; 181 FunctionPass *createCFGPrinterLegacyPassPass (); 182 FunctionPass *createCFGOnlyPrinterLegacyPassPass (); 183 } // End llvm namespace 184 185 #endif 186