blob: aaefc11653dda5cef454bbb6f0c28b0b392bef2d [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===-- CFGPrinter.h - CFG printer external interface -----------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
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
28namespace llvm {
29class CFGViewerPass
30 : public PassInfoMixin<CFGViewerPass> {
31public:
32 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
33};
34
35class CFGOnlyViewerPass
36 : public PassInfoMixin<CFGOnlyViewerPass> {
37public:
38 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
39};
40
41class CFGPrinterPass
42 : public PassInfoMixin<CFGPrinterPass> {
43public:
44 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
45};
46
47class CFGOnlyPrinterPass
48 : public PassInfoMixin<CFGOnlyPrinterPass> {
49public:
50 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
51};
52
53template<>
54struct 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) {
Andrew Walbran16937d02019-10-22 13:54:20 +0100152 const Instruction *TI = Node->getTerminator();
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100153 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).
Andrew Scull0372a572018-11-16 15:47:06 +0000174 return ("label=\"W:" + Twine(Weight->getZExtValue()) + "\"").str();
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100175 }
176};
177} // End llvm namespace
178
179namespace llvm {
180 class FunctionPass;
181 FunctionPass *createCFGPrinterLegacyPassPass ();
182 FunctionPass *createCFGOnlyPrinterLegacyPassPass ();
183} // End llvm namespace
184
185#endif