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