| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 1 | //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// | 
| Misha Brukman | 01808ca | 2005-04-21 21:13:18 +0000 | [diff] [blame] | 2 | // | 
| Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 | 
| Misha Brukman | 01808ca | 2005-04-21 21:13:18 +0000 | [diff] [blame] | 6 | // | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | // | 
| Chandler Carruth | d46f580 | 2018-10-09 04:30:23 +0000 | [diff] [blame] | 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. | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 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 |  | 
| Brian Gaeke | 104341f | 2004-04-26 16:27:08 +0000 | [diff] [blame] | 20 | #include "llvm/Analysis/CFGPrinter.h" | 
| Chris Lattner | da42426 | 2009-10-18 04:09:11 +0000 | [diff] [blame] | 21 | #include "llvm/Pass.h" | 
| Benjamin Kramer | d59664f | 2014-04-29 23:26:49 +0000 | [diff] [blame] | 22 | #include "llvm/Support/FileSystem.h" | 
| Chris Lattner | 62aff84 | 2003-12-11 21:48:18 +0000 | [diff] [blame] | 23 | using namespace llvm; | 
| Brian Gaeke | 960707c | 2003-11-11 22:41:34 +0000 | [diff] [blame] | 24 |  | 
| Xinliang David Li | 45a607e | 2018-07-25 17:22:12 +0000 | [diff] [blame] | 25 | static cl::opt<std::string> CFGFuncName( | 
|  | 26 | "cfg-func-name", cl::Hidden, | 
|  | 27 | cl::desc("The name of a function (or its substring)" | 
|  | 28 | " whose CFG is viewed/printed.")); | 
|  | 29 |  | 
| Chandler Carruth | d46f580 | 2018-10-09 04:30:23 +0000 | [diff] [blame] | 30 | static cl::opt<std::string> CFGDotFilenamePrefix( | 
|  | 31 | "cfg-dot-filename-prefix", cl::Hidden, | 
|  | 32 | cl::desc("The prefix used for the CFG dot file names.")); | 
|  | 33 |  | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 34 | namespace { | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 35 | struct CFGViewerLegacyPass : public FunctionPass { | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 36 | static char ID; // Pass identifcation, replacement for typeid | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 37 | CFGViewerLegacyPass() : FunctionPass(ID) { | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 38 | initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry()); | 
| Owen Anderson | 6c18d1a | 2010-10-19 17:21:58 +0000 | [diff] [blame] | 39 | } | 
| Devang Patel | 864970e | 2008-03-18 00:39:19 +0000 | [diff] [blame] | 40 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 41 | bool runOnFunction(Function &F) override { | 
|  | 42 | F.viewCFG(); | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 43 | return false; | 
|  | 44 | } | 
|  | 45 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 46 | void print(raw_ostream &OS, const Module* = nullptr) const override {} | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 47 |  | 
| Craig Topper | e9ba759 | 2014-03-05 07:30:04 +0000 | [diff] [blame] | 48 | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 49 | AU.setPreservesAll(); | 
|  | 50 | } | 
|  | 51 | }; | 
| Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 52 | } | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 53 |  | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 54 | char CFGViewerLegacyPass::ID = 0; | 
|  | 55 | INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true) | 
|  | 56 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 57 | PreservedAnalyses CFGViewerPass::run(Function &F, | 
|  | 58 | FunctionAnalysisManager &AM) { | 
|  | 59 | F.viewCFG(); | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 60 | return PreservedAnalyses::all(); | 
|  | 61 | } | 
|  | 62 |  | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 63 |  | 
| Dan Gohman | d78c400 | 2008-05-13 00:00:25 +0000 | [diff] [blame] | 64 | namespace { | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 65 | struct CFGOnlyViewerLegacyPass : public FunctionPass { | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 66 | static char ID; // Pass identifcation, replacement for typeid | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 67 | CFGOnlyViewerLegacyPass() : FunctionPass(ID) { | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 68 | initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry()); | 
| Owen Anderson | 6c18d1a | 2010-10-19 17:21:58 +0000 | [diff] [blame] | 69 | } | 
| Devang Patel | 864970e | 2008-03-18 00:39:19 +0000 | [diff] [blame] | 70 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 71 | bool runOnFunction(Function &F) override { | 
|  | 72 | F.viewCFGOnly(); | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 73 | return false; | 
|  | 74 | } | 
|  | 75 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 76 | void print(raw_ostream &OS, const Module* = nullptr) const override {} | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 77 |  | 
| Craig Topper | e9ba759 | 2014-03-05 07:30:04 +0000 | [diff] [blame] | 78 | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 79 | AU.setPreservesAll(); | 
|  | 80 | } | 
|  | 81 | }; | 
| Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 82 | } | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 83 |  | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 84 | char CFGOnlyViewerLegacyPass::ID = 0; | 
|  | 85 | INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only", | 
| Owen Anderson | df7a4f2 | 2010-10-07 22:25:06 +0000 | [diff] [blame] | 86 | "View CFG of function (with no function bodies)", false, true) | 
| Dan Gohman | 90d97ac | 2007-05-14 14:25:08 +0000 | [diff] [blame] | 87 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 88 | PreservedAnalyses CFGOnlyViewerPass::run(Function &F, | 
|  | 89 | FunctionAnalysisManager &AM) { | 
|  | 90 | F.viewCFGOnly(); | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 91 | return PreservedAnalyses::all(); | 
|  | 92 | } | 
|  | 93 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 94 | static void writeCFGToDotFile(Function &F, bool CFGOnly = false) { | 
| Xinliang David Li | 45a607e | 2018-07-25 17:22:12 +0000 | [diff] [blame] | 95 | if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) | 
|  | 96 | return; | 
| Chandler Carruth | d46f580 | 2018-10-09 04:30:23 +0000 | [diff] [blame] | 97 | std::string Filename = | 
|  | 98 | (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str(); | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 99 | errs() << "Writing '" << Filename << "'..."; | 
|  | 100 |  | 
|  | 101 | std::error_code EC; | 
| Fangrui Song | d9b948b | 2019-08-05 05:43:48 +0000 | [diff] [blame] | 102 | raw_fd_ostream File(Filename, EC, sys::fs::OF_Text); | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 103 |  | 
|  | 104 | if (!EC) | 
|  | 105 | WriteGraph(File, (const Function*)&F, CFGOnly); | 
|  | 106 | else | 
|  | 107 | errs() << "  error opening file for writing!"; | 
|  | 108 | errs() << "\n"; | 
|  | 109 | } | 
|  | 110 |  | 
| Dan Gohman | d78c400 | 2008-05-13 00:00:25 +0000 | [diff] [blame] | 111 | namespace { | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 112 | struct CFGPrinterLegacyPass : public FunctionPass { | 
| Nick Lewycky | e7da2d6 | 2007-05-06 13:37:16 +0000 | [diff] [blame] | 113 | static char ID; // Pass identification, replacement for typeid | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 114 | CFGPrinterLegacyPass() : FunctionPass(ID) { | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 115 | initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); | 
| Owen Anderson | 6c18d1a | 2010-10-19 17:21:58 +0000 | [diff] [blame] | 116 | } | 
| Devang Patel | 864970e | 2008-03-18 00:39:19 +0000 | [diff] [blame] | 117 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 118 | bool runOnFunction(Function &F) override { | 
|  | 119 | writeCFGToDotFile(F); | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 120 | return false; | 
|  | 121 | } | 
|  | 122 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 123 | void print(raw_ostream &OS, const Module* = nullptr) const override {} | 
| Misha Brukman | 01808ca | 2005-04-21 21:13:18 +0000 | [diff] [blame] | 124 |  | 
| Craig Topper | e9ba759 | 2014-03-05 07:30:04 +0000 | [diff] [blame] | 125 | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 126 | AU.setPreservesAll(); | 
|  | 127 | } | 
|  | 128 | }; | 
| Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 129 | } | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 130 |  | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 131 | char CFGPrinterLegacyPass::ID = 0; | 
| Fangrui Song | f78650a | 2018-07-30 19:41:25 +0000 | [diff] [blame] | 132 | INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file", | 
| Owen Anderson | df7a4f2 | 2010-10-07 22:25:06 +0000 | [diff] [blame] | 133 | false, true) | 
| Chris Lattner | 62aff84 | 2003-12-11 21:48:18 +0000 | [diff] [blame] | 134 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 135 | PreservedAnalyses CFGPrinterPass::run(Function &F, | 
|  | 136 | FunctionAnalysisManager &AM) { | 
|  | 137 | writeCFGToDotFile(F); | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 138 | return PreservedAnalyses::all(); | 
|  | 139 | } | 
|  | 140 |  | 
| Dan Gohman | d78c400 | 2008-05-13 00:00:25 +0000 | [diff] [blame] | 141 | namespace { | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 142 | struct CFGOnlyPrinterLegacyPass : public FunctionPass { | 
| Nick Lewycky | e7da2d6 | 2007-05-06 13:37:16 +0000 | [diff] [blame] | 143 | static char ID; // Pass identification, replacement for typeid | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 144 | CFGOnlyPrinterLegacyPass() : FunctionPass(ID) { | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 145 | initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); | 
| Owen Anderson | 6c18d1a | 2010-10-19 17:21:58 +0000 | [diff] [blame] | 146 | } | 
| Craig Topper | e9ba759 | 2014-03-05 07:30:04 +0000 | [diff] [blame] | 147 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 148 | bool runOnFunction(Function &F) override { | 
|  | 149 | writeCFGToDotFile(F, /*CFGOnly=*/true); | 
| Chris Lattner | 62aff84 | 2003-12-11 21:48:18 +0000 | [diff] [blame] | 150 | return false; | 
|  | 151 | } | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 152 | void print(raw_ostream &OS, const Module* = nullptr) const override {} | 
| Misha Brukman | 01808ca | 2005-04-21 21:13:18 +0000 | [diff] [blame] | 153 |  | 
| Craig Topper | e9ba759 | 2014-03-05 07:30:04 +0000 | [diff] [blame] | 154 | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
| Chris Lattner | 62aff84 | 2003-12-11 21:48:18 +0000 | [diff] [blame] | 155 | AU.setPreservesAll(); | 
|  | 156 | } | 
|  | 157 | }; | 
| Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 158 | } | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 159 |  | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 160 | char CFGOnlyPrinterLegacyPass::ID = 0; | 
|  | 161 | INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only", | 
| Owen Anderson | d31d82d | 2010-08-23 17:52:01 +0000 | [diff] [blame] | 162 | "Print CFG of function to 'dot' file (with no function bodies)", | 
| Owen Anderson | df7a4f2 | 2010-10-07 22:25:06 +0000 | [diff] [blame] | 163 | false, true) | 
| Dan Gohman | d78c400 | 2008-05-13 00:00:25 +0000 | [diff] [blame] | 164 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 165 | PreservedAnalyses CFGOnlyPrinterPass::run(Function &F, | 
|  | 166 | FunctionAnalysisManager &AM) { | 
|  | 167 | writeCFGToDotFile(F, /*CFGOnly=*/true); | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 168 | return PreservedAnalyses::all(); | 
|  | 169 | } | 
|  | 170 |  | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 171 | /// viewCFG - This function is meant for use from the debugger.  You can just | 
|  | 172 | /// say 'call F->viewCFG()' and a ghostview window should pop up from the | 
|  | 173 | /// program, displaying the CFG of the current function.  This depends on there | 
|  | 174 | /// being a 'dot' and 'gv' program in your path. | 
|  | 175 | /// | 
|  | 176 | void Function::viewCFG() const { | 
| Xinliang David Li | 45a607e | 2018-07-25 17:22:12 +0000 | [diff] [blame] | 177 | if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) | 
|  | 178 | return; | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 179 | ViewGraph(this, "cfg" + getName()); | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 180 | } | 
|  | 181 |  | 
|  | 182 | /// viewCFGOnly - This function is meant for use from the debugger.  It works | 
|  | 183 | /// just like viewCFG, but it does not include the contents of basic blocks | 
| Eric Christopher | 650c8f2 | 2014-05-20 17:11:11 +0000 | [diff] [blame] | 184 | /// into the nodes, just the label.  If you are only interested in the CFG | 
|  | 185 | /// this can make the graph smaller. | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 186 | /// | 
|  | 187 | void Function::viewCFGOnly() const { | 
| Xinliang David Li | 45a607e | 2018-07-25 17:22:12 +0000 | [diff] [blame] | 188 | if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) | 
|  | 189 | return; | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 190 | ViewGraph(this, "cfg" + getName(), true); | 
| Chris Lattner | a93d11b | 2003-10-22 16:03:49 +0000 | [diff] [blame] | 191 | } | 
| Brian Gaeke | 104341f | 2004-04-26 16:27:08 +0000 | [diff] [blame] | 192 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 193 | FunctionPass *llvm::createCFGPrinterLegacyPassPass () { | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 194 | return new CFGPrinterLegacyPass(); | 
| Brian Gaeke | 104341f | 2004-04-26 16:27:08 +0000 | [diff] [blame] | 195 | } | 
|  | 196 |  | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 197 | FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () { | 
| Sriraman Tallam | 06a67ba | 2016-09-15 18:35:27 +0000 | [diff] [blame] | 198 | return new CFGOnlyPrinterLegacyPass(); | 
| Brian Gaeke | 104341f | 2004-04-26 16:27:08 +0000 | [diff] [blame] | 199 | } | 
| Sean Fertile | cd0d763 | 2018-06-29 17:48:58 +0000 | [diff] [blame] | 200 |  |