2 * Copyright 2011 Christoph Bumiller
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include "codegen/nv50_ir_graph.h"
27 #include "codegen/nv50_ir.h"
40 for (IteratorRef it
= safeIteratorDFS(); !it
->end(); it
->next())
41 reinterpret_cast<Node
*>(it
->get())->cut();
44 void Graph::insert(Node
*node
)
53 void Graph::Edge::unlink()
56 prev
[0]->next
[0] = next
[0];
57 next
[0]->prev
[0] = prev
[0];
58 if (origin
->out
== this)
59 origin
->out
= (next
[0] == this) ? NULL
: next
[0];
64 prev
[1]->next
[1] = next
[1];
65 next
[1]->prev
[1] = prev
[1];
66 if (target
->in
== this)
67 target
->in
= (next
[1] == this) ? NULL
: next
[1];
73 const char *Graph::Edge::typeStr() const
76 case TREE
: return "tree";
77 case FORWARD
: return "forward";
78 case BACK
: return "back";
79 case CROSS
: return "cross";
86 Graph::Node::Node(void *priv
) : data(priv
),
87 in(0), out(0), graph(0),
89 inCount(0), outCount(0)
94 void Graph::Node::attach(Node
*node
, Edge::Type kind
)
96 Edge
*edge
= new Edge(this, node
, kind
);
100 edge
->next
[0] = this->out
;
101 edge
->prev
[0] = this->out
->prev
[0];
102 edge
->prev
[0]->next
[0] = edge
;
103 this->out
->prev
[0] = edge
;
108 edge
->next
[1] = node
->in
;
109 edge
->prev
[1] = node
->in
->prev
[1];
110 edge
->prev
[1]->next
[1] = edge
;
111 node
->in
->prev
[1] = edge
;
118 assert(graph
|| node
->graph
);
122 node
->graph
->insert(this);
124 if (kind
== Edge::UNKNOWN
)
125 graph
->classifyEdges();
128 bool Graph::Node::detach(Graph::Node
*node
)
130 EdgeIterator ei
= this->outgoing();
131 for (; !ei
.end(); ei
.next())
132 if (ei
.getNode() == node
)
135 ERROR("no such node attached\n");
142 // Cut a node from the graph, deleting all attached edges.
143 void Graph::Node::cut()
151 if (graph
->root
== this)
157 Graph::Edge::Edge(Node
*org
, Node
*tgt
, Type kind
)
163 next
[0] = next
[1] = this;
164 prev
[0] = prev
[1] = this;
168 Graph::Node::reachableBy(const Node
*node
, const Node
*term
) const
170 std::stack
<const Node
*> stack
;
171 const Node
*pos
= NULL
;
172 const int seq
= graph
->nextSequence();
176 while (!stack
.empty()) {
185 for (EdgeIterator ei
= pos
->outgoing(); !ei
.end(); ei
.next()) {
186 if (ei
.getType() == Edge::BACK
)
188 if (ei
.getNode()->visit(seq
))
189 stack
.push(ei
.getNode());
195 class DFSIterator
: public Iterator
198 DFSIterator(Graph
*graph
, const bool preorder
)
200 unsigned int seq
= graph
->nextSequence();
202 nodes
= new Graph::Node
* [graph
->getSize() + 1];
205 nodes
[graph
->getSize()] = 0;
207 if (graph
->getRoot()) {
208 graph
->getRoot()->visit(seq
);
209 search(graph
->getRoot(), preorder
, seq
);
219 void search(Graph::Node
*node
, const bool preorder
, const int sequence
)
222 nodes
[count
++] = node
;
224 for (Graph::EdgeIterator ei
= node
->outgoing(); !ei
.end(); ei
.next())
225 if (ei
.getNode()->visit(sequence
))
226 search(ei
.getNode(), preorder
, sequence
);
229 nodes
[count
++] = node
;
232 virtual bool end() const { return pos
>= count
; }
233 virtual void next() { if (pos
< count
) ++pos
; }
234 virtual void *get() const { return nodes
[pos
]; }
235 virtual void reset() { pos
= 0; }
243 IteratorRef
Graph::iteratorDFS(bool preorder
)
245 return IteratorRef(new DFSIterator(this, preorder
));
248 IteratorRef
Graph::safeIteratorDFS(bool preorder
)
250 return this->iteratorDFS(preorder
);
253 class CFGIterator
: public Iterator
256 CFGIterator(Graph
*graph
)
258 nodes
= new Graph::Node
* [graph
->getSize() + 1];
261 nodes
[graph
->getSize()] = 0;
263 // TODO: argh, use graph->sequence instead of tag and just raise it by > 1
264 for (IteratorRef it
= graph
->iteratorDFS(); !it
->end(); it
->next())
265 reinterpret_cast<Graph::Node
*>(it
->get())->tag
= 0;
267 if (graph
->getRoot())
268 search(graph
->getRoot(), graph
->nextSequence());
277 virtual void *get() const { return nodes
[pos
]; }
278 virtual bool end() const { return pos
>= count
; }
279 virtual void next() { if (pos
< count
) ++pos
; }
280 virtual void reset() { pos
= 0; }
283 void search(Graph::Node
*node
, const int sequence
)
289 while (bb
.getSize() || cross
.getSize()) {
290 if (bb
.getSize() == 0)
293 node
= reinterpret_cast<Graph::Node
*>(bb
.pop().u
.p
);
295 if (!node
->visit(sequence
))
299 for (Graph::EdgeIterator ei
= node
->outgoing(); !ei
.end(); ei
.next()) {
300 switch (ei
.getType()) {
301 case Graph::Edge::TREE
:
302 case Graph::Edge::FORWARD
:
303 if (++(ei
.getNode()->tag
) == ei
.getNode()->incidentCountFwd())
304 bb
.push(ei
.getNode());
306 case Graph::Edge::BACK
:
308 case Graph::Edge::CROSS
:
309 if (++(ei
.getNode()->tag
) == 1)
310 cross
.push(ei
.getNode());
313 assert(!"unknown edge kind in CFG");
317 nodes
[count
++] = node
;
327 IteratorRef
Graph::iteratorCFG()
329 return IteratorRef(new CFGIterator(this));
332 IteratorRef
Graph::safeIteratorCFG()
334 return this->iteratorCFG();
338 * Edge classification:
340 * We have a graph and want to classify the edges into one of four types:
341 * - TREE: edges that belong to a spanning tree of the graph
342 * - FORWARD: edges from a node to a descendent in the spanning tree
343 * - BACK: edges from a node to a parent (or itself) in the spanning tree
344 * - CROSS: all other edges (because they cross between branches in the
347 void Graph::classifyEdges()
351 for (IteratorRef it
= iteratorDFS(true); !it
->end(); it
->next()) {
352 Node
*node
= reinterpret_cast<Node
*>(it
->get());
357 classifyDFS(root
, (seq
= 0));
362 void Graph::classifyDFS(Node
*curr
, int& seq
)
370 for (edge
= curr
->out
; edge
; edge
= edge
->next
[0]) {
373 if (node
->getSequence() == 0) {
374 edge
->type
= Edge::TREE
;
375 classifyDFS(node
, seq
);
377 if (node
->getSequence() > curr
->getSequence()) {
378 edge
->type
= Edge::FORWARD
;
380 edge
->type
= node
->tag
? Edge::BACK
: Edge::CROSS
;
384 for (edge
= curr
->in
; edge
; edge
= edge
->next
[1]) {
387 if (node
->getSequence() == 0) {
388 edge
->type
= Edge::TREE
;
389 classifyDFS(node
, seq
);
391 if (node
->getSequence() > curr
->getSequence()) {
392 edge
->type
= Edge::FORWARD
;
394 edge
->type
= node
->tag
? Edge::BACK
: Edge::CROSS
;
401 // @dist is indexed by Node::tag, returns -1 if no path found
403 Graph::findLightestPathWeight(Node
*a
, Node
*b
, const std::vector
<int> &weight
)
405 std::vector
<int> path(weight
.size(), std::numeric_limits
<int>::max());
406 std::list
<Node
*> nodeList
;
407 const int seq
= nextSequence();
410 for (Node
*c
= a
; c
&& c
!= b
;) {
411 const int p
= path
[c
->tag
] + weight
[c
->tag
];
412 for (EdgeIterator ei
= c
->outgoing(); !ei
.end(); ei
.next()) {
413 Node
*t
= ei
.getNode();
414 if (t
->getSequence() < seq
) {
415 if (path
[t
->tag
] == std::numeric_limits
<int>::max())
416 nodeList
.push_front(t
);
417 if (p
< path
[t
->tag
])
423 for (std::list
<Node
*>::iterator n
= nodeList
.begin();
424 n
!= nodeList
.end(); ++n
) {
425 if (!next
|| path
[(*n
)->tag
] < path
[next
->tag
])
429 n
= nodeList
.erase(n
);
435 if (path
[b
->tag
] == std::numeric_limits
<int>::max())
440 } // namespace nv50_ir