1 //===-- DOTGraphTraitsPass.h - Print/View dotty graphs-----------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Templates to create dotty viewer and printer passes for GraphTraits graphs.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
14 #define LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
15 
16 #include "llvm/Analysis/CFGPrinter.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/GraphWriter.h"
19 
20 namespace llvm {
21 
22 /// Default traits class for extracting a graph from an analysis pass.
23 ///
24 /// This assumes that 'GraphT' is 'AnalysisT::Result *', and pass it through
25 template <typename Result, typename GraphT = Result *>
26 struct DefaultAnalysisGraphTraits {
27   static GraphT getGraph(Result R) { return &R; }
28 };
29 
30 template <typename GraphT>
31 void viewGraphForFunction(Function &F, GraphT Graph, StringRef Name,
32                           bool IsSimple) {
33   std::string GraphName = DOTGraphTraits<GraphT *>::getGraphName(&Graph);
34 
35   ViewGraph(Graph, Name, IsSimple,
36             GraphName + " for '" + F.getName() + "' function");
37 }
38 
39 template <typename AnalysisT, bool IsSimple,
40           typename GraphT = typename AnalysisT::Result *,
41           typename AnalysisGraphTraitsT =
42               DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>>
43 struct DOTGraphTraitsViewer
44     : public PassInfoMixin<DOTGraphTraitsViewer<AnalysisT, IsSimple, GraphT,
45                                                 AnalysisGraphTraitsT>> {
46   DOTGraphTraitsViewer(StringRef GraphName) : Name(GraphName) {}
47   virtual ~DOTGraphTraitsViewer() {}
48 
49   /// Return true if this function should be processed.
50   ///
51   /// An implementation of this class my override this function to indicate that
52   /// only certain functions should be viewed.
53   ///
54   /// @param Result The current analysis result for this function.
55   virtual bool processFunction(Function &F,
56                                const typename AnalysisT::Result &Result) {
57     return true;
58   }
59 
60   PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
61     auto &Result = FAM.getResult<AnalysisT>(F);
62     if (!processFunction(F, Result))
63       return PreservedAnalyses::all();
64 
65     GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
66     viewGraphForFunction(F, Graph, Name, IsSimple);
67 
68     return PreservedAnalyses::all();
69   };
70 
71 private:
72   StringRef Name;
73 };
74 
75 template <typename GraphT>
76 void printGraphForFunction(Function &F, GraphT Graph, StringRef Name,
77                            bool IsSimple) {
78   std::string Filename = Name.str() + "." + F.getName().str() + ".dot";
79   std::error_code EC;
80 
81   errs() << "Writing '" << Filename << "'...";
82 
83   raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
84   std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
85 
86   if (!EC)
87     WriteGraph(File, Graph, IsSimple,
88                GraphName + " for '" + F.getName() + "' function");
89   else
90     errs() << "  error opening file for writing!";
91   errs() << "\n";
92 }
93 
94 template <typename AnalysisT, bool IsSimple,
95           typename GraphT = typename AnalysisT::Result *,
96           typename AnalysisGraphTraitsT =
97               DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>>
98 struct DOTGraphTraitsPrinter
99     : public PassInfoMixin<DOTGraphTraitsPrinter<AnalysisT, IsSimple, GraphT,
100                                                  AnalysisGraphTraitsT>> {
101   DOTGraphTraitsPrinter(StringRef GraphName) : Name(GraphName) {}
102   virtual ~DOTGraphTraitsPrinter() {}
103 
104   /// Return true if this function should be processed.
105   ///
106   /// An implementation of this class my override this function to indicate that
107   /// only certain functions should be viewed.
108   ///
109   /// @param Analysis The current analysis result for this function.
110   virtual bool processFunction(Function &F,
111                                const typename AnalysisT::Result &Result) {
112     return true;
113   }
114 
115   PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
116     auto &Result = FAM.getResult<AnalysisT>(F);
117     if (!processFunction(F, Result))
118       return PreservedAnalyses::all();
119 
120     GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
121 
122     printGraphForFunction(F, Graph, Name, IsSimple);
123 
124     return PreservedAnalyses::all();
125   };
126 
127 private:
128   StringRef Name;
129 };
130 
131 /// Default traits class for extracting a graph from an analysis pass.
132 ///
133 /// This assumes that 'GraphT' is 'AnalysisT *' and so just passes it through.
134 template <typename AnalysisT, typename GraphT = AnalysisT *>
135 struct LegacyDefaultAnalysisGraphTraits {
136   static GraphT getGraph(AnalysisT *A) { return A; }
137 };
138 
139 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
140           typename AnalysisGraphTraitsT =
141               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
142 class DOTGraphTraitsViewerWrapperPass : public FunctionPass {
143 public:
144   DOTGraphTraitsViewerWrapperPass(StringRef GraphName, char &ID)
145       : FunctionPass(ID), Name(GraphName) {}
146 
147   /// Return true if this function should be processed.
148   ///
149   /// An implementation of this class my override this function to indicate that
150   /// only certain functions should be viewed.
151   ///
152   /// @param Analysis The current analysis result for this function.
153   virtual bool processFunction(Function &F, AnalysisT &Analysis) {
154     return true;
155   }
156 
157   bool runOnFunction(Function &F) override {
158     auto &Analysis = getAnalysis<AnalysisT>();
159 
160     if (!processFunction(F, Analysis))
161       return false;
162 
163     GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
164     viewGraphForFunction(F, Graph, Name, IsSimple);
165 
166     return false;
167   }
168 
169   void getAnalysisUsage(AnalysisUsage &AU) const override {
170     AU.setPreservesAll();
171     AU.addRequired<AnalysisT>();
172   }
173 
174 private:
175   std::string Name;
176 };
177 
178 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
179           typename AnalysisGraphTraitsT =
180               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
181 class DOTGraphTraitsPrinterWrapperPass : public FunctionPass {
182 public:
183   DOTGraphTraitsPrinterWrapperPass(StringRef GraphName, char &ID)
184       : FunctionPass(ID), Name(GraphName) {}
185 
186   /// Return true if this function should be processed.
187   ///
188   /// An implementation of this class my override this function to indicate that
189   /// only certain functions should be printed.
190   ///
191   /// @param Analysis The current analysis result for this function.
192   virtual bool processFunction(Function &F, AnalysisT &Analysis) {
193     return true;
194   }
195 
196   bool runOnFunction(Function &F) override {
197     auto &Analysis = getAnalysis<AnalysisT>();
198 
199     if (!processFunction(F, Analysis))
200       return false;
201 
202     GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
203     printGraphForFunction(F, Graph, Name, IsSimple);
204 
205     return false;
206   }
207 
208   void getAnalysisUsage(AnalysisUsage &AU) const override {
209     AU.setPreservesAll();
210     AU.addRequired<AnalysisT>();
211   }
212 
213 private:
214   std::string Name;
215 };
216 
217 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
218           typename AnalysisGraphTraitsT =
219               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
220 class DOTGraphTraitsModuleViewerWrapperPass : public ModulePass {
221 public:
222   DOTGraphTraitsModuleViewerWrapperPass(StringRef GraphName, char &ID)
223       : ModulePass(ID), Name(GraphName) {}
224 
225   bool runOnModule(Module &M) override {
226     GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
227     std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
228 
229     ViewGraph(Graph, Name, IsSimple, Title);
230 
231     return false;
232   }
233 
234   void getAnalysisUsage(AnalysisUsage &AU) const override {
235     AU.setPreservesAll();
236     AU.addRequired<AnalysisT>();
237   }
238 
239 private:
240   std::string Name;
241 };
242 
243 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
244           typename AnalysisGraphTraitsT =
245               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
246 class DOTGraphTraitsModulePrinterWrapperPass : public ModulePass {
247 public:
248   DOTGraphTraitsModulePrinterWrapperPass(StringRef GraphName, char &ID)
249       : ModulePass(ID), Name(GraphName) {}
250 
251   bool runOnModule(Module &M) override {
252     GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
253     std::string Filename = Name + ".dot";
254     std::error_code EC;
255 
256     errs() << "Writing '" << Filename << "'...";
257 
258     raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
259     std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
260 
261     if (!EC)
262       WriteGraph(File, Graph, IsSimple, Title);
263     else
264       errs() << "  error opening file for writing!";
265     errs() << "\n";
266 
267     return false;
268   }
269 
270   void getAnalysisUsage(AnalysisUsage &AU) const override {
271     AU.setPreservesAll();
272     AU.addRequired<AnalysisT>();
273   }
274 
275 private:
276   std::string Name;
277 };
278 
279 template <typename GraphT>
280 void WriteDOTGraphToFile(Function &F, GraphT &&Graph,
281                          std::string FileNamePrefix, bool IsSimple) {
282   std::string Filename = FileNamePrefix + "." + F.getName().str() + ".dot";
283   std::error_code EC;
284 
285   errs() << "Writing '" << Filename << "'...";
286 
287   raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
288   std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
289   std::string Title = GraphName + " for '" + F.getName().str() + "' function";
290 
291   if (!EC)
292     WriteGraph(File, Graph, IsSimple, Title);
293   else
294     errs() << "  error opening file for writing!";
295   errs() << "\n";
296 }
297 
298 } // end namespace llvm
299 
300 #endif
301