CFGPrinter.cpp revision 353358
1193323Sed//===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//
2193323Sed//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6193323Sed//
7193323Sed//===----------------------------------------------------------------------===//
8193323Sed//
9344779Sdim// This file defines a `-dot-cfg` analysis pass, which emits the
10344779Sdim// `<prefix>.<fnname>.dot` file for each function in the program, with a graph
11344779Sdim// of the CFG for that function. The default value for `<prefix>` is `cfg` but
12344779Sdim// can be customized as needed.
13193323Sed//
14193323Sed// The other main feature of this file is that it implements the
15193323Sed// Function::viewCFG method, which is useful for debugging passes which operate
16193323Sed// on the CFG.
17193323Sed//
18193323Sed//===----------------------------------------------------------------------===//
19193323Sed
20198396Srdivacky#include "llvm/Analysis/CFGPrinter.h"
21193323Sed#include "llvm/Pass.h"
22276479Sdim#include "llvm/Support/FileSystem.h"
23193323Sedusing namespace llvm;
24193323Sed
25341825Sdimstatic cl::opt<std::string> CFGFuncName(
26341825Sdim    "cfg-func-name", cl::Hidden,
27341825Sdim    cl::desc("The name of a function (or its substring)"
28341825Sdim             " whose CFG is viewed/printed."));
29341825Sdim
30344779Sdimstatic cl::opt<std::string> CFGDotFilenamePrefix(
31344779Sdim    "cfg-dot-filename-prefix", cl::Hidden,
32344779Sdim    cl::desc("The prefix used for the CFG dot file names."));
33344779Sdim
34193323Sednamespace {
35314564Sdim  struct CFGViewerLegacyPass : public FunctionPass {
36193323Sed    static char ID; // Pass identifcation, replacement for typeid
37314564Sdim    CFGViewerLegacyPass() : FunctionPass(ID) {
38314564Sdim      initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
39218893Sdim    }
40193323Sed
41276479Sdim    bool runOnFunction(Function &F) override {
42193323Sed      F.viewCFG();
43193323Sed      return false;
44193323Sed    }
45193323Sed
46276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
47193323Sed
48276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
49193323Sed      AU.setPreservesAll();
50193323Sed    }
51193323Sed  };
52193323Sed}
53193323Sed
54314564Sdimchar CFGViewerLegacyPass::ID = 0;
55314564SdimINITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
56193323Sed
57314564SdimPreservedAnalyses CFGViewerPass::run(Function &F,
58314564Sdim                                     FunctionAnalysisManager &AM) {
59314564Sdim  F.viewCFG();
60314564Sdim  return PreservedAnalyses::all();
61314564Sdim}
62314564Sdim
63314564Sdim
64193323Sednamespace {
65314564Sdim  struct CFGOnlyViewerLegacyPass : public FunctionPass {
66193323Sed    static char ID; // Pass identifcation, replacement for typeid
67314564Sdim    CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
68314564Sdim      initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
69218893Sdim    }
70193323Sed
71276479Sdim    bool runOnFunction(Function &F) override {
72198090Srdivacky      F.viewCFGOnly();
73193323Sed      return false;
74193323Sed    }
75193323Sed
76276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
77193323Sed
78276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
79193323Sed      AU.setPreservesAll();
80193323Sed    }
81193323Sed  };
82193323Sed}
83193323Sed
84314564Sdimchar CFGOnlyViewerLegacyPass::ID = 0;
85314564SdimINITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
86218893Sdim                "View CFG of function (with no function bodies)", false, true)
87193323Sed
88314564SdimPreservedAnalyses CFGOnlyViewerPass::run(Function &F,
89314564Sdim                                         FunctionAnalysisManager &AM) {
90314564Sdim  F.viewCFGOnly();
91314564Sdim  return PreservedAnalyses::all();
92314564Sdim}
93314564Sdim
94327952Sdimstatic void writeCFGToDotFile(Function &F, bool CFGOnly = false) {
95341825Sdim  if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
96341825Sdim     return;
97344779Sdim  std::string Filename =
98344779Sdim      (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
99314564Sdim  errs() << "Writing '" << Filename << "'...";
100314564Sdim
101314564Sdim  std::error_code EC;
102314564Sdim  raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
103314564Sdim
104314564Sdim  if (!EC)
105327952Sdim    WriteGraph(File, (const Function*)&F, CFGOnly);
106314564Sdim  else
107314564Sdim    errs() << "  error opening file for writing!";
108314564Sdim  errs() << "\n";
109314564Sdim}
110314564Sdim
111193323Sednamespace {
112314564Sdim  struct CFGPrinterLegacyPass : public FunctionPass {
113193323Sed    static char ID; // Pass identification, replacement for typeid
114314564Sdim    CFGPrinterLegacyPass() : FunctionPass(ID) {
115314564Sdim      initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
116218893Sdim    }
117193323Sed
118276479Sdim    bool runOnFunction(Function &F) override {
119314564Sdim      writeCFGToDotFile(F);
120193323Sed      return false;
121193323Sed    }
122193323Sed
123276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
124193323Sed
125276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
126193323Sed      AU.setPreservesAll();
127193323Sed    }
128193323Sed  };
129193323Sed}
130193323Sed
131314564Sdimchar CFGPrinterLegacyPass::ID = 0;
132341825SdimINITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file",
133218893Sdim                false, true)
134193323Sed
135314564SdimPreservedAnalyses CFGPrinterPass::run(Function &F,
136314564Sdim                                      FunctionAnalysisManager &AM) {
137314564Sdim  writeCFGToDotFile(F);
138314564Sdim  return PreservedAnalyses::all();
139314564Sdim}
140314564Sdim
141193323Sednamespace {
142314564Sdim  struct CFGOnlyPrinterLegacyPass : public FunctionPass {
143193323Sed    static char ID; // Pass identification, replacement for typeid
144314564Sdim    CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
145314564Sdim      initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
146218893Sdim    }
147276479Sdim
148276479Sdim    bool runOnFunction(Function &F) override {
149327952Sdim      writeCFGToDotFile(F, /*CFGOnly=*/true);
150193323Sed      return false;
151193323Sed    }
152276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
153193323Sed
154276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
155193323Sed      AU.setPreservesAll();
156193323Sed    }
157193323Sed  };
158193323Sed}
159193323Sed
160314564Sdimchar CFGOnlyPrinterLegacyPass::ID = 0;
161314564SdimINITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
162212904Sdim   "Print CFG of function to 'dot' file (with no function bodies)",
163218893Sdim   false, true)
164193323Sed
165314564SdimPreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
166314564Sdim                                          FunctionAnalysisManager &AM) {
167327952Sdim  writeCFGToDotFile(F, /*CFGOnly=*/true);
168314564Sdim  return PreservedAnalyses::all();
169314564Sdim}
170314564Sdim
171193323Sed/// viewCFG - This function is meant for use from the debugger.  You can just
172193323Sed/// say 'call F->viewCFG()' and a ghostview window should pop up from the
173193323Sed/// program, displaying the CFG of the current function.  This depends on there
174193323Sed/// being a 'dot' and 'gv' program in your path.
175193323Sed///
176193323Sedvoid Function::viewCFG() const {
177341825Sdim  if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
178341825Sdim     return;
179234353Sdim  ViewGraph(this, "cfg" + getName());
180193323Sed}
181193323Sed
182193323Sed/// viewCFGOnly - This function is meant for use from the debugger.  It works
183193323Sed/// just like viewCFG, but it does not include the contents of basic blocks
184276479Sdim/// into the nodes, just the label.  If you are only interested in the CFG
185276479Sdim/// this can make the graph smaller.
186193323Sed///
187193323Sedvoid Function::viewCFGOnly() const {
188341825Sdim  if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
189341825Sdim     return;
190234353Sdim  ViewGraph(this, "cfg" + getName(), true);
191193323Sed}
192193323Sed
193314564SdimFunctionPass *llvm::createCFGPrinterLegacyPassPass () {
194314564Sdim  return new CFGPrinterLegacyPass();
195193323Sed}
196193323Sed
197314564SdimFunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
198314564Sdim  return new CFGOnlyPrinterLegacyPass();
199193323Sed}
200193323Sed
201