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