1 //===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
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
7 //===----------------------------------------------------------------------===//
9 // This implements the SelectionDAG::viewGraph method.
11 //===----------------------------------------------------------------------===//
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"
23 #define DEBUG_TYPE "dag-printer"
27 struct DOTGraphTraits
<SelectionDAG
*> : public DefaultDOTGraphTraits
{
29 explicit DOTGraphTraits(bool isSimple
=false) :
30 DefaultDOTGraphTraits(isSimple
) {}
32 static bool hasEdgeDestLabels() {
36 static unsigned numEdgeDestLabels(const void *Node
) {
37 return ((const SDNode
*) Node
)->getNumValues();
40 static std::string
getEdgeDestLabel(const void *Node
, unsigned i
) {
41 return ((const SDNode
*) Node
)->getValueType(i
).getEVTString();
44 template<typename EdgeIter
>
45 static std::string
getEdgeSourceLabel(const void *Node
, EdgeIter I
) {
46 return itostr(I
- SDNodeIterator::begin((const SDNode
*) Node
));
49 /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
50 /// should actually target another edge source, not a node. If this method
51 /// is implemented, getEdgeTarget should be implemented.
52 template<typename EdgeIter
>
53 static bool edgeTargetsEdgeSource(const void *Node
, EdgeIter I
) {
57 /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
58 /// called to determine which outgoing edge of Node is the target of this
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());
68 static std::string
getGraphName(const SelectionDAG
*G
) {
69 return std::string(G
->getMachineFunction().getName());
72 static bool renderGraphFromBottomUp() {
76 static std::string
getNodeIdentifierLabel(const SDNode
*Node
,
77 const SelectionDAG
*Graph
) {
79 raw_string_ostream
OS(R
);
81 OS
<< 't' << Node
->PersistentId
;
83 OS
<< static_cast<const void *>(Node
);
88 /// If you want to override the dot attributes printed for a particular
89 /// 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();
96 return "color=red,style=bold";
97 else if (VT
== MVT::Other
)
98 return "color=blue,style=dashed";
103 static std::string
getSimpleNodeLabel(const SDNode
*Node
,
104 const SelectionDAG
*G
) {
105 std::string Result
= Node
->getOperationName(G
);
107 raw_string_ostream
OS(Result
);
108 Node
->print_details(OS
, G
);
112 std::string
getNodeLabel(const SDNode
*Node
, const SelectionDAG
*Graph
);
113 static std::string
getNodeAttributes(const SDNode
*N
,
114 const SelectionDAG
*Graph
) {
116 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
;
124 return "shape=Mrecord";
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");
137 std::string DOTGraphTraits
<SelectionDAG
*>::getNodeLabel(const SDNode
*Node
,
138 const SelectionDAG
*G
) {
139 return DOTGraphTraits
<SelectionDAG
*>::getSimpleNodeLabel(Node
, G
);
143 /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
144 /// rendered using 'dot'.
146 void SelectionDAG::viewGraph(const std::string
&Title
) {
147 // This code is only for debugging!
149 ViewGraph(this, "dag." + getMachineFunction().getName(),
152 errs() << "SelectionDAG::viewGraph is only available in debug builds on "
153 << "systems with Graphviz or gv!\n";
157 // This overload is defined out-of-line here instead of just using a
158 // default parameter because this is easiest for gdb to call.
159 void SelectionDAG::viewGraph() {
163 /// Just dump dot graph to a user-provided path and title.
164 /// This doesn't open the dot viewer program and
165 /// helps visualization when outside debugging session.
166 /// FileName expects absolute path. If provided
167 /// without any path separators then the file
168 /// 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)
171 LLVM_DUMP_METHOD
void SelectionDAG::dumpDotGraph(const Twine
&FileName
,
172 const Twine
&Title
) {
173 dumpDotGraphToFile(this, FileName
, Title
);
177 /// clearGraphAttrs - Clear all previously defined node graph attributes.
178 /// Intended to be used from a debugging tool (eg. gdb).
179 void SelectionDAG::clearGraphAttrs() {
180 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
181 NodeGraphAttrs
.clear();
183 errs() << "SelectionDAG::clearGraphAttrs is only available in builds with "
184 << "ABI breaking checks enabled on systems with Graphviz or gv!\n";
189 /// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
191 void SelectionDAG::setGraphAttrs(const SDNode
*N
, const char *Attrs
) {
192 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
193 NodeGraphAttrs
[N
] = Attrs
;
195 errs() << "SelectionDAG::setGraphAttrs is only available in builds with "
196 << "ABI breaking checks enabled on systems with Graphviz or gv!\n";
201 /// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
202 /// Used from getNodeAttributes.
203 std::string
SelectionDAG::getGraphAttrs(const SDNode
*N
) const {
204 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
205 std::map
<const SDNode
*, std::string
>::const_iterator I
=
206 NodeGraphAttrs
.find(N
);
208 if (I
!= NodeGraphAttrs
.end())
213 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();
219 /// setGraphColor - Convenience for setting node color attribute.
221 void SelectionDAG::setGraphColor(const SDNode
*N
, const char *Color
) {
222 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
223 NodeGraphAttrs
[N
] = std::string("color=") + Color
;
225 errs() << "SelectionDAG::setGraphColor is only available in builds with "
226 << "ABI breaking checks enabled on systems with Graphviz or gv!\n";
230 /// setSubgraphColorHelper - Implement setSubgraphColor. Return
231 /// whether we truncated the search.
233 bool SelectionDAG::setSubgraphColorHelper(SDNode
*N
, const char *Color
, DenseSet
<SDNode
*> &visited
,
234 int level
, bool &printed
) {
235 bool hit_limit
= false;
241 LLVM_DEBUG(dbgs() << "setSubgraphColor hit max level\n");
246 unsigned oldSize
= visited
.size();
248 if (visited
.size() != oldSize
) {
249 setGraphColor(N
, Color
);
250 for(SDNodeIterator i
= SDNodeIterator::begin(N
), iend
= SDNodeIterator::end(N
);
253 hit_limit
= setSubgraphColorHelper(*i
, Color
, visited
, level
+1, printed
) || hit_limit
;
257 errs() << "SelectionDAG::setSubgraphColor is only available in debug builds"
258 << " on systems with Graphviz or gv!\n";
263 /// setSubgraphColor - Convenience for setting subgraph color attribute.
265 void SelectionDAG::setSubgraphColor(SDNode
*N
, const char *Color
) {
267 DenseSet
<SDNode
*> visited
;
268 bool printed
= false;
269 if (setSubgraphColorHelper(N
, Color
, visited
, 0, printed
)) {
270 // Visually mark that we hit the limit
271 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
);
279 errs() << "SelectionDAG::setSubgraphColor is only available in debug builds"
280 << " on systems with Graphviz or gv!\n";
284 std::string
ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit
*SU
) const {
286 raw_string_ostream
O(s
);
287 O
<< "SU(" << SU
->NodeNum
<< "): ";
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())
300 O
<< "CROSS RC COPY";
305 void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter
<ScheduleDAG
*> &GW
) const {
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");