CFGPrinter.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- CFGPrinter.h - CFG printer external interface -----------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file defines a 'dot-cfg' analysis pass, which emits the
  15. // cfg.<fnname>.dot file for each function in the program, with a graph of the
  16. // CFG for that function.
  17. //
  18. // This file defines external functions that can be called to explicitly
  19. // instantiate the CFG printer.
  20. //
  21. //===----------------------------------------------------------------------===//
  22. #ifndef LLVM_ANALYSIS_CFGPRINTER_H
  23. #define LLVM_ANALYSIS_CFGPRINTER_H
  24. #include "llvm/Analysis/BlockFrequencyInfo.h"
  25. #include "llvm/Analysis/BranchProbabilityInfo.h"
  26. #include "llvm/Analysis/HeatUtils.h"
  27. #include "llvm/IR/CFG.h"
  28. #include "llvm/IR/Constants.h"
  29. #include "llvm/IR/Function.h"
  30. #include "llvm/IR/Instructions.h"
  31. #include "llvm/IR/PassManager.h"
  32. #include "llvm/IR/ProfDataUtils.h"
  33. #include "llvm/Support/DOTGraphTraits.h"
  34. #include "llvm/Support/FormatVariadic.h"
  35. namespace llvm {
  36. template <class GraphType> struct GraphTraits;
  37. class CFGViewerPass : public PassInfoMixin<CFGViewerPass> {
  38. public:
  39. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
  40. };
  41. class CFGOnlyViewerPass : public PassInfoMixin<CFGOnlyViewerPass> {
  42. public:
  43. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
  44. };
  45. class CFGPrinterPass : public PassInfoMixin<CFGPrinterPass> {
  46. public:
  47. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
  48. };
  49. class CFGOnlyPrinterPass : public PassInfoMixin<CFGOnlyPrinterPass> {
  50. public:
  51. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
  52. };
  53. class DOTFuncInfo {
  54. private:
  55. const Function *F;
  56. const BlockFrequencyInfo *BFI;
  57. const BranchProbabilityInfo *BPI;
  58. uint64_t MaxFreq;
  59. bool ShowHeat;
  60. bool EdgeWeights;
  61. bool RawWeights;
  62. public:
  63. DOTFuncInfo(const Function *F) : DOTFuncInfo(F, nullptr, nullptr, 0) {}
  64. DOTFuncInfo(const Function *F, const BlockFrequencyInfo *BFI,
  65. const BranchProbabilityInfo *BPI, uint64_t MaxFreq)
  66. : F(F), BFI(BFI), BPI(BPI), MaxFreq(MaxFreq) {
  67. ShowHeat = false;
  68. EdgeWeights = !!BPI; // Print EdgeWeights when BPI is available.
  69. RawWeights = !!BFI; // Print RawWeights when BFI is available.
  70. }
  71. const BlockFrequencyInfo *getBFI() const { return BFI; }
  72. const BranchProbabilityInfo *getBPI() const { return BPI; }
  73. const Function *getFunction() const { return this->F; }
  74. uint64_t getMaxFreq() const { return MaxFreq; }
  75. uint64_t getFreq(const BasicBlock *BB) const {
  76. return BFI->getBlockFreq(BB).getFrequency();
  77. }
  78. void setHeatColors(bool ShowHeat) { this->ShowHeat = ShowHeat; }
  79. bool showHeatColors() { return ShowHeat; }
  80. void setRawEdgeWeights(bool RawWeights) { this->RawWeights = RawWeights; }
  81. bool useRawEdgeWeights() { return RawWeights; }
  82. void setEdgeWeights(bool EdgeWeights) { this->EdgeWeights = EdgeWeights; }
  83. bool showEdgeWeights() { return EdgeWeights; }
  84. };
  85. template <>
  86. struct GraphTraits<DOTFuncInfo *> : public GraphTraits<const BasicBlock *> {
  87. static NodeRef getEntryNode(DOTFuncInfo *CFGInfo) {
  88. return &(CFGInfo->getFunction()->getEntryBlock());
  89. }
  90. // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
  91. using nodes_iterator = pointer_iterator<Function::const_iterator>;
  92. static nodes_iterator nodes_begin(DOTFuncInfo *CFGInfo) {
  93. return nodes_iterator(CFGInfo->getFunction()->begin());
  94. }
  95. static nodes_iterator nodes_end(DOTFuncInfo *CFGInfo) {
  96. return nodes_iterator(CFGInfo->getFunction()->end());
  97. }
  98. static size_t size(DOTFuncInfo *CFGInfo) {
  99. return CFGInfo->getFunction()->size();
  100. }
  101. };
  102. template <typename BasicBlockT>
  103. std::string SimpleNodeLabelString(const BasicBlockT *Node) {
  104. if (!Node->getName().empty())
  105. return Node->getName().str();
  106. std::string Str;
  107. raw_string_ostream OS(Str);
  108. Node->printAsOperand(OS, false);
  109. return OS.str();
  110. }
  111. template <typename BasicBlockT>
  112. std::string CompleteNodeLabelString(
  113. const BasicBlockT *Node,
  114. function_ref<void(raw_string_ostream &, const BasicBlockT &)>
  115. HandleBasicBlock,
  116. function_ref<void(std::string &, unsigned &, unsigned)>
  117. HandleComment) {
  118. enum { MaxColumns = 80 };
  119. std::string Str;
  120. raw_string_ostream OS(Str);
  121. if (Node->getName().empty()) {
  122. Node->printAsOperand(OS, false);
  123. OS << ':';
  124. }
  125. HandleBasicBlock(OS, *Node);
  126. std::string OutStr = OS.str();
  127. if (OutStr[0] == '\n')
  128. OutStr.erase(OutStr.begin());
  129. unsigned ColNum = 0;
  130. unsigned LastSpace = 0;
  131. for (unsigned i = 0; i != OutStr.length(); ++i) {
  132. if (OutStr[i] == '\n') { // Left justify
  133. OutStr[i] = '\\';
  134. OutStr.insert(OutStr.begin() + i + 1, 'l');
  135. ColNum = 0;
  136. LastSpace = 0;
  137. } else if (OutStr[i] == ';') { // Delete comments!
  138. unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
  139. HandleComment(OutStr, i, Idx);
  140. } else if (ColNum == MaxColumns) { // Wrap lines.
  141. // Wrap very long names even though we can't find a space.
  142. if (!LastSpace)
  143. LastSpace = i;
  144. OutStr.insert(LastSpace, "\\l...");
  145. ColNum = i - LastSpace;
  146. LastSpace = 0;
  147. i += 3; // The loop will advance 'i' again.
  148. } else
  149. ++ColNum;
  150. if (OutStr[i] == ' ')
  151. LastSpace = i;
  152. }
  153. return OutStr;
  154. }
  155. template <>
  156. struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
  157. // Cache for is hidden property
  158. DenseMap<const BasicBlock *, bool> isOnDeoptOrUnreachablePath;
  159. DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
  160. static void eraseComment(std::string &OutStr, unsigned &I, unsigned Idx) {
  161. OutStr.erase(OutStr.begin() + I, OutStr.begin() + Idx);
  162. --I;
  163. }
  164. static std::string getGraphName(DOTFuncInfo *CFGInfo) {
  165. return "CFG for '" + CFGInfo->getFunction()->getName().str() + "' function";
  166. }
  167. static std::string getSimpleNodeLabel(const BasicBlock *Node, DOTFuncInfo *) {
  168. return SimpleNodeLabelString(Node);
  169. }
  170. static std::string getCompleteNodeLabel(
  171. const BasicBlock *Node, DOTFuncInfo *,
  172. function_ref<void(raw_string_ostream &, const BasicBlock &)>
  173. HandleBasicBlock = [](raw_string_ostream &OS,
  174. const BasicBlock &Node) -> void { OS << Node; },
  175. function_ref<void(std::string &, unsigned &, unsigned)>
  176. HandleComment = eraseComment) {
  177. return CompleteNodeLabelString(Node, HandleBasicBlock, HandleComment);
  178. }
  179. std::string getNodeLabel(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
  180. if (isSimple())
  181. return getSimpleNodeLabel(Node, CFGInfo);
  182. else
  183. return getCompleteNodeLabel(Node, CFGInfo);
  184. }
  185. static std::string getEdgeSourceLabel(const BasicBlock *Node,
  186. const_succ_iterator I) {
  187. // Label source of conditional branches with "T" or "F"
  188. if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator()))
  189. if (BI->isConditional())
  190. return (I == succ_begin(Node)) ? "T" : "F";
  191. // Label source of switch edges with the associated value.
  192. if (const SwitchInst *SI = dyn_cast<SwitchInst>(Node->getTerminator())) {
  193. unsigned SuccNo = I.getSuccessorIndex();
  194. if (SuccNo == 0)
  195. return "def";
  196. std::string Str;
  197. raw_string_ostream OS(Str);
  198. auto Case = *SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo);
  199. OS << Case.getCaseValue()->getValue();
  200. return OS.str();
  201. }
  202. return "";
  203. }
  204. /// Display the raw branch weights from PGO.
  205. std::string getEdgeAttributes(const BasicBlock *Node, const_succ_iterator I,
  206. DOTFuncInfo *CFGInfo) {
  207. if (!CFGInfo->showEdgeWeights())
  208. return "";
  209. const Instruction *TI = Node->getTerminator();
  210. if (TI->getNumSuccessors() == 1)
  211. return "penwidth=2";
  212. unsigned OpNo = I.getSuccessorIndex();
  213. if (OpNo >= TI->getNumSuccessors())
  214. return "";
  215. BasicBlock *SuccBB = TI->getSuccessor(OpNo);
  216. auto BranchProb = CFGInfo->getBPI()->getEdgeProbability(Node, SuccBB);
  217. double WeightPercent = ((double)BranchProb.getNumerator()) /
  218. ((double)BranchProb.getDenominator());
  219. double Width = 1 + WeightPercent;
  220. if (!CFGInfo->useRawEdgeWeights())
  221. return formatv("label=\"{0:P}\" penwidth={1}", WeightPercent, Width)
  222. .str();
  223. // Prepend a 'W' to indicate that this is a weight rather than the actual
  224. // profile count (due to scaling).
  225. uint64_t Freq = CFGInfo->getFreq(Node);
  226. std::string Attrs = formatv("label=\"W:{0}\" penwidth={1}",
  227. (uint64_t)(Freq * WeightPercent), Width);
  228. if (Attrs.size())
  229. return Attrs;
  230. MDNode *WeightsNode = getBranchWeightMDNode(*TI);
  231. if (!WeightsNode)
  232. return "";
  233. OpNo = I.getSuccessorIndex() + 1;
  234. if (OpNo >= WeightsNode->getNumOperands())
  235. return "";
  236. ConstantInt *Weight =
  237. mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(OpNo));
  238. if (!Weight)
  239. return "";
  240. return ("label=\"W:" + std::to_string(Weight->getZExtValue()) +
  241. "\" penwidth=" + std::to_string(Width));
  242. }
  243. std::string getNodeAttributes(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
  244. if (!CFGInfo->showHeatColors())
  245. return "";
  246. uint64_t Freq = CFGInfo->getFreq(Node);
  247. std::string Color = getHeatColor(Freq, CFGInfo->getMaxFreq());
  248. std::string EdgeColor = (Freq <= (CFGInfo->getMaxFreq() / 2))
  249. ? (getHeatColor(0))
  250. : (getHeatColor(1));
  251. std::string Attrs = "color=\"" + EdgeColor + "ff\", style=filled," +
  252. " fillcolor=\"" + Color + "70\"";
  253. return Attrs;
  254. }
  255. bool isNodeHidden(const BasicBlock *Node, const DOTFuncInfo *CFGInfo);
  256. void computeDeoptOrUnreachablePaths(const Function *F);
  257. };
  258. } // End llvm namespace
  259. namespace llvm {
  260. class FunctionPass;
  261. FunctionPass *createCFGPrinterLegacyPassPass();
  262. FunctionPass *createCFGOnlyPrinterLegacyPassPass();
  263. } // End llvm namespace
  264. #endif
  265. #ifdef __GNUC__
  266. #pragma GCC diagnostic pop
  267. #endif