Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===- llvm/Support/GraphWriter.h - Write graph to a .dot file --*- 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. // This file defines a simple interface that can be used to print out generic
  10. // LLVM graphs to ".dot" files.  "dot" is a tool that is part of the AT&T
  11. // graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
  12. // be used to turn the files output by this interface into a variety of
  13. // different graphics formats.
  14. //
  15. // Graphs do not need to implement any interface past what is already required
  16. // by the GraphTraits template, but they can choose to implement specializations
  17. // of the DOTGraphTraits template if they want to customize the graphs output in
  18. // any way.
  19. //
  20. //===----------------------------------------------------------------------===//
  21.  
  22. #ifndef LLVM_SUPPORT_GRAPHWRITER_H
  23. #define LLVM_SUPPORT_GRAPHWRITER_H
  24.  
  25. #include "llvm/ADT/GraphTraits.h"
  26. #include "llvm/ADT/StringRef.h"
  27. #include "llvm/ADT/Twine.h"
  28. #include "llvm/Support/DOTGraphTraits.h"
  29. #include "llvm/Support/FileSystem.h"
  30. #include "llvm/Support/raw_ostream.h"
  31. #include <iterator>
  32. #include <string>
  33. #include <type_traits>
  34. #include <vector>
  35.  
  36. namespace llvm {
  37.  
  38. namespace DOT {  // Private functions...
  39.  
  40. std::string EscapeString(const std::string &Label);
  41.  
  42. /// Get a color string for this node number. Simply round-robin selects
  43. /// from a reasonable number of colors.
  44. StringRef getColorString(unsigned NodeNumber);
  45.  
  46. } // end namespace DOT
  47.  
  48. namespace GraphProgram {
  49.  
  50. enum Name {
  51.   DOT,
  52.   FDP,
  53.   NEATO,
  54.   TWOPI,
  55.   CIRCO
  56. };
  57.  
  58. } // end namespace GraphProgram
  59.  
  60. bool DisplayGraph(StringRef Filename, bool wait = true,
  61.                   GraphProgram::Name program = GraphProgram::DOT);
  62.  
  63. template<typename GraphType>
  64. class GraphWriter {
  65.   raw_ostream &O;
  66.   const GraphType &G;
  67.   bool RenderUsingHTML = false;
  68.  
  69.   using DOTTraits = DOTGraphTraits<GraphType>;
  70.   using GTraits = GraphTraits<GraphType>;
  71.   using NodeRef = typename GTraits::NodeRef;
  72.   using node_iterator = typename GTraits::nodes_iterator;
  73.   using child_iterator = typename GTraits::ChildIteratorType;
  74.   DOTTraits DTraits;
  75.  
  76.   static_assert(std::is_pointer<NodeRef>::value,
  77.                 "FIXME: Currently GraphWriter requires the NodeRef type to be "
  78.                 "a pointer.\nThe pointer usage should be moved to "
  79.                 "DOTGraphTraits, and removed from GraphWriter itself.");
  80.  
  81.   // Writes the edge labels of the node to O and returns true if there are any
  82.   // edge labels not equal to the empty string "".
  83.   bool getEdgeSourceLabels(raw_ostream &O, NodeRef Node) {
  84.     child_iterator EI = GTraits::child_begin(Node);
  85.     child_iterator EE = GTraits::child_end(Node);
  86.     bool hasEdgeSourceLabels = false;
  87.  
  88.     if (RenderUsingHTML)
  89.       O << "</tr><tr>";
  90.  
  91.     for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
  92.       std::string label = DTraits.getEdgeSourceLabel(Node, EI);
  93.  
  94.       if (label.empty())
  95.         continue;
  96.  
  97.       hasEdgeSourceLabels = true;
  98.  
  99.       if (RenderUsingHTML)
  100.         O << "<td colspan=\"1\" port=\"s" << i << "\">" << label << "</td>";
  101.       else {
  102.         if (i)
  103.           O << "|";
  104.  
  105.         O << "<s" << i << ">" << DOT::EscapeString(label);
  106.       }
  107.     }
  108.  
  109.     if (EI != EE && hasEdgeSourceLabels) {
  110.       if (RenderUsingHTML)
  111.         O << "<td colspan=\"1\" port=\"s64\">truncated...</td>";
  112.       else
  113.         O << "|<s64>truncated...";
  114.     }
  115.  
  116.     return hasEdgeSourceLabels;
  117.   }
  118.  
  119. public:
  120.   GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
  121.     DTraits = DOTTraits(SN);
  122.     RenderUsingHTML = DTraits.renderNodesUsingHTML();
  123.   }
  124.  
  125.   void writeGraph(const std::string &Title = "") {
  126.     // Output the header for the graph...
  127.     writeHeader(Title);
  128.  
  129.     // Emit all of the nodes in the graph...
  130.     writeNodes();
  131.  
  132.     // Output any customizations on the graph
  133.     DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, *this);
  134.  
  135.     // Output the end of the graph
  136.     writeFooter();
  137.   }
  138.  
  139.   void writeHeader(const std::string &Title) {
  140.     std::string GraphName(DTraits.getGraphName(G));
  141.  
  142.     if (!Title.empty())
  143.       O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n";
  144.     else if (!GraphName.empty())
  145.       O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
  146.     else
  147.       O << "digraph unnamed {\n";
  148.  
  149.     if (DTraits.renderGraphFromBottomUp())
  150.       O << "\trankdir=\"BT\";\n";
  151.  
  152.     if (!Title.empty())
  153.       O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n";
  154.     else if (!GraphName.empty())
  155.       O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
  156.     O << DTraits.getGraphProperties(G);
  157.     O << "\n";
  158.   }
  159.  
  160.   void writeFooter() {
  161.     // Finish off the graph
  162.     O << "}\n";
  163.   }
  164.  
  165.   void writeNodes() {
  166.     // Loop over the graph, printing it out...
  167.     for (const auto Node : nodes<GraphType>(G))
  168.       if (!isNodeHidden(Node))
  169.         writeNode(Node);
  170.   }
  171.  
  172.   bool isNodeHidden(NodeRef Node) { return DTraits.isNodeHidden(Node, G); }
  173.  
  174.   void writeNode(NodeRef Node) {
  175.     std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
  176.  
  177.     O << "\tNode" << static_cast<const void *>(Node) << " [shape=";
  178.     if (RenderUsingHTML)
  179.       O << "none,";
  180.     else
  181.       O << "record,";
  182.  
  183.     if (!NodeAttributes.empty()) O << NodeAttributes << ",";
  184.     O << "label=";
  185.  
  186.     if (RenderUsingHTML) {
  187.       // Count the numbewr of edges out of the node to determine how
  188.       // many columns to span (max 64)
  189.       unsigned ColSpan = 0;
  190.       child_iterator EI = GTraits::child_begin(Node);
  191.       child_iterator EE = GTraits::child_end(Node);
  192.       for (; EI != EE && ColSpan != 64; ++EI, ++ColSpan)
  193.         ;
  194.       if (ColSpan == 0)
  195.         ColSpan = 1;
  196.       // Include truncated messages when counting.
  197.       if (EI != EE)
  198.         ++ColSpan;
  199.       O << "<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\""
  200.         << " cellpadding=\"0\"><tr><td align=\"text\" colspan=\"" << ColSpan
  201.         << "\">";
  202.     } else
  203.       O << "\"{";
  204.  
  205.     if (!DTraits.renderGraphFromBottomUp()) {
  206.       if (RenderUsingHTML)
  207.         O << DTraits.getNodeLabel(Node, G) << "</td>";
  208.       else
  209.         O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
  210.  
  211.       // If we should include the address of the node in the label, do so now.
  212.       std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
  213.       if (!Id.empty())
  214.         O << "|" << DOT::EscapeString(Id);
  215.  
  216.       std::string NodeDesc = DTraits.getNodeDescription(Node, G);
  217.       if (!NodeDesc.empty())
  218.         O << "|" << DOT::EscapeString(NodeDesc);
  219.     }
  220.  
  221.     std::string edgeSourceLabels;
  222.     raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
  223.     bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
  224.  
  225.     if (hasEdgeSourceLabels) {
  226.       if (!DTraits.renderGraphFromBottomUp())
  227.         if (!RenderUsingHTML)
  228.           O << "|";
  229.  
  230.       if (RenderUsingHTML)
  231.         O << EdgeSourceLabels.str();
  232.       else
  233.         O << "{" << EdgeSourceLabels.str() << "}";
  234.  
  235.       if (DTraits.renderGraphFromBottomUp())
  236.         if (!RenderUsingHTML)
  237.           O << "|";
  238.     }
  239.  
  240.     if (DTraits.renderGraphFromBottomUp()) {
  241.       if (RenderUsingHTML)
  242.         O << DTraits.getNodeLabel(Node, G);
  243.       else
  244.         O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
  245.  
  246.       // If we should include the address of the node in the label, do so now.
  247.       std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
  248.       if (!Id.empty())
  249.         O << "|" << DOT::EscapeString(Id);
  250.  
  251.       std::string NodeDesc = DTraits.getNodeDescription(Node, G);
  252.       if (!NodeDesc.empty())
  253.         O << "|" << DOT::EscapeString(NodeDesc);
  254.     }
  255.  
  256.     if (DTraits.hasEdgeDestLabels()) {
  257.       O << "|{";
  258.  
  259.       unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
  260.       for (; i != e && i != 64; ++i) {
  261.         if (i) O << "|";
  262.         O << "<d" << i << ">"
  263.           << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
  264.       }
  265.  
  266.       if (i != e)
  267.         O << "|<d64>truncated...";
  268.       O << "}";
  269.     }
  270.  
  271.     if (RenderUsingHTML)
  272.       O << "</tr></table>>";
  273.     else
  274.       O << "}\"";
  275.     O << "];\n"; // Finish printing the "node" line
  276.  
  277.     // Output all of the edges now
  278.     child_iterator EI = GTraits::child_begin(Node);
  279.     child_iterator EE = GTraits::child_end(Node);
  280.     for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
  281.       if (!DTraits.isNodeHidden(*EI, G))
  282.         writeEdge(Node, i, EI);
  283.     for (; EI != EE; ++EI)
  284.       if (!DTraits.isNodeHidden(*EI, G))
  285.         writeEdge(Node, 64, EI);
  286.   }
  287.  
  288.   void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI) {
  289.     if (NodeRef TargetNode = *EI) {
  290.       int DestPort = -1;
  291.       if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
  292.         child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
  293.  
  294.         // Figure out which edge this targets...
  295.         unsigned Offset =
  296.           (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
  297.         DestPort = static_cast<int>(Offset);
  298.       }
  299.  
  300.       if (DTraits.getEdgeSourceLabel(Node, EI).empty())
  301.         edgeidx = -1;
  302.  
  303.       emitEdge(static_cast<const void*>(Node), edgeidx,
  304.                static_cast<const void*>(TargetNode), DestPort,
  305.                DTraits.getEdgeAttributes(Node, EI, G));
  306.     }
  307.   }
  308.  
  309.   /// emitSimpleNode - Outputs a simple (non-record) node
  310.   void emitSimpleNode(const void *ID, const std::string &Attr,
  311.                    const std::string &Label, unsigned NumEdgeSources = 0,
  312.                    const std::vector<std::string> *EdgeSourceLabels = nullptr) {
  313.     O << "\tNode" << ID << "[ ";
  314.     if (!Attr.empty())
  315.       O << Attr << ",";
  316.     O << " label =\"";
  317.     if (NumEdgeSources) O << "{";
  318.     O << DOT::EscapeString(Label);
  319.     if (NumEdgeSources) {
  320.       O << "|{";
  321.  
  322.       for (unsigned i = 0; i != NumEdgeSources; ++i) {
  323.         if (i) O << "|";
  324.         O << "<s" << i << ">";
  325.         if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
  326.       }
  327.       O << "}}";
  328.     }
  329.     O << "\"];\n";
  330.   }
  331.  
  332.   /// emitEdge - Output an edge from a simple node into the graph...
  333.   void emitEdge(const void *SrcNodeID, int SrcNodePort,
  334.                 const void *DestNodeID, int DestNodePort,
  335.                 const std::string &Attrs) {
  336.     if (SrcNodePort  > 64) return;             // Eminating from truncated part?
  337.     if (DestNodePort > 64) DestNodePort = 64;  // Targeting the truncated part?
  338.  
  339.     O << "\tNode" << SrcNodeID;
  340.     if (SrcNodePort >= 0)
  341.       O << ":s" << SrcNodePort;
  342.     O << " -> Node" << DestNodeID;
  343.     if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
  344.       O << ":d" << DestNodePort;
  345.  
  346.     if (!Attrs.empty())
  347.       O << "[" << Attrs << "]";
  348.     O << ";\n";
  349.   }
  350.  
  351.   /// getOStream - Get the raw output stream into the graph file. Useful to
  352.   /// write fancy things using addCustomGraphFeatures().
  353.   raw_ostream &getOStream() {
  354.     return O;
  355.   }
  356. };
  357.  
  358. template<typename GraphType>
  359. raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
  360.                         bool ShortNames = false,
  361.                         const Twine &Title = "") {
  362.   // Start the graph emission process...
  363.   GraphWriter<GraphType> W(O, G, ShortNames);
  364.  
  365.   // Emit the graph.
  366.   W.writeGraph(Title.str());
  367.  
  368.   return O;
  369. }
  370.  
  371. std::string createGraphFilename(const Twine &Name, int &FD);
  372.  
  373. /// Writes graph into a provided @c Filename.
  374. /// If @c Filename is empty, generates a random one.
  375. /// \return The resulting filename, or an empty string if writing
  376. /// failed.
  377. template <typename GraphType>
  378. std::string WriteGraph(const GraphType &G, const Twine &Name,
  379.                        bool ShortNames = false,
  380.                        const Twine &Title = "",
  381.                        std::string Filename = "") {
  382.   int FD;
  383.   if (Filename.empty()) {
  384.     Filename = createGraphFilename(Name.str(), FD);
  385.   } else {
  386.     std::error_code EC = sys::fs::openFileForWrite(
  387.         Filename, FD, sys::fs::CD_CreateAlways, sys::fs::OF_Text);
  388.  
  389.     // Writing over an existing file is not considered an error.
  390.     if (EC == std::errc::file_exists) {
  391.       errs() << "file exists, overwriting" << "\n";
  392.     } else if (EC) {
  393.       errs() << "error writing into file" << "\n";
  394.       return "";
  395.     } else {
  396.       errs() << "writing to the newly created file " << Filename << "\n";
  397.     }
  398.   }
  399.   raw_fd_ostream O(FD, /*shouldClose=*/ true);
  400.  
  401.   if (FD == -1) {
  402.     errs() << "error opening file '" << Filename << "' for writing!\n";
  403.     return "";
  404.   }
  405.  
  406.   llvm::WriteGraph(O, G, ShortNames, Title);
  407.   errs() << " done. \n";
  408.  
  409.   return Filename;
  410. }
  411.  
  412. /// DumpDotGraph - Just dump a dot graph to the user-provided file name.
  413. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  414. template <typename GraphType>
  415. LLVM_DUMP_METHOD void
  416. dumpDotGraphToFile(const GraphType &G, const Twine &FileName,
  417.                    const Twine &Title, bool ShortNames = false,
  418.                    const Twine &Name = "") {
  419.   llvm::WriteGraph(G, Name, ShortNames, Title, FileName.str());
  420. }
  421. #endif
  422.  
  423. /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
  424. /// then cleanup.  For use from the debugger.
  425. ///
  426. template<typename GraphType>
  427. void ViewGraph(const GraphType &G, const Twine &Name,
  428.                bool ShortNames = false, const Twine &Title = "",
  429.                GraphProgram::Name Program = GraphProgram::DOT) {
  430.   std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
  431.  
  432.   if (Filename.empty())
  433.     return;
  434.  
  435.   DisplayGraph(Filename, false, Program);
  436. }
  437.  
  438. } // end namespace llvm
  439.  
  440. #endif // LLVM_SUPPORT_GRAPHWRITER_H
  441.