Home | History | Annotate | Line # | Download | only in SelectionDAG
      1 //===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
      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 implements the SelectionDAG::viewGraph method.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "ScheduleDAGSDNodes.h"
     14 #include "llvm/ADT/DenseSet.h"
     15 #include "llvm/ADT/StringExtras.h"
     16 #include "llvm/CodeGen/MachineConstantPool.h"
     17 #include "llvm/CodeGen/MachineFunction.h"
     18 #include "llvm/CodeGen/SelectionDAG.h"
     19 #include "llvm/CodeGen/TargetRegisterInfo.h"
     20 #include "llvm/IR/Constants.h"
     21 #include "llvm/Support/Debug.h"
     22 #include "llvm/Support/GraphWriter.h"
     23 #include "llvm/Support/raw_ostream.h"
     24 #include "llvm/Target/TargetMachine.h"
     25 using namespace llvm;
     26 
     27 #define DEBUG_TYPE "dag-printer"
     28 
     29 namespace llvm {
     30   template<>
     31   struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
     32 
     33     explicit DOTGraphTraits(bool isSimple=false) :
     34       DefaultDOTGraphTraits(isSimple) {}
     35 
     36     static bool hasEdgeDestLabels() {
     37       return true;
     38     }
     39 
     40     static unsigned numEdgeDestLabels(const void *Node) {
     41       return ((const SDNode *) Node)->getNumValues();
     42     }
     43 
     44     static std::string getEdgeDestLabel(const void *Node, unsigned i) {
     45       return ((const SDNode *) Node)->getValueType(i).getEVTString();
     46     }
     47 
     48     template<typename EdgeIter>
     49     static std::string getEdgeSourceLabel(const void *Node, EdgeIter I) {
     50       return itostr(I - SDNodeIterator::begin((const SDNode *) Node));
     51     }
     52 
     53     /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
     54     /// should actually target another edge source, not a node.  If this method
     55     /// is implemented, getEdgeTarget should be implemented.
     56     template<typename EdgeIter>
     57     static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
     58       return true;
     59     }
     60 
     61     /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
     62     /// called to determine which outgoing edge of Node is the target of this
     63     /// edge.
     64     template<typename EdgeIter>
     65     static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
     66       SDNode *TargetNode = *I;
     67       SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
     68       std::advance(NI, I.getNode()->getOperand(I.getOperand()).getResNo());
     69       return NI;
     70     }
     71 
     72     static std::string getGraphName(const SelectionDAG *G) {
     73       return std::string(G->getMachineFunction().getName());
     74     }
     75 
     76     static bool renderGraphFromBottomUp() {
     77       return true;
     78     }
     79 
     80     static std::string getNodeIdentifierLabel(const SDNode *Node,
     81                                               const SelectionDAG *Graph) {
     82       std::string R;
     83       raw_string_ostream OS(R);
     84 #ifndef NDEBUG
     85       OS << 't' << Node->PersistentId;
     86 #else
     87       OS << static_cast<const void *>(Node);
     88 #endif
     89       return R;
     90     }
     91 
     92     /// If you want to override the dot attributes printed for a particular
     93     /// edge, override this method.
     94     template<typename EdgeIter>
     95     static std::string getEdgeAttributes(const void *Node, EdgeIter EI,
     96                                          const SelectionDAG *Graph) {
     97       SDValue Op = EI.getNode()->getOperand(EI.getOperand());
     98       EVT VT = Op.getValueType();
     99       if (VT == MVT::Glue)
    100         return "color=red,style=bold";
    101       else if (VT == MVT::Other)
    102         return "color=blue,style=dashed";
    103       return "";
    104     }
    105 
    106 
    107     static std::string getSimpleNodeLabel(const SDNode *Node,
    108                                           const SelectionDAG *G) {
    109       std::string Result = Node->getOperationName(G);
    110       {
    111         raw_string_ostream OS(Result);
    112         Node->print_details(OS, G);
    113       }
    114       return Result;
    115     }
    116     std::string getNodeLabel(const SDNode *Node, const SelectionDAG *Graph);
    117     static std::string getNodeAttributes(const SDNode *N,
    118                                          const SelectionDAG *Graph) {
    119 #ifndef NDEBUG
    120       const std::string &Attrs = Graph->getGraphAttrs(N);
    121       if (!Attrs.empty()) {
    122         if (Attrs.find("shape=") == std::string::npos)
    123           return std::string("shape=Mrecord,") + Attrs;
    124         else
    125           return Attrs;
    126       }
    127 #endif
    128       return "shape=Mrecord";
    129     }
    130 
    131     static void addCustomGraphFeatures(SelectionDAG *G,
    132                                        GraphWriter<SelectionDAG*> &GW) {
    133       GW.emitSimpleNode(nullptr, "plaintext=circle", "GraphRoot");
    134       if (G->getRoot().getNode())
    135         GW.emitEdge(nullptr, -1, G->getRoot().getNode(), G->getRoot().getResNo(),
    136                     "color=blue,style=dashed");
    137     }
    138   };
    139 }
    140 
    141 std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
    142                                                         const SelectionDAG *G) {
    143   return DOTGraphTraits<SelectionDAG*>::getSimpleNodeLabel(Node, G);
    144 }
    145 
    146 
    147 /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
    148 /// rendered using 'dot'.
    149 ///
    150 void SelectionDAG::viewGraph(const std::string &Title) {
    151 // This code is only for debugging!
    152 #ifndef NDEBUG
    153   ViewGraph(this, "dag." + getMachineFunction().getName(),
    154             false, Title);
    155 #else
    156   errs() << "SelectionDAG::viewGraph is only available in debug builds on "
    157          << "systems with Graphviz or gv!\n";
    158 #endif  // NDEBUG
    159 }
    160 
    161 // This overload is defined out-of-line here instead of just using a
    162 // default parameter because this is easiest for gdb to call.
    163 void SelectionDAG::viewGraph() {
    164   viewGraph("");
    165 }
    166 
    167 /// Just dump dot graph to a user-provided path and title.
    168 /// This doesn't open the dot viewer program and
    169 /// helps visualization when outside debugging session.
    170 /// FileName expects absolute path. If provided
    171 /// without any path separators then the file
    172 /// will be created in the current directory.
    173 /// Error will be emitted if the path is insane.
    174 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
    175 LLVM_DUMP_METHOD void SelectionDAG::dumpDotGraph(const Twine &FileName,
    176                                                  const Twine &Title) {
    177   dumpDotGraphToFile(this, FileName, Title);
    178 }
    179 #endif
    180 
    181 /// clearGraphAttrs - Clear all previously defined node graph attributes.
    182 /// Intended to be used from a debugging tool (eg. gdb).
    183 void SelectionDAG::clearGraphAttrs() {
    184 #ifndef NDEBUG
    185   NodeGraphAttrs.clear();
    186 #else
    187   errs() << "SelectionDAG::clearGraphAttrs is only available in debug builds"
    188          << " on systems with Graphviz or gv!\n";
    189 #endif
    190 }
    191 
    192 
    193 /// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
    194 ///
    195 void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
    196 #ifndef NDEBUG
    197   NodeGraphAttrs[N] = Attrs;
    198 #else
    199   errs() << "SelectionDAG::setGraphAttrs is only available in debug builds"
    200          << " on systems with Graphviz or gv!\n";
    201 #endif
    202 }
    203 
    204 
    205 /// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
    206 /// Used from getNodeAttributes.
    207 std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
    208 #ifndef NDEBUG
    209   std::map<const SDNode *, std::string>::const_iterator I =
    210     NodeGraphAttrs.find(N);
    211 
    212   if (I != NodeGraphAttrs.end())
    213     return I->second;
    214   else
    215     return "";
    216 #else
    217   errs() << "SelectionDAG::getGraphAttrs is only available in debug builds"
    218          << " on systems with Graphviz or gv!\n";
    219   return std::string();
    220 #endif
    221 }
    222 
    223 /// setGraphColor - Convenience for setting node color attribute.
    224 ///
    225 void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
    226 #ifndef NDEBUG
    227   NodeGraphAttrs[N] = std::string("color=") + Color;
    228 #else
    229   errs() << "SelectionDAG::setGraphColor is only available in debug builds"
    230          << " on systems with Graphviz or gv!\n";
    231 #endif
    232 }
    233 
    234 /// setSubgraphColorHelper - Implement setSubgraphColor.  Return
    235 /// whether we truncated the search.
    236 ///
    237 bool SelectionDAG::setSubgraphColorHelper(SDNode *N, const char *Color, DenseSet<SDNode *> &visited,
    238                                           int level, bool &printed) {
    239   bool hit_limit = false;
    240 
    241 #ifndef NDEBUG
    242   if (level >= 20) {
    243     if (!printed) {
    244       printed = true;
    245       LLVM_DEBUG(dbgs() << "setSubgraphColor hit max level\n");
    246     }
    247     return true;
    248   }
    249 
    250   unsigned oldSize = visited.size();
    251   visited.insert(N);
    252   if (visited.size() != oldSize) {
    253     setGraphColor(N, Color);
    254     for(SDNodeIterator i = SDNodeIterator::begin(N), iend = SDNodeIterator::end(N);
    255         i != iend;
    256         ++i) {
    257       hit_limit = setSubgraphColorHelper(*i, Color, visited, level+1, printed) || hit_limit;
    258     }
    259   }
    260 #else
    261   errs() << "SelectionDAG::setSubgraphColor is only available in debug builds"
    262          << " on systems with Graphviz or gv!\n";
    263 #endif
    264   return hit_limit;
    265 }
    266 
    267 /// setSubgraphColor - Convenience for setting subgraph color attribute.
    268 ///
    269 void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) {
    270 #ifndef NDEBUG
    271   DenseSet<SDNode *> visited;
    272   bool printed = false;
    273   if (setSubgraphColorHelper(N, Color, visited, 0, printed)) {
    274     // Visually mark that we hit the limit
    275     if (strcmp(Color, "red") == 0) {
    276       setSubgraphColorHelper(N, "blue", visited, 0, printed);
    277     } else if (strcmp(Color, "yellow") == 0) {
    278       setSubgraphColorHelper(N, "green", visited, 0, printed);
    279     }
    280   }
    281 
    282 #else
    283   errs() << "SelectionDAG::setSubgraphColor is only available in debug builds"
    284          << " on systems with Graphviz or gv!\n";
    285 #endif
    286 }
    287 
    288 std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const {
    289   std::string s;
    290   raw_string_ostream O(s);
    291   O << "SU(" << SU->NodeNum << "): ";
    292   if (SU->getNode()) {
    293     SmallVector<SDNode *, 4> GluedNodes;
    294     for (SDNode *N = SU->getNode(); N; N = N->getGluedNode())
    295       GluedNodes.push_back(N);
    296     while (!GluedNodes.empty()) {
    297       O << DOTGraphTraits<SelectionDAG*>
    298         ::getSimpleNodeLabel(GluedNodes.back(), DAG);
    299       GluedNodes.pop_back();
    300       if (!GluedNodes.empty())
    301         O << "\n    ";
    302     }
    303   } else {
    304     O << "CROSS RC COPY";
    305   }
    306   return O.str();
    307 }
    308 
    309 void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const {
    310   if (DAG) {
    311     // Draw a special "GraphRoot" node to indicate the root of the graph.
    312     GW.emitSimpleNode(nullptr, "plaintext=circle", "GraphRoot");
    313     const SDNode *N = DAG->getRoot().getNode();
    314     if (N && N->getNodeId() != -1)
    315       GW.emitEdge(nullptr, -1, &SUnits[N->getNodeId()], -1,
    316                   "color=blue,style=dashed");
    317   }
    318 }
    319