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 { 30 static GraphT getGraph(Result R) { return &R; } 31 }; 32 33 template <typename GraphT> 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>> { 49 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. 57 virtual bool processFunction(Function &F, 58 const typename AnalysisT::Result &Result) { 59 return true; 60 } 61 62 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. 83 ~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.insert(FN).second) 95 break; 96 FN.resize(--len); 97 strLen--; 98 } 99 } 100 101 template <typename GraphT> 102 void printGraphForFunction(Function &F, GraphT Graph, StringRef Name, 103 bool IsSimple) { 104 std::string Filename = Name.str() + "." + F.getName().str(); 105 shortenFileName(Filename); 106 Filename = Filename + ".dot"; 107 std::error_code EC; 108 109 errs() << "Writing '" << Filename << "'..."; 110 111 raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF); 112 std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph); 113 114 if (!EC) 115 WriteGraph(File, Graph, IsSimple, 116 GraphName + " for '" + F.getName() + "' function"); 117 else 118 errs() << " error opening file for writing!"; 119 errs() << "\n"; 120 } 121 122 template <typename AnalysisT, bool IsSimple, 123 typename GraphT = typename AnalysisT::Result *, 124 typename AnalysisGraphTraitsT = 125 DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>> 126 struct DOTGraphTraitsPrinter 127 : PassInfoMixin<DOTGraphTraitsPrinter<AnalysisT, IsSimple, GraphT, 128 AnalysisGraphTraitsT>> { 129 DOTGraphTraitsPrinter(StringRef GraphName) : Name(GraphName) {} 130 131 /// Return true if this function should be processed. 132 /// 133 /// An implementation of this class my override this function to indicate that 134 /// only certain functions should be viewed. 135 /// 136 /// @param Result The current analysis result for this function. 137 virtual bool processFunction(Function &F, 138 const typename AnalysisT::Result &Result) { 139 return true; 140 } 141 142 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) { 143 auto &Result = FAM.getResult<AnalysisT>(F); 144 if (!processFunction(F, Result)) 145 return PreservedAnalyses::all(); 146 147 GraphT Graph = AnalysisGraphTraitsT::getGraph(Result); 148 149 printGraphForFunction(F, Graph, Name, IsSimple); 150 151 return PreservedAnalyses::all(); 152 }; 153 154 protected: 155 /// Avoid compiler warning "has virtual functions but non-virtual destructor 156 /// [-Wnon-virtual-dtor]" in derived classes. 157 /// 158 /// DOTGraphTraitsPrinter is also used as a mixin for avoiding repeated 159 /// implementation of printer passes, ie there should be no 160 /// runtime-polymorphisms/downcasting involving this class and hence no 161 /// virtual destructor needed. Making this dtor protected stops accidental 162 /// invocation when the derived class destructor should have been called. 163 /// Those derived classes sould be marked final to avoid the warning. 164 ~DOTGraphTraitsPrinter() {} 165 166 private: 167 StringRef Name; 168 }; 169 170 /// Default traits class for extracting a graph from an analysis pass. 171 /// 172 /// This assumes that 'GraphT' is 'AnalysisT *' and so just passes it through. 173 template <typename AnalysisT, typename GraphT = AnalysisT *> 174 struct LegacyDefaultAnalysisGraphTraits { 175 static GraphT getGraph(AnalysisT *A) { return A; } 176 }; 177 178 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *, 179 typename AnalysisGraphTraitsT = 180 LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>> 181 class DOTGraphTraitsViewerWrapperPass : public FunctionPass { 182 public: 183 DOTGraphTraitsViewerWrapperPass(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 viewed. 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 viewGraphForFunction(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 DOTGraphTraitsPrinterWrapperPass : public FunctionPass { 221 public: 222 DOTGraphTraitsPrinterWrapperPass(StringRef GraphName, char &ID) 223 : FunctionPass(ID), Name(GraphName) {} 224 225 /// Return true if this function should be processed. 226 /// 227 /// An implementation of this class my override this function to indicate that 228 /// only certain functions should be printed. 229 /// 230 /// @param Analysis The current analysis result for this function. 231 virtual bool processFunction(Function &F, AnalysisT &Analysis) { 232 return true; 233 } 234 235 bool runOnFunction(Function &F) override { 236 auto &Analysis = getAnalysis<AnalysisT>(); 237 238 if (!processFunction(F, Analysis)) 239 return false; 240 241 GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis); 242 printGraphForFunction(F, Graph, Name, IsSimple); 243 244 return false; 245 } 246 247 void getAnalysisUsage(AnalysisUsage &AU) const override { 248 AU.setPreservesAll(); 249 AU.addRequired<AnalysisT>(); 250 } 251 252 private: 253 std::string Name; 254 }; 255 256 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *, 257 typename AnalysisGraphTraitsT = 258 LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>> 259 class DOTGraphTraitsModuleViewerWrapperPass : public ModulePass { 260 public: 261 DOTGraphTraitsModuleViewerWrapperPass(StringRef GraphName, char &ID) 262 : ModulePass(ID), Name(GraphName) {} 263 264 bool runOnModule(Module &M) override { 265 GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>()); 266 std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph); 267 268 ViewGraph(Graph, Name, IsSimple, Title); 269 270 return false; 271 } 272 273 void getAnalysisUsage(AnalysisUsage &AU) const override { 274 AU.setPreservesAll(); 275 AU.addRequired<AnalysisT>(); 276 } 277 278 private: 279 std::string Name; 280 }; 281 282 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *, 283 typename AnalysisGraphTraitsT = 284 LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>> 285 class DOTGraphTraitsModulePrinterWrapperPass : public ModulePass { 286 public: 287 DOTGraphTraitsModulePrinterWrapperPass(StringRef GraphName, char &ID) 288 : ModulePass(ID), Name(GraphName) {} 289 290 bool runOnModule(Module &M) override { 291 GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>()); 292 shortenFileName(Name); 293 std::string Filename = Name + ".dot"; 294 std::error_code EC; 295 296 errs() << "Writing '" << Filename << "'..."; 297 298 raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF); 299 std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph); 300 301 if (!EC) 302 WriteGraph(File, Graph, IsSimple, Title); 303 else 304 errs() << " error opening file for writing!"; 305 errs() << "\n"; 306 307 return false; 308 } 309 310 void getAnalysisUsage(AnalysisUsage &AU) const override { 311 AU.setPreservesAll(); 312 AU.addRequired<AnalysisT>(); 313 } 314 315 private: 316 std::string Name; 317 }; 318 319 template <typename GraphT> 320 void WriteDOTGraphToFile(Function &F, GraphT &&Graph, 321 std::string FileNamePrefix, bool IsSimple) { 322 std::string Filename = FileNamePrefix + "." + F.getName().str(); 323 shortenFileName(Filename); 324 Filename = Filename + ".dot"; 325 std::error_code EC; 326 327 errs() << "Writing '" << Filename << "'..."; 328 329 raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF); 330 std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph); 331 std::string Title = GraphName + " for '" + F.getName().str() + "' function"; 332 333 if (!EC) 334 WriteGraph(File, Graph, IsSimple, Title); 335 else 336 errs() << " error opening file for writing!"; 337 errs() << "\n"; 338 } 339 340 } // end namespace llvm 341 342 #endif 343