Internals: Ordering internals realigned with thread branch.

This commit is contained in:
Wilson Snyder 2018-06-22 23:01:50 -04:00
parent 3444dad9ce
commit 2edfe7b8a8
2 changed files with 228 additions and 103 deletions

View File

@ -103,6 +103,9 @@
#include "V3OrderGraph.h"
#include "V3EmitV.h"
#include VL_INCLUDE_UNORDERED_MAP
#include VL_INCLUDE_UNORDERED_SET
class OrderMoveDomScope;
static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top);
@ -410,6 +413,187 @@ public:
bool isClkAss() { return m_clkAss; }
};
//######################################################################
// ProcessMoveBuildGraph
template <class T_MoveVertex>
class ProcessMoveBuildGraph {
// ProcessMoveBuildGraph takes as input the fine-grained graph of
// OrderLogicVertex, OrderVarVertex, etc; this is 'm_graph' in
// OrderVisitor. It produces a slightly coarsened graph to drive the
// code scheduling.
//
// * The new graph contains nodes of type OrderMoveVertex.
//
// * The difference in output type is abstracted away by the
// 'T_MoveVertex' template parameter.
// TYPES
typedef std::pair<const V3GraphVertex*, const AstSenTree*> VxDomPair;
// Maps an (original graph vertex, domain) pair to a T_MoveVertex
// Not vl_unordered_map, because std::pair doesn't provide std::hash
typedef std::map<VxDomPair, T_MoveVertex*> Var2Move;
typedef vl_unordered_map<const OrderLogicVertex*, T_MoveVertex*> Logic2Move;
public:
class MoveVertexMaker {
public:
// Clients of ProcessMoveBuildGraph must supply MoveVertexMaker
// which creates new T_MoveVertex's. Each new vertex wraps lvertexp
// (which may be NULL.)
virtual T_MoveVertex* makeVertexp(OrderLogicVertex* lvertexp,
const OrderEitherVertex* varVertexp,
const AstScope* scopep,
const AstSenTree* domainp) = 0;
virtual void freeVertexp(T_MoveVertex* freeMep) = 0;
};
private:
// MEMBERS
const V3Graph* m_graphp; // Input graph of OrderLogicVertex's etc
V3Graph* m_outGraphp; // Output graph of T_MoveVertex's
MoveVertexMaker* m_vxMakerp; // Factory class for T_MoveVertex's
Logic2Move m_logic2move; // Map Logic to Vertex
Var2Move m_var2move; // Map Vars to Vertex
public:
// CONSTRUCTORS
ProcessMoveBuildGraph(const V3Graph* logicGraphp, // Input graph of OrderLogicVertex etc.
V3Graph* outGraphp, // Output graph of T_MoveVertex's
MoveVertexMaker* vxMakerp)
: m_graphp(logicGraphp),
m_outGraphp(outGraphp),
m_vxMakerp(vxMakerp) {}
virtual ~ProcessMoveBuildGraph() {}
// METHODS
void build() {
// How this works:
// - Create a T_MoveVertex for each OrderLogicVertex.
// - Following each OrderLogicVertex, search forward in the context of
// its domain...
// * If we encounter another OrderLogicVertex in non-exclusive
// domain, make the T_MoveVertex->T_MoveVertex edge.
// * If we encounter an OrderVarVertex, make a Vertex for the
// (OrderVarVertex, domain) pair and continue to search
// forward in the context of the same domain. Unless we
// already created that pair, in which case, we've already
// done the forward search, so stop.
// For each logic node, make a T_MoveVertex
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp;
itp=itp->verticesNextp()) {
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
T_MoveVertex* moveVxp =
m_vxMakerp->makeVertexp(lvertexp, NULL, lvertexp->scopep(),
lvertexp->domainp());
if (moveVxp) {
// Cross link so we can find it later
m_logic2move[lvertexp] = moveVxp;
}
}
}
// Build edges between logic vertices
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp;
itp=itp->verticesNextp()) {
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
T_MoveVertex* moveVxp = m_logic2move[lvertexp];
if (moveVxp) {
iterate(moveVxp, lvertexp, lvertexp->domainp());
}
}
}
}
private:
// Return true if moveVxp has downstream dependencies
bool iterate(T_MoveVertex* moveVxp, const V3GraphVertex* origVxp,
const AstSenTree* domainp) {
bool madeDeps = false;
// Search forward from given original vertex, making new edges from
// moveVxp forward
for (V3GraphEdge* edgep = origVxp->outBeginp(); edgep; edgep=edgep->outNextp()) {
if (edgep->weight()==0) { // Was cut
continue;
}
int weight = edgep->weight();
if (const OrderLogicVertex* toLVertexp =
dynamic_cast<const OrderLogicVertex*>(edgep->top())) {
// Do not construct dependencies across exclusive domains.
if (domainsExclusive(domainp, toLVertexp->domainp())) continue;
// Path from vertexp to a logic vertex; new edge.
// Note we use the last edge's weight, not some function of
// multiple edges
new OrderEdge(m_outGraphp, moveVxp,
m_logic2move[toLVertexp], weight);
madeDeps = true;
} else {
// This is an OrderVarVertex or other vertex representing
// data. (Could be var, settle, or input type vertex.)
const V3GraphVertex* nonLogicVxp = edgep->top();
VxDomPair key(nonLogicVxp, domainp);
if (!m_var2move[key]) {
const OrderEitherVertex* eithp =
dynamic_cast<const OrderEitherVertex*>(nonLogicVxp);
T_MoveVertex* newMoveVxp =
m_vxMakerp->makeVertexp(NULL, eithp, eithp->scopep(), domainp);
m_var2move[key] = newMoveVxp;
// Find downstream logics that depend on (var, domain)
if (!iterate(newMoveVxp, edgep->top(), domainp)) {
// No downstream dependencies, so remove this
// intermediate vertex.
m_var2move[key] = NULL;
m_vxMakerp->freeVertexp(newMoveVxp);
continue;
}
}
// Create incoming edge, from previous logic that writes
// this var, to the Vertex representing the (var,domain)
new OrderEdge(m_outGraphp, moveVxp, m_var2move[key], weight);
madeDeps = true;
}
}
return madeDeps;
}
VL_UNCOPYABLE(ProcessMoveBuildGraph);
};
//######################################################################
// OrderMoveVertexMaker
class OrderMoveVertexMaker
: public ProcessMoveBuildGraph<OrderMoveVertex>::MoveVertexMaker {
// MEMBERS
V3Graph* m_pomGraphp;
V3List<OrderMoveVertex*>* m_pomWaitingp;
public:
// CONSTRUCTORS
OrderMoveVertexMaker(V3Graph* pomGraphp,
V3List<OrderMoveVertex*>* pomWaitingp)
: m_pomGraphp(pomGraphp),
m_pomWaitingp(pomWaitingp) {}
// METHODS
OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp,
const OrderEitherVertex*,
const AstScope* scopep,
const AstSenTree* domainp) {
OrderMoveVertex* resultp =
new OrderMoveVertex(m_pomGraphp, lvertexp);
resultp->domScopep(OrderMoveDomScope::findCreate(domainp, scopep));
resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp);
return resultp;
}
void freeVertexp(OrderMoveVertex* freeMep) {
freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep);
freeMep->unlinkDelete(m_pomGraphp);
}
private:
VL_UNCOPYABLE(OrderMoveVertexMaker);
};
//######################################################################
// Order class functions
@ -520,8 +704,6 @@ private:
void processMove();
void processMoveClear();
void processMoveBuildGraph();
void processMoveBuildGraphIterate (OrderMoveVertex* moveVxp, V3GraphVertex* vertexp, int weightmin);
void processMovePrepScopes();
void processMovePrepReady();
void processMoveReadyOne(OrderMoveVertex* vertexp);
void processMoveDoneOne(OrderMoveVertex* vertexp);
@ -1044,6 +1226,26 @@ static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top) {
return fromSenListp->edgeType().exclusiveEdge(toSenListp->edgeType());
}
//######################################################################
// OrderMoveDomScope methods
// Check the domScope is on ready list, add if not
inline void OrderMoveDomScope::ready(OrderVisitor* ovp) {
if (!m_onReadyList) {
m_onReadyList = true;
m_readyDomScopeE.pushBack(ovp->m_pomReadyDomScope, this);
}
}
// Mark one vertex as finished, remove from ready list if done
inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* vertexp) {
UASSERT(m_onReadyList, "Moving vertex from ready when nothing was on que as ready.");
if (m_readyVertices.empty()) { // Else more work to get to later
m_onReadyList = false;
m_readyDomScopeE.unlink(ovp->m_pomReadyDomScope, this);
}
}
//######################################################################
// OrderVisitor - Clock propagation
@ -1340,60 +1542,10 @@ void OrderVisitor::processMoveBuildGraph() {
processMoveClear();
m_pomGraph.userClearVertices(); // Vertex::user() // OrderMoveVertex*, last edge added or NULL for none
// For each logic node, make a graph node
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
OrderMoveVertex* moveVxp = new OrderMoveVertex(&m_pomGraph, lvertexp);
moveVxp->m_pomWaitingE.pushBack(m_pomWaiting, moveVxp);
// Cross link so we can find it later
lvertexp->moveVxp(moveVxp);
}
}
// Build edges between logic vertices
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
OrderMoveVertex* moveVxp = lvertexp->moveVxp();
processMoveBuildGraphIterate(moveVxp, lvertexp, 0);
}
}
}
void OrderVisitor::processMoveBuildGraphIterate (OrderMoveVertex* moveVxp, V3GraphVertex* vertexp, int weightmin) {
// Search forward from given logic vertex, making new edges based on moveVxp
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
if (edgep->weight()!=0) { // was cut
int weight = weightmin;
if (weight==0 || weight>edgep->weight()) weight=edgep->weight();
if (OrderLogicVertex* toLVertexp = dynamic_cast<OrderLogicVertex*>(edgep->top())) {
// "Initial" and "settle" domains run at time 0 and never
// again. Everything else runs at time >0 and never before.
// Ignore deps that cross the time-zero/nonzero boundary.
// We'll never run both vertices in the same eval() pass
// so there's no need to order them.
bool toInitial = (toLVertexp->domainp()->hasInitial()
|| toLVertexp->domainp()->hasSettle());
bool fromInitial = (moveVxp->logicp()->domainp()->hasInitial()
|| moveVxp->logicp()->domainp()->hasSettle());
if (toInitial != fromInitial) {
continue;
}
// Sometimes we get deps between 'always @(posedge clk)' and
// 'always @(negedge clk)' domains. Discard these. We'll never
// evaluate both logic vertices on the same eval() pass so
// there's no need to order them.
if (domainsExclusive(moveVxp->logicp()->domainp(),
toLVertexp->domainp())) {
continue;
}
// Path from vertexp to a logic vertex; new edge
// Note we use the last edge's weight, not some function of multiple edges
new OrderEdge(&m_pomGraph, moveVxp, toLVertexp->moveVxp(), weight);
}
else { // Keep hunting forward for a logic node
processMoveBuildGraphIterate(moveVxp, edgep->top(), weight);
}
}
}
OrderMoveVertexMaker createOrderMoveVertex(&m_pomGraph, &m_pomWaiting);
ProcessMoveBuildGraph<OrderMoveVertex> serialPMBG(
&m_graph, &m_pomGraph, &createOrderMoveVertex);
serialPMBG.build();
}
//######################################################################
@ -1412,7 +1564,6 @@ void OrderVisitor::processMove() {
// Move logic to ordered active
// Any children that have all inputs now ready move from waiting->ready graph
// (This may add nodes the for loop directly above needs to detext)
processMovePrepScopes();
processMovePrepReady();
// New domain... another loop
@ -1447,18 +1598,6 @@ void OrderVisitor::processMove() {
processMoveClear();
}
void OrderVisitor::processMovePrepScopes() {
UINFO(5," MovePrepScopes\n");
// Create a OrderMoveDomScope every domain/scope pairing
for (OrderMoveVertex* vertexp = m_pomWaiting.begin(); vertexp; vertexp=vertexp->pomWaitingNextp()) {
AstSenTree* domainp = vertexp->logicp()->domainp();
AstScope* scopep = vertexp->logicp()->scopep();
// Create the dom pairing for later lookup
OrderMoveDomScope* domScopep = OrderMoveDomScope::findCreate(domainp, scopep);
vertexp->domScopep(domScopep);
}
}
void OrderVisitor::processMovePrepReady() {
// Make list of ready nodes
UINFO(5," MovePrepReady\n");
@ -1477,17 +1616,25 @@ void OrderVisitor::processMoveReadyOne(OrderMoveVertex* vertexp) {
vertexp->setReady();
// Remove node from waiting list
vertexp->m_pomWaitingE.unlink(m_pomWaiting, vertexp);
// Add to ready list (indexed by domain and scope)
vertexp->m_readyVerticesE.pushBack(vertexp->domScopep()->m_readyVertices, vertexp);
vertexp->domScopep()->ready(this);
if (vertexp->logicp()) {
// Add to ready list (indexed by domain and scope)
vertexp->m_readyVerticesE.pushBack(vertexp->domScopep()->m_readyVertices, vertexp);
vertexp->domScopep()->ready(this);
} else {
// vertexp represents a non-logic vertex.
// Recurse to mark its following neighbors ready.
processMoveDoneOne(vertexp);
}
}
void OrderVisitor::processMoveDoneOne(OrderMoveVertex* vertexp) {
// Move one node from ready to completion
vertexp->setMoved();
// Unlink from ready lists
vertexp->m_readyVerticesE.unlink(vertexp->domScopep()->m_readyVertices, vertexp);
vertexp->domScopep()->movedVertex(this, vertexp);
if (vertexp->logicp()) {
vertexp->m_readyVerticesE.unlink(vertexp->domScopep()->m_readyVertices, vertexp);
vertexp->domScopep()->movedVertex(this, vertexp);
}
// Don't need to add it to another list, as we're done with it
// Mark our outputs as one closer to ready
for (V3GraphEdge* edgep = vertexp->outBeginp(), *nextp; edgep; edgep=nextp) {
@ -1573,23 +1720,6 @@ AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp,
return activep;
}
// Check the domScope is on ready list, add if not
inline void OrderMoveDomScope::ready(OrderVisitor* ovp) {
if (!m_onReadyList) {
m_onReadyList = true;
m_readyDomScopeE.pushBack(ovp->m_pomReadyDomScope, this);
}
}
// Mark one vertex as finished, remove from ready list if done
inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* vertexp) {
UASSERT(m_onReadyList, "Moving vertex from ready when nothing was on que as ready.");
if (m_readyVertices.empty()) { // Else more work to get to later
m_onReadyList = false;
m_readyDomScopeE.unlink(ovp->m_pomReadyDomScope, this);
}
}
//######################################################################
// OrderVisitor - Top processing

View File

@ -50,6 +50,7 @@
class OrderVisitor;
class OrderMoveVertex;
class OrderMoveVertexMaker;
class OrderMoveDomScope;
//######################################################################
@ -188,13 +189,12 @@ public:
class OrderLogicVertex : public OrderEitherVertex {
AstNode* m_nodep;
OrderMoveVertex* m_moveVxp;
protected:
OrderLogicVertex(V3Graph* graphp, const OrderLogicVertex& old)
: OrderEitherVertex(graphp, old), m_nodep(old.m_nodep), m_moveVxp(old.m_moveVxp) {}
: OrderEitherVertex(graphp, old), m_nodep(old.m_nodep) {}
public:
OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstNode* nodep)
: OrderEitherVertex(graphp, scopep, domainp), m_nodep(nodep), m_moveVxp(NULL) {}
: OrderEitherVertex(graphp, scopep, domainp), m_nodep(nodep) {}
virtual ~OrderLogicVertex() {}
virtual OrderLogicVertex* clone(V3Graph* graphp) const {
return new OrderLogicVertex(graphp, *this); }
@ -204,8 +204,6 @@ public:
virtual string name() const { return (cvtToStr((void*)m_nodep)+"\\n "+cvtToStr(nodep()->typeName())); }
AstNode* nodep() const { return m_nodep; }
virtual string dotColor() const { return "yellow"; }
OrderMoveVertex* moveVxp() const { return m_moveVxp; }
void moveVxp(OrderMoveVertex* moveVxp) { m_moveVxp = moveVxp; }
};
class OrderVarVertex : public OrderEitherVertex {
@ -315,21 +313,18 @@ class OrderMoveVertex : public V3GraphVertex {
protected:
friend class OrderVisitor;
friend class OrderMoveVertexMaker;
// These only contain the "next" item,
// for the head of the list, see the same var name under OrderVisitor
V3ListEnt<OrderMoveVertex*> m_pomWaitingE; // List of nodes needing inputs to become ready
V3ListEnt<OrderMoveVertex*> m_readyVerticesE;// List of ready under domain/scope
// CONSTRUCTORS
OrderMoveVertex(V3Graph* graphp, const OrderMoveVertex& old)
: V3GraphVertex(graphp, old), m_logicp(old.m_logicp), m_state(old.m_state)
, m_domScopep(old.m_domScopep) {}
public:
// CONSTRUCTORS
OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp)
: V3GraphVertex(graphp), m_logicp(logicp), m_state(POM_WAIT), m_domScopep(NULL) {}
: V3GraphVertex(graphp), m_logicp(logicp), m_state(POM_WAIT), m_domScopep(NULL) {}
virtual ~OrderMoveVertex() {}
virtual OrderMoveVertex* clone(V3Graph* graphp) const {
return new OrderMoveVertex(graphp, *this);
}
v3fatalSrc("Unsupported"); return NULL; }
// METHODS
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; }
virtual string dotColor() const {