CFGPrinter.h 9.9 KB

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