From 2edfe7b8a805fad817764d5ca5aeb2b7b1881002 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 22 Jun 2018 23:01:50 -0400 Subject: [PATCH] Internals: Ordering internals realigned with thread branch. --- src/V3Order.cpp | 312 ++++++++++++++++++++++++++++++++------------- src/V3OrderGraph.h | 19 +-- 2 files changed, 228 insertions(+), 103 deletions(-) diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 135e80ed7..ac98faa97 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -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 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 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 Var2Move; + typedef vl_unordered_map 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(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(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(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(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::MoveVertexMaker { + // MEMBERS + V3Graph* m_pomGraphp; + V3List* m_pomWaitingp; +public: + // CONSTRUCTORS + OrderMoveVertexMaker(V3Graph* pomGraphp, + V3List* 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(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(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(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 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 diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index 13dcaca15..e08f1fab4 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -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 m_pomWaitingE; // List of nodes needing inputs to become ready V3ListEnt 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 {