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