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";
80 case DUMMY
: return "dummy";
87 Graph::Node::Node(void *priv
) : data(priv
),
88 in(0), out(0), graph(0),
90 inCount(0), outCount(0)
95 void Graph::Node::attach(Node
*node
, Edge::Type kind
)
97 Edge
*edge
= new Edge(this, node
, kind
);
101 edge
->next
[0] = this->out
;
102 edge
->prev
[0] = this->out
->prev
[0];
103 edge
->prev
[0]->next
[0] = edge
;
104 this->out
->prev
[0] = edge
;
109 edge
->next
[1] = node
->in
;
110 edge
->prev
[1] = node
->in
->prev
[1];
111 edge
->prev
[1]->next
[1] = edge
;
112 node
->in
->prev
[1] = edge
;
119 assert(graph
|| node
->graph
);
123 node
->graph
->insert(this);
125 if (kind
== Edge::UNKNOWN
)
126 graph
->classifyEdges();
129 bool Graph::Node::detach(Graph::Node
*node
)
131 EdgeIterator ei
= this->outgoing();
132 for (; !ei
.end(); ei
.next())
133 if (ei
.getNode() == node
)
136 ERROR("no such node attached\n");
143 // Cut a node from the graph, deleting all attached edges.
144 void Graph::Node::cut()
152 if (graph
->root
== this)
158 Graph::Edge::Edge(Node
*org
, Node
*tgt
, Type kind
)
164 next
[0] = next
[1] = this;
165 prev
[0] = prev
[1] = this;
169 Graph::Node::reachableBy(const Node
*node
, const Node
*term
) const
171 std::stack
<const Node
*> stack
;
172 const Node
*pos
= NULL
;
173 const int seq
= graph
->nextSequence();
177 while (!stack
.empty()) {
186 for (EdgeIterator ei
= pos
->outgoing(); !ei
.end(); ei
.next()) {
187 if (ei
.getType() == Edge::BACK
|| ei
.getType() == Edge::DUMMY
)
189 if (ei
.getNode()->visit(seq
))
190 stack
.push(ei
.getNode());
196 class DFSIterator
: public Iterator
199 DFSIterator(Graph
*graph
, const bool preorder
)
201 unsigned int seq
= graph
->nextSequence();
203 nodes
= new Graph::Node
* [graph
->getSize() + 1];
206 nodes
[graph
->getSize()] = 0;
208 if (graph
->getRoot()) {
209 graph
->getRoot()->visit(seq
);
210 search(graph
->getRoot(), preorder
, seq
);
220 void search(Graph::Node
*node
, const bool preorder
, const int sequence
)
223 nodes
[count
++] = node
;
225 for (Graph::EdgeIterator ei
= node
->outgoing(); !ei
.end(); ei
.next())
226 if (ei
.getNode()->visit(sequence
))
227 search(ei
.getNode(), preorder
, sequence
);
230 nodes
[count
++] = node
;
233 virtual bool end() const { return pos
>= count
; }
234 virtual void next() { if (pos
< count
) ++pos
; }
235 virtual void *get() const { return nodes
[pos
]; }
236 virtual void reset() { pos
= 0; }
244 IteratorRef
Graph::iteratorDFS(bool preorder
)
246 return IteratorRef(new DFSIterator(this, preorder
));
249 IteratorRef
Graph::safeIteratorDFS(bool preorder
)
251 return this->iteratorDFS(preorder
);
254 class CFGIterator
: public Iterator
257 CFGIterator(Graph
*graph
)
259 nodes
= new Graph::Node
* [graph
->getSize() + 1];
262 nodes
[graph
->getSize()] = 0;
264 // TODO: argh, use graph->sequence instead of tag and just raise it by > 1
265 for (IteratorRef it
= graph
->iteratorDFS(); !it
->end(); it
->next())
266 reinterpret_cast<Graph::Node
*>(it
->get())->tag
= 0;
268 if (graph
->getRoot())
269 search(graph
->getRoot(), graph
->nextSequence());
278 virtual void *get() const { return nodes
[pos
]; }
279 virtual bool end() const { return pos
>= count
; }
280 virtual void next() { if (pos
< count
) ++pos
; }
281 virtual void reset() { pos
= 0; }
284 void search(Graph::Node
*node
, const int sequence
)
290 while (bb
.getSize()) {
291 node
= reinterpret_cast<Graph::Node
*>(bb
.pop().u
.p
);
293 if (!node
->visit(sequence
))
297 for (Graph::EdgeIterator ei
= node
->outgoing(); !ei
.end(); ei
.next()) {
298 switch (ei
.getType()) {
299 case Graph::Edge::TREE
:
300 case Graph::Edge::FORWARD
:
301 case Graph::Edge::DUMMY
:
302 if (++(ei
.getNode()->tag
) == ei
.getNode()->incidentCountFwd())
303 bb
.push(ei
.getNode());
305 case Graph::Edge::BACK
:
307 case Graph::Edge::CROSS
:
308 if (++(ei
.getNode()->tag
) == 1)
309 cross
.push(ei
.getNode());
312 assert(!"unknown edge kind in CFG");
316 nodes
[count
++] = node
;
318 if (bb
.getSize() == 0)
329 IteratorRef
Graph::iteratorCFG()
331 return IteratorRef(new CFGIterator(this));
334 IteratorRef
Graph::safeIteratorCFG()
336 return this->iteratorCFG();
339 void Graph::classifyEdges()
343 for (IteratorRef it
= iteratorDFS(true); !it
->end(); it
->next()) {
344 Node
*node
= reinterpret_cast<Node
*>(it
->get());
349 classifyDFS(root
, (seq
= 0));
354 void Graph::classifyDFS(Node
*curr
, int& seq
)
362 for (edge
= curr
->out
; edge
; edge
= edge
->next
[0]) {
364 if (edge
->type
== Edge::DUMMY
)
367 if (node
->getSequence() == 0) {
368 edge
->type
= Edge::TREE
;
369 classifyDFS(node
, seq
);
371 if (node
->getSequence() > curr
->getSequence()) {
372 edge
->type
= Edge::FORWARD
;
374 edge
->type
= node
->tag
? Edge::BACK
: Edge::CROSS
;
378 for (edge
= curr
->in
; edge
; edge
= edge
->next
[1]) {
380 if (edge
->type
== Edge::DUMMY
)
383 if (node
->getSequence() == 0) {
384 edge
->type
= Edge::TREE
;
385 classifyDFS(node
, seq
);
387 if (node
->getSequence() > curr
->getSequence()) {
388 edge
->type
= Edge::FORWARD
;
390 edge
->type
= node
->tag
? Edge::BACK
: Edge::CROSS
;
397 // @dist is indexed by Node::tag, returns -1 if no path found
399 Graph::findLightestPathWeight(Node
*a
, Node
*b
, const std::vector
<int> &weight
)
401 std::vector
<int> path(weight
.size(), std::numeric_limits
<int>::max());
402 std::list
<Node
*> nodeList
;
403 const int seq
= nextSequence();
406 for (Node
*c
= a
; c
&& c
!= b
;) {
407 const int p
= path
[c
->tag
] + weight
[c
->tag
];
408 for (EdgeIterator ei
= c
->outgoing(); !ei
.end(); ei
.next()) {
409 Node
*t
= ei
.getNode();
410 if (t
->getSequence() < seq
) {
411 if (path
[t
->tag
] == std::numeric_limits
<int>::max())
412 nodeList
.push_front(t
);
413 if (p
< path
[t
->tag
])
419 for (std::list
<Node
*>::iterator n
= nodeList
.begin();
420 n
!= nodeList
.end(); ++n
) {
421 if (!next
|| path
[(*n
)->tag
] < path
[next
->tag
])
425 n
= nodeList
.erase(n
);
431 if (path
[b
->tag
] == std::numeric_limits
<int>::max())
436 } // namespace nv50_ir