mirror of
https://github.com/verilator/verilator.git
synced 2025-04-16 01:26:54 +00:00
Internals: Make graph sorting usable in other visitors, in prep for future
changes. No functional change.
This commit is contained in:
parent
ddbfc176b6
commit
14756fa131
1
TODO
1
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
|
||||
|
10
src/V3Ast.h
10
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();
|
||||
|
||||
|
@ -188,6 +188,14 @@ template< class T> std::string cvtToStr (const T& t) {
|
||||
ostringstream os; os<<t; return os.str();
|
||||
}
|
||||
|
||||
inline uint32_t cvtToHash(void* vp) {
|
||||
// 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;
|
||||
return u.l.upper^u.l.lower;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class FileLine {
|
||||
|
@ -94,6 +94,26 @@ bool V3GraphVertex::outSize1() const {
|
||||
return !outEmpty() && outBeginp()->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="<<vertexp->name();
|
||||
if (vertexp->rank()) os<<" r"<<vertexp->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()
|
||||
|
@ -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: "<<vertexp); }
|
||||
virtual void loopsVertexCb(V3GraphVertex* vertexp);
|
||||
@ -129,7 +141,6 @@ class V3GraphVertex : public AstNUser {
|
||||
// Vertices may be a 'gate'/wire statement OR a variable
|
||||
protected:
|
||||
friend class V3Graph; friend class V3GraphEdge;
|
||||
friend class GraphOrderEdgeCmp; friend class GraphOrderVertexCmp;
|
||||
friend class GraphAcyc; friend class GraphAlgRank;
|
||||
V3ListEnt<V3GraphVertex*> m_vertices;// All vertices, linked list
|
||||
V3List<V3GraphEdge*> 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<V3GraphEdge*> m_outs; // Next Outbound edge for same vertex (linked list)
|
||||
V3ListEnt<V3GraphEdge*> 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; }
|
||||
|
@ -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<V3GraphVertex*> vertices;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
vertices.push_back(vertexp);
|
||||
}
|
||||
std::sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
|
||||
this->verticesUnlink();
|
||||
for (vector<V3GraphVertex*>::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<V3GraphEdge*> 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<V3GraphEdge*>::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<V3GraphVertex*> vertices;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
vertices.push_back(vertexp);
|
||||
}
|
||||
sort(vertices.begin(), vertices.end(), GraphOrderVertexCmp());
|
||||
this->verticesUnlink();
|
||||
for (vector<V3GraphVertex*>::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<V3GraphEdge*> 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<V3GraphEdge*>::iterator it = edges.begin(); it!=edges.end(); ++it) {
|
||||
(*it)->outPushBack();
|
||||
}
|
||||
// Prep for next
|
||||
edges.clear();
|
||||
}
|
||||
sortEdges();
|
||||
}
|
||||
|
||||
double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) {
|
||||
|
@ -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; }
|
||||
|
Loading…
Reference in New Issue
Block a user