V3Order: Minor refactoring for clarity

Refactor ProcessMoveBuildGraph utilizing the fact that OrderGraph is a
bipartite graph, also remove unnecessary unordered_map and distribute
variable domain map. No functional change.
This commit is contained in:
Geza Lore 2022-08-25 15:17:38 +01:00
parent 8de21e9bb7
commit 546aeab9f2
1 changed files with 69 additions and 82 deletions

View File

@ -542,10 +542,9 @@ inline std::ostream& operator<<(std::ostream& lhs, const OrderMoveDomScope& rhs)
template <class T_MoveVertex>
class ProcessMoveBuildGraph final {
// 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.
// ProcessMoveBuildGraph takes as input the fine-grained bipartite OrderGraph of
// OrderLogicVertex and OrderVarVertex vertices. It produces a slightly coarsened graph to
// drive the code scheduling.
//
// * For the serial code scheduler, the new graph contains
// nodes of type OrderMoveVertex.
@ -561,8 +560,7 @@ class ProcessMoveBuildGraph final {
// AstSenTree::user1p() -> AstSenTree: Original AstSenTree for trigger
// TYPES
using VxDomPair = std::pair<const V3GraphVertex*, const AstSenTree*>;
using Logic2Move = std::unordered_map<const OrderLogicVertex*, T_MoveVertex*>;
using DomainMap = std::map<const AstSenTree*, T_MoveVertex*>;
public:
class MoveVertexMaker VL_NOT_FINAL {
@ -574,31 +572,28 @@ public:
const OrderEitherVertex* varVertexp,
const AstSenTree* domainp)
= 0;
virtual void freeVertexp(T_MoveVertex* freeMep) = 0;
};
private:
// MEMBERS
const V3Graph* m_graphp; // Input graph of OrderLogicVertex's etc
const OrderGraph* const m_graphp; // Input OrderGraph
V3Graph* const m_outGraphp; // Output graph of T_MoveVertex vertices
// Map from Trigger reference AstSenItem to the original AstSenTree
const std::unordered_map<const AstSenItem*, const AstSenTree*>& m_trigToSen;
V3Graph* m_outGraphp; // Output graph of T_MoveVertex's
MoveVertexMaker* const m_vxMakerp; // Factory class for T_MoveVertex's
Logic2Move m_logic2move; // Map Logic to Vertex
// Maps an (original graph vertex, domain) pair to a T_MoveVertex
// Not std::unordered_map, because std::pair doesn't provide std::hash
std::map<VxDomPair, T_MoveVertex*> m_var2move;
// Storage for domain -> T_MoveVertex, maps held in OrderVarVertex::userp()
std::deque<DomainMap> m_domainMaps;
public:
// CONSTRUCTORS
ProcessMoveBuildGraph(
const V3Graph* logicGraphp, // Input graph of OrderLogicVertex etc.
const std::unordered_map<const AstSenItem*, const AstSenTree*>& trigToSen,
const OrderGraph* logicGraphp, // Input graph of OrderLogicVertex etc.
V3Graph* outGraphp, // Output graph of T_MoveVertex's
const std::unordered_map<const AstSenItem*, const AstSenTree*>& trigToSen,
MoveVertexMaker* vxMakerp)
: m_graphp{logicGraphp}
, m_trigToSen{trigToSen}
, m_outGraphp{outGraphp}
, m_trigToSen{trigToSen}
, m_vxMakerp{vxMakerp} {}
virtual ~ProcessMoveBuildGraph() = default;
@ -616,22 +611,20 @@ public:
// 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 each logic vertex, make a T_MoveVertex, for each variable vertex, allocate storage
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (OrderLogicVertex* const lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
T_MoveVertex* const moveVxp
= m_vxMakerp->makeVertexp(lvertexp, nullptr, lvertexp->domainp());
if (moveVxp) {
// Cross link so we can find it later
m_logic2move[lvertexp] = moveVxp;
}
if (OrderLogicVertex* const lvtxp = dynamic_cast<OrderLogicVertex*>(itp)) {
lvtxp->userp(m_vxMakerp->makeVertexp(lvtxp, nullptr, lvtxp->domainp()));
} else {
// This is an OrderVarVertex
m_domainMaps.emplace_back();
itp->userp(&m_domainMaps.back());
}
}
// Build edges between logic vertices
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (OrderLogicVertex* const lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
T_MoveVertex* const moveVxp = m_logic2move[lvertexp];
if (moveVxp) iterate(moveVxp, lvertexp, lvertexp->domainp());
if (OrderLogicVertex* const lvtxp = dynamic_cast<OrderLogicVertex*>(itp)) {
iterateLogicVertex(lvtxp);
}
}
}
@ -695,61 +688,62 @@ private:
return fromSenItemp->edgeType().exclusiveEdge(toSenItemp->edgeType());
}
// Return true if moveVxp has downstream dependencies
bool iterate(T_MoveVertex* moveVxp, const V3GraphVertex* origVxp, 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;
}
const int weight = edgep->weight();
if (const OrderLogicVertex* const toLVertexp
= dynamic_cast<const OrderLogicVertex*>(edgep->top())) {
void iterateLogicVertex(const OrderLogicVertex* lvtxp) {
AstSenTree* const domainp = lvtxp->domainp();
T_MoveVertex* const lMoveVtxp = static_cast<T_MoveVertex*>(lvtxp->userp());
// Search forward from lvtxp, making new edges from lMoveVtxp forward
for (V3GraphEdge* edgep = lvtxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (edgep->weight() == 0) continue; // Was cut
// Do not construct dependencies across exclusive domains.
if (domainsExclusive(domainp, toLVertexp->domainp())) continue;
// OrderGraph is a bipartite graph, so we know it's an OrderVarVertex
const OrderVarVertex* const vvtxp = static_cast<const OrderVarVertex*>(edgep->top());
// Path from vertexp to a logic vertex; new edge.
// Note we use the last edge's weight, not some function of
// multiple edges
new V3GraphEdge(m_outGraphp, moveVxp, m_logic2move[toLVertexp], weight);
madeDeps = true;
} else {
// This is an OrderVarVertex.
const V3GraphVertex* nonLogicVxp = edgep->top();
const VxDomPair key(nonLogicVxp, domainp);
if (!m_var2move[key]) {
const OrderVarVertex* const eithp
= static_cast<const OrderVarVertex*>(nonLogicVxp);
T_MoveVertex* const newMoveVxp
= m_vxMakerp->makeVertexp(nullptr, eithp, domainp);
m_var2move[key] = newMoveVxp;
// Look up T_MoveVertex for this domain on this variable
DomainMap& mapp = *static_cast<DomainMap*>(vvtxp->userp());
const auto pair = mapp.emplace(domainp, nullptr);
// Reference to the mapped T_MoveVertex
T_MoveVertex*& vMoveVtxp = pair.first->second;
// 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] = nullptr;
m_vxMakerp->freeVertexp(newMoveVxp);
continue;
}
}
// On first encounter, visit downstream logic dependent on this (var, domain)
if (pair.second) vMoveVtxp = iterateVarVertex(vvtxp, domainp);
// Create incoming edge, from previous logic that writes
// this var, to the Vertex representing the (var,domain)
new V3GraphEdge(m_outGraphp, moveVxp, m_var2move[key], weight);
madeDeps = true;
}
// If no downstream dependents from this variable, then there is no need to add this
// variable as a dependent.
if (!vMoveVtxp) continue;
// Add this (variable, domain) as dependent of the logic that writes it.
new V3GraphEdge{m_outGraphp, lMoveVtxp, vMoveVtxp, 1};
}
return madeDeps;
}
// Return the T_MoveVertex for this (var, domain) pair, iff it has downstream dependencies,
// otherwise return nullptr.
T_MoveVertex* iterateVarVertex(const OrderVarVertex* vvtxp, AstSenTree* domainp) {
T_MoveVertex* vMoveVtxp = nullptr;
// Search forward from vvtxp, making new edges from vMoveVtxp forward
for (V3GraphEdge* edgep = vvtxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (edgep->weight() == 0) continue; // Was cut
// OrderGraph is a bipartite graph, so we know it's an OrderLogicVertex
const OrderLogicVertex* const lvtxp
= static_cast<const OrderLogicVertex*>(edgep->top());
// Do not construct dependencies across exclusive domains.
if (domainsExclusive(domainp, lvtxp->domainp())) continue;
// there is a path from this vvtx to a logic vertex. Add the new edge.
if (!vMoveVtxp) vMoveVtxp = m_vxMakerp->makeVertexp(nullptr, vvtxp, domainp);
T_MoveVertex* const lMoveVxp = static_cast<T_MoveVertex*>(lvtxp->userp());
new V3GraphEdge{m_outGraphp, vMoveVtxp, lMoveVxp, 1};
}
return vMoveVtxp;
}
VL_UNCOPYABLE(ProcessMoveBuildGraph);
};
//######################################################################
// OrderMoveVertexMaker and related
// ######################################################################
// OrderMoveVertexMaker and related
class OrderMoveVertexMaker final : public ProcessMoveBuildGraph<OrderMoveVertex>::MoveVertexMaker {
// MEMBERS
@ -770,10 +764,6 @@ public:
resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp);
return resultp;
}
virtual void freeVertexp(OrderMoveVertex* freeMep) override {
freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep);
freeMep->unlinkDelete(m_pomGraphp);
}
private:
VL_UNCOPYABLE(OrderMoveVertexMaker);
@ -791,9 +781,6 @@ public:
const AstSenTree* domainp) override {
return new MTaskMoveVertex(m_pomGraphp, lvertexp, varVertexp, domainp);
}
virtual void freeVertexp(MTaskMoveVertex* freeMep) override {
freeMep->unlinkDelete(m_pomGraphp);
}
private:
VL_UNCOPYABLE(OrderMTaskMoveVertexMaker);
@ -1109,7 +1096,7 @@ void OrderProcess::processMoveBuildGraph() {
m_pomGraph.userClearVertices();
OrderMoveVertexMaker createOrderMoveVertex(&m_pomGraph, &m_pomWaiting);
ProcessMoveBuildGraph<OrderMoveVertex> serialPMBG(&m_graph, m_trigToSen, &m_pomGraph,
ProcessMoveBuildGraph<OrderMoveVertex> serialPMBG(&m_graph, &m_pomGraph, m_trigToSen,
&createOrderMoveVertex);
serialPMBG.build();
}
@ -1326,7 +1313,7 @@ void OrderProcess::processMTasks() {
// This is quite similar to the 'm_pomGraph' of the serial code gen:
V3Graph logicGraph;
OrderMTaskMoveVertexMaker create_mtask_vertex(&logicGraph);
ProcessMoveBuildGraph<MTaskMoveVertex> mtask_pmbg(&m_graph, m_trigToSen, &logicGraph,
ProcessMoveBuildGraph<MTaskMoveVertex> mtask_pmbg(&m_graph, &logicGraph, m_trigToSen,
&create_mtask_vertex);
mtask_pmbg.build();