Path: blob/21.2-virgl/src/gallium/drivers/nouveau/codegen/nv50_ir_graph.cpp
4574 views
/*1* Copyright 2011 Christoph Bumiller2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#include "codegen/nv50_ir_graph.h"23#include <limits>24#include <list>25#include <stack>26#include "codegen/nv50_ir.h"2728namespace nv50_ir {2930Graph::Graph()31{32root = NULL;33size = 0;34sequence = 0;35}3637Graph::~Graph()38{39for (IteratorRef it = safeIteratorDFS(); !it->end(); it->next())40reinterpret_cast<Node *>(it->get())->cut();41}4243void Graph::insert(Node *node)44{45if (!root)46root = node;4748node->graph = this;49size++;50}5152void Graph::Edge::unlink()53{54if (origin) {55prev[0]->next[0] = next[0];56next[0]->prev[0] = prev[0];57if (origin->out == this)58origin->out = (next[0] == this) ? NULL : next[0];5960--origin->outCount;61}62if (target) {63prev[1]->next[1] = next[1];64next[1]->prev[1] = prev[1];65if (target->in == this)66target->in = (next[1] == this) ? NULL : next[1];6768--target->inCount;69}70}7172const char *Graph::Edge::typeStr() const73{74switch (type) {75case TREE: return "tree";76case FORWARD: return "forward";77case BACK: return "back";78case CROSS: return "cross";79case UNKNOWN:80default:81return "unk";82}83}8485Graph::Node::Node(void *priv) : data(priv),86in(0), out(0), graph(0),87visited(0),88inCount(0), outCount(0),89tag(0)90{91// nothing to do92}9394void Graph::Node::attach(Node *node, Edge::Type kind)95{96Edge *edge = new Edge(this, node, kind);9798// insert head99if (this->out) {100edge->next[0] = this->out;101edge->prev[0] = this->out->prev[0];102edge->prev[0]->next[0] = edge;103this->out->prev[0] = edge;104}105this->out = edge;106107if (node->in) {108edge->next[1] = node->in;109edge->prev[1] = node->in->prev[1];110edge->prev[1]->next[1] = edge;111node->in->prev[1] = edge;112}113node->in = edge;114115++this->outCount;116++node->inCount;117118assert(graph || node->graph);119if (!node->graph)120graph->insert(node);121if (!graph)122node->graph->insert(this);123124if (kind == Edge::UNKNOWN)125graph->classifyEdges();126}127128bool Graph::Node::detach(Graph::Node *node)129{130EdgeIterator ei = this->outgoing();131for (; !ei.end(); ei.next())132if (ei.getNode() == node)133break;134if (ei.end()) {135ERROR("no such node attached\n");136return false;137}138delete ei.getEdge();139return true;140}141142// Cut a node from the graph, deleting all attached edges.143void Graph::Node::cut()144{145while (out)146delete out;147while (in)148delete in;149150if (graph) {151if (graph->root == this)152graph->root = NULL;153graph = NULL;154}155}156157Graph::Edge::Edge(Node *org, Node *tgt, Type kind)158{159target = tgt;160origin = org;161type = kind;162163next[0] = next[1] = this;164prev[0] = prev[1] = this;165}166167bool168Graph::Node::reachableBy(const Node *node, const Node *term) const169{170std::stack<const Node *> stack;171const Node *pos = NULL;172const int seq = graph->nextSequence();173174stack.push(node);175176while (!stack.empty()) {177pos = stack.top();178stack.pop();179180if (pos == this)181return true;182if (pos == term)183continue;184185for (EdgeIterator ei = pos->outgoing(); !ei.end(); ei.next()) {186if (ei.getType() == Edge::BACK)187continue;188if (ei.getNode()->visit(seq))189stack.push(ei.getNode());190}191}192return pos == this;193}194195class DFSIterator : public Iterator196{197public:198DFSIterator(Graph *graph, const bool preorder)199{200unsigned int seq = graph->nextSequence();201202nodes = new Graph::Node * [graph->getSize() + 1];203count = 0;204pos = 0;205nodes[graph->getSize()] = 0;206207if (graph->getRoot()) {208graph->getRoot()->visit(seq);209search(graph->getRoot(), preorder, seq);210}211}212213~DFSIterator()214{215if (nodes)216delete[] nodes;217}218219void search(Graph::Node *node, const bool preorder, const int sequence)220{221if (preorder)222nodes[count++] = node;223224for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next())225if (ei.getNode()->visit(sequence))226search(ei.getNode(), preorder, sequence);227228if (!preorder)229nodes[count++] = node;230}231232virtual bool end() const { return pos >= count; }233virtual void next() { if (pos < count) ++pos; }234virtual void *get() const { return nodes[pos]; }235virtual void reset() { pos = 0; }236237protected:238Graph::Node **nodes;239int count;240int pos;241};242243IteratorRef Graph::iteratorDFS(bool preorder)244{245return IteratorRef(new DFSIterator(this, preorder));246}247248IteratorRef Graph::safeIteratorDFS(bool preorder)249{250return this->iteratorDFS(preorder);251}252253class CFGIterator : public Iterator254{255public:256CFGIterator(Graph *graph)257{258nodes = new Graph::Node * [graph->getSize() + 1];259count = 0;260pos = 0;261nodes[graph->getSize()] = 0;262263// TODO: argh, use graph->sequence instead of tag and just raise it by > 1264for (IteratorRef it = graph->iteratorDFS(); !it->end(); it->next())265reinterpret_cast<Graph::Node *>(it->get())->tag = 0;266267if (graph->getRoot())268search(graph->getRoot(), graph->nextSequence());269}270271~CFGIterator()272{273if (nodes)274delete[] nodes;275}276277virtual void *get() const { return nodes[pos]; }278virtual bool end() const { return pos >= count; }279virtual void next() { if (pos < count) ++pos; }280virtual void reset() { pos = 0; }281282private:283void search(Graph::Node *node, const int sequence)284{285Stack bb, cross;286287bb.push(node);288289while (bb.getSize() || cross.getSize()) {290if (bb.getSize() == 0)291cross.moveTo(bb);292293node = reinterpret_cast<Graph::Node *>(bb.pop().u.p);294assert(node);295if (!node->visit(sequence))296continue;297node->tag = 0;298299for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next()) {300switch (ei.getType()) {301case Graph::Edge::TREE:302case Graph::Edge::FORWARD:303if (++(ei.getNode()->tag) == ei.getNode()->incidentCountFwd())304bb.push(ei.getNode());305break;306case Graph::Edge::BACK:307continue;308case Graph::Edge::CROSS:309if (++(ei.getNode()->tag) == 1)310cross.push(ei.getNode());311break;312default:313assert(!"unknown edge kind in CFG");314break;315}316}317nodes[count++] = node;318}319}320321private:322Graph::Node **nodes;323int count;324int pos;325};326327IteratorRef Graph::iteratorCFG()328{329return IteratorRef(new CFGIterator(this));330}331332IteratorRef Graph::safeIteratorCFG()333{334return this->iteratorCFG();335}336337/**338* Edge classification:339*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 graph342* - FORWARD: edges from a node to a descendent in the spanning tree343* - BACK: edges from a node to a parent (or itself) in the spanning tree344* - CROSS: all other edges (because they cross between branches in the345* spanning tree)346*/347void Graph::classifyEdges()348{349int seq;350351for (IteratorRef it = iteratorDFS(true); !it->end(); it->next()) {352Node *node = reinterpret_cast<Node *>(it->get());353node->visit(0);354node->tag = 0;355}356357classifyDFS(root, (seq = 0));358359sequence = seq;360}361362void Graph::classifyDFS(Node *curr, int& seq)363{364Graph::Edge *edge;365Graph::Node *node;366367curr->visit(++seq);368curr->tag = 1;369370for (edge = curr->out; edge; edge = edge->next[0]) {371node = edge->target;372373if (node->getSequence() == 0) {374edge->type = Edge::TREE;375classifyDFS(node, seq);376} else377if (node->getSequence() > curr->getSequence()) {378edge->type = Edge::FORWARD;379} else {380edge->type = node->tag ? Edge::BACK : Edge::CROSS;381}382}383384for (edge = curr->in; edge; edge = edge->next[1]) {385node = edge->origin;386387if (node->getSequence() == 0) {388edge->type = Edge::TREE;389classifyDFS(node, seq);390} else391if (node->getSequence() > curr->getSequence()) {392edge->type = Edge::FORWARD;393} else {394edge->type = node->tag ? Edge::BACK : Edge::CROSS;395}396}397398curr->tag = 0;399}400401// @dist is indexed by Node::tag, returns -1 if no path found402int403Graph::findLightestPathWeight(Node *a, Node *b, const std::vector<int> &weight)404{405std::vector<int> path(weight.size(), std::numeric_limits<int>::max());406std::list<Node *> nodeList;407const int seq = nextSequence();408409path[a->tag] = 0;410for (Node *c = a; c && c != b;) {411const int p = path[c->tag] + weight[c->tag];412for (EdgeIterator ei = c->outgoing(); !ei.end(); ei.next()) {413Node *t = ei.getNode();414if (t->getSequence() < seq) {415if (path[t->tag] == std::numeric_limits<int>::max())416nodeList.push_front(t);417if (p < path[t->tag])418path[t->tag] = p;419}420}421c->visit(seq);422Node *next = NULL;423for (std::list<Node *>::iterator n = nodeList.begin();424n != nodeList.end(); ++n) {425if (!next || path[(*n)->tag] < path[next->tag])426next = *n;427if ((*n) == c) {428// erase visited429n = nodeList.erase(n);430--n;431}432}433c = next;434}435if (path[b->tag] == std::numeric_limits<int>::max())436return -1;437return path[b->tag];438}439440} // namespace nv50_ir441442443