CFGPrinter.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//
  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. // `<prefix>.<fnname>.dot` file for each function in the program, with a graph
  11. // of the CFG for that function. The default value for `<prefix>` is `cfg` but
  12. // can be customized as needed.
  13. //
  14. // The other main feature of this file is that it implements the
  15. // Function::viewCFG method, which is useful for debugging passes which operate
  16. // on the CFG.
  17. //
  18. //===----------------------------------------------------------------------===//
  19. #include "llvm/Analysis/CFGPrinter.h"
  20. #include "llvm/ADT/PostOrderIterator.h"
  21. #include "llvm/InitializePasses.h"
  22. #include "llvm/Pass.h"
  23. #include "llvm/Support/CommandLine.h"
  24. #include "llvm/Support/FileSystem.h"
  25. #include <algorithm>
  26. using namespace llvm;
  27. static cl::opt<std::string>
  28. CFGFuncName("cfg-func-name", cl::Hidden,
  29. cl::desc("The name of a function (or its substring)"
  30. " whose CFG is viewed/printed."));
  31. static cl::opt<std::string> CFGDotFilenamePrefix(
  32. "cfg-dot-filename-prefix", cl::Hidden,
  33. cl::desc("The prefix used for the CFG dot file names."));
  34. static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths",
  35. cl::init(false));
  36. static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths",
  37. cl::init(false));
  38. static cl::opt<double> HideColdPaths(
  39. "cfg-hide-cold-paths", cl::init(0.0),
  40. cl::desc("Hide blocks with relative frequency below the given value"));
  41. static cl::opt<bool> ShowHeatColors("cfg-heat-colors", cl::init(true),
  42. cl::Hidden,
  43. cl::desc("Show heat colors in CFG"));
  44. static cl::opt<bool> UseRawEdgeWeight("cfg-raw-weights", cl::init(false),
  45. cl::Hidden,
  46. cl::desc("Use raw weights for labels. "
  47. "Use percentages as default."));
  48. static cl::opt<bool>
  49. ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden,
  50. cl::desc("Show edges labeled with weights"));
  51. static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
  52. BranchProbabilityInfo *BPI, uint64_t MaxFreq,
  53. bool CFGOnly = false) {
  54. std::string Filename =
  55. (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
  56. errs() << "Writing '" << Filename << "'...";
  57. std::error_code EC;
  58. raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
  59. DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
  60. CFGInfo.setHeatColors(ShowHeatColors);
  61. CFGInfo.setEdgeWeights(ShowEdgeWeight);
  62. CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
  63. if (!EC)
  64. WriteGraph(File, &CFGInfo, CFGOnly);
  65. else
  66. errs() << " error opening file for writing!";
  67. errs() << "\n";
  68. }
  69. static void viewCFG(Function &F, const BlockFrequencyInfo *BFI,
  70. const BranchProbabilityInfo *BPI, uint64_t MaxFreq,
  71. bool CFGOnly = false) {
  72. DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
  73. CFGInfo.setHeatColors(ShowHeatColors);
  74. CFGInfo.setEdgeWeights(ShowEdgeWeight);
  75. CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
  76. ViewGraph(&CFGInfo, "cfg." + F.getName(), CFGOnly);
  77. }
  78. namespace {
  79. struct CFGViewerLegacyPass : public FunctionPass {
  80. static char ID; // Pass identifcation, replacement for typeid
  81. CFGViewerLegacyPass() : FunctionPass(ID) {
  82. initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
  83. }
  84. bool runOnFunction(Function &F) override {
  85. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  86. return false;
  87. auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
  88. auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
  89. viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
  90. return false;
  91. }
  92. void print(raw_ostream &OS, const Module * = nullptr) const override {}
  93. void getAnalysisUsage(AnalysisUsage &AU) const override {
  94. FunctionPass::getAnalysisUsage(AU);
  95. AU.addRequired<BlockFrequencyInfoWrapperPass>();
  96. AU.addRequired<BranchProbabilityInfoWrapperPass>();
  97. AU.setPreservesAll();
  98. }
  99. };
  100. } // namespace
  101. char CFGViewerLegacyPass::ID = 0;
  102. INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false,
  103. true)
  104. PreservedAnalyses CFGViewerPass::run(Function &F, FunctionAnalysisManager &AM) {
  105. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  106. return PreservedAnalyses::all();
  107. auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
  108. auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
  109. viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
  110. return PreservedAnalyses::all();
  111. }
  112. namespace {
  113. struct CFGOnlyViewerLegacyPass : public FunctionPass {
  114. static char ID; // Pass identifcation, replacement for typeid
  115. CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
  116. initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
  117. }
  118. bool runOnFunction(Function &F) override {
  119. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  120. return false;
  121. auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
  122. auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
  123. viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
  124. return false;
  125. }
  126. void print(raw_ostream &OS, const Module * = nullptr) const override {}
  127. void getAnalysisUsage(AnalysisUsage &AU) const override {
  128. FunctionPass::getAnalysisUsage(AU);
  129. AU.addRequired<BlockFrequencyInfoWrapperPass>();
  130. AU.addRequired<BranchProbabilityInfoWrapperPass>();
  131. AU.setPreservesAll();
  132. }
  133. };
  134. } // namespace
  135. char CFGOnlyViewerLegacyPass::ID = 0;
  136. INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
  137. "View CFG of function (with no function bodies)", false, true)
  138. PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
  139. FunctionAnalysisManager &AM) {
  140. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  141. return PreservedAnalyses::all();
  142. auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
  143. auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
  144. viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
  145. return PreservedAnalyses::all();
  146. }
  147. namespace {
  148. struct CFGPrinterLegacyPass : public FunctionPass {
  149. static char ID; // Pass identification, replacement for typeid
  150. CFGPrinterLegacyPass() : FunctionPass(ID) {
  151. initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
  152. }
  153. bool runOnFunction(Function &F) override {
  154. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  155. return false;
  156. auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
  157. auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
  158. writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
  159. return false;
  160. }
  161. void print(raw_ostream &OS, const Module * = nullptr) const override {}
  162. void getAnalysisUsage(AnalysisUsage &AU) const override {
  163. FunctionPass::getAnalysisUsage(AU);
  164. AU.addRequired<BlockFrequencyInfoWrapperPass>();
  165. AU.addRequired<BranchProbabilityInfoWrapperPass>();
  166. AU.setPreservesAll();
  167. }
  168. };
  169. } // namespace
  170. char CFGPrinterLegacyPass::ID = 0;
  171. INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg",
  172. "Print CFG of function to 'dot' file", false, true)
  173. PreservedAnalyses CFGPrinterPass::run(Function &F,
  174. FunctionAnalysisManager &AM) {
  175. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  176. return PreservedAnalyses::all();
  177. auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
  178. auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
  179. writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
  180. return PreservedAnalyses::all();
  181. }
  182. namespace {
  183. struct CFGOnlyPrinterLegacyPass : public FunctionPass {
  184. static char ID; // Pass identification, replacement for typeid
  185. CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
  186. initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
  187. }
  188. bool runOnFunction(Function &F) override {
  189. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  190. return false;
  191. auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
  192. auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
  193. writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
  194. return false;
  195. }
  196. void print(raw_ostream &OS, const Module * = nullptr) const override {}
  197. void getAnalysisUsage(AnalysisUsage &AU) const override {
  198. FunctionPass::getAnalysisUsage(AU);
  199. AU.addRequired<BlockFrequencyInfoWrapperPass>();
  200. AU.addRequired<BranchProbabilityInfoWrapperPass>();
  201. AU.setPreservesAll();
  202. }
  203. };
  204. } // namespace
  205. char CFGOnlyPrinterLegacyPass::ID = 0;
  206. INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
  207. "Print CFG of function to 'dot' file (with no function bodies)",
  208. false, true)
  209. PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
  210. FunctionAnalysisManager &AM) {
  211. if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
  212. return PreservedAnalyses::all();
  213. auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
  214. auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
  215. writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
  216. return PreservedAnalyses::all();
  217. }
  218. /// viewCFG - This function is meant for use from the debugger. You can just
  219. /// say 'call F->viewCFG()' and a ghostview window should pop up from the
  220. /// program, displaying the CFG of the current function. This depends on there
  221. /// being a 'dot' and 'gv' program in your path.
  222. ///
  223. void Function::viewCFG() const { viewCFG(false, nullptr, nullptr); }
  224. void Function::viewCFG(bool ViewCFGOnly, const BlockFrequencyInfo *BFI,
  225. const BranchProbabilityInfo *BPI) const {
  226. if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
  227. return;
  228. DOTFuncInfo CFGInfo(this, BFI, BPI, BFI ? getMaxFreq(*this, BFI) : 0);
  229. ViewGraph(&CFGInfo, "cfg" + getName(), ViewCFGOnly);
  230. }
  231. /// viewCFGOnly - This function is meant for use from the debugger. It works
  232. /// just like viewCFG, but it does not include the contents of basic blocks
  233. /// into the nodes, just the label. If you are only interested in the CFG
  234. /// this can make the graph smaller.
  235. ///
  236. void Function::viewCFGOnly() const { viewCFGOnly(nullptr, nullptr); }
  237. void Function::viewCFGOnly(const BlockFrequencyInfo *BFI,
  238. const BranchProbabilityInfo *BPI) const {
  239. viewCFG(true, BFI, BPI);
  240. }
  241. FunctionPass *llvm::createCFGPrinterLegacyPassPass() {
  242. return new CFGPrinterLegacyPass();
  243. }
  244. FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass() {
  245. return new CFGOnlyPrinterLegacyPass();
  246. }
  247. /// Find all blocks on the paths which terminate with a deoptimize or
  248. /// unreachable (i.e. all blocks which are post-dominated by a deoptimize
  249. /// or unreachable). These paths are hidden if the corresponding cl::opts
  250. /// are enabled.
  251. void DOTGraphTraits<DOTFuncInfo *>::computeDeoptOrUnreachablePaths(
  252. const Function *F) {
  253. auto evaluateBB = [&](const BasicBlock *Node) {
  254. if (succ_empty(Node)) {
  255. const Instruction *TI = Node->getTerminator();
  256. isOnDeoptOrUnreachablePath[Node] =
  257. (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
  258. (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
  259. return;
  260. }
  261. isOnDeoptOrUnreachablePath[Node] =
  262. llvm::all_of(successors(Node), [this](const BasicBlock *BB) {
  263. return isOnDeoptOrUnreachablePath[BB];
  264. });
  265. };
  266. /// The post order traversal iteration is done to know the status of
  267. /// isOnDeoptOrUnreachablePath for all the successors on the current BB.
  268. llvm::for_each(post_order(&F->getEntryBlock()), evaluateBB);
  269. }
  270. bool DOTGraphTraits<DOTFuncInfo *>::isNodeHidden(const BasicBlock *Node,
  271. const DOTFuncInfo *CFGInfo) {
  272. if (HideColdPaths.getNumOccurrences() > 0)
  273. if (auto *BFI = CFGInfo->getBFI()) {
  274. uint64_t NodeFreq = BFI->getBlockFreq(Node).getFrequency();
  275. uint64_t EntryFreq = BFI->getEntryFreq();
  276. // Hide blocks with relative frequency below HideColdPaths threshold.
  277. if ((double)NodeFreq / EntryFreq < HideColdPaths)
  278. return true;
  279. }
  280. if (HideUnreachablePaths || HideDeoptimizePaths) {
  281. if (isOnDeoptOrUnreachablePath.find(Node) ==
  282. isOnDeoptOrUnreachablePath.end())
  283. computeDeoptOrUnreachablePaths(Node->getParent());
  284. return isOnDeoptOrUnreachablePath[Node];
  285. }
  286. return false;
  287. }