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