| 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; |
| 102 | raw_fd_ostream File(Filename, EC, sys::fs::F_Text); |
| 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 | |