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"
21360784Sdim#include "llvm/InitializePasses.h"
22193323Sed#include "llvm/Pass.h"
23360784Sdim#include "llvm/Support/CommandLine.h"
24276479Sdim#include "llvm/Support/FileSystem.h"
25193323Sedusing namespace llvm;
26193323Sed
27341825Sdimstatic cl::opt<std::string> CFGFuncName(
28341825Sdim    "cfg-func-name", cl::Hidden,
29341825Sdim    cl::desc("The name of a function (or its substring)"
30341825Sdim             " whose CFG is viewed/printed."));
31341825Sdim
32344779Sdimstatic cl::opt<std::string> CFGDotFilenamePrefix(
33344779Sdim    "cfg-dot-filename-prefix", cl::Hidden,
34344779Sdim    cl::desc("The prefix used for the CFG dot file names."));
35344779Sdim
36193323Sednamespace {
37314564Sdim  struct CFGViewerLegacyPass : public FunctionPass {
38193323Sed    static char ID; // Pass identifcation, replacement for typeid
39314564Sdim    CFGViewerLegacyPass() : FunctionPass(ID) {
40314564Sdim      initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
41218893Sdim    }
42193323Sed
43276479Sdim    bool runOnFunction(Function &F) override {
44193323Sed      F.viewCFG();
45193323Sed      return false;
46193323Sed    }
47193323Sed
48276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
49193323Sed
50276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
51193323Sed      AU.setPreservesAll();
52193323Sed    }
53193323Sed  };
54193323Sed}
55193323Sed
56314564Sdimchar CFGViewerLegacyPass::ID = 0;
57314564SdimINITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
58193323Sed
59314564SdimPreservedAnalyses CFGViewerPass::run(Function &F,
60314564Sdim                                     FunctionAnalysisManager &AM) {
61314564Sdim  F.viewCFG();
62314564Sdim  return PreservedAnalyses::all();
63314564Sdim}
64314564Sdim
65314564Sdim
66193323Sednamespace {
67314564Sdim  struct CFGOnlyViewerLegacyPass : public FunctionPass {
68193323Sed    static char ID; // Pass identifcation, replacement for typeid
69314564Sdim    CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
70314564Sdim      initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
71218893Sdim    }
72193323Sed
73276479Sdim    bool runOnFunction(Function &F) override {
74198090Srdivacky      F.viewCFGOnly();
75193323Sed      return false;
76193323Sed    }
77193323Sed
78276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
79193323Sed
80276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
81193323Sed      AU.setPreservesAll();
82193323Sed    }
83193323Sed  };
84193323Sed}
85193323Sed
86314564Sdimchar CFGOnlyViewerLegacyPass::ID = 0;
87314564SdimINITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
88218893Sdim                "View CFG of function (with no function bodies)", false, true)
89193323Sed
90314564SdimPreservedAnalyses CFGOnlyViewerPass::run(Function &F,
91314564Sdim                                         FunctionAnalysisManager &AM) {
92314564Sdim  F.viewCFGOnly();
93314564Sdim  return PreservedAnalyses::all();
94314564Sdim}
95314564Sdim
96327952Sdimstatic void writeCFGToDotFile(Function &F, bool CFGOnly = false) {
97341825Sdim  if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))
98341825Sdim     return;
99344779Sdim  std::string Filename =
100344779Sdim      (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
101314564Sdim  errs() << "Writing '" << Filename << "'...";
102314564Sdim
103314564Sdim  std::error_code EC;
104360784Sdim  raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
105314564Sdim
106314564Sdim  if (!EC)
107327952Sdim    WriteGraph(File, (const Function*)&F, CFGOnly);
108314564Sdim  else
109314564Sdim    errs() << "  error opening file for writing!";
110314564Sdim  errs() << "\n";
111314564Sdim}
112314564Sdim
113193323Sednamespace {
114314564Sdim  struct CFGPrinterLegacyPass : public FunctionPass {
115193323Sed    static char ID; // Pass identification, replacement for typeid
116314564Sdim    CFGPrinterLegacyPass() : FunctionPass(ID) {
117314564Sdim      initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
118218893Sdim    }
119193323Sed
120276479Sdim    bool runOnFunction(Function &F) override {
121314564Sdim      writeCFGToDotFile(F);
122193323Sed      return false;
123193323Sed    }
124193323Sed
125276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
126193323Sed
127276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
128193323Sed      AU.setPreservesAll();
129193323Sed    }
130193323Sed  };
131193323Sed}
132193323Sed
133314564Sdimchar CFGPrinterLegacyPass::ID = 0;
134341825SdimINITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file",
135218893Sdim                false, true)
136193323Sed
137314564SdimPreservedAnalyses CFGPrinterPass::run(Function &F,
138314564Sdim                                      FunctionAnalysisManager &AM) {
139314564Sdim  writeCFGToDotFile(F);
140314564Sdim  return PreservedAnalyses::all();
141314564Sdim}
142314564Sdim
143193323Sednamespace {
144314564Sdim  struct CFGOnlyPrinterLegacyPass : public FunctionPass {
145193323Sed    static char ID; // Pass identification, replacement for typeid
146314564Sdim    CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
147314564Sdim      initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
148218893Sdim    }
149276479Sdim
150276479Sdim    bool runOnFunction(Function &F) override {
151327952Sdim      writeCFGToDotFile(F, /*CFGOnly=*/true);
152193323Sed      return false;
153193323Sed    }
154276479Sdim    void print(raw_ostream &OS, const Module* = nullptr) const override {}
155193323Sed
156276479Sdim    void getAnalysisUsage(AnalysisUsage &AU) const override {
157193323Sed      AU.setPreservesAll();
158193323Sed    }
159193323Sed  };
160193323Sed}
161193323Sed
162314564Sdimchar CFGOnlyPrinterLegacyPass::ID = 0;
163314564SdimINITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
164212904Sdim   "Print CFG of function to 'dot' file (with no function bodies)",
165218893Sdim   false, true)
166193323Sed
167314564SdimPreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
168314564Sdim                                          FunctionAnalysisManager &AM) {
169327952Sdim  writeCFGToDotFile(F, /*CFGOnly=*/true);
170314564Sdim  return PreservedAnalyses::all();
171314564Sdim}
172314564Sdim
173193323Sed/// viewCFG - This function is meant for use from the debugger.  You can just
174193323Sed/// say 'call F->viewCFG()' and a ghostview window should pop up from the
175193323Sed/// program, displaying the CFG of the current function.  This depends on there
176193323Sed/// being a 'dot' and 'gv' program in your path.
177193323Sed///
178193323Sedvoid Function::viewCFG() const {
179341825Sdim  if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
180341825Sdim     return;
181234353Sdim  ViewGraph(this, "cfg" + getName());
182193323Sed}
183193323Sed
184193323Sed/// viewCFGOnly - This function is meant for use from the debugger.  It works
185193323Sed/// just like viewCFG, but it does not include the contents of basic blocks
186276479Sdim/// into the nodes, just the label.  If you are only interested in the CFG
187276479Sdim/// this can make the graph smaller.
188193323Sed///
189193323Sedvoid Function::viewCFGOnly() const {
190341825Sdim  if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
191341825Sdim     return;
192234353Sdim  ViewGraph(this, "cfg" + getName(), true);
193193323Sed}
194193323Sed
195314564SdimFunctionPass *llvm::createCFGPrinterLegacyPassPass () {
196314564Sdim  return new CFGPrinterLegacyPass();
197193323Sed}
198193323Sed
199314564SdimFunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
200314564Sdim  return new CFGOnlyPrinterLegacyPass();
201193323Sed}
202193323Sed
203