10b57cec5SDimitry Andric //===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This implements the SelectionDAG::viewGraph method. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "ScheduleDAGSDNodes.h" 140b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 150b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 180b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 190b57cec5SDimitry Andric #include "llvm/Support/GraphWriter.h" 200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "dag-printer" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace llvm { 260b57cec5SDimitry Andric template<> 270b57cec5SDimitry Andric struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits { 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric explicit DOTGraphTraits(bool isSimple=false) : 300b57cec5SDimitry Andric DefaultDOTGraphTraits(isSimple) {} 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric static bool hasEdgeDestLabels() { 330b57cec5SDimitry Andric return true; 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric static unsigned numEdgeDestLabels(const void *Node) { 370b57cec5SDimitry Andric return ((const SDNode *) Node)->getNumValues(); 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric static std::string getEdgeDestLabel(const void *Node, unsigned i) { 410b57cec5SDimitry Andric return ((const SDNode *) Node)->getValueType(i).getEVTString(); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric template<typename EdgeIter> 450b57cec5SDimitry Andric static std::string getEdgeSourceLabel(const void *Node, EdgeIter I) { 460b57cec5SDimitry Andric return itostr(I - SDNodeIterator::begin((const SDNode *) Node)); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric /// edgeTargetsEdgeSource - This method returns true if this outgoing edge 500b57cec5SDimitry Andric /// should actually target another edge source, not a node. If this method 510b57cec5SDimitry Andric /// is implemented, getEdgeTarget should be implemented. 520b57cec5SDimitry Andric template<typename EdgeIter> 530b57cec5SDimitry Andric static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) { 540b57cec5SDimitry Andric return true; 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is 580b57cec5SDimitry Andric /// called to determine which outgoing edge of Node is the target of this 590b57cec5SDimitry Andric /// edge. 600b57cec5SDimitry Andric template<typename EdgeIter> 610b57cec5SDimitry Andric static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) { 620b57cec5SDimitry Andric SDNode *TargetNode = *I; 630b57cec5SDimitry Andric SDNodeIterator NI = SDNodeIterator::begin(TargetNode); 640b57cec5SDimitry Andric std::advance(NI, I.getNode()->getOperand(I.getOperand()).getResNo()); 650b57cec5SDimitry Andric return NI; 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric static std::string getGraphName(const SelectionDAG *G) { 695ffd83dbSDimitry Andric return std::string(G->getMachineFunction().getName()); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric static bool renderGraphFromBottomUp() { 730b57cec5SDimitry Andric return true; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric static std::string getNodeIdentifierLabel(const SDNode *Node, 770b57cec5SDimitry Andric const SelectionDAG *Graph) { 780b57cec5SDimitry Andric std::string R; 790b57cec5SDimitry Andric raw_string_ostream OS(R); 800b57cec5SDimitry Andric #ifndef NDEBUG 810b57cec5SDimitry Andric OS << 't' << Node->PersistentId; 820b57cec5SDimitry Andric #else 830b57cec5SDimitry Andric OS << static_cast<const void *>(Node); 840b57cec5SDimitry Andric #endif 850b57cec5SDimitry Andric return R; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric /// If you want to override the dot attributes printed for a particular 890b57cec5SDimitry Andric /// edge, override this method. 900b57cec5SDimitry Andric template<typename EdgeIter> 910b57cec5SDimitry Andric static std::string getEdgeAttributes(const void *Node, EdgeIter EI, 920b57cec5SDimitry Andric const SelectionDAG *Graph) { 930b57cec5SDimitry Andric SDValue Op = EI.getNode()->getOperand(EI.getOperand()); 940b57cec5SDimitry Andric EVT VT = Op.getValueType(); 950b57cec5SDimitry Andric if (VT == MVT::Glue) 960b57cec5SDimitry Andric return "color=red,style=bold"; 970b57cec5SDimitry Andric else if (VT == MVT::Other) 980b57cec5SDimitry Andric return "color=blue,style=dashed"; 990b57cec5SDimitry Andric return ""; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric static std::string getSimpleNodeLabel(const SDNode *Node, 1040b57cec5SDimitry Andric const SelectionDAG *G) { 1050b57cec5SDimitry Andric std::string Result = Node->getOperationName(G); 1060b57cec5SDimitry Andric { 1070b57cec5SDimitry Andric raw_string_ostream OS(Result); 1080b57cec5SDimitry Andric Node->print_details(OS, G); 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric return Result; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric std::string getNodeLabel(const SDNode *Node, const SelectionDAG *Graph); 1130b57cec5SDimitry Andric static std::string getNodeAttributes(const SDNode *N, 1140b57cec5SDimitry Andric const SelectionDAG *Graph) { 1150b57cec5SDimitry Andric #ifndef NDEBUG 1160b57cec5SDimitry Andric const std::string &Attrs = Graph->getGraphAttrs(N); 1170b57cec5SDimitry Andric if (!Attrs.empty()) { 1180b57cec5SDimitry Andric if (Attrs.find("shape=") == std::string::npos) 1190b57cec5SDimitry Andric return std::string("shape=Mrecord,") + Attrs; 1200b57cec5SDimitry Andric else 1210b57cec5SDimitry Andric return Attrs; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric #endif 1240b57cec5SDimitry Andric return "shape=Mrecord"; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric static void addCustomGraphFeatures(SelectionDAG *G, 1280b57cec5SDimitry Andric GraphWriter<SelectionDAG*> &GW) { 1290b57cec5SDimitry Andric GW.emitSimpleNode(nullptr, "plaintext=circle", "GraphRoot"); 1300b57cec5SDimitry Andric if (G->getRoot().getNode()) 1310b57cec5SDimitry Andric GW.emitEdge(nullptr, -1, G->getRoot().getNode(), G->getRoot().getResNo(), 1320b57cec5SDimitry Andric "color=blue,style=dashed"); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric }; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node, 1380b57cec5SDimitry Andric const SelectionDAG *G) { 1390b57cec5SDimitry Andric return DOTGraphTraits<SelectionDAG*>::getSimpleNodeLabel(Node, G); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG 1440b57cec5SDimitry Andric /// rendered using 'dot'. 1450b57cec5SDimitry Andric /// 1460b57cec5SDimitry Andric void SelectionDAG::viewGraph(const std::string &Title) { 1470b57cec5SDimitry Andric // This code is only for debugging! 1480b57cec5SDimitry Andric #ifndef NDEBUG 1490b57cec5SDimitry Andric ViewGraph(this, "dag." + getMachineFunction().getName(), 1500b57cec5SDimitry Andric false, Title); 1510b57cec5SDimitry Andric #else 1520b57cec5SDimitry Andric errs() << "SelectionDAG::viewGraph is only available in debug builds on " 1530b57cec5SDimitry Andric << "systems with Graphviz or gv!\n"; 1540b57cec5SDimitry Andric #endif // NDEBUG 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric // This overload is defined out-of-line here instead of just using a 1580b57cec5SDimitry Andric // default parameter because this is easiest for gdb to call. 1590b57cec5SDimitry Andric void SelectionDAG::viewGraph() { 1600b57cec5SDimitry Andric viewGraph(""); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1635ffd83dbSDimitry Andric /// Just dump dot graph to a user-provided path and title. 1645ffd83dbSDimitry Andric /// This doesn't open the dot viewer program and 1655ffd83dbSDimitry Andric /// helps visualization when outside debugging session. 1665ffd83dbSDimitry Andric /// FileName expects absolute path. If provided 1675ffd83dbSDimitry Andric /// without any path separators then the file 1685ffd83dbSDimitry Andric /// will be created in the current directory. 1695ffd83dbSDimitry Andric /// Error will be emitted if the path is insane. 1705ffd83dbSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1715ffd83dbSDimitry Andric LLVM_DUMP_METHOD void SelectionDAG::dumpDotGraph(const Twine &FileName, 1725ffd83dbSDimitry Andric const Twine &Title) { 1735ffd83dbSDimitry Andric dumpDotGraphToFile(this, FileName, Title); 1745ffd83dbSDimitry Andric } 1755ffd83dbSDimitry Andric #endif 1765ffd83dbSDimitry Andric 1770b57cec5SDimitry Andric /// clearGraphAttrs - Clear all previously defined node graph attributes. 1780b57cec5SDimitry Andric /// Intended to be used from a debugging tool (eg. gdb). 1790b57cec5SDimitry Andric void SelectionDAG::clearGraphAttrs() { 18081ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 1810b57cec5SDimitry Andric NodeGraphAttrs.clear(); 1820b57cec5SDimitry Andric #else 18381ad6265SDimitry Andric errs() << "SelectionDAG::clearGraphAttrs is only available in builds with " 18481ad6265SDimitry Andric << "ABI breaking checks enabled on systems with Graphviz or gv!\n"; 1850b57cec5SDimitry Andric #endif 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric /// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".) 1900b57cec5SDimitry Andric /// 1910b57cec5SDimitry Andric void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) { 19281ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 1930b57cec5SDimitry Andric NodeGraphAttrs[N] = Attrs; 1940b57cec5SDimitry Andric #else 19581ad6265SDimitry Andric errs() << "SelectionDAG::setGraphAttrs is only available in builds with " 19681ad6265SDimitry Andric << "ABI breaking checks enabled on systems with Graphviz or gv!\n"; 1970b57cec5SDimitry Andric #endif 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric /// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".) 2020b57cec5SDimitry Andric /// Used from getNodeAttributes. 203fe6060f1SDimitry Andric std::string SelectionDAG::getGraphAttrs(const SDNode *N) const { 20481ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 2050b57cec5SDimitry Andric std::map<const SDNode *, std::string>::const_iterator I = 2060b57cec5SDimitry Andric NodeGraphAttrs.find(N); 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric if (I != NodeGraphAttrs.end()) 2090b57cec5SDimitry Andric return I->second; 2100b57cec5SDimitry Andric else 2110b57cec5SDimitry Andric return ""; 2120b57cec5SDimitry Andric #else 21381ad6265SDimitry Andric errs() << "SelectionDAG::getGraphAttrs is only available in builds with " 21481ad6265SDimitry Andric << "ABI breaking checks enabled on systems with Graphviz or gv!\n"; 2150b57cec5SDimitry Andric return std::string(); 2160b57cec5SDimitry Andric #endif 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric /// setGraphColor - Convenience for setting node color attribute. 2200b57cec5SDimitry Andric /// 2210b57cec5SDimitry Andric void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) { 22281ad6265SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 2230b57cec5SDimitry Andric NodeGraphAttrs[N] = std::string("color=") + Color; 2240b57cec5SDimitry Andric #else 22581ad6265SDimitry Andric errs() << "SelectionDAG::setGraphColor is only available in builds with " 22681ad6265SDimitry Andric << "ABI breaking checks enabled on systems with Graphviz or gv!\n"; 2270b57cec5SDimitry Andric #endif 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric /// setSubgraphColorHelper - Implement setSubgraphColor. Return 2310b57cec5SDimitry Andric /// whether we truncated the search. 2320b57cec5SDimitry Andric /// 2330b57cec5SDimitry Andric bool SelectionDAG::setSubgraphColorHelper(SDNode *N, const char *Color, DenseSet<SDNode *> &visited, 2340b57cec5SDimitry Andric int level, bool &printed) { 2350b57cec5SDimitry Andric bool hit_limit = false; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric #ifndef NDEBUG 2380b57cec5SDimitry Andric if (level >= 20) { 2390b57cec5SDimitry Andric if (!printed) { 2400b57cec5SDimitry Andric printed = true; 2410b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "setSubgraphColor hit max level\n"); 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric return true; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric unsigned oldSize = visited.size(); 2470b57cec5SDimitry Andric visited.insert(N); 2480b57cec5SDimitry Andric if (visited.size() != oldSize) { 2490b57cec5SDimitry Andric setGraphColor(N, Color); 2500b57cec5SDimitry Andric for(SDNodeIterator i = SDNodeIterator::begin(N), iend = SDNodeIterator::end(N); 2510b57cec5SDimitry Andric i != iend; 2520b57cec5SDimitry Andric ++i) { 2530b57cec5SDimitry Andric hit_limit = setSubgraphColorHelper(*i, Color, visited, level+1, printed) || hit_limit; 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric #else 2570b57cec5SDimitry Andric errs() << "SelectionDAG::setSubgraphColor is only available in debug builds" 2580b57cec5SDimitry Andric << " on systems with Graphviz or gv!\n"; 2590b57cec5SDimitry Andric #endif 2600b57cec5SDimitry Andric return hit_limit; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric /// setSubgraphColor - Convenience for setting subgraph color attribute. 2640b57cec5SDimitry Andric /// 2650b57cec5SDimitry Andric void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) { 2660b57cec5SDimitry Andric #ifndef NDEBUG 2670b57cec5SDimitry Andric DenseSet<SDNode *> visited; 2680b57cec5SDimitry Andric bool printed = false; 2690b57cec5SDimitry Andric if (setSubgraphColorHelper(N, Color, visited, 0, printed)) { 2700b57cec5SDimitry Andric // Visually mark that we hit the limit 2710b57cec5SDimitry Andric if (strcmp(Color, "red") == 0) { 2720b57cec5SDimitry Andric setSubgraphColorHelper(N, "blue", visited, 0, printed); 2730b57cec5SDimitry Andric } else if (strcmp(Color, "yellow") == 0) { 2740b57cec5SDimitry Andric setSubgraphColorHelper(N, "green", visited, 0, printed); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric #else 2790b57cec5SDimitry Andric errs() << "SelectionDAG::setSubgraphColor is only available in debug builds" 2800b57cec5SDimitry Andric << " on systems with Graphviz or gv!\n"; 2810b57cec5SDimitry Andric #endif 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const { 2850b57cec5SDimitry Andric std::string s; 2860b57cec5SDimitry Andric raw_string_ostream O(s); 2870b57cec5SDimitry Andric O << "SU(" << SU->NodeNum << "): "; 2880b57cec5SDimitry Andric if (SU->getNode()) { 2890b57cec5SDimitry Andric SmallVector<SDNode *, 4> GluedNodes; 2900b57cec5SDimitry Andric for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) 2910b57cec5SDimitry Andric GluedNodes.push_back(N); 2920b57cec5SDimitry Andric while (!GluedNodes.empty()) { 2930b57cec5SDimitry Andric O << DOTGraphTraits<SelectionDAG*> 2940b57cec5SDimitry Andric ::getSimpleNodeLabel(GluedNodes.back(), DAG); 2950b57cec5SDimitry Andric GluedNodes.pop_back(); 2960b57cec5SDimitry Andric if (!GluedNodes.empty()) 2970b57cec5SDimitry Andric O << "\n "; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } else { 3000b57cec5SDimitry Andric O << "CROSS RC COPY"; 3010b57cec5SDimitry Andric } 302*0fca6ea1SDimitry Andric return s; 3030b57cec5SDimitry Andric } 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const { 3060b57cec5SDimitry Andric if (DAG) { 3070b57cec5SDimitry Andric // Draw a special "GraphRoot" node to indicate the root of the graph. 3080b57cec5SDimitry Andric GW.emitSimpleNode(nullptr, "plaintext=circle", "GraphRoot"); 3090b57cec5SDimitry Andric const SDNode *N = DAG->getRoot().getNode(); 3100b57cec5SDimitry Andric if (N && N->getNodeId() != -1) 3110b57cec5SDimitry Andric GW.emitEdge(nullptr, -1, &SUnits[N->getNodeId()], -1, 3120b57cec5SDimitry Andric "color=blue,style=dashed"); 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric } 315