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     : PassInfoMixin<DOTGraphTraitsViewer<AnalysisT, IsSimple, GraphT,
45                                          AnalysisGraphTraitsT>> {
46   DOTGraphTraitsViewer(StringRef GraphName) : Name(GraphName) {}
47 
48   /// Return true if this function should be processed.
49   ///
50   /// An implementation of this class my override this function to indicate that
51   /// only certain functions should be viewed.
52   ///
53   /// @param Result The current analysis result for this function.
54   virtual bool processFunction(Function &F,
55                                const typename AnalysisT::Result &Result) {
56     return true;
57   }
58 
59   PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
60     auto &Result = FAM.getResult<AnalysisT>(F);
61     if (!processFunction(F, Result))
62       return PreservedAnalyses::all();
63 
64     GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
65     viewGraphForFunction(F, Graph, Name, IsSimple);
66 
67     return PreservedAnalyses::all();
68   };
69 
70 protected:
71   /// Avoid compiler warning "has virtual functions but non-virtual destructor
72   /// [-Wnon-virtual-dtor]" in derived classes.
73   ///
74   /// DOTGraphTraitsViewer is also used as a mixin for avoiding repeated
75   /// implementation of viewer passes, ie there should be no
76   /// runtime-polymorphisms/downcasting involving this class and hence no
77   /// virtual destructor needed. Making this dtor protected stops accidental
78   /// invocation when the derived class destructor should have been called.
79   /// Those derived classes sould be marked final to avoid the warning.
80   ~DOTGraphTraitsViewer() {}
81 
82 private:
83   StringRef Name;
84 };
85 
86 template <typename GraphT>
87 void printGraphForFunction(Function &F, GraphT Graph, StringRef Name,
88                            bool IsSimple) {
89   std::string Filename = Name.str() + "." + F.getName().str() + ".dot";
90   std::error_code EC;
91 
92   errs() << "Writing '" << Filename << "'...";
93 
94   raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
95   std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
96 
97   if (!EC)
98     WriteGraph(File, Graph, IsSimple,
99                GraphName + " for '" + F.getName() + "' function");
100   else
101     errs() << "  error opening file for writing!";
102   errs() << "\n";
103 }
104 
105 template <typename AnalysisT, bool IsSimple,
106           typename GraphT = typename AnalysisT::Result *,
107           typename AnalysisGraphTraitsT =
108               DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>>
109 struct DOTGraphTraitsPrinter
110     : PassInfoMixin<DOTGraphTraitsPrinter<AnalysisT, IsSimple, GraphT,
111                                           AnalysisGraphTraitsT>> {
112   DOTGraphTraitsPrinter(StringRef GraphName) : Name(GraphName) {}
113 
114   /// Return true if this function should be processed.
115   ///
116   /// An implementation of this class my override this function to indicate that
117   /// only certain functions should be viewed.
118   ///
119   /// @param Analysis The current analysis result for this function.
120   virtual bool processFunction(Function &F,
121                                const typename AnalysisT::Result &Result) {
122     return true;
123   }
124 
125   PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
126     auto &Result = FAM.getResult<AnalysisT>(F);
127     if (!processFunction(F, Result))
128       return PreservedAnalyses::all();
129 
130     GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
131 
132     printGraphForFunction(F, Graph, Name, IsSimple);
133 
134     return PreservedAnalyses::all();
135   };
136 
137 protected:
138   /// Avoid compiler warning "has virtual functions but non-virtual destructor
139   /// [-Wnon-virtual-dtor]" in derived classes.
140   ///
141   /// DOTGraphTraitsPrinter is also used as a mixin for avoiding repeated
142   /// implementation of printer passes, ie there should be no
143   /// runtime-polymorphisms/downcasting involving this class and hence no
144   /// virtual destructor needed. Making this dtor protected stops accidental
145   /// invocation when the derived class destructor should have been called.
146   /// Those derived classes sould be marked final to avoid the warning.
147   ~DOTGraphTraitsPrinter() {}
148 
149 private:
150   StringRef Name;
151 };
152 
153 /// Default traits class for extracting a graph from an analysis pass.
154 ///
155 /// This assumes that 'GraphT' is 'AnalysisT *' and so just passes it through.
156 template <typename AnalysisT, typename GraphT = AnalysisT *>
157 struct LegacyDefaultAnalysisGraphTraits {
158   static GraphT getGraph(AnalysisT *A) { return A; }
159 };
160 
161 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
162           typename AnalysisGraphTraitsT =
163               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
164 class DOTGraphTraitsViewerWrapperPass : public FunctionPass {
165 public:
166   DOTGraphTraitsViewerWrapperPass(StringRef GraphName, char &ID)
167       : FunctionPass(ID), Name(GraphName) {}
168 
169   /// Return true if this function should be processed.
170   ///
171   /// An implementation of this class my override this function to indicate that
172   /// only certain functions should be viewed.
173   ///
174   /// @param Analysis The current analysis result for this function.
175   virtual bool processFunction(Function &F, AnalysisT &Analysis) {
176     return true;
177   }
178 
179   bool runOnFunction(Function &F) override {
180     auto &Analysis = getAnalysis<AnalysisT>();
181 
182     if (!processFunction(F, Analysis))
183       return false;
184 
185     GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
186     viewGraphForFunction(F, Graph, Name, IsSimple);
187 
188     return false;
189   }
190 
191   void getAnalysisUsage(AnalysisUsage &AU) const override {
192     AU.setPreservesAll();
193     AU.addRequired<AnalysisT>();
194   }
195 
196 private:
197   std::string Name;
198 };
199 
200 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
201           typename AnalysisGraphTraitsT =
202               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
203 class DOTGraphTraitsPrinterWrapperPass : public FunctionPass {
204 public:
205   DOTGraphTraitsPrinterWrapperPass(StringRef GraphName, char &ID)
206       : FunctionPass(ID), Name(GraphName) {}
207 
208   /// Return true if this function should be processed.
209   ///
210   /// An implementation of this class my override this function to indicate that
211   /// only certain functions should be printed.
212   ///
213   /// @param Analysis The current analysis result for this function.
214   virtual bool processFunction(Function &F, AnalysisT &Analysis) {
215     return true;
216   }
217 
218   bool runOnFunction(Function &F) override {
219     auto &Analysis = getAnalysis<AnalysisT>();
220 
221     if (!processFunction(F, Analysis))
222       return false;
223 
224     GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
225     printGraphForFunction(F, Graph, Name, IsSimple);
226 
227     return false;
228   }
229 
230   void getAnalysisUsage(AnalysisUsage &AU) const override {
231     AU.setPreservesAll();
232     AU.addRequired<AnalysisT>();
233   }
234 
235 private:
236   std::string Name;
237 };
238 
239 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
240           typename AnalysisGraphTraitsT =
241               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
242 class DOTGraphTraitsModuleViewerWrapperPass : public ModulePass {
243 public:
244   DOTGraphTraitsModuleViewerWrapperPass(StringRef GraphName, char &ID)
245       : ModulePass(ID), Name(GraphName) {}
246 
247   bool runOnModule(Module &M) override {
248     GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
249     std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
250 
251     ViewGraph(Graph, Name, IsSimple, Title);
252 
253     return false;
254   }
255 
256   void getAnalysisUsage(AnalysisUsage &AU) const override {
257     AU.setPreservesAll();
258     AU.addRequired<AnalysisT>();
259   }
260 
261 private:
262   std::string Name;
263 };
264 
265 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
266           typename AnalysisGraphTraitsT =
267               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
268 class DOTGraphTraitsModulePrinterWrapperPass : public ModulePass {
269 public:
270   DOTGraphTraitsModulePrinterWrapperPass(StringRef GraphName, char &ID)
271       : ModulePass(ID), Name(GraphName) {}
272 
273   bool runOnModule(Module &M) override {
274     GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
275     std::string Filename = Name + ".dot";
276     std::error_code EC;
277 
278     errs() << "Writing '" << Filename << "'...";
279 
280     raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
281     std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
282 
283     if (!EC)
284       WriteGraph(File, Graph, IsSimple, Title);
285     else
286       errs() << "  error opening file for writing!";
287     errs() << "\n";
288 
289     return false;
290   }
291 
292   void getAnalysisUsage(AnalysisUsage &AU) const override {
293     AU.setPreservesAll();
294     AU.addRequired<AnalysisT>();
295   }
296 
297 private:
298   std::string Name;
299 };
300 
301 template <typename GraphT>
302 void WriteDOTGraphToFile(Function &F, GraphT &&Graph,
303                          std::string FileNamePrefix, bool IsSimple) {
304   std::string Filename = FileNamePrefix + "." + F.getName().str() + ".dot";
305   std::error_code EC;
306 
307   errs() << "Writing '" << Filename << "'...";
308 
309   raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
310   std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
311   std::string Title = GraphName + " for '" + F.getName().str() + "' function";
312 
313   if (!EC)
314     WriteGraph(File, Graph, IsSimple, Title);
315   else
316     errs() << "  error opening file for writing!";
317   errs() << "\n";
318 }
319 
320 } // end namespace llvm
321 
322 #endif
323