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