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