/* * Copyright 2011 Christoph Bumiller * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef __NV50_IR_GRAPH_H__ #define __NV50_IR_GRAPH_H__ #include "nv50_ir_util.h" #include <vector> namespace nv50_ir { #define ITER_NODE(x) reinterpret_cast<Graph::Node *>((x).get()) #define ITER_EDGE(x) reinterpret_cast<Graph::Edge *>((x).get()) // A connected graph. class Graph { public: class Node; class Edge { public: enum Type { UNKNOWN, TREE, FORWARD, BACK, CROSS, // e.g. loop break DUMMY }; Edge(Node *dst, Node *src, Type kind); ~Edge() { unlink(); } inline Node *getOrigin() const { return origin; } inline Node *getTarget() const { return target; } inline Type getType() const { return type; } const char *typeStr() const; private: Node *origin; Node *target; Type type; Edge *next[2]; // next edge outgoing/incident from/to origin/target Edge *prev[2]; void unlink(); friend class Graph; }; class EdgeIterator : public Iterator { public: EdgeIterator() : e(0), t(0), d(0), rev(false) { } EdgeIterator(Graph::Edge *first, int dir, bool reverse) : d(dir), rev(reverse) { t = e = ((rev && first) ? first->prev[d] : first); } virtual void next() { Graph::Edge *n = (rev ? e->prev[d] : e->next[d]); e = (n == t ? NULL : n); } virtual bool end() const { return !e; } virtual void *get() const { return e; } inline Node *getNode() const { assert(e); return d ? e->origin : e->target; } inline Edge *getEdge() const { return e; } inline Edge::Type getType() { return e ? e->getType() : Edge::UNKNOWN; } private: Graph::Edge *e; Graph::Edge *t; int d; bool rev; }; class Node { public: Node(void *); ~Node() { cut(); } void attach(Node *, Edge::Type); bool detach(Node *); void cut(); inline EdgeIterator outgoing(bool reverse = false) const; inline EdgeIterator incident(bool reverse = false) const; inline Node *parent() const; // returns NULL if count(incident edges) != 1 bool reachableBy(const Node *node, const Node *term) const; inline bool visit(int); inline int getSequence() const; inline int incidentCountFwd() const; // count of incident non-back edges inline int incidentCount() const { return inCount; } inline int outgoingCount() const { return outCount; } Graph *getGraph() const { return graph; } void *data; private: Edge *in; Edge *out; Graph *graph; int visited; int16_t inCount; int16_t outCount; public: int tag; // for temporary use friend class Graph; }; public: Graph(); ~Graph(); // does *not* free the nodes (make it an option ?) inline Node *getRoot() const { return root; } inline unsigned int getSize() const { return size; } inline int nextSequence(); void insert(Node *node); // attach to or set as root IteratorRef iteratorDFS(bool preorder = true); IteratorRef iteratorCFG(); // safe iterators are unaffected by changes to the *edges* of the graph IteratorRef safeIteratorDFS(bool preorder = true); IteratorRef safeIteratorCFG(); void classifyEdges(); // @weights: indexed by Node::tag int findLightestPathWeight(Node *, Node *, const std::vector<int>& weights); private: void classifyDFS(Node *, int&); private: Node *root; unsigned int size; int sequence; }; int Graph::nextSequence() { return ++sequence; } Graph::Node *Graph::Node::parent() const { if (inCount != 1) return NULL; assert(in); return in->origin; } bool Graph::Node::visit(int v) { if (visited == v) return false; visited = v; return true; } int Graph::Node::getSequence() const { return visited; } Graph::EdgeIterator Graph::Node::outgoing(bool reverse) const { return EdgeIterator(out, 0, reverse); } Graph::EdgeIterator Graph::Node::incident(bool reverse) const { return EdgeIterator(in, 1, reverse); } int Graph::Node::incidentCountFwd() const { int n = 0; for (EdgeIterator ei = incident(); !ei.end(); ei.next()) if (ei.getType() != Edge::BACK) ++n; return n; } } // namespace nv50_ir #endif // __NV50_IR_GRAPH_H__