Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:12

0001 //===-- DOTGraphTraitsPass.h - Print/View dotty graphs-----------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Templates to create dotty viewer and printer passes for GraphTraits graphs.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
0014 #define LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
0015 
0016 #include "llvm/Analysis/CFGPrinter.h"
0017 #include "llvm/Support/FileSystem.h"
0018 #include "llvm/Support/GraphWriter.h"
0019 #include <unordered_set>
0020 
0021 static std::unordered_set<std::string> nameObj;
0022 
0023 namespace llvm {
0024 
0025 /// Default traits class for extracting a graph from an analysis pass.
0026 ///
0027 /// This assumes that 'GraphT' is 'AnalysisT::Result *', and pass it through
0028 template <typename Result, typename GraphT = Result *>
0029 struct DefaultAnalysisGraphTraits {
0030   static GraphT getGraph(Result R) { return &R; }
0031 };
0032 
0033 template <typename GraphT>
0034 void viewGraphForFunction(Function &F, GraphT Graph, StringRef Name,
0035                           bool IsSimple) {
0036   std::string GraphName = DOTGraphTraits<GraphT *>::getGraphName(&Graph);
0037 
0038   ViewGraph(Graph, Name, IsSimple,
0039             GraphName + " for '" + F.getName() + "' function");
0040 }
0041 
0042 template <typename AnalysisT, bool IsSimple,
0043           typename GraphT = typename AnalysisT::Result *,
0044           typename AnalysisGraphTraitsT =
0045               DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>>
0046 struct DOTGraphTraitsViewer
0047     : PassInfoMixin<DOTGraphTraitsViewer<AnalysisT, IsSimple, GraphT,
0048                                          AnalysisGraphTraitsT>> {
0049   DOTGraphTraitsViewer(StringRef GraphName) : Name(GraphName) {}
0050 
0051   /// Return true if this function should be processed.
0052   ///
0053   /// An implementation of this class my override this function to indicate that
0054   /// only certain functions should be viewed.
0055   ///
0056   /// @param Result The current analysis result for this function.
0057   virtual bool processFunction(Function &F,
0058                                const typename AnalysisT::Result &Result) {
0059     return true;
0060   }
0061 
0062   PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
0063     auto &Result = FAM.getResult<AnalysisT>(F);
0064     if (!processFunction(F, Result))
0065       return PreservedAnalyses::all();
0066 
0067     GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
0068     viewGraphForFunction(F, Graph, Name, IsSimple);
0069 
0070     return PreservedAnalyses::all();
0071   };
0072 
0073 protected:
0074   /// Avoid compiler warning "has virtual functions but non-virtual destructor
0075   /// [-Wnon-virtual-dtor]" in derived classes.
0076   ///
0077   /// DOTGraphTraitsViewer is also used as a mixin for avoiding repeated
0078   /// implementation of viewer passes, ie there should be no
0079   /// runtime-polymorphisms/downcasting involving this class and hence no
0080   /// virtual destructor needed. Making this dtor protected stops accidental
0081   /// invocation when the derived class destructor should have been called.
0082   /// Those derived classes sould be marked final to avoid the warning.
0083   ~DOTGraphTraitsViewer() {}
0084 
0085 private:
0086   StringRef Name;
0087 };
0088 
0089 static inline void shortenFileName(std::string &FN, unsigned char len = 250) {
0090   if (FN.length() > len)
0091     FN.resize(len);
0092   auto strLen = FN.length();
0093   while (strLen > 0) {
0094     if (nameObj.insert(FN).second)
0095       break;
0096     FN.resize(--len);
0097     strLen--;
0098   }
0099 }
0100 
0101 template <typename GraphT>
0102 void printGraphForFunction(Function &F, GraphT Graph, StringRef Name,
0103                            bool IsSimple) {
0104   std::string Filename = Name.str() + "." + F.getName().str();
0105   shortenFileName(Filename);
0106   Filename = Filename + ".dot";
0107   std::error_code EC;
0108 
0109   errs() << "Writing '" << Filename << "'...";
0110 
0111   raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
0112   std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
0113 
0114   if (!EC)
0115     WriteGraph(File, Graph, IsSimple,
0116                GraphName + " for '" + F.getName() + "' function");
0117   else
0118     errs() << "  error opening file for writing!";
0119   errs() << "\n";
0120 }
0121 
0122 template <typename AnalysisT, bool IsSimple,
0123           typename GraphT = typename AnalysisT::Result *,
0124           typename AnalysisGraphTraitsT =
0125               DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>>
0126 struct DOTGraphTraitsPrinter
0127     : PassInfoMixin<DOTGraphTraitsPrinter<AnalysisT, IsSimple, GraphT,
0128                                           AnalysisGraphTraitsT>> {
0129   DOTGraphTraitsPrinter(StringRef GraphName) : Name(GraphName) {}
0130 
0131   /// Return true if this function should be processed.
0132   ///
0133   /// An implementation of this class my override this function to indicate that
0134   /// only certain functions should be viewed.
0135   ///
0136   /// @param Result The current analysis result for this function.
0137   virtual bool processFunction(Function &F,
0138                                const typename AnalysisT::Result &Result) {
0139     return true;
0140   }
0141 
0142   PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
0143     auto &Result = FAM.getResult<AnalysisT>(F);
0144     if (!processFunction(F, Result))
0145       return PreservedAnalyses::all();
0146 
0147     GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
0148 
0149     printGraphForFunction(F, Graph, Name, IsSimple);
0150 
0151     return PreservedAnalyses::all();
0152   };
0153 
0154 protected:
0155   /// Avoid compiler warning "has virtual functions but non-virtual destructor
0156   /// [-Wnon-virtual-dtor]" in derived classes.
0157   ///
0158   /// DOTGraphTraitsPrinter is also used as a mixin for avoiding repeated
0159   /// implementation of printer passes, ie there should be no
0160   /// runtime-polymorphisms/downcasting involving this class and hence no
0161   /// virtual destructor needed. Making this dtor protected stops accidental
0162   /// invocation when the derived class destructor should have been called.
0163   /// Those derived classes sould be marked final to avoid the warning.
0164   ~DOTGraphTraitsPrinter() {}
0165 
0166 private:
0167   StringRef Name;
0168 };
0169 
0170 /// Default traits class for extracting a graph from an analysis pass.
0171 ///
0172 /// This assumes that 'GraphT' is 'AnalysisT *' and so just passes it through.
0173 template <typename AnalysisT, typename GraphT = AnalysisT *>
0174 struct LegacyDefaultAnalysisGraphTraits {
0175   static GraphT getGraph(AnalysisT *A) { return A; }
0176 };
0177 
0178 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
0179           typename AnalysisGraphTraitsT =
0180               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
0181 class DOTGraphTraitsViewerWrapperPass : public FunctionPass {
0182 public:
0183   DOTGraphTraitsViewerWrapperPass(StringRef GraphName, char &ID)
0184       : FunctionPass(ID), Name(GraphName) {}
0185 
0186   /// Return true if this function should be processed.
0187   ///
0188   /// An implementation of this class my override this function to indicate that
0189   /// only certain functions should be viewed.
0190   ///
0191   /// @param Analysis The current analysis result for this function.
0192   virtual bool processFunction(Function &F, AnalysisT &Analysis) {
0193     return true;
0194   }
0195 
0196   bool runOnFunction(Function &F) override {
0197     auto &Analysis = getAnalysis<AnalysisT>();
0198 
0199     if (!processFunction(F, Analysis))
0200       return false;
0201 
0202     GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
0203     viewGraphForFunction(F, Graph, Name, IsSimple);
0204 
0205     return false;
0206   }
0207 
0208   void getAnalysisUsage(AnalysisUsage &AU) const override {
0209     AU.setPreservesAll();
0210     AU.addRequired<AnalysisT>();
0211   }
0212 
0213 private:
0214   std::string Name;
0215 };
0216 
0217 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
0218           typename AnalysisGraphTraitsT =
0219               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
0220 class DOTGraphTraitsPrinterWrapperPass : public FunctionPass {
0221 public:
0222   DOTGraphTraitsPrinterWrapperPass(StringRef GraphName, char &ID)
0223       : FunctionPass(ID), Name(GraphName) {}
0224 
0225   /// Return true if this function should be processed.
0226   ///
0227   /// An implementation of this class my override this function to indicate that
0228   /// only certain functions should be printed.
0229   ///
0230   /// @param Analysis The current analysis result for this function.
0231   virtual bool processFunction(Function &F, AnalysisT &Analysis) {
0232     return true;
0233   }
0234 
0235   bool runOnFunction(Function &F) override {
0236     auto &Analysis = getAnalysis<AnalysisT>();
0237 
0238     if (!processFunction(F, Analysis))
0239       return false;
0240 
0241     GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
0242     printGraphForFunction(F, Graph, Name, IsSimple);
0243 
0244     return false;
0245   }
0246 
0247   void getAnalysisUsage(AnalysisUsage &AU) const override {
0248     AU.setPreservesAll();
0249     AU.addRequired<AnalysisT>();
0250   }
0251 
0252 private:
0253   std::string Name;
0254 };
0255 
0256 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
0257           typename AnalysisGraphTraitsT =
0258               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
0259 class DOTGraphTraitsModuleViewerWrapperPass : public ModulePass {
0260 public:
0261   DOTGraphTraitsModuleViewerWrapperPass(StringRef GraphName, char &ID)
0262       : ModulePass(ID), Name(GraphName) {}
0263 
0264   bool runOnModule(Module &M) override {
0265     GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
0266     std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
0267 
0268     ViewGraph(Graph, Name, IsSimple, Title);
0269 
0270     return false;
0271   }
0272 
0273   void getAnalysisUsage(AnalysisUsage &AU) const override {
0274     AU.setPreservesAll();
0275     AU.addRequired<AnalysisT>();
0276   }
0277 
0278 private:
0279   std::string Name;
0280 };
0281 
0282 template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
0283           typename AnalysisGraphTraitsT =
0284               LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
0285 class DOTGraphTraitsModulePrinterWrapperPass : public ModulePass {
0286 public:
0287   DOTGraphTraitsModulePrinterWrapperPass(StringRef GraphName, char &ID)
0288       : ModulePass(ID), Name(GraphName) {}
0289 
0290   bool runOnModule(Module &M) override {
0291     GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
0292     shortenFileName(Name);
0293     std::string Filename = Name + ".dot";
0294     std::error_code EC;
0295 
0296     errs() << "Writing '" << Filename << "'...";
0297 
0298     raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
0299     std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
0300 
0301     if (!EC)
0302       WriteGraph(File, Graph, IsSimple, Title);
0303     else
0304       errs() << "  error opening file for writing!";
0305     errs() << "\n";
0306 
0307     return false;
0308   }
0309 
0310   void getAnalysisUsage(AnalysisUsage &AU) const override {
0311     AU.setPreservesAll();
0312     AU.addRequired<AnalysisT>();
0313   }
0314 
0315 private:
0316   std::string Name;
0317 };
0318 
0319 template <typename GraphT>
0320 void WriteDOTGraphToFile(Function &F, GraphT &&Graph,
0321                          std::string FileNamePrefix, bool IsSimple) {
0322   std::string Filename = FileNamePrefix + "." + F.getName().str();
0323   shortenFileName(Filename);
0324   Filename = Filename + ".dot";
0325   std::error_code EC;
0326 
0327   errs() << "Writing '" << Filename << "'...";
0328 
0329   raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
0330   std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
0331   std::string Title = GraphName + " for '" + F.getName().str() + "' function";
0332 
0333   if (!EC)
0334     WriteGraph(File, Graph, IsSimple, Title);
0335   else
0336     errs() << "  error opening file for writing!";
0337   errs() << "\n";
0338 }
0339 
0340 } // end namespace llvm
0341 
0342 #endif