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