From 14756fa131e73919d02b6917f0ad797b8d7a937b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 20 Nov 2008 09:04:29 -0500 Subject: [PATCH] Internals: Make graph sorting usable in other visitors, in prep for future changes. No functional change. --- TODO | 1 + src/V3Ast.h | 10 +---- src/V3Error.h | 8 ++++ src/V3Graph.cpp | 26 +++++++++++- src/V3Graph.h | 39 ++++++++++++++---- src/V3GraphAlg.cpp | 100 ++++++++++++++++++++++++--------------------- src/V3Options.h | 2 + 7 files changed, 123 insertions(+), 63 deletions(-) diff --git a/TODO b/TODO index 2114adc6f..6b1d3b429 100644 --- a/TODO +++ b/TODO @@ -54,6 +54,7 @@ Usability: Internal Code: Eliminate the AstNUser* passed to all visitors; its only needed in V3Width, and removing it will speed up and simplify all the other code. + V3Graph should be templated container type, taking in Vertex + Edge types Performance: Constant propagation diff --git a/src/V3Ast.h b/src/V3Ast.h index 17ea84943..7299ea8ef 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -443,13 +443,7 @@ public: // Creating from raw data (sameHash functions) V3Hash() { setBoth(1,0); } V3Hash(uint32_t val) { setBoth(1,val); } - V3Hash(void* vp) { - // It's just a hash, so we can shove a 64 bit pointer into a 32 bit bucket - // On 32 bit systems, lower is always 0, but who cares? - union { void* up; struct {uint32_t upper; uint32_t lower;} l;} u; - u.l.upper=0; u.l.lower=0; u.up=vp; - setBoth(1,u.l.upper^u.l.lower); - } + V3Hash(void* vp) { setBoth(1,cvtToHash(vp)); } V3Hash(const string& name); V3Hash(V3Hash lh, V3Hash rh) { setBoth(1,lh.hshval()*31+rh.hshval()); @@ -522,7 +516,7 @@ protected: // CONSTUCTORS AstNode() {init(); } AstNode(FileLine* fileline) {init(); m_fileline = fileline; } - virtual AstNode* clone() = 0; // Generally, cloneTree/cloneNode is what you want + virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead virtual void cloneRelink() {} void cloneRelinkTree(); diff --git a/src/V3Error.h b/src/V3Error.h index dea7ffd0c..470aa7b13 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -188,6 +188,14 @@ template< class T> std::string cvtToStr (const T& t) { ostringstream os; os<outNextp()==NULL; } +uint32_t V3GraphVertex::inHash() const { + // We want the same hash ignoring the order of edges. + // So we need an associative operator, like XOR. + // However with XOR multiple edges to the same source will cancel out, + // so we use ADD. (Generally call this only after removing duplicates though) + uint32_t hash=0; + for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep=edgep->inNextp()) { + hash += cvtToHash(edgep->fromp()); + } + return hash; +} + +uint32_t V3GraphVertex::outHash() const { + uint32_t hash=0; + for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep=edgep->outNextp()) { + hash += cvtToHash(edgep->top()); + } + return hash; +} + ostream& operator<<(ostream& os, V3GraphVertex* vertexp) { os<<" VERTEX="<name(); if (vertexp->rank()) os<<" r"<rank(); @@ -176,8 +196,10 @@ void V3Graph::clear() { void V3Graph::userClearVertices() { // Clear user() in all of tree - // We may use the userCnt trick in V3Ast later... For now we don't call this often, and - // the extra code on each read of user() would probably slow things down more than help. + // We may use the userCnt trick in V3Ast later... (but gblCnt would be + // in V3Graph instead of static) For now we don't call this often, and + // the extra code on each read of user() would probably slow things + // down more than help. for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { vertexp->user(0); vertexp->userp(NULL); // Its a union, but might be different size than user() diff --git a/src/V3Graph.h b/src/V3Graph.h index 82c09d45d..bbee56c54 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -31,7 +31,6 @@ class V3Graph; class V3GraphVertex; class V3GraphEdge; -class GraphOrder; class GraphAcycEdge; class OrderEitherVertex; class OrderLogicVertex; @@ -70,9 +69,12 @@ public: // METHODS void clear(); // Empty it of all vertices/edges, as if making a new object - void clearColors(); + V3GraphVertex* verticesBeginp() const { return m_vertices.begin(); } + + // METHODS - ALGORITHMS + /// Assign same color to all vertices in the same weakly connected component /// Thus different color if there's no edges between the two subgraphs void weaklyConnected(V3EdgeFuncP edgeFuncp); @@ -82,11 +84,22 @@ public: /// (I.E. all loops will occur within each color, not between them.) void stronglyConnected(V3EdgeFuncP edgeFuncp); + /// Assign same color to all destination vertices that have same + /// subgraph feeding into them + /// (I.E. all "from" nodes are common within each color) + /// See V3ClkGater if this is needed again; it got specialized + /// Assign a ordering number to all vertexes in a tree. /// All nodes with no inputs will get rank 1 void rank(V3EdgeFuncP edgeFuncp); void rank(); + /// Sort all vertices and edges using the V3GraphVertex::sortCmp() function + void sortVertices(); + /// Sort all edges and edges using the V3GraphEdge::sortCmp() function + void sortEdges(); + + /// Order all vertices by rank and fanout, lowest first /// Sort all vertices by rank and fanout, lowest first /// Sort all edges by weight, lowest first void order(); @@ -116,8 +129,7 @@ public: void userClearVertices(); void userClearEdges(); static void test(); - // - V3GraphVertex* verticesBeginp() const { return m_vertices.begin(); } + // CALLBACKS virtual void loopsMessageCb(V3GraphVertex* vertexp) { v3fatalSrc("Loops detected in graph: "< m_vertices;// All vertices, linked list V3List m_outs; // Outbound edges,linked list @@ -146,7 +157,8 @@ protected: // ACCESSORS void fanout(double fanout) { m_fanout = fanout; } void rank(uint32_t rank) { m_rank = rank; } - void outUnlink() { m_outs.reset(); } + void inUnlink() { m_ins.reset(); } // Low level; normally unlinkDelete is what you want + void outUnlink() { m_outs.reset(); } // Low level; normally unlinkDelete is what you want public: // CONSTRUCTION V3GraphVertex(V3Graph* graphp); @@ -159,6 +171,14 @@ public: virtual string dotShape() const { return ""; } virtual string dotStyle() const { return ""; } virtual string dotName() const { return ""; } + virtual int sortCmp(const V3GraphVertex* rhsp) const { + // LHS goes first if of lower rank, or lower fanout + if (m_rank < rhsp->m_rank) return -1; + if (m_rank > rhsp->m_rank) return 1; + if (m_fanout < rhsp->m_fanout) return -1; + if (m_fanout > rhsp->m_fanout) return 1; + return 0; + } uint32_t color() const { return m_color; } void color(uint32_t color) { m_color = color; } uint32_t rank() const { return m_rank; } @@ -172,9 +192,11 @@ public: V3GraphEdge* inBeginp() const { return m_ins.begin(); } bool inEmpty() const { return inBeginp()==NULL; } bool inSize1() const; + uint32_t inHash() const; V3GraphEdge* outBeginp() const { return m_outs.begin(); } bool outEmpty() const { return outBeginp()==NULL; } bool outSize1() const; + uint32_t outHash() const; // METHODS void rerouteEdges(V3Graph* graphp); ///< Edges are routed around this vertex to point from "from" directly to "to" }; @@ -187,7 +209,6 @@ class V3GraphEdge { // Wires/variables aren't edges. Edges have only a single to/from vertex protected: friend class V3Graph; friend class V3GraphVertex; - friend class GraphOrderEdgeCmp; friend class GraphOrderVertexCmp; friend class GraphAcyc; friend class GraphAcycEdge; V3ListEnt m_outs; // Next Outbound edge for same vertex (linked list) V3ListEnt m_ins; // Next Inbound edge for same vertex (linked list) @@ -216,6 +237,10 @@ public: virtual string dotLabel() const { return ""; } virtual string dotColor() const { return cutable()?"yellowGreen":"red"; } virtual string dotStyle() const { return cutable()?"dashed":""; } + virtual int sortCmp(const V3GraphEdge* rhsp) const { + if (!m_weight || !rhsp->m_weight) return 0; + return top()->sortCmp(rhsp->top()); + } void unlinkDelete(); // ACCESSORS int weight() const { return m_weight; } diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index 996605716..7e38d1ff5 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -390,6 +390,57 @@ void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) { } } +//###################################################################### +//###################################################################### +// Algorithms - sorting + +struct GraphSortVertexCmp { + inline bool operator () (const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { + return lhsp->sortCmp(rhsp) < 0; + } +}; +struct GraphSortEdgeCmp { + inline bool operator () (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { + return lhsp->sortCmp(rhsp) < 0; + } +}; + +void V3Graph::sortVertices() { + // Sort list of vertices by rank, then fanout + vector vertices; + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + vertices.push_back(vertexp); + } + std::sort(vertices.begin(), vertices.end(), GraphSortVertexCmp()); + this->verticesUnlink(); + for (vector::iterator it = vertices.begin(); it!=vertices.end(); ++it) { + (*it)->verticesPushBack(this); + } +} + +void V3Graph::sortEdges() { + // Sort edges by rank then fanout of node they point to + vector edges; + for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { + // Make a vector + for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { + edges.push_back(edgep); + } + // Sort + std::sort(edges.begin(), edges.end(), GraphSortEdgeCmp()); + + // Relink edges in specified order + // We know the vector contains all of the edges that were + // there originally (didn't delete or add) + vertexp->outUnlink(); + for (vector::const_iterator it = edges.begin(); it!=edges.end(); ++it) { + (*it)->outPushBack(); + } + // Prep for next + edges.clear(); + } +} + //###################################################################### //###################################################################### // Algorithms - ordering @@ -398,24 +449,6 @@ void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) { // Visit edges and assign ranks to keep minimal crossings // (Results in better dcache packing.) -struct GraphOrderVertexCmp { - inline bool operator () (const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { - // LHS goes first if of lower rank, or lower fanout - if (lhsp->m_rank < rhsp->m_rank) return 1; - if (lhsp->m_rank > rhsp->m_rank) return 0; - return (lhsp->m_fanout < rhsp->m_fanout); - } -}; -struct GraphOrderEdgeCmp { - inline bool operator () (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { - if (!lhsp->m_weight || !rhsp->m_weight) return 0; - GraphOrderVertexCmp cmp; - return (cmp(lhsp->m_top, rhsp->m_top)); - } -}; - -//-------------------------------------------------------------------- - void V3Graph::order() { UINFO(2,"Order:\n"); @@ -430,36 +463,11 @@ void V3Graph::order() { orderDFSIterate(vertexp); } } - // Speed up subsequent accesses. - { // Sort list of vertices by rank, then fanout - vector vertices; - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { - vertices.push_back(vertexp); - } - sort(vertices.begin(), vertices.end(), GraphOrderVertexCmp()); - this->verticesUnlink(); - for (vector::iterator it = vertices.begin(); it!=vertices.end(); ++it) { - (*it)->verticesPushBack(this); - } - } + // Sort list of vertices by rank, then fanout + sortVertices(); // Sort edges by rank then fanout of node they point to - vector edges; - for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { - // Make a vector - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { - edges.push_back(edgep); - } - // Sort - sort(edges.begin(), edges.end(), GraphOrderEdgeCmp()); - // Extract - vertexp->outUnlink(); - for (vector::iterator it = edges.begin(); it!=edges.end(); ++it) { - (*it)->outPushBack(); - } - // Prep for next - edges.clear(); - } + sortEdges(); } double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) { diff --git a/src/V3Options.h b/src/V3Options.h index 892246ade..55e7c3411 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -139,6 +139,7 @@ class V3Options { bool m_oCombine; // main switch: -Ob: common icode packing bool m_oConst; // main switch: -Oc: constant folding bool m_oExpand; // main switch: -Ox: expansion of C macros + bool m_oFlopGater; // main switch: -Of: flop gater detection bool m_oGate; // main switch: -Og: gate wire elimination bool m_oLife; // main switch: -Ol: variable lifetime bool m_oLifePost; // main switch: -Ot: delayed assignment elimination @@ -237,6 +238,7 @@ class V3Options { bool oCombine() const { return m_oCombine; } bool oConst() const { return m_oConst; } bool oExpand() const { return m_oExpand; } + bool oFlopGater() const { return m_oFlopGater; } bool oGate() const { return m_oGate; } bool oDup() const { return oLife(); } bool oLife() const { return m_oLife; }