1//===-- DOTGraphTraitsPass.h - Print/View dotty graphs-----------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Templates to create dotty viewer and printer passes for GraphTraits graphs.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
15#define LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
16
17#include "llvm/Analysis/CFGPrinter.h"
18#include "llvm/Pass.h"
19#include "llvm/Support/FileSystem.h"
20
21namespace llvm {
22
23/// \brief Default traits class for extracting a graph from an analysis pass.
24///
25/// This assumes that 'GraphT' is 'AnalysisT *' and so just passes it through.
26template <typename AnalysisT, typename GraphT = AnalysisT *>
27struct DefaultAnalysisGraphTraits {
28  static GraphT getGraph(AnalysisT *A) { return A; }
29};
30
31template <
32    typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
33    typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT, GraphT> >
34class DOTGraphTraitsViewer : public FunctionPass {
35public:
36  DOTGraphTraitsViewer(StringRef GraphName, char &ID)
37      : FunctionPass(ID), Name(GraphName) {}
38
39  /// @brief Return true if this function should be processed.
40  ///
41  /// An implementation of this class my override this function to indicate that
42  /// only certain functions should be viewed.
43  ///
44  /// @param Analysis The current analysis result for this function.
45  virtual bool processFunction(Function &F, AnalysisT &Analysis) {
46    return true;
47  }
48
49  bool runOnFunction(Function &F) override {
50    auto &Analysis = getAnalysis<AnalysisT>();
51
52    if (!processFunction(F, Analysis))
53      return false;
54
55    GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
56    std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
57    std::string Title = GraphName + " for '" + F.getName().str() + "' function";
58
59    ViewGraph(Graph, Name, IsSimple, Title);
60
61    return false;
62  }
63
64  void getAnalysisUsage(AnalysisUsage &AU) const override {
65    AU.setPreservesAll();
66    AU.addRequired<AnalysisT>();
67  }
68
69private:
70  std::string Name;
71};
72
73template <
74    typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
75    typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT, GraphT> >
76class DOTGraphTraitsPrinter : public FunctionPass {
77public:
78  DOTGraphTraitsPrinter(StringRef GraphName, char &ID)
79      : FunctionPass(ID), Name(GraphName) {}
80
81  /// @brief Return true if this function should be processed.
82  ///
83  /// An implementation of this class my override this function to indicate that
84  /// only certain functions should be printed.
85  ///
86  /// @param Analysis The current analysis result for this function.
87  virtual bool processFunction(Function &F, AnalysisT &Analysis) {
88    return true;
89  }
90
91  bool runOnFunction(Function &F) override {
92    auto &Analysis = getAnalysis<AnalysisT>();
93
94    if (!processFunction(F, Analysis))
95      return false;
96
97    GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
98    std::string Filename = Name + "." + F.getName().str() + ".dot";
99    std::error_code EC;
100
101    errs() << "Writing '" << Filename << "'...";
102
103    raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
104    std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
105    std::string Title = GraphName + " for '" + F.getName().str() + "' function";
106
107    if (!EC)
108      WriteGraph(File, Graph, IsSimple, Title);
109    else
110      errs() << "  error opening file for writing!";
111    errs() << "\n";
112
113    return false;
114  }
115
116  void getAnalysisUsage(AnalysisUsage &AU) const override {
117    AU.setPreservesAll();
118    AU.addRequired<AnalysisT>();
119  }
120
121private:
122  std::string Name;
123};
124
125template <
126    typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
127    typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT, GraphT> >
128class DOTGraphTraitsModuleViewer : public ModulePass {
129public:
130  DOTGraphTraitsModuleViewer(StringRef GraphName, char &ID)
131      : ModulePass(ID), Name(GraphName) {}
132
133  bool runOnModule(Module &M) override {
134    GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
135    std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
136
137    ViewGraph(Graph, Name, IsSimple, Title);
138
139    return false;
140  }
141
142  void getAnalysisUsage(AnalysisUsage &AU) const override {
143    AU.setPreservesAll();
144    AU.addRequired<AnalysisT>();
145  }
146
147private:
148  std::string Name;
149};
150
151template <
152    typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
153    typename AnalysisGraphTraitsT = DefaultAnalysisGraphTraits<AnalysisT, GraphT> >
154class DOTGraphTraitsModulePrinter : public ModulePass {
155public:
156  DOTGraphTraitsModulePrinter(StringRef GraphName, char &ID)
157      : ModulePass(ID), Name(GraphName) {}
158
159  bool runOnModule(Module &M) override {
160    GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
161    std::string Filename = Name + ".dot";
162    std::error_code EC;
163
164    errs() << "Writing '" << Filename << "'...";
165
166    raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
167    std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
168
169    if (!EC)
170      WriteGraph(File, Graph, IsSimple, Title);
171    else
172      errs() << "  error opening file for writing!";
173    errs() << "\n";
174
175    return false;
176  }
177
178  void getAnalysisUsage(AnalysisUsage &AU) const override {
179    AU.setPreservesAll();
180    AU.addRequired<AnalysisT>();
181  }
182
183private:
184  std::string Name;
185};
186
187} // end namespace llvm
188
189#endif
190