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