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.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> 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>> { 132 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. 140 virtual bool processFunction(Function &F, 141 const typename AnalysisT::Result &Result) { 142 return true; 143 } 144 145 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. 167 ~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 { 178 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: 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. 195 virtual bool processFunction(Function &F, AnalysisT &Analysis) { 196 return true; 197 } 198 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 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: 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. 234 virtual bool processFunction(Function &F, AnalysisT &Analysis) { 235 return true; 236 } 237 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 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: 264 DOTGraphTraitsModuleViewerWrapperPass(StringRef GraphName, char &ID) 265 : ModulePass(ID), Name(GraphName) {} 266 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 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: 290 DOTGraphTraitsModulePrinterWrapperPass(StringRef GraphName, char &ID) 291 : ModulePass(ID), Name(GraphName) {} 292 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 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> 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