xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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