blob: 619b675b58d88bbe88306081652e10aac227e344 [file] [log] [blame]
Chris Lattnera93d11b2003-10-22 16:03:49 +00001//===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//
Misha Brukman01808ca2005-04-21 21:13:18 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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 Brukman01808ca2005-04-21 21:13:18 +00006//
Chris Lattnera93d11b2003-10-22 16:03:49 +00007//===----------------------------------------------------------------------===//
8//
Chandler Carruthd46f5802018-10-09 04:30:23 +00009// 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 Lattnera93d11b2003-10-22 16:03:49 +000013//
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 Gaeke104341f2004-04-26 16:27:08 +000020#include "llvm/Analysis/CFGPrinter.h"
Chris Lattnerda424262009-10-18 04:09:11 +000021#include "llvm/Pass.h"
Benjamin Kramerd59664f2014-04-29 23:26:49 +000022#include "llvm/Support/FileSystem.h"
Chris Lattner62aff842003-12-11 21:48:18 +000023using namespace llvm;
Brian Gaeke960707c2003-11-11 22:41:34 +000024
Xinliang David Li45a607e2018-07-25 17:22:12 +000025static 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 Carruthd46f5802018-10-09 04:30:23 +000030static 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 Lattnera93d11b2003-10-22 16:03:49 +000034namespace {
Sean Fertilecd0d7632018-06-29 17:48:58 +000035 struct CFGViewerLegacyPass : public FunctionPass {
Dan Gohman90d97ac2007-05-14 14:25:08 +000036 static char ID; // Pass identifcation, replacement for typeid
Sean Fertilecd0d7632018-06-29 17:48:58 +000037 CFGViewerLegacyPass() : FunctionPass(ID) {
Sriraman Tallam06a67ba2016-09-15 18:35:27 +000038 initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
Owen Anderson6c18d1a2010-10-19 17:21:58 +000039 }
Devang Patel864970e2008-03-18 00:39:19 +000040
Sean Fertilecd0d7632018-06-29 17:48:58 +000041 bool runOnFunction(Function &F) override {
42 F.viewCFG();
Dan Gohman90d97ac2007-05-14 14:25:08 +000043 return false;
44 }
45
Sean Fertilecd0d7632018-06-29 17:48:58 +000046 void print(raw_ostream &OS, const Module* = nullptr) const override {}
Dan Gohman90d97ac2007-05-14 14:25:08 +000047
Craig Toppere9ba7592014-03-05 07:30:04 +000048 void getAnalysisUsage(AnalysisUsage &AU) const override {
Dan Gohman90d97ac2007-05-14 14:25:08 +000049 AU.setPreservesAll();
50 }
51 };
Alexander Kornienkof00654e2015-06-23 09:49:53 +000052}
Dan Gohman90d97ac2007-05-14 14:25:08 +000053
Sriraman Tallam06a67ba2016-09-15 18:35:27 +000054char CFGViewerLegacyPass::ID = 0;
55INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
56
Sean Fertilecd0d7632018-06-29 17:48:58 +000057PreservedAnalyses CFGViewerPass::run(Function &F,
58 FunctionAnalysisManager &AM) {
59 F.viewCFG();
Sriraman Tallam06a67ba2016-09-15 18:35:27 +000060 return PreservedAnalyses::all();
61}
62
Dan Gohman90d97ac2007-05-14 14:25:08 +000063
Dan Gohmand78c4002008-05-13 00:00:25 +000064namespace {
Sean Fertilecd0d7632018-06-29 17:48:58 +000065 struct CFGOnlyViewerLegacyPass : public FunctionPass {
Dan Gohman90d97ac2007-05-14 14:25:08 +000066 static char ID; // Pass identifcation, replacement for typeid
Sean Fertilecd0d7632018-06-29 17:48:58 +000067 CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
Sriraman Tallam06a67ba2016-09-15 18:35:27 +000068 initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
Owen Anderson6c18d1a2010-10-19 17:21:58 +000069 }
Devang Patel864970e2008-03-18 00:39:19 +000070
Sean Fertilecd0d7632018-06-29 17:48:58 +000071 bool runOnFunction(Function &F) override {
72 F.viewCFGOnly();
Dan Gohman90d97ac2007-05-14 14:25:08 +000073 return false;
74 }
75
Sean Fertilecd0d7632018-06-29 17:48:58 +000076 void print(raw_ostream &OS, const Module* = nullptr) const override {}
Dan Gohman90d97ac2007-05-14 14:25:08 +000077
Craig Toppere9ba7592014-03-05 07:30:04 +000078 void getAnalysisUsage(AnalysisUsage &AU) const override {
Dan Gohman90d97ac2007-05-14 14:25:08 +000079 AU.setPreservesAll();
80 }
81 };
Alexander Kornienkof00654e2015-06-23 09:49:53 +000082}
Dan Gohman90d97ac2007-05-14 14:25:08 +000083
Sriraman Tallam06a67ba2016-09-15 18:35:27 +000084char CFGOnlyViewerLegacyPass::ID = 0;
85INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
Owen Andersondf7a4f22010-10-07 22:25:06 +000086 "View CFG of function (with no function bodies)", false, true)
Dan Gohman90d97ac2007-05-14 14:25:08 +000087
Sean Fertilecd0d7632018-06-29 17:48:58 +000088PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
89 FunctionAnalysisManager &AM) {
90 F.viewCFGOnly();
Sriraman Tallam06a67ba2016-09-15 18:35:27 +000091 return PreservedAnalyses::all();
92}
93
Sean Fertilecd0d7632018-06-29 17:48:58 +000094static void writeCFGToDotFile(Function &F, bool CFGOnly = false) {
Xinliang David Li45a607e2018-07-25 17:22:12 +000095 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
96 return;
Chandler Carruthd46f5802018-10-09 04:30:23 +000097 std::string Filename =
98 (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
Sean Fertilecd0d7632018-06-29 17:48:58 +000099 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 Gohmand78c4002008-05-13 00:00:25 +0000111namespace {
Sean Fertilecd0d7632018-06-29 17:48:58 +0000112 struct CFGPrinterLegacyPass : public FunctionPass {
Nick Lewyckye7da2d62007-05-06 13:37:16 +0000113 static char ID; // Pass identification, replacement for typeid
Sean Fertilecd0d7632018-06-29 17:48:58 +0000114 CFGPrinterLegacyPass() : FunctionPass(ID) {
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000115 initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
Owen Anderson6c18d1a2010-10-19 17:21:58 +0000116 }
Devang Patel864970e2008-03-18 00:39:19 +0000117
Sean Fertilecd0d7632018-06-29 17:48:58 +0000118 bool runOnFunction(Function &F) override {
119 writeCFGToDotFile(F);
Chris Lattnera93d11b2003-10-22 16:03:49 +0000120 return false;
121 }
122
Sean Fertilecd0d7632018-06-29 17:48:58 +0000123 void print(raw_ostream &OS, const Module* = nullptr) const override {}
Misha Brukman01808ca2005-04-21 21:13:18 +0000124
Craig Toppere9ba7592014-03-05 07:30:04 +0000125 void getAnalysisUsage(AnalysisUsage &AU) const override {
Chris Lattnera93d11b2003-10-22 16:03:49 +0000126 AU.setPreservesAll();
127 }
128 };
Alexander Kornienkof00654e2015-06-23 09:49:53 +0000129}
Chris Lattnera93d11b2003-10-22 16:03:49 +0000130
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000131char CFGPrinterLegacyPass::ID = 0;
Fangrui Songf78650a2018-07-30 19:41:25 +0000132INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file",
Owen Andersondf7a4f22010-10-07 22:25:06 +0000133 false, true)
Chris Lattner62aff842003-12-11 21:48:18 +0000134
Sean Fertilecd0d7632018-06-29 17:48:58 +0000135PreservedAnalyses CFGPrinterPass::run(Function &F,
136 FunctionAnalysisManager &AM) {
137 writeCFGToDotFile(F);
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000138 return PreservedAnalyses::all();
139}
140
Dan Gohmand78c4002008-05-13 00:00:25 +0000141namespace {
Sean Fertilecd0d7632018-06-29 17:48:58 +0000142 struct CFGOnlyPrinterLegacyPass : public FunctionPass {
Nick Lewyckye7da2d62007-05-06 13:37:16 +0000143 static char ID; // Pass identification, replacement for typeid
Sean Fertilecd0d7632018-06-29 17:48:58 +0000144 CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000145 initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
Owen Anderson6c18d1a2010-10-19 17:21:58 +0000146 }
Craig Toppere9ba7592014-03-05 07:30:04 +0000147
Sean Fertilecd0d7632018-06-29 17:48:58 +0000148 bool runOnFunction(Function &F) override {
149 writeCFGToDotFile(F, /*CFGOnly=*/true);
Chris Lattner62aff842003-12-11 21:48:18 +0000150 return false;
151 }
Sean Fertilecd0d7632018-06-29 17:48:58 +0000152 void print(raw_ostream &OS, const Module* = nullptr) const override {}
Misha Brukman01808ca2005-04-21 21:13:18 +0000153
Craig Toppere9ba7592014-03-05 07:30:04 +0000154 void getAnalysisUsage(AnalysisUsage &AU) const override {
Chris Lattner62aff842003-12-11 21:48:18 +0000155 AU.setPreservesAll();
156 }
157 };
Alexander Kornienkof00654e2015-06-23 09:49:53 +0000158}
Chris Lattnera93d11b2003-10-22 16:03:49 +0000159
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000160char CFGOnlyPrinterLegacyPass::ID = 0;
161INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
Owen Andersond31d82d2010-08-23 17:52:01 +0000162 "Print CFG of function to 'dot' file (with no function bodies)",
Owen Andersondf7a4f22010-10-07 22:25:06 +0000163 false, true)
Dan Gohmand78c4002008-05-13 00:00:25 +0000164
Sean Fertilecd0d7632018-06-29 17:48:58 +0000165PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
166 FunctionAnalysisManager &AM) {
167 writeCFGToDotFile(F, /*CFGOnly=*/true);
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000168 return PreservedAnalyses::all();
169}
170
Chris Lattnera93d11b2003-10-22 16:03:49 +0000171/// 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///
176void Function::viewCFG() const {
Xinliang David Li45a607e2018-07-25 17:22:12 +0000177 if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
178 return;
Sean Fertilecd0d7632018-06-29 17:48:58 +0000179 ViewGraph(this, "cfg" + getName());
Chris Lattnera93d11b2003-10-22 16:03:49 +0000180}
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 Christopher650c8f22014-05-20 17:11:11 +0000184/// into the nodes, just the label. If you are only interested in the CFG
185/// this can make the graph smaller.
Chris Lattnera93d11b2003-10-22 16:03:49 +0000186///
187void Function::viewCFGOnly() const {
Xinliang David Li45a607e2018-07-25 17:22:12 +0000188 if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
189 return;
Sean Fertilecd0d7632018-06-29 17:48:58 +0000190 ViewGraph(this, "cfg" + getName(), true);
Chris Lattnera93d11b2003-10-22 16:03:49 +0000191}
Brian Gaeke104341f2004-04-26 16:27:08 +0000192
Sean Fertilecd0d7632018-06-29 17:48:58 +0000193FunctionPass *llvm::createCFGPrinterLegacyPassPass () {
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000194 return new CFGPrinterLegacyPass();
Brian Gaeke104341f2004-04-26 16:27:08 +0000195}
196
Sean Fertilecd0d7632018-06-29 17:48:58 +0000197FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
Sriraman Tallam06a67ba2016-09-15 18:35:27 +0000198 return new CFGOnlyPrinterLegacyPass();
Brian Gaeke104341f2004-04-26 16:27:08 +0000199}
Sean Fertilecd0d7632018-06-29 17:48:58 +0000200