2012-04-13 01:08:20 +00:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Graph optimizations
|
|
|
|
|
//
|
2008-04-25 12:14:27 +00:00
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2018-01-02 23:05:06 +00:00
|
|
|
|
// Copyright 2003-2018 by Wilson Snyder. This program is free software; you can
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 21:07:57 +00:00
|
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
|
|
#ifndef _V3GRAPH_H_
|
|
|
|
|
#define _V3GRAPH_H_ 1
|
2006-12-18 19:20:45 +00:00
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 11:35:28 +00:00
|
|
|
|
#include "V3Error.h"
|
|
|
|
|
#include "V3List.h"
|
2011-11-30 03:09:50 +00:00
|
|
|
|
#include "V3Ast.h"
|
2006-08-26 11:35:28 +00:00
|
|
|
|
#include <vector>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
class V3Graph;
|
|
|
|
|
class V3GraphVertex;
|
|
|
|
|
class V3GraphEdge;
|
|
|
|
|
class GraphAcycEdge;
|
|
|
|
|
class OrderEitherVertex;
|
|
|
|
|
class OrderLogicVertex;
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
// Most graph algorithms accept an arbitrary function that returns
|
|
|
|
|
// True for those edges we should honor.
|
|
|
|
|
|
|
|
|
|
typedef bool (*V3EdgeFuncP)(const V3GraphEdge* edgep);
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
|
|
class V3Graph {
|
|
|
|
|
private:
|
|
|
|
|
// STATE
|
|
|
|
|
V3List<V3GraphVertex*> m_vertices; // All vertices
|
|
|
|
|
static int s_debug;
|
|
|
|
|
protected:
|
|
|
|
|
friend class V3GraphVertex; friend class V3GraphEdge;
|
|
|
|
|
friend class GraphAcyc;
|
|
|
|
|
// METHODS
|
|
|
|
|
void acyclicDFS();
|
|
|
|
|
void acyclicDFSIterate(V3GraphVertex *vertexp, int depth, uint32_t currentRank);
|
|
|
|
|
void acyclicCut();
|
|
|
|
|
void acyclicLoop(V3GraphVertex* vertexp, int depth);
|
|
|
|
|
double orderDFSIterate(V3GraphVertex* vertexp);
|
2018-02-02 02:24:41 +00:00
|
|
|
|
void dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
void verticesUnlink() { m_vertices.reset(); }
|
|
|
|
|
// ACCESSORS
|
|
|
|
|
static int debug();
|
|
|
|
|
public:
|
|
|
|
|
V3Graph();
|
|
|
|
|
virtual ~V3Graph();
|
|
|
|
|
static void debug(int level) { s_debug = level; }
|
2017-10-26 22:42:50 +00:00
|
|
|
|
virtual string dotRankDir() const { return "TB"; } // rankdir for dot plotting
|
2008-06-10 01:25:10 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// METHODS
|
|
|
|
|
void clear(); // Empty it of all vertices/edges, as if making a new object
|
|
|
|
|
void clearColors();
|
|
|
|
|
|
2008-11-20 14:04:29 +00:00
|
|
|
|
V3GraphVertex* verticesBeginp() const { return m_vertices.begin(); }
|
|
|
|
|
|
|
|
|
|
// METHODS - ALGORITHMS
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
/// 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);
|
|
|
|
|
|
|
|
|
|
/// Assign same color to all vertices that are strongly connected
|
|
|
|
|
/// Thus different color if there's no directional circuit within the subgraphs.
|
|
|
|
|
/// (I.E. all loops will occur within each color, not between them.)
|
|
|
|
|
void stronglyConnected(V3EdgeFuncP edgeFuncp);
|
|
|
|
|
|
2008-11-20 14:04:29 +00:00
|
|
|
|
/// 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
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
/// 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();
|
|
|
|
|
|
2008-11-20 14:04:29 +00:00
|
|
|
|
/// 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
|
2006-08-26 11:35:28 +00:00
|
|
|
|
/// Sort all vertices by rank and fanout, lowest first
|
|
|
|
|
/// Sort all edges by weight, lowest first
|
|
|
|
|
void order();
|
|
|
|
|
|
|
|
|
|
/// Make acyclical (into a tree) by breaking a minimal subset of cutable edges.
|
|
|
|
|
void acyclic(V3EdgeFuncP edgeFuncp);
|
|
|
|
|
|
|
|
|
|
/// Delete any nodes with only outputs
|
|
|
|
|
void deleteCutableOnlyEdges();
|
|
|
|
|
|
|
|
|
|
/// Any cutable edged become non-cutable
|
|
|
|
|
void makeEdgesNonCutable(V3EdgeFuncP edgeFuncp);
|
|
|
|
|
|
|
|
|
|
/// Remove any redundant edges, weights become MAX of any other weight
|
|
|
|
|
void removeRedundantEdges(V3EdgeFuncP edgeFuncp);
|
|
|
|
|
|
|
|
|
|
/// Remove any redundant edges, weights become SUM of any other weight
|
|
|
|
|
void removeRedundantEdgesSum(V3EdgeFuncP edgeFuncp);
|
|
|
|
|
|
2013-02-27 03:26:47 +00:00
|
|
|
|
/// Call loopsVertexCb on any one loop starting where specified
|
2006-08-26 11:35:28 +00:00
|
|
|
|
void reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp);
|
|
|
|
|
|
2013-02-27 03:26:47 +00:00
|
|
|
|
/// Build a subgraph of all loops starting where specified
|
|
|
|
|
void subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp);
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
/// Debugging
|
2018-02-02 02:24:41 +00:00
|
|
|
|
void dump(std::ostream& os=std::cout);
|
2017-10-26 22:42:50 +00:00
|
|
|
|
void dumpDotFile(const string& filename, bool colorAsSubgraph) const;
|
|
|
|
|
void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph=false) const;
|
|
|
|
|
void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph=false) const;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
void userClearVertices();
|
|
|
|
|
void userClearEdges();
|
2017-10-30 23:01:58 +00:00
|
|
|
|
static void selfTest();
|
2008-11-20 14:04:29 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// CALLBACKS
|
|
|
|
|
virtual void loopsMessageCb(V3GraphVertex* vertexp) { v3fatalSrc("Loops detected in graph: "<<vertexp); }
|
|
|
|
|
virtual void loopsVertexCb(V3GraphVertex* vertexp);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
2016-11-27 14:40:12 +00:00
|
|
|
|
class V3GraphVertex {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Vertices may be a 'gate'/wire statement OR a variable
|
|
|
|
|
protected:
|
|
|
|
|
friend class V3Graph; friend class V3GraphEdge;
|
|
|
|
|
friend class GraphAcyc; friend class GraphAlgRank;
|
|
|
|
|
V3ListEnt<V3GraphVertex*> m_vertices;// All vertices, linked list
|
|
|
|
|
V3List<V3GraphEdge*> m_outs; // Outbound edges,linked list
|
|
|
|
|
V3List<V3GraphEdge*> m_ins; // Inbound edges, linked list
|
|
|
|
|
double m_fanout; // Order fanout
|
|
|
|
|
uint32_t m_color; // Color of the node
|
|
|
|
|
uint32_t m_rank; // Rank of edge
|
|
|
|
|
union {
|
|
|
|
|
void* m_userp; // Marker for some algorithms
|
|
|
|
|
uint32_t m_user; // Marker for some algorithms
|
|
|
|
|
};
|
|
|
|
|
// METHODS
|
|
|
|
|
void verticesPushBack(V3Graph* graphp);
|
|
|
|
|
// ACCESSORS
|
|
|
|
|
void fanout(double fanout) { m_fanout = fanout; }
|
|
|
|
|
void rank(uint32_t rank) { m_rank = rank; }
|
2008-11-20 14:04:29 +00:00
|
|
|
|
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
|
2013-02-26 02:03:50 +00:00
|
|
|
|
protected:
|
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
public:
|
2015-10-04 02:33:06 +00:00
|
|
|
|
explicit V3GraphVertex(V3Graph* graphp);
|
2013-02-26 02:03:50 +00:00
|
|
|
|
//! Clone copy constructor. Doesn't copy edges or user/userp.
|
|
|
|
|
virtual V3GraphVertex* clone(V3Graph* graphp) const {
|
|
|
|
|
return new V3GraphVertex(graphp, *this); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual ~V3GraphVertex() {}
|
|
|
|
|
void unlinkEdges(V3Graph* graphp);
|
|
|
|
|
void unlinkDelete(V3Graph* graphp);
|
2013-02-27 03:26:47 +00:00
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// ACCESSORS
|
|
|
|
|
virtual string name() const { return ""; }
|
|
|
|
|
virtual string dotColor() const { return "black"; }
|
|
|
|
|
virtual string dotShape() const { return ""; }
|
|
|
|
|
virtual string dotStyle() const { return ""; }
|
|
|
|
|
virtual string dotName() const { return ""; }
|
2017-11-18 22:42:35 +00:00
|
|
|
|
virtual uint32_t rankAdder() const { return 1; }
|
2008-11-20 14:04:29 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
uint32_t color() const { return m_color; }
|
|
|
|
|
void color(uint32_t color) { m_color = color; }
|
|
|
|
|
uint32_t rank() const { return m_rank; }
|
|
|
|
|
double fanout() const { return m_fanout; }
|
|
|
|
|
void user(uint32_t user) { m_user = user; }
|
|
|
|
|
uint32_t user() const { return m_user; }
|
|
|
|
|
void userp(void* userp) { m_userp = userp; }
|
|
|
|
|
void* userp() const { return m_userp; }
|
|
|
|
|
// ITERATORS
|
|
|
|
|
V3GraphVertex* verticesNextp() const { return m_vertices.nextp(); }
|
|
|
|
|
V3GraphEdge* inBeginp() const { return m_ins.begin(); }
|
|
|
|
|
bool inEmpty() const { return inBeginp()==NULL; }
|
|
|
|
|
bool inSize1() const;
|
2008-11-20 14:04:29 +00:00
|
|
|
|
uint32_t inHash() const;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
V3GraphEdge* outBeginp() const { return m_outs.begin(); }
|
|
|
|
|
bool outEmpty() const { return outBeginp()==NULL; }
|
|
|
|
|
bool outSize1() const;
|
2008-11-20 14:04:29 +00:00
|
|
|
|
uint32_t outHash() const;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// METHODS
|
|
|
|
|
void rerouteEdges(V3Graph* graphp); ///< Edges are routed around this vertex to point from "from" directly to "to"
|
|
|
|
|
};
|
|
|
|
|
|
2018-02-02 02:24:41 +00:00
|
|
|
|
std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
|
|
class V3GraphEdge {
|
|
|
|
|
// Wires/variables aren't edges. Edges have only a single to/from vertex
|
2013-02-26 02:03:50 +00:00
|
|
|
|
public:
|
|
|
|
|
// ENUMS
|
|
|
|
|
enum Cuttable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
|
2006-08-26 11:35:28 +00:00
|
|
|
|
protected:
|
|
|
|
|
friend class V3Graph; friend class V3GraphVertex;
|
|
|
|
|
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)
|
|
|
|
|
//
|
|
|
|
|
V3GraphVertex* m_fromp; // Vertices pointing to this edge
|
|
|
|
|
V3GraphVertex* m_top; // Vertices this edge points to
|
|
|
|
|
int m_weight; // Weight of the connection
|
|
|
|
|
bool m_cutable; // Interconnect may be broken in order sorting
|
|
|
|
|
union {
|
|
|
|
|
void* m_userp; // Marker for some algorithms
|
|
|
|
|
uint32_t m_user; // Marker for some algorithms
|
|
|
|
|
};
|
|
|
|
|
// METHODS
|
2013-02-26 02:03:50 +00:00
|
|
|
|
void init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
void cut() { m_weight = 0; } // 0 weight is same as disconnected
|
|
|
|
|
void outPushBack();
|
|
|
|
|
void inPushBack();
|
2013-02-26 02:03:50 +00:00
|
|
|
|
// CONSTRUCTORS
|
|
|
|
|
protected:
|
|
|
|
|
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const V3GraphEdge& old) {
|
|
|
|
|
init(graphp, fromp, top, old.m_weight, old.m_cutable);
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
public:
|
2013-02-26 02:03:50 +00:00
|
|
|
|
//! Add DAG from one node to the specified node
|
|
|
|
|
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false) {
|
|
|
|
|
init(graphp, fromp, top, weight, cutable);
|
|
|
|
|
}
|
|
|
|
|
//! Clone copy constructor. Doesn't copy existing vertices or user/userp.
|
|
|
|
|
virtual V3GraphEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
|
|
|
|
|
return new V3GraphEdge(graphp, fromp, top, *this); }
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual ~V3GraphEdge() {}
|
|
|
|
|
// METHODS
|
|
|
|
|
virtual string name() const { return m_fromp->name()+"->"+m_top->name(); }
|
|
|
|
|
virtual string dotLabel() const { return ""; }
|
|
|
|
|
virtual string dotColor() const { return cutable()?"yellowGreen":"red"; }
|
|
|
|
|
virtual string dotStyle() const { return cutable()?"dashed":""; }
|
2008-11-20 14:04:29 +00:00
|
|
|
|
virtual int sortCmp(const V3GraphEdge* rhsp) const {
|
|
|
|
|
if (!m_weight || !rhsp->m_weight) return 0;
|
|
|
|
|
return top()->sortCmp(rhsp->top());
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
void unlinkDelete();
|
2013-02-19 23:49:36 +00:00
|
|
|
|
V3GraphEdge* relinkFromp(V3GraphVertex* newFromp);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// ACCESSORS
|
|
|
|
|
int weight() const { return m_weight; }
|
|
|
|
|
void weight(int weight) { m_weight=weight; }
|
|
|
|
|
bool cutable() const { return m_cutable; }
|
|
|
|
|
void cutable(bool cutable) { m_cutable=cutable; }
|
|
|
|
|
void userp(void* user) { m_userp = user; }
|
|
|
|
|
void* userp() const { return m_userp; }
|
|
|
|
|
void user(uint32_t user) { m_user = user; }
|
|
|
|
|
uint32_t user() const { return m_user; }
|
|
|
|
|
V3GraphVertex* fromp() const { return m_fromp; }
|
|
|
|
|
V3GraphVertex* top() const { return m_top; }
|
|
|
|
|
// STATIC ACCESSORS
|
|
|
|
|
static bool followNotCutable(const V3GraphEdge* edgep) { return !edgep->m_cutable; }
|
|
|
|
|
static bool followAlwaysTrue(const V3GraphEdge*) { return true; }
|
|
|
|
|
// ITERATORS
|
|
|
|
|
V3GraphEdge* outNextp() const { return m_outs.nextp(); }
|
|
|
|
|
V3GraphEdge* inNextp() const { return m_ins.nextp(); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
|
|
#endif // Guard
|