mirror of
https://github.com/verilator/verilator.git
synced 2025-01-03 21:27:35 +00:00
Internals: Use runtime type info instead of dynamic_cast
for faster graph type checks (#4397)
This commit is contained in:
parent
96ee81fa3f
commit
ffbbd438ae
@ -47,6 +47,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
// Extend V3GraphVertex class for use in latch detection graph
|
||||
|
||||
class LatchDetectGraphVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(LatchDetectGraphVertex, V3GraphVertex)
|
||||
public:
|
||||
enum VertexType : uint8_t { VT_BLOCK, VT_BRANCH, VT_OUTPUT };
|
||||
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
// Support classes
|
||||
|
||||
class GateEitherVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(GateEitherVertex, V3GraphVertex)
|
||||
AstScope* const m_scopep; // Scope vertex refers to
|
||||
bool m_reducible = true; // True if this node should be able to be eliminated
|
||||
bool m_dedupable = true; // True if this node should be able to be deduped
|
||||
@ -122,6 +123,7 @@ public:
|
||||
};
|
||||
|
||||
class GateVarVertex final : public GateEitherVertex {
|
||||
VL_RTTI_IMPL(GateVarVertex, GateEitherVertex)
|
||||
AstVarScope* const m_varScp;
|
||||
bool m_isTop = false;
|
||||
bool m_isClock = false;
|
||||
@ -164,6 +166,7 @@ public:
|
||||
};
|
||||
|
||||
class GateLogicVertex final : public GateEitherVertex {
|
||||
VL_RTTI_IMPL(GateLogicVertex, GateEitherVertex)
|
||||
AstNode* const m_nodep;
|
||||
AstActive* const m_activep; // Under what active; nullptr is ok (under cfunc or such)
|
||||
const bool m_slow; // In slow block
|
||||
@ -568,7 +571,7 @@ public:
|
||||
|
||||
void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp);
|
||||
GateVarVertex* const vvertexp = itp->cast<GateVarVertex>();
|
||||
|
||||
// Consider "inlining" variables
|
||||
if (!vvertexp) continue;
|
||||
@ -710,7 +713,7 @@ void GateVisitor::consumedMove() {
|
||||
// We need the "usually" block logic to do a better job at this
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(vertexp)) {
|
||||
if (const GateVarVertex* const vvertexp = vertexp->cast<GateVarVertex>()) {
|
||||
if (!vvertexp->consumed() && !vvertexp->user()) {
|
||||
UINFO(8, "Unconsumed " << vvertexp->varScp() << endl);
|
||||
}
|
||||
@ -734,7 +737,7 @@ void GateVisitor::consumedMove() {
|
||||
void GateVisitor::warnSignals() {
|
||||
AstNode::user2ClearTree();
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (const GateVarVertex* const vvertexp = itp->cast<GateVarVertex>()) {
|
||||
const AstVarScope* const vscp = vvertexp->varScp();
|
||||
const AstNode* const sp = vvertexp->rstSyncNodep();
|
||||
const AstNode* const ap = vvertexp->rstAsyncNodep();
|
||||
@ -1136,14 +1139,14 @@ void GateVisitor::dedupe() {
|
||||
// Traverse starting from each of the clocks
|
||||
UINFO(9, "Gate dedupe() clocks:\n");
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vvertexp = itp->cast<GateVarVertex>()) {
|
||||
if (vvertexp->isClock()) deduper.dedupeTree(vvertexp);
|
||||
}
|
||||
}
|
||||
// Traverse starting from each of the outputs
|
||||
UINFO(9, "Gate dedupe() outputs:\n");
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vvertexp = itp->cast<GateVarVertex>()) {
|
||||
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isWritable()) {
|
||||
deduper.dedupeTree(vvertexp);
|
||||
}
|
||||
@ -1187,8 +1190,7 @@ private:
|
||||
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) {
|
||||
V3GraphEdge* oldedgep = edgep;
|
||||
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
|
||||
if (GateLogicVertex* const lvertexp
|
||||
= dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
|
||||
if (GateLogicVertex* const lvertexp = oldedgep->fromp()->cast<GateLogicVertex>()) {
|
||||
if (AstNodeAssign* const assignp = VN_CAST(lvertexp->nodep(), NodeAssign)) {
|
||||
// if (lvertexp->outSize1() && VN_IS(assignp->lhsp(), Sel)) {
|
||||
if (VN_IS(assignp->lhsp(), Sel) && lvertexp->outSize1()) {
|
||||
@ -1274,7 +1276,7 @@ void GateVisitor::mergeAssigns() {
|
||||
UINFO(6, "mergeAssigns\n");
|
||||
GateMergeAssignsGraphVisitor merger{&m_graph};
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vvertexp = itp->cast<GateVarVertex>()) {
|
||||
merger.mergeAssignsTree(vvertexp);
|
||||
}
|
||||
}
|
||||
@ -1460,7 +1462,7 @@ void GateVisitor::decomposeClkVectors() {
|
||||
AstNode::user2ClearTree();
|
||||
GateClkDecompGraphVisitor decomposer{&m_graph};
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (GateVarVertex* const vertp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
if (GateVarVertex* const vertp = itp->cast<GateVarVertex>()) {
|
||||
const AstVarScope* const vsp = vertp->varScp();
|
||||
if (vsp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
|
||||
if (vsp->varp()->width() > 1) {
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3List.h"
|
||||
#include "V3Rtti.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -173,6 +174,7 @@ public:
|
||||
//============================================================================
|
||||
|
||||
class V3GraphVertex VL_NOT_FINAL {
|
||||
VL_RTTI_IMPL_BASE(V3GraphVertex)
|
||||
// Vertices may be a 'gate'/wire statement OR a variable
|
||||
protected:
|
||||
friend class V3Graph;
|
||||
@ -209,6 +211,40 @@ public:
|
||||
void unlinkEdges(V3Graph* graphp);
|
||||
void unlinkDelete(V3Graph* graphp);
|
||||
|
||||
// METHODS
|
||||
// Return true iff of type T
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
static_assert(std::is_base_of<V3GraphVertex, T>::value,
|
||||
"'T' must be a subtype of V3GraphVertex");
|
||||
static_assert(std::is_same<typename std::remove_cv<T>::type,
|
||||
VTypeListFront<typename T::RttiThisAndBaseClassesList>>::value,
|
||||
"Missing VL_RTTI_IMPL(...) call in 'T'");
|
||||
return this->isInstanceOfClassWithId(T::rttiClassId());
|
||||
}
|
||||
|
||||
// Return cast to subtype T and assert of that type
|
||||
template <typename T>
|
||||
T* as() {
|
||||
UASSERT_OBJ(is<T>(), this, "V3GraphVertex is not of expected type");
|
||||
return static_cast<T*>(this);
|
||||
}
|
||||
template <typename T>
|
||||
const T* as() const {
|
||||
UASSERT_OBJ(is<T>(), this, "V3GraphVertex is not of expected type");
|
||||
return static_cast<const T*>(this);
|
||||
}
|
||||
|
||||
// Return cast to subtype T, else nullptr if different type
|
||||
template <typename T>
|
||||
T* cast() {
|
||||
return is<T>() ? static_cast<T*>(this) : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
const T* cast() const {
|
||||
return is<T>() ? static_cast<const T*>(this) : nullptr;
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
virtual string name() const { return ""; }
|
||||
virtual string dotColor() const { return "black"; }
|
||||
@ -262,6 +298,7 @@ std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp);
|
||||
//============================================================================
|
||||
|
||||
class V3GraphEdge VL_NOT_FINAL {
|
||||
VL_RTTI_IMPL_BASE(V3GraphEdge)
|
||||
// Wires/variables aren't edges. Edges have only a single to/from vertex
|
||||
public:
|
||||
// ENUMS
|
||||
@ -308,6 +345,39 @@ public:
|
||||
}
|
||||
virtual ~V3GraphEdge() = default;
|
||||
// METHODS
|
||||
// Return true iff of type T
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
static_assert(std::is_base_of<V3GraphEdge, T>::value,
|
||||
"'T' must be a subtype of V3GraphEdge");
|
||||
static_assert(std::is_same<typename std::remove_cv<T>::type,
|
||||
VTypeListFront<typename T::RttiThisAndBaseClassesList>>::value,
|
||||
"Missing VL_RTTI_IMPL(...) call in 'T'");
|
||||
return this->isInstanceOfClassWithId(T::rttiClassId());
|
||||
}
|
||||
|
||||
// Return cast to subtype T and assert of that type
|
||||
template <typename T>
|
||||
T* as() {
|
||||
UASSERT(is<T>(), "V3GraphEdge is not of expected type");
|
||||
return static_cast<T*>(this);
|
||||
}
|
||||
template <typename T>
|
||||
const T* as() const {
|
||||
UASSERT(is<T>(), "V3GraphEdge is not of expected type");
|
||||
return static_cast<const T*>(this);
|
||||
}
|
||||
|
||||
// Return cast to subtype T, else nullptr if different type
|
||||
template <typename T>
|
||||
T* cast() {
|
||||
return is<T>() ? static_cast<T*>(this) : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
const T* cast() const {
|
||||
return is<T>() ? static_cast<const T*>(this) : nullptr;
|
||||
}
|
||||
|
||||
virtual string name() const { return m_fromp->name() + "->" + m_top->name(); }
|
||||
virtual string dotLabel() const { return ""; }
|
||||
virtual string dotColor() const { return cutable() ? "yellowGreen" : "red"; }
|
||||
|
@ -32,6 +32,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
// Break the minimal number of backward edges to make the graph acyclic
|
||||
|
||||
class GraphAcycVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(GraphAcycVertex, V3GraphVertex)
|
||||
// user() is used for various sub-algorithm pieces
|
||||
V3GraphVertex* const m_origVertexp; // Pointer to first vertex this represents
|
||||
protected:
|
||||
@ -56,6 +57,7 @@ public:
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
class GraphAcycEdge final : public V3GraphEdge {
|
||||
VL_RTTI_IMPL(GraphAcycEdge, V3GraphEdge)
|
||||
// userp() is always used to point to the head original graph edge
|
||||
private:
|
||||
using OrigEdgeList = std::list<V3GraphEdge*>; // List of orig edges, see also GraphAcyc's decl
|
||||
|
@ -52,6 +52,7 @@ public:
|
||||
// Vertices and nodes
|
||||
|
||||
class V3GraphTestVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(V3GraphTestVertex, V3GraphVertex)
|
||||
const string m_name;
|
||||
|
||||
public:
|
||||
|
@ -333,7 +333,7 @@ private:
|
||||
}
|
||||
for (V3GraphVertex* mtaskVxp = nodep->depGraphp()->verticesBeginp(); mtaskVxp;
|
||||
mtaskVxp = mtaskVxp->verticesNextp()) {
|
||||
const ExecMTask* const mtaskp = dynamic_cast<ExecMTask*>(mtaskVxp);
|
||||
const ExecMTask* const mtaskp = mtaskVxp->as<ExecMTask>();
|
||||
m_execMTaskp = mtaskp;
|
||||
m_sequence = 0;
|
||||
iterate(mtaskp->bodyp());
|
||||
|
@ -52,6 +52,7 @@ public:
|
||||
};
|
||||
|
||||
class LinkCellsVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(LinkCellsVertex, V3GraphVertex)
|
||||
AstNodeModule* const m_modp;
|
||||
|
||||
public:
|
||||
@ -69,6 +70,7 @@ public:
|
||||
};
|
||||
|
||||
class LibraryVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(LibraryVertex, V3GraphVertex)
|
||||
public:
|
||||
explicit LibraryVertex(V3Graph* graphp)
|
||||
: V3GraphVertex{graphp} {}
|
||||
@ -77,7 +79,7 @@ public:
|
||||
};
|
||||
|
||||
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
|
||||
if (const LinkCellsVertex* const vvertexp = dynamic_cast<LinkCellsVertex*>(vertexp)) {
|
||||
if (const LinkCellsVertex* const vvertexp = vertexp->cast<LinkCellsVertex>()) {
|
||||
vvertexp->modp()->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Recursive multiple modules (module instantiates "
|
||||
"something leading back to itself): "
|
||||
@ -171,7 +173,7 @@ private:
|
||||
if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed("linkcells");
|
||||
m_graph.rank();
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (const LinkCellsVertex* const vvertexp = dynamic_cast<LinkCellsVertex*>(itp)) {
|
||||
if (const LinkCellsVertex* const vvertexp = itp->cast<LinkCellsVertex>()) {
|
||||
// +1 so we leave level 1 for the new wrapper we'll make in a moment
|
||||
AstNodeModule* const modp = vvertexp->modp();
|
||||
modp->level(vvertexp->rank() + 1);
|
||||
|
@ -597,7 +597,7 @@ public:
|
||||
|
||||
// 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 lvtxp = dynamic_cast<OrderLogicVertex*>(itp)) {
|
||||
if (OrderLogicVertex* const lvtxp = itp->cast<OrderLogicVertex>()) {
|
||||
lvtxp->userp(m_vxMakerp->makeVertexp(lvtxp, nullptr, lvtxp->domainp()));
|
||||
} else {
|
||||
// This is an OrderVarVertex
|
||||
@ -607,7 +607,7 @@ public:
|
||||
}
|
||||
// Build edges between logic vertices
|
||||
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (OrderLogicVertex* const lvtxp = dynamic_cast<OrderLogicVertex*>(itp)) {
|
||||
if (OrderLogicVertex* const lvtxp = itp->cast<OrderLogicVertex>()) {
|
||||
iterateLogicVertex(lvtxp);
|
||||
}
|
||||
}
|
||||
@ -941,8 +941,8 @@ void OrderMoveDomScope::movedVertex(OrderProcess* opp, OrderMoveVertex* vertexp)
|
||||
|
||||
void OrderProcess::processDomains() {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
OrderEitherVertex* const vertexp = dynamic_cast<OrderEitherVertex*>(itp);
|
||||
UASSERT(vertexp, "Null or vertex not derived from EitherVertex");
|
||||
UASSERT(itp, "Vertex should not be null");
|
||||
OrderEitherVertex* const vertexp = itp->as<OrderEitherVertex>();
|
||||
processDomainsIterate(vertexp);
|
||||
}
|
||||
}
|
||||
@ -958,7 +958,7 @@ void OrderProcess::processDomainsIterate(OrderEitherVertex* vertexp) {
|
||||
|
||||
UINFO(5, " pdi: " << vertexp << endl);
|
||||
AstSenTree* domainp = nullptr;
|
||||
if (OrderLogicVertex* const lvtxp = dynamic_cast<OrderLogicVertex*>(vertexp)) {
|
||||
if (OrderLogicVertex* const lvtxp = vertexp->cast<OrderLogicVertex>()) {
|
||||
domainp = lvtxp->hybridp();
|
||||
}
|
||||
|
||||
@ -970,7 +970,7 @@ void OrderProcess::processDomainsIterate(OrderEitherVertex* vertexp) {
|
||||
AstSenTree* fromDomainp = fromVertexp->domainp();
|
||||
UASSERT(!fromDomainp->hasCombo(), "There should be no need for combinational domains");
|
||||
|
||||
if (OrderVarVertex* const varVtxp = dynamic_cast<OrderVarVertex*>(fromVertexp)) {
|
||||
if (OrderVarVertex* const varVtxp = fromVertexp->cast<OrderVarVertex>()) {
|
||||
AstVarScope* const vscp = varVtxp->vscp();
|
||||
// Add in any external domains
|
||||
externalDomainps.clear();
|
||||
@ -1023,13 +1023,13 @@ void OrderProcess::processEdgeReport() {
|
||||
for (const auto& pair : m_trigToSen) trigToSen.emplace(*pair.first, pair.second);
|
||||
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (OrderVarVertex* const vvertexp = dynamic_cast<OrderVarVertex*>(itp)) {
|
||||
if (OrderVarVertex* const vvertexp = itp->cast<OrderVarVertex>()) {
|
||||
string name(vvertexp->vscp()->prettyName());
|
||||
if (dynamic_cast<OrderVarPreVertex*>(itp)) {
|
||||
if (itp->is<OrderVarPreVertex>()) {
|
||||
name += " {PRE}";
|
||||
} else if (dynamic_cast<OrderVarPostVertex*>(itp)) {
|
||||
} else if (itp->is<OrderVarPostVertex>()) {
|
||||
name += " {POST}";
|
||||
} else if (dynamic_cast<OrderVarPordVertex*>(itp)) {
|
||||
} else if (itp->is<OrderVarPordVertex>()) {
|
||||
name += " {PORD}";
|
||||
}
|
||||
std::ostringstream os;
|
||||
@ -1335,8 +1335,7 @@ void OrderProcess::processMTasks() {
|
||||
// information in V3EmitC when we lay out var's in memory.
|
||||
const OrderLogicVertex* const logicp = movep->logicp();
|
||||
for (const V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
const OrderVarVertex* const pre_varp
|
||||
= dynamic_cast<const OrderVarVertex*>(edgep->fromp());
|
||||
const OrderVarVertex* const pre_varp = edgep->fromp()->cast<const OrderVarVertex>();
|
||||
if (!pre_varp) continue;
|
||||
AstVar* const varp = pre_varp->vscp()->varp();
|
||||
// varp depends on logicp, so logicp produces varp,
|
||||
@ -1344,8 +1343,7 @@ void OrderProcess::processMTasks() {
|
||||
varp->addProducingMTaskId(mtaskId);
|
||||
}
|
||||
for (const V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
const OrderVarVertex* const post_varp
|
||||
= dynamic_cast<const OrderVarVertex*>(edgep->top());
|
||||
const OrderVarVertex* const post_varp = edgep->top()->cast<const OrderVarVertex>();
|
||||
if (!post_varp) continue;
|
||||
AstVar* const varp = post_varp->vscp()->varp();
|
||||
varp->addConsumingMTaskId(mtaskId);
|
||||
|
@ -102,6 +102,7 @@ public:
|
||||
// Vertex types
|
||||
|
||||
class OrderEitherVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(OrderEitherVertex, V3GraphVertex)
|
||||
// Event domain of vertex. For OrderLogicVertex this represents the conditions when the logic
|
||||
// block must be executed. For OrderVarVertex, this is the union of the domains of all the
|
||||
// OrderLogicVertex vertices that drive the variable. If initially set to nullptr (e.g.: all
|
||||
@ -133,6 +134,7 @@ public:
|
||||
};
|
||||
|
||||
class OrderLogicVertex final : public OrderEitherVertex {
|
||||
VL_RTTI_IMPL(OrderLogicVertex, OrderEitherVertex)
|
||||
AstNode* const m_nodep; // The logic this vertex represents
|
||||
AstScope* const m_scopep; // Scope the logic is under
|
||||
AstSenTree* const m_hybridp; // Additional sensitivities for hybrid combinational logic
|
||||
@ -167,6 +169,7 @@ public:
|
||||
};
|
||||
|
||||
class OrderVarVertex VL_NOT_FINAL : public OrderEitherVertex {
|
||||
VL_RTTI_IMPL(OrderVarVertex, OrderEitherVertex)
|
||||
AstVarScope* const m_vscp;
|
||||
|
||||
public:
|
||||
@ -189,6 +192,7 @@ public:
|
||||
};
|
||||
|
||||
class OrderVarStdVertex final : public OrderVarVertex {
|
||||
VL_RTTI_IMPL(OrderVarStdVertex, OrderVarVertex)
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
OrderVarStdVertex(OrderGraph* graphp, AstVarScope* vscp)
|
||||
@ -205,6 +209,7 @@ public:
|
||||
};
|
||||
|
||||
class OrderVarPreVertex final : public OrderVarVertex {
|
||||
VL_RTTI_IMPL(OrderVarPreVertex, OrderVarVertex)
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
OrderVarPreVertex(OrderGraph* graphp, AstVarScope* vscp)
|
||||
@ -221,6 +226,7 @@ public:
|
||||
};
|
||||
|
||||
class OrderVarPostVertex final : public OrderVarVertex {
|
||||
VL_RTTI_IMPL(OrderVarPostVertex, OrderVarVertex)
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
OrderVarPostVertex(OrderGraph* graphp, AstVarScope* vscp)
|
||||
@ -237,6 +243,7 @@ public:
|
||||
};
|
||||
|
||||
class OrderVarPordVertex final : public OrderVarVertex {
|
||||
VL_RTTI_IMPL(OrderVarPordVertex, OrderVarVertex)
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
OrderVarPordVertex(OrderGraph* graphp, AstVarScope* vscp)
|
||||
@ -256,6 +263,7 @@ public:
|
||||
// Edge type
|
||||
|
||||
class OrderEdge final : public V3GraphEdge {
|
||||
VL_RTTI_IMPL(OrderEdge, V3GraphEdge)
|
||||
friend class OrderGraph; // Only the OrderGraph can create these
|
||||
// CONSTRUCTOR
|
||||
OrderEdge(OrderGraph* graphp, OrderEitherVertex* fromp, OrderEitherVertex* top, int weight,
|
||||
|
@ -33,6 +33,7 @@
|
||||
class OrderMoveDomScope;
|
||||
|
||||
class OrderMoveVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(OrderMoveVertex, V3GraphVertex)
|
||||
enum OrderMState : uint8_t { POM_WAIT, POM_READY, POM_MOVED };
|
||||
|
||||
OrderLogicVertex* const m_logicp;
|
||||
@ -92,6 +93,7 @@ public:
|
||||
|
||||
// Similar to OrderMoveVertex, but modified for threaded code generation.
|
||||
class MTaskMoveVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(MTaskMoveVertex, V3GraphVertex)
|
||||
// This could be more compact, since we know m_varp and m_logicp
|
||||
// cannot both be set. Each MTaskMoveVertex represents a logic node
|
||||
// or a var node, it can't be both.
|
||||
|
@ -448,10 +448,10 @@ private:
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
SiblingMC* toSiblingMC(); // Instead of dynamic_cast
|
||||
const SiblingMC* toSiblingMC() const; // Instead of dynamic_cast
|
||||
MTaskEdge* toMTaskEdge(); // Instead of dynamic_cast
|
||||
const MTaskEdge* toMTaskEdge() const; // Instead of dynamic_cast
|
||||
SiblingMC* toSiblingMC(); // Instead of cast<>/as<>
|
||||
const SiblingMC* toSiblingMC() const; // Instead of cast<>/as<>
|
||||
MTaskEdge* toMTaskEdge(); // Instead of cast<>/as<>
|
||||
const MTaskEdge* toMTaskEdge() const; // Instead of cast<>/as<>
|
||||
bool mergeWouldCreateCycle() const; // Instead of virtual method
|
||||
|
||||
inline void rescore();
|
||||
@ -511,6 +511,7 @@ static_assert(!std::is_polymorphic<SiblingMC>::value, "Should not have a vtable"
|
||||
|
||||
// GraphEdge for the MTask graph
|
||||
class MTaskEdge final : public V3GraphEdge, public MergeCandidate {
|
||||
VL_RTTI_IMPL(MTaskEdge, V3GraphEdge)
|
||||
friend class LogicMTask;
|
||||
template <GraphWay::en T_Way>
|
||||
friend class PartPropagateCp;
|
||||
@ -806,7 +807,7 @@ public:
|
||||
UINFO(0, " Parallelism factor = " << parallelismFactor() << endl);
|
||||
}
|
||||
static uint32_t vertexCost(const V3GraphVertex* vertexp) {
|
||||
return dynamic_cast<const AbstractMTask*>(vertexp)->cost();
|
||||
return vertexp->as<const AbstractMTask>()->cost();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -857,7 +858,7 @@ static void partInitCriticalPaths(V3Graph* mtasksp) {
|
||||
// They would have been all zeroes on initial creation of the MTaskEdges.
|
||||
for (V3GraphVertex* vxp = mtasksp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
MTaskEdge* const mtedgep = dynamic_cast<MTaskEdge*>(edgep);
|
||||
MTaskEdge* const mtedgep = edgep->as<MTaskEdge>();
|
||||
mtedgep->resetCriticalPaths();
|
||||
}
|
||||
}
|
||||
@ -1966,7 +1967,7 @@ private:
|
||||
void findAdjacentTasks(const OrderVarStdVertex* varVtxp, TasksByRank& tasksByRank) {
|
||||
// Find all writer tasks for this variable, group by rank.
|
||||
for (V3GraphEdge* edgep = varVtxp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
if (const auto* const logicVtxp = dynamic_cast<OrderLogicVertex*>(edgep->fromp())) {
|
||||
if (const auto* const logicVtxp = edgep->fromp()->cast<OrderLogicVertex>()) {
|
||||
LogicMTask* const writerMtaskp = static_cast<LogicMTask*>(logicVtxp->userp());
|
||||
tasksByRank[writerMtaskp->rank()].insert(writerMtaskp);
|
||||
}
|
||||
@ -2058,7 +2059,7 @@ public:
|
||||
nextp = vtxp->verticesNextp();
|
||||
// Only consider OrderVarStdVertex which reflects
|
||||
// an actual lvalue assignment; the others do not.
|
||||
if (const OrderVarStdVertex* const vvtxp = dynamic_cast<OrderVarStdVertex*>(vtxp)) {
|
||||
if (const OrderVarStdVertex* const vvtxp = vtxp->cast<OrderVarStdVertex>()) {
|
||||
if (vvtxp->vscp()->varp()->isSc()) {
|
||||
systemCVars.push_back(vvtxp);
|
||||
} else {
|
||||
@ -2203,7 +2204,7 @@ public:
|
||||
const uint32_t thisThreadId = threadId(mtaskp);
|
||||
uint32_t result = 0;
|
||||
for (V3GraphEdge* edgep = mtaskp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
const ExecMTask* const prevp = dynamic_cast<ExecMTask*>(edgep->fromp());
|
||||
const ExecMTask* const prevp = edgep->fromp()->as<ExecMTask>();
|
||||
if (threadId(prevp) != thisThreadId) ++result;
|
||||
}
|
||||
return result;
|
||||
@ -2248,7 +2249,7 @@ void ThreadSchedule::dumpDotFile(const V3Graph& graph, const string& filename) c
|
||||
// Find minimum cost MTask for scaling MTask node widths
|
||||
uint32_t minCost = UINT32_MAX;
|
||||
for (const V3GraphVertex* vxp = graph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
if (const ExecMTask* const mtaskp = dynamic_cast<const ExecMTask*>(vxp)) {
|
||||
if (const ExecMTask* const mtaskp = vxp->cast<const ExecMTask>()) {
|
||||
minCost = minCost > mtaskp->cost() ? mtaskp->cost() : minCost;
|
||||
}
|
||||
}
|
||||
@ -2271,13 +2272,13 @@ void ThreadSchedule::dumpDotFile(const V3Graph& graph, const string& filename) c
|
||||
|
||||
// Emit MTasks
|
||||
for (const V3GraphVertex* vxp = graph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
if (const ExecMTask* const mtaskp = dynamic_cast<const ExecMTask*>(vxp)) emitMTask(mtaskp);
|
||||
if (const ExecMTask* const mtaskp = vxp->cast<const ExecMTask>()) emitMTask(mtaskp);
|
||||
}
|
||||
|
||||
// Emit MTask dependency edges
|
||||
*logp << "\n // MTask dependencies\n";
|
||||
for (const V3GraphVertex* vxp = graph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
if (const ExecMTask* const mtaskp = dynamic_cast<const ExecMTask*>(vxp)) {
|
||||
if (const ExecMTask* const mtaskp = vxp->cast<const ExecMTask>()) {
|
||||
for (V3GraphEdge* edgep = mtaskp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
const V3GraphVertex* const top = edgep->top();
|
||||
*logp << " " << vxp->name() << " -> " << top->name() << "\n";
|
||||
@ -2365,7 +2366,7 @@ private:
|
||||
|
||||
bool isReady(ThreadSchedule& schedule, const ExecMTask* mtaskp) {
|
||||
for (V3GraphEdge* edgeInp = mtaskp->inBeginp(); edgeInp; edgeInp = edgeInp->inNextp()) {
|
||||
const ExecMTask* const prevp = dynamic_cast<ExecMTask*>(edgeInp->fromp());
|
||||
const ExecMTask* const prevp = edgeInp->fromp()->as<const ExecMTask>();
|
||||
if (schedule.threadId(prevp) == ThreadSchedule::UNASSIGNED) {
|
||||
// This predecessor is not assigned yet
|
||||
return false;
|
||||
@ -2388,7 +2389,7 @@ public:
|
||||
|
||||
// Build initial ready list
|
||||
for (V3GraphVertex* vxp = mtaskGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
ExecMTask* const mtaskp = dynamic_cast<ExecMTask*>(vxp);
|
||||
ExecMTask* const mtaskp = vxp->as<ExecMTask>();
|
||||
if (isReady(schedule, mtaskp)) readyMTasks.insert(mtaskp);
|
||||
}
|
||||
|
||||
@ -2409,7 +2410,7 @@ public:
|
||||
}
|
||||
for (V3GraphEdge* edgep = mtaskp->inBeginp(); edgep;
|
||||
edgep = edgep->inNextp()) {
|
||||
const ExecMTask* const priorp = dynamic_cast<ExecMTask*>(edgep->fromp());
|
||||
const ExecMTask* const priorp = edgep->fromp()->as<ExecMTask>();
|
||||
const uint32_t priorEndTime = completionTime(schedule, priorp, threadId);
|
||||
if (priorEndTime > timeBegin) timeBegin = priorEndTime;
|
||||
}
|
||||
@ -2449,7 +2450,7 @@ public:
|
||||
UASSERT_OBJ(erased > 0, bestMtaskp, "Should have erased something?");
|
||||
for (V3GraphEdge* edgeOutp = bestMtaskp->outBeginp(); edgeOutp;
|
||||
edgeOutp = edgeOutp->outNextp()) {
|
||||
ExecMTask* const nextp = dynamic_cast<ExecMTask*>(edgeOutp->top());
|
||||
ExecMTask* const nextp = edgeOutp->top()->as<ExecMTask>();
|
||||
// Dependent MTask should not yet be assigned to a thread
|
||||
UASSERT(schedule.threadId(nextp) == ThreadSchedule::UNASSIGNED,
|
||||
"Tasks after one being assigned should not be assigned yet");
|
||||
@ -2540,7 +2541,7 @@ void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stag
|
||||
for (const V3GraphVertex* mtaskp = graphp->verticesBeginp(); mtaskp;
|
||||
mtaskp = mtaskp->verticesNextp()) {
|
||||
++mtaskCount;
|
||||
uint32_t mtaskCost = dynamic_cast<const AbstractMTask*>(mtaskp)->cost();
|
||||
uint32_t mtaskCost = mtaskp->as<const AbstractMTask>()->cost();
|
||||
totalCost += mtaskCost;
|
||||
|
||||
unsigned log2Cost = 0;
|
||||
@ -2928,7 +2929,7 @@ static void fillinCosts(V3Graph* execMTaskGraphp) {
|
||||
|
||||
for (const V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp;
|
||||
vxp = vxp->verticesNextp()) {
|
||||
ExecMTask* const mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
|
||||
ExecMTask* const mtp = const_cast<V3GraphVertex*>(vxp)->as<ExecMTask>();
|
||||
// Compute name of mtask, for hash lookup
|
||||
mtp->hashName(m_uniqueNames.get(mtp->bodyp()));
|
||||
|
||||
@ -2949,7 +2950,7 @@ static void fillinCosts(V3Graph* execMTaskGraphp) {
|
||||
int missingProfiles = 0;
|
||||
for (const V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp;
|
||||
vxp = vxp->verticesNextp()) {
|
||||
ExecMTask* const mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
|
||||
ExecMTask* const mtp = const_cast<V3GraphVertex*>(vxp)->as<ExecMTask>();
|
||||
const uint32_t costEstimate = costs[mtp->id()].first;
|
||||
const uint64_t costProfiled = costs[mtp->id()].second;
|
||||
UINFO(9, "ce = " << costEstimate << " cp=" << costProfiled << endl);
|
||||
@ -2978,14 +2979,14 @@ static void fillinCosts(V3Graph* execMTaskGraphp) {
|
||||
static void finalizeCosts(V3Graph* execMTaskGraphp) {
|
||||
GraphStreamUnordered ser(execMTaskGraphp, GraphWay::REVERSE);
|
||||
while (const V3GraphVertex* const vxp = ser.nextp()) {
|
||||
ExecMTask* const mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
|
||||
ExecMTask* const mtp = const_cast<V3GraphVertex*>(vxp)->as<ExecMTask>();
|
||||
// "Priority" is the critical path from the start of the mtask, to
|
||||
// the end of the graph reachable from this mtask. Given the
|
||||
// choice among several ready mtasks, we'll want to start the
|
||||
// highest priority one first, so we're always working on the "long
|
||||
// pole"
|
||||
for (V3GraphEdge* edgep = mtp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
const ExecMTask* const followp = dynamic_cast<ExecMTask*>(edgep->top());
|
||||
const ExecMTask* const followp = edgep->top()->as<ExecMTask>();
|
||||
if ((followp->priority() + mtp->cost()) > mtp->priority()) {
|
||||
mtp->priority(followp->priority() + mtp->cost());
|
||||
}
|
||||
@ -2996,7 +2997,7 @@ static void finalizeCosts(V3Graph* execMTaskGraphp) {
|
||||
// (It's common for tasks to shrink to nothing when V3LifePost
|
||||
// removes dly assignments.)
|
||||
for (V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp;) {
|
||||
ExecMTask* const mtp = dynamic_cast<ExecMTask*>(vxp);
|
||||
ExecMTask* const mtp = vxp->as<ExecMTask>();
|
||||
vxp = vxp->verticesNextp(); // Advance before delete
|
||||
|
||||
// Don't rely on checking mtp->cost() == 0 to detect an empty task.
|
||||
@ -3100,7 +3101,7 @@ static void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t th
|
||||
|
||||
// For any dependent mtask that's on another thread, signal one dependency completion.
|
||||
for (V3GraphEdge* edgep = mtaskp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
const ExecMTask* const nextp = dynamic_cast<ExecMTask*>(edgep->top());
|
||||
const ExecMTask* const nextp = edgep->top()->as<ExecMTask>();
|
||||
if (schedule.threadId(nextp) != threadId) {
|
||||
addStrStmt("vlSelf->__Vm_mtaskstate_" + cvtToStr(nextp->id())
|
||||
+ ".signalUpstreamDone(even_cycle);\n");
|
||||
|
@ -29,6 +29,7 @@
|
||||
// MTasks and graph structures
|
||||
|
||||
class AbstractMTask VL_NOT_FINAL : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(AbstractMTask, V3GraphVertex)
|
||||
public:
|
||||
explicit AbstractMTask(V3Graph* graphp)
|
||||
: V3GraphVertex{graphp} {}
|
||||
@ -38,6 +39,7 @@ public:
|
||||
};
|
||||
|
||||
class AbstractLogicMTask VL_NOT_FINAL : public AbstractMTask {
|
||||
VL_RTTI_IMPL(AbstractLogicMTask, AbstractMTask)
|
||||
public:
|
||||
// TYPES
|
||||
using VxList = std::list<MTaskMoveVertex*>;
|
||||
@ -53,6 +55,7 @@ public:
|
||||
};
|
||||
|
||||
class ExecMTask final : public AbstractMTask {
|
||||
VL_RTTI_IMPL(ExecMTask, AbstractMTask)
|
||||
private:
|
||||
AstMTaskBody* const m_bodyp; // Task body
|
||||
const uint32_t m_id; // Unique id of this mtask.
|
||||
|
131
src/V3Rtti.h
Normal file
131
src/V3Rtti.h
Normal file
@ -0,0 +1,131 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Simple and efficient Run-Time Type Information
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2023 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3RTTI_H_
|
||||
#define VERILATOR_V3RTTI_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
// Holds list of types as template parameter pack.
|
||||
// Useful in compile-time code generation.
|
||||
template <typename... TN>
|
||||
struct VTypeList {
|
||||
template <typename... UN>
|
||||
constexpr VTypeList<TN..., UN...> operator+(VTypeList<UN...>) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// Holds one type.
|
||||
// Can be safely used as a return or argument type, and even instantiated, without triggering any
|
||||
// potential limitations or effects of the held type.
|
||||
template <typename T>
|
||||
struct VTypeWrapper {
|
||||
using type_t = T;
|
||||
};
|
||||
|
||||
// Implementation details of other constructs defined in this header.
|
||||
namespace V3RttiInternal {
|
||||
|
||||
// Helper function for extracting first type from VTypeList.
|
||||
template <typename T0, typename... TN>
|
||||
static inline constexpr VTypeWrapper<T0> vlTypeListFront(VTypeList<T0, TN...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Overload for empty type list. Returns false.
|
||||
inline static constexpr bool isClassIdOfOneOf(uintptr_t id, VTypeList<>) VL_PURE { return false; }
|
||||
|
||||
// Returns true iff `id` has the same value as `T::rttiClassId()`, where `T` is any type held by
|
||||
// `VTypeList` object passed as the second argument.
|
||||
template <typename Base0, typename... BaseN>
|
||||
inline static constexpr bool isClassIdOfOneOf(uintptr_t id, VTypeList<Base0, BaseN...>) VL_PURE {
|
||||
return id == Base0::rttiClassId() || isClassIdOfOneOf(id, VTypeList<BaseN...>{});
|
||||
}
|
||||
|
||||
} // namespace V3RttiInternal
|
||||
|
||||
// Alias for the first (frontmost) type held by type list `TL`.
|
||||
template <typename TL>
|
||||
using VTypeListFront = typename decltype(::V3RttiInternal::vlTypeListFront(TL{}))::type_t;
|
||||
|
||||
// `VTypeList` holding types from type lists `TL1` followed by types from type list `TL2`.
|
||||
template <typename TL1, typename TL2>
|
||||
using VJoinedTypeLists = decltype(TL1{} + TL2{});
|
||||
|
||||
// Common code used by VL_RTTI_COMMON_IMPL and VL_RTTI_COMMON_IMPL_BASE.
|
||||
#define V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \
|
||||
private: \
|
||||
/* A type used only for implementation of the static_assert below. */ \
|
||||
struct RttiUniqueTypeForThisClass {}; \
|
||||
static_assert( \
|
||||
std::is_same<RttiUniqueTypeForThisClass, ThisClass::RttiUniqueTypeForThisClass>::value, \
|
||||
"'ThisClass' argument (" #ThisClass ") does not match the class name"); \
|
||||
\
|
||||
public: \
|
||||
/* Returns unique ID of the class. Useful with `isInstanceOfClassWithId()` method. */ \
|
||||
static uintptr_t rttiClassId() VL_PURE { \
|
||||
/* The only purpose of the following variable is to occupy an unique memory address. */ \
|
||||
/* This address is used as an unique class ID. */ \
|
||||
static char aStaticVariable; \
|
||||
return reinterpret_cast<uintptr_t>(&aStaticVariable); \
|
||||
}
|
||||
|
||||
// Call this macro at the beginning of class definition if the class derives from a
|
||||
// class with VL_RTTI_IMPL or VL_RTTI_IMPL_BASE calls.
|
||||
#define VL_RTTI_IMPL(ThisClass, DirectBaseClass) \
|
||||
V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \
|
||||
static_assert( \
|
||||
std::is_same<DirectBaseClass, \
|
||||
VTypeListFront<DirectBaseClass::RttiThisAndBaseClassesList>>::value, \
|
||||
"Missing VL_RTTI_IMPL(...) in the direct base class (" #DirectBaseClass ")"); \
|
||||
\
|
||||
public: \
|
||||
/* Type list containing this class and all classes from the inheritance chain. */ \
|
||||
using RttiThisAndBaseClassesList \
|
||||
= VJoinedTypeLists<VTypeList<ThisClass>, \
|
||||
typename DirectBaseClass::RttiThisAndBaseClassesList>; \
|
||||
\
|
||||
protected: \
|
||||
/* Returns true iff `id` has the same value as `T::rttiClassId()`, where `T` is either this \
|
||||
* class or any class from this class' inheritance chain. */ \
|
||||
bool isInstanceOfClassWithId(uintptr_t id) const override VL_PURE { \
|
||||
return ::V3RttiInternal::isClassIdOfOneOf(id, RttiThisAndBaseClassesList{}); \
|
||||
} \
|
||||
\
|
||||
private: /* Revert to private visibility after this macro */
|
||||
|
||||
// Call this macro at the beginning of a base class to implement class type queries using
|
||||
// `p->isInstanceOfClassWithId(ClassName::rttiClassId())`.
|
||||
#define VL_RTTI_IMPL_BASE(ThisClass) \
|
||||
V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \
|
||||
public: \
|
||||
/* Type list containing this class and all classes from the inheritance chain. */ \
|
||||
using RttiThisAndBaseClassesList = VTypeList<ThisClass>; \
|
||||
\
|
||||
protected: \
|
||||
/* Returns true iff `id` has the same value as value returned by this class' \
|
||||
`rttiClassId()` method. */ \
|
||||
virtual bool isInstanceOfClassWithId(uintptr_t id) const VL_PURE { \
|
||||
return id == rttiClassId(); \
|
||||
} \
|
||||
\
|
||||
private: /* Revert to private visibility after this macro */
|
||||
|
||||
#endif // Guard
|
@ -59,17 +59,18 @@ namespace {
|
||||
// ##############################################################################
|
||||
// Data structures (graph types)
|
||||
|
||||
class LogicVertex final : public V3GraphVertex {
|
||||
class SchedAcyclicLogicVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(SchedAcyclicLogicVertex, V3GraphVertex)
|
||||
AstNode* const m_logicp; // The logic node this vertex represents
|
||||
AstScope* const m_scopep; // The enclosing AstScope of the logic node
|
||||
|
||||
public:
|
||||
LogicVertex(V3Graph* graphp, AstNode* logicp, AstScope* scopep)
|
||||
SchedAcyclicLogicVertex(V3Graph* graphp, AstNode* logicp, AstScope* scopep)
|
||||
: V3GraphVertex{graphp}
|
||||
, m_logicp{logicp}
|
||||
, m_scopep{scopep} {}
|
||||
V3GraphVertex* clone(V3Graph* graphp) const override {
|
||||
return new LogicVertex{graphp, logicp(), scopep()};
|
||||
return new SchedAcyclicLogicVertex{graphp, logicp(), scopep()};
|
||||
}
|
||||
|
||||
AstNode* logicp() const { return m_logicp; }
|
||||
@ -81,16 +82,19 @@ public:
|
||||
// LCOV_EXCL_STOP
|
||||
};
|
||||
|
||||
class VarVertex final : public V3GraphVertex {
|
||||
class SchedAcyclicVarVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(SchedAcyclicVarVertex, V3GraphVertex)
|
||||
AstVarScope* const m_vscp; // The AstVarScope this vertex represents
|
||||
|
||||
public:
|
||||
VarVertex(V3Graph* graphp, AstVarScope* vscp)
|
||||
SchedAcyclicVarVertex(V3Graph* graphp, AstVarScope* vscp)
|
||||
: V3GraphVertex{graphp}
|
||||
, m_vscp{vscp} {}
|
||||
AstVarScope* vscp() const { return m_vscp; }
|
||||
AstVar* varp() const { return m_vscp->varp(); }
|
||||
V3GraphVertex* clone(V3Graph* graphp) const override { return new VarVertex{graphp, vscp()}; }
|
||||
V3GraphVertex* clone(V3Graph* graphp) const override {
|
||||
return new SchedAcyclicVarVertex{graphp, vscp()};
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START // Debug code
|
||||
string name() const override VL_MT_STABLE { return m_vscp->name(); }
|
||||
@ -102,13 +106,12 @@ public:
|
||||
class Graph final : public V3Graph {
|
||||
void loopsVertexCb(V3GraphVertex* vtxp) override {
|
||||
// TODO: 'typeName' is an internal thing. This should be more human readable.
|
||||
if (LogicVertex* const lvtxp = dynamic_cast<LogicVertex*>(vtxp)) {
|
||||
if (SchedAcyclicLogicVertex* const lvtxp = vtxp->cast<SchedAcyclicLogicVertex>()) {
|
||||
AstNode* const logicp = lvtxp->logicp();
|
||||
std::cerr << logicp->fileline()->warnOtherStandalone()
|
||||
<< " Example path: " << logicp->typeName() << endl;
|
||||
} else {
|
||||
VarVertex* const vvtxp = dynamic_cast<VarVertex*>(vtxp);
|
||||
UASSERT(vvtxp, "Cannot be anything else");
|
||||
SchedAcyclicVarVertex* const vvtxp = vtxp->as<SchedAcyclicVarVertex>();
|
||||
AstVarScope* const vscp = vvtxp->vscp();
|
||||
std::cerr << vscp->fileline()->warnOtherStandalone()
|
||||
<< " Example path: " << vscp->prettyName() << endl;
|
||||
@ -125,8 +128,8 @@ std::unique_ptr<Graph> buildGraph(const LogicByScope& lbs) {
|
||||
// AstVarScope::user1() -> VarVertx
|
||||
const VNUser1InUse user1InUse;
|
||||
const auto getVarVertex = [&](AstVarScope* vscp) {
|
||||
if (!vscp->user1p()) vscp->user1p(new VarVertex{graphp.get(), vscp});
|
||||
return vscp->user1u().to<VarVertex*>();
|
||||
if (!vscp->user1p()) vscp->user1p(new SchedAcyclicVarVertex{graphp.get(), vscp});
|
||||
return vscp->user1u().to<SchedAcyclicVarVertex*>();
|
||||
};
|
||||
|
||||
const auto addEdge = [&](V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cuttable) {
|
||||
@ -141,13 +144,14 @@ std::unique_ptr<Graph> buildGraph(const LogicByScope& lbs) {
|
||||
// Can safely ignore Postponed as we generate them all
|
||||
if (VN_IS(nodep, AlwaysPostponed)) continue;
|
||||
|
||||
LogicVertex* const lvtxp = new LogicVertex{graphp.get(), nodep, scopep};
|
||||
SchedAcyclicLogicVertex* const lvtxp
|
||||
= new SchedAcyclicLogicVertex{graphp.get(), nodep, scopep};
|
||||
const VNUser2InUse user2InUse;
|
||||
const VNUser3InUse user3InUse;
|
||||
|
||||
nodep->foreach([&](AstVarRef* refp) {
|
||||
AstVarScope* const vscp = refp->varScopep();
|
||||
VarVertex* const vvtxp = getVarVertex(vscp);
|
||||
SchedAcyclicVarVertex* const vvtxp = getVarVertex(vscp);
|
||||
// We want to cut the narrowest signals
|
||||
const int weight = vscp->width() / 8 + 1;
|
||||
// If written, add logic -> var edge
|
||||
@ -208,7 +212,7 @@ void removeNonCyclic(Graph* graphp) {
|
||||
}
|
||||
|
||||
// Has this VarVertex been cut? (any edges in or out has been cut)
|
||||
bool isCut(const VarVertex* vtxp) {
|
||||
bool isCut(const SchedAcyclicVarVertex* vtxp) {
|
||||
for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
if (edgep->weight() == 0) return true;
|
||||
}
|
||||
@ -218,33 +222,33 @@ bool isCut(const VarVertex* vtxp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<VarVertex*> findCutVertices(Graph* graphp) {
|
||||
std::vector<VarVertex*> result;
|
||||
std::vector<SchedAcyclicVarVertex*> findCutVertices(Graph* graphp) {
|
||||
std::vector<SchedAcyclicVarVertex*> result;
|
||||
const VNUser1InUse user1InUse; // bool: already added to result
|
||||
for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) {
|
||||
if (VarVertex* const vvtxp = dynamic_cast<VarVertex*>(vtxp)) {
|
||||
if (SchedAcyclicVarVertex* const vvtxp = vtxp->cast<SchedAcyclicVarVertex>()) {
|
||||
if (!vvtxp->vscp()->user1SetOnce() && isCut(vvtxp)) result.push_back(vvtxp);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void resetEdgeWeights(const std::vector<VarVertex*>& cutVertices) {
|
||||
for (VarVertex* const vvtxp : cutVertices) {
|
||||
void resetEdgeWeights(const std::vector<SchedAcyclicVarVertex*>& cutVertices) {
|
||||
for (SchedAcyclicVarVertex* const vvtxp : cutVertices) {
|
||||
for (V3GraphEdge* ep = vvtxp->inBeginp(); ep; ep = ep->inNextp()) ep->weight(1);
|
||||
for (V3GraphEdge* ep = vvtxp->outBeginp(); ep; ep = ep->outNextp()) ep->weight(1);
|
||||
}
|
||||
}
|
||||
|
||||
// A VarVertex together with its fanout
|
||||
using Candidate = std::pair<VarVertex*, unsigned>;
|
||||
using Candidate = std::pair<SchedAcyclicVarVertex*, unsigned>;
|
||||
|
||||
// Gather all splitting candidates that are in the same SCC as the given vertex
|
||||
void gatherSCCCandidates(V3GraphVertex* vtxp, std::vector<Candidate>& candidates) {
|
||||
if (vtxp->user()) return; // Already done
|
||||
vtxp->user(true);
|
||||
|
||||
if (VarVertex* const vvtxp = dynamic_cast<VarVertex*>(vtxp)) {
|
||||
if (SchedAcyclicVarVertex* const vvtxp = vtxp->cast<SchedAcyclicVarVertex>()) {
|
||||
AstVar* const varp = vvtxp->varp();
|
||||
const string name = varp->prettyName();
|
||||
if (!varp->user3SetOnce() // Only consider each AstVar once
|
||||
@ -270,7 +274,7 @@ void gatherSCCCandidates(V3GraphVertex* vtxp, std::vector<Candidate>& candidates
|
||||
}
|
||||
|
||||
// Find all variables in a loop (SCC) that are candidates for splitting to break loops.
|
||||
void reportLoopVars(Graph* graphp, VarVertex* vvtxp) {
|
||||
void reportLoopVars(Graph* graphp, SchedAcyclicVarVertex* vvtxp) {
|
||||
// Vector of variables in UNOPTFLAT loop that are candidates for splitting.
|
||||
std::vector<Candidate> candidates;
|
||||
{
|
||||
@ -325,8 +329,8 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) {
|
||||
V3Stats::addStat("Scheduling, split_var, candidates", splittable);
|
||||
}
|
||||
|
||||
void reportCycles(Graph* graphp, const std::vector<VarVertex*>& cutVertices) {
|
||||
for (VarVertex* vvtxp : cutVertices) {
|
||||
void reportCycles(Graph* graphp, const std::vector<SchedAcyclicVarVertex*>& cutVertices) {
|
||||
for (SchedAcyclicVarVertex* vvtxp : cutVertices) {
|
||||
AstVarScope* const vscp = vvtxp->vscp();
|
||||
FileLine* const flp = vscp->fileline();
|
||||
|
||||
@ -350,16 +354,18 @@ void reportCycles(Graph* graphp, const std::vector<VarVertex*>& cutVertices) {
|
||||
}
|
||||
}
|
||||
|
||||
LogicByScope fixCuts(AstNetlist* netlistp, const std::vector<VarVertex*>& cutVertices) {
|
||||
LogicByScope fixCuts(AstNetlist* netlistp,
|
||||
const std::vector<SchedAcyclicVarVertex*>& cutVertices) {
|
||||
// For all logic that reads a cut vertex, build a map from logic -> list of cut AstVarScope
|
||||
// they read. Also build a vector of the involved logic for deterministic results.
|
||||
std::unordered_map<LogicVertex*, std::vector<AstVarScope*>> lvtx2Cuts;
|
||||
std::vector<LogicVertex*> lvtxps;
|
||||
std::unordered_map<SchedAcyclicLogicVertex*, std::vector<AstVarScope*>> lvtx2Cuts;
|
||||
std::vector<SchedAcyclicLogicVertex*> lvtxps;
|
||||
{
|
||||
const VNUser1InUse user1InUse; // bool: already added to 'lvtxps'
|
||||
for (VarVertex* const vvtxp : cutVertices) {
|
||||
for (SchedAcyclicVarVertex* const vvtxp : cutVertices) {
|
||||
for (V3GraphEdge* edgep = vvtxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
LogicVertex* const lvtxp = static_cast<LogicVertex*>(edgep->top());
|
||||
SchedAcyclicLogicVertex* const lvtxp
|
||||
= static_cast<SchedAcyclicLogicVertex*>(edgep->top());
|
||||
if (!lvtxp->logicp()->user1SetOnce()) lvtxps.push_back(lvtxp);
|
||||
lvtx2Cuts[lvtxp].push_back(vvtxp->vscp());
|
||||
}
|
||||
@ -370,7 +376,7 @@ LogicByScope fixCuts(AstNetlist* netlistp, const std::vector<VarVertex*>& cutVer
|
||||
// explicit additional triggers on the cut variables)
|
||||
LogicByScope result;
|
||||
SenTreeFinder finder{netlistp};
|
||||
for (LogicVertex* const lvtxp : lvtxps) {
|
||||
for (SchedAcyclicLogicVertex* const lvtxp : lvtxps) {
|
||||
AstNode* const logicp = lvtxp->logicp();
|
||||
logicp->unlinkFrBack();
|
||||
FileLine* const flp = logicp->fileline();
|
||||
@ -412,7 +418,7 @@ LogicByScope breakCycles(AstNetlist* netlistp, LogicByScope& combinationalLogic)
|
||||
graphp->acyclic(&V3GraphEdge::followAlwaysTrue);
|
||||
|
||||
// Find all cut vertices
|
||||
const std::vector<VarVertex*> cutVertices = findCutVertices(graphp.get());
|
||||
const std::vector<SchedAcyclicVarVertex*> cutVertices = findCutVertices(graphp.get());
|
||||
|
||||
// Reset edge weights for reporting
|
||||
resetEdgeWeights(cutVertices);
|
||||
|
@ -55,6 +55,7 @@ namespace V3Sched {
|
||||
namespace {
|
||||
|
||||
class SchedSenVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(SchedSenVertex, V3GraphVertex)
|
||||
const AstSenItem* const m_senItemp;
|
||||
|
||||
public:
|
||||
@ -74,6 +75,7 @@ public:
|
||||
};
|
||||
|
||||
class SchedLogicVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(SchedLogicVertex, V3GraphVertex)
|
||||
AstScope* const m_scopep;
|
||||
AstSenTree* const m_senTreep;
|
||||
AstNode* const m_logicp;
|
||||
@ -97,6 +99,7 @@ public:
|
||||
};
|
||||
|
||||
class SchedVarVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(SchedVarVertex, V3GraphVertex)
|
||||
const AstVarScope* const m_vscp;
|
||||
|
||||
public:
|
||||
@ -299,7 +302,7 @@ void colorActiveRegion(const V3Graph& graph) {
|
||||
|
||||
// Trace from all SchedSenVertex
|
||||
for (V3GraphVertex* vtxp = graph.verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) {
|
||||
if (const auto activeEventVtxp = dynamic_cast<SchedSenVertex*>(vtxp)) {
|
||||
if (const auto activeEventVtxp = vtxp->cast<SchedSenVertex>()) {
|
||||
queue.push_back(activeEventVtxp);
|
||||
}
|
||||
}
|
||||
@ -323,9 +326,9 @@ void colorActiveRegion(const V3Graph& graph) {
|
||||
// If this is a logic vertex, also enqueue all variable vertices that are driven from this
|
||||
// logic. This will ensure that if a variable is set in the active region, then all
|
||||
// settings of that variable will be in the active region.
|
||||
if (dynamic_cast<SchedLogicVertex*>(&vtx)) {
|
||||
if (vtx.is<SchedLogicVertex>()) {
|
||||
for (V3GraphEdge* edgep = vtx.outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
UASSERT(dynamic_cast<SchedVarVertex*>(edgep->top()), "Should be var vertex");
|
||||
UASSERT(edgep->top()->is<SchedVarVertex>(), "Should be var vertex");
|
||||
queue.push_back(edgep->top());
|
||||
}
|
||||
}
|
||||
@ -350,7 +353,7 @@ LogicRegions partition(LogicByScope& clockedLogic, LogicByScope& combinationalLo
|
||||
LogicRegions result;
|
||||
|
||||
for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) {
|
||||
if (const auto lvtxp = dynamic_cast<SchedLogicVertex*>(vtxp)) {
|
||||
if (const auto lvtxp = vtxp->cast<SchedLogicVertex>()) {
|
||||
LogicByScope& lbs = lvtxp->color() ? result.m_act : result.m_nba;
|
||||
AstNode* const logicp = lvtxp->logicp();
|
||||
logicp->unlinkFrBack();
|
||||
|
@ -59,11 +59,12 @@ enum RegionFlags : uint8_t {
|
||||
//##############################################################################
|
||||
// Data structures (graph types)
|
||||
|
||||
class Vertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
RegionFlags m_drivingRegions{NONE}; // The regions driving this vertex
|
||||
class SchedReplicateVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(SchedReplicateVertex, V3GraphVertex)
|
||||
RegionFlags m_drivingRegions{RegionFlags::NONE}; // The regions driving this vertex
|
||||
|
||||
public:
|
||||
explicit Vertex(V3Graph* graphp)
|
||||
explicit SchedReplicateVertex(V3Graph* graphp)
|
||||
: V3GraphVertex{graphp} {}
|
||||
uint8_t drivingRegions() const { return m_drivingRegions; }
|
||||
void addDrivingRegions(uint8_t regions) {
|
||||
@ -87,16 +88,17 @@ public:
|
||||
// LCOV_EXCL_STOP
|
||||
};
|
||||
|
||||
class LogicVertex final : public Vertex {
|
||||
class SchedReplicateLogicVertex final : public SchedReplicateVertex {
|
||||
VL_RTTI_IMPL(SchedReplicateLogicVertex, SchedReplicateVertex)
|
||||
AstScope* const m_scopep; // The enclosing AstScope of the logic node
|
||||
AstSenTree* const m_senTreep; // The sensitivity of the logic node
|
||||
AstNode* const m_logicp; // The logic node this vertex represents
|
||||
RegionFlags const m_assignedRegion; // The region this logic is originally assigned to
|
||||
|
||||
public:
|
||||
LogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* senTreep, AstNode* logicp,
|
||||
RegionFlags assignedRegion)
|
||||
: Vertex{graphp}
|
||||
SchedReplicateLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* senTreep,
|
||||
AstNode* logicp, RegionFlags assignedRegion)
|
||||
: SchedReplicateVertex{graphp}
|
||||
, m_scopep{scopep}
|
||||
, m_senTreep{senTreep}
|
||||
, m_logicp{logicp}
|
||||
@ -113,12 +115,13 @@ public:
|
||||
string dotShape() const override { return "rectangle"; }
|
||||
};
|
||||
|
||||
class VarVertex final : public Vertex {
|
||||
class SchedReplicateVarVertex final : public SchedReplicateVertex {
|
||||
VL_RTTI_IMPL(SchedReplicateVarVertex, SchedReplicateVertex)
|
||||
AstVarScope* const m_vscp; // The AstVarScope this vertex represents
|
||||
|
||||
public:
|
||||
VarVertex(V3Graph* graphp, AstVarScope* vscp)
|
||||
: Vertex{graphp}
|
||||
SchedReplicateVarVertex(V3Graph* graphp, AstVarScope* vscp)
|
||||
: SchedReplicateVertex{graphp}
|
||||
, m_vscp{vscp} {
|
||||
// Top level inputs are
|
||||
if (varp()->isPrimaryInish() || varp()->isSigUserRWPublic() || varp()->isWrittenByDpi()) {
|
||||
@ -149,11 +152,11 @@ std::unique_ptr<Graph> buildGraph(const LogicRegions& logicRegions) {
|
||||
// AstVarScope::user1() -> VarVertx
|
||||
const VNUser1InUse user1InUse;
|
||||
const auto getVarVertex = [&](AstVarScope* vscp) {
|
||||
if (!vscp->user1p()) vscp->user1p(new VarVertex{graphp.get(), vscp});
|
||||
return vscp->user1u().to<VarVertex*>();
|
||||
if (!vscp->user1p()) vscp->user1p(new SchedReplicateVarVertex{graphp.get(), vscp});
|
||||
return vscp->user1u().to<SchedReplicateVarVertex*>();
|
||||
};
|
||||
|
||||
const auto addEdge = [&](Vertex* fromp, Vertex* top) {
|
||||
const auto addEdge = [&](SchedReplicateVertex* fromp, SchedReplicateVertex* top) {
|
||||
new V3GraphEdge{graphp.get(), fromp, top, 1};
|
||||
};
|
||||
|
||||
@ -182,14 +185,14 @@ std::unique_ptr<Graph> buildGraph(const LogicRegions& logicRegions) {
|
||||
}
|
||||
|
||||
for (AstNode* nodep = activep->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
LogicVertex* const lvtxp
|
||||
= new LogicVertex{graphp.get(), scopep, senTreep, nodep, region};
|
||||
SchedReplicateLogicVertex* const lvtxp
|
||||
= new SchedReplicateLogicVertex{graphp.get(), scopep, senTreep, nodep, region};
|
||||
const VNUser2InUse user2InUse;
|
||||
const VNUser3InUse user3InUse;
|
||||
|
||||
nodep->foreach([&](AstVarRef* refp) {
|
||||
AstVarScope* const vscp = refp->varScopep();
|
||||
VarVertex* const vvtxp = getVarVertex(vscp);
|
||||
SchedReplicateVarVertex* const vvtxp = getVarVertex(vscp);
|
||||
|
||||
// If read, add var -> logic edge
|
||||
// Note: Use same heuristic as ordering does to ignore written variables
|
||||
@ -216,7 +219,7 @@ std::unique_ptr<Graph> buildGraph(const LogicRegions& logicRegions) {
|
||||
return graphp;
|
||||
}
|
||||
|
||||
void propagateDrivingRegions(Vertex* vtxp) {
|
||||
void propagateDrivingRegions(SchedReplicateVertex* vtxp) {
|
||||
// Note: The graph is always acyclic, so the recursion will terminate
|
||||
|
||||
// Nothing to do if already visited
|
||||
@ -225,7 +228,7 @@ void propagateDrivingRegions(Vertex* vtxp) {
|
||||
// Compute union of driving regions of all inputs
|
||||
uint8_t drivingRegions = 0;
|
||||
for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
Vertex* const srcp = static_cast<Vertex*>(edgep->fromp());
|
||||
SchedReplicateVertex* const srcp = edgep->fromp()->as<SchedReplicateVertex>();
|
||||
propagateDrivingRegions(srcp);
|
||||
drivingRegions |= srcp->drivingRegions();
|
||||
}
|
||||
@ -240,7 +243,7 @@ void propagateDrivingRegions(Vertex* vtxp) {
|
||||
LogicReplicas replicate(Graph* graphp) {
|
||||
LogicReplicas result;
|
||||
for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) {
|
||||
if (LogicVertex* const lvtxp = dynamic_cast<LogicVertex*>(vtxp)) {
|
||||
if (SchedReplicateLogicVertex* const lvtxp = vtxp->cast<SchedReplicateLogicVertex>()) {
|
||||
const auto replicateTo = [&](LogicByScope& lbs) {
|
||||
lbs.add(lvtxp->scopep(), lvtxp->senTreep(), lvtxp->logicp()->cloneTree(false));
|
||||
};
|
||||
@ -264,7 +267,7 @@ LogicReplicas replicateLogic(LogicRegions& logicRegionsRegions) {
|
||||
if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-replicate");
|
||||
// Propagate driving region flags
|
||||
for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) {
|
||||
propagateDrivingRegions(static_cast<Vertex*>(vtxp));
|
||||
propagateDrivingRegions(vtxp->as<SchedReplicateVertex>());
|
||||
}
|
||||
// Dump for debug
|
||||
if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-replicate-propagated");
|
||||
|
@ -99,6 +99,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
// Support classes
|
||||
|
||||
class SplitNodeVertex VL_NOT_FINAL : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(SplitNodeVertex, V3GraphVertex)
|
||||
AstNode* const m_nodep;
|
||||
|
||||
protected:
|
||||
@ -117,6 +118,7 @@ public:
|
||||
};
|
||||
|
||||
class SplitPliVertex final : public SplitNodeVertex {
|
||||
VL_RTTI_IMPL(SplitPliVertex, SplitNodeVertex)
|
||||
public:
|
||||
explicit SplitPliVertex(V3Graph* graphp, AstNode* nodep)
|
||||
: SplitNodeVertex{graphp, nodep} {}
|
||||
@ -126,6 +128,7 @@ public:
|
||||
};
|
||||
|
||||
class SplitLogicVertex final : public SplitNodeVertex {
|
||||
VL_RTTI_IMPL(SplitLogicVertex, SplitNodeVertex)
|
||||
public:
|
||||
SplitLogicVertex(V3Graph* graphp, AstNode* nodep)
|
||||
: SplitNodeVertex{graphp, nodep} {}
|
||||
@ -134,6 +137,7 @@ public:
|
||||
};
|
||||
|
||||
class SplitVarStdVertex final : public SplitNodeVertex {
|
||||
VL_RTTI_IMPL(SplitVarStdVertex, SplitNodeVertex)
|
||||
public:
|
||||
SplitVarStdVertex(V3Graph* graphp, AstNode* nodep)
|
||||
: SplitNodeVertex{graphp, nodep} {}
|
||||
@ -142,6 +146,7 @@ public:
|
||||
};
|
||||
|
||||
class SplitVarPostVertex final : public SplitNodeVertex {
|
||||
VL_RTTI_IMPL(SplitVarPostVertex, SplitNodeVertex)
|
||||
public:
|
||||
SplitVarPostVertex(V3Graph* graphp, AstNode* nodep)
|
||||
: SplitNodeVertex{graphp, nodep} {}
|
||||
@ -154,6 +159,7 @@ public:
|
||||
// Edge types
|
||||
|
||||
class SplitEdge VL_NOT_FINAL : public V3GraphEdge {
|
||||
VL_RTTI_IMPL(SplitEdge, V3GraphEdge)
|
||||
uint32_t m_ignoreInStep = 0; // Step number that if set to, causes this edge to be ignored
|
||||
static uint32_t s_stepNum; // Global step number
|
||||
protected:
|
||||
@ -170,14 +176,12 @@ public:
|
||||
void setIgnoreThisStep() { m_ignoreInStep = s_stepNum; }
|
||||
virtual bool followScoreboard() const = 0;
|
||||
static bool followScoreboard(const V3GraphEdge* edgep) {
|
||||
const SplitEdge* const oedgep = dynamic_cast<const SplitEdge*>(edgep);
|
||||
if (!oedgep) v3fatalSrc("Following edge of non-SplitEdge type");
|
||||
const SplitEdge* const oedgep = edgep->as<SplitEdge>();
|
||||
if (oedgep->ignoreThisStep()) return false;
|
||||
return oedgep->followScoreboard();
|
||||
}
|
||||
static bool followCyclic(const V3GraphEdge* edgep) {
|
||||
const SplitEdge* const oedgep = dynamic_cast<const SplitEdge*>(edgep);
|
||||
if (!oedgep) v3fatalSrc("Following edge of non-SplitEdge type");
|
||||
const SplitEdge* const oedgep = edgep->as<SplitEdge>();
|
||||
return (!oedgep->ignoreThisStep());
|
||||
}
|
||||
string dotStyle() const override {
|
||||
@ -187,6 +191,7 @@ public:
|
||||
uint32_t SplitEdge::s_stepNum = 0;
|
||||
|
||||
class SplitPostEdge final : public SplitEdge {
|
||||
VL_RTTI_IMPL(SplitPostEdge, SplitEdge)
|
||||
public:
|
||||
SplitPostEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
|
||||
: SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {}
|
||||
@ -196,6 +201,7 @@ public:
|
||||
};
|
||||
|
||||
class SplitLVEdge final : public SplitEdge {
|
||||
VL_RTTI_IMPL(SplitLVEdge, SplitEdge)
|
||||
public:
|
||||
SplitLVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
|
||||
: SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {}
|
||||
@ -205,6 +211,7 @@ public:
|
||||
};
|
||||
|
||||
class SplitRVEdge final : public SplitEdge {
|
||||
VL_RTTI_IMPL(SplitRVEdge, SplitEdge)
|
||||
public:
|
||||
SplitRVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
|
||||
: SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {}
|
||||
@ -213,7 +220,8 @@ public:
|
||||
string dotColor() const override { return "green"; }
|
||||
};
|
||||
|
||||
struct SplitScorebdEdge : public SplitEdge {
|
||||
class SplitScorebdEdge final : public SplitEdge {
|
||||
VL_RTTI_IMPL(SplitScorebdEdge, SplitEdge)
|
||||
public:
|
||||
SplitScorebdEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
|
||||
: SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {}
|
||||
@ -222,7 +230,8 @@ public:
|
||||
string dotColor() const override { return "blue"; }
|
||||
};
|
||||
|
||||
struct SplitStrictEdge : public SplitEdge {
|
||||
class SplitStrictEdge final : public SplitEdge {
|
||||
VL_RTTI_IMPL(SplitStrictEdge, SplitEdge)
|
||||
// A strict order, based on the original statement order in the graph
|
||||
// The only non-cutable edge type
|
||||
public:
|
||||
@ -316,14 +325,14 @@ protected:
|
||||
void pruneDepsOnInputs() {
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (!vertexp->outBeginp() && dynamic_cast<SplitVarStdVertex*>(vertexp)) {
|
||||
if (!vertexp->outBeginp() && vertexp->is<SplitVarStdVertex>()) {
|
||||
if (debug() >= 9) {
|
||||
const SplitVarStdVertex* const stdp = static_cast<SplitVarStdVertex*>(vertexp);
|
||||
UINFO(0, "Will prune deps on var " << stdp->nodep() << endl);
|
||||
stdp->nodep()->dumpTree("- ");
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
SplitEdge* const oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
SplitEdge* const oedgep = edgep->as<SplitEdge>();
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
}
|
||||
@ -474,17 +483,16 @@ protected:
|
||||
// vertexes not involved with this step as unimportant
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (const SplitLogicVertex* const vvertexp
|
||||
= dynamic_cast<SplitLogicVertex*>(vertexp)) {
|
||||
if (!vvertexp->user()) {
|
||||
if (!vertexp->user()) {
|
||||
if (const SplitLogicVertex* const vvertexp = vertexp->cast<SplitLogicVertex>()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep;
|
||||
edgep = edgep->inNextp()) {
|
||||
SplitEdge* const oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
SplitEdge* const oedgep = edgep->as<SplitEdge>();
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep;
|
||||
edgep = edgep->outNextp()) {
|
||||
SplitEdge* const oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
SplitEdge* const oedgep = edgep->as<SplitEdge>();
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
}
|
||||
@ -903,7 +911,7 @@ protected:
|
||||
// inputs) prune all edges that depend on the 'if'.
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
const SplitLogicVertex* const logicp = dynamic_cast<SplitLogicVertex*>(vertexp);
|
||||
const SplitLogicVertex* const logicp = vertexp->cast<const SplitLogicVertex>();
|
||||
if (!logicp) continue;
|
||||
|
||||
const AstNodeIf* const ifNodep = VN_CAST(logicp->nodep(), NodeIf);
|
||||
@ -911,7 +919,7 @@ protected:
|
||||
|
||||
bool pruneMe = true;
|
||||
for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
const SplitEdge* const oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
const SplitEdge* const oedgep = edgep->as<const SplitEdge>();
|
||||
if (!oedgep->ignoreThisStep()) {
|
||||
// This if conditional depends on something we can't
|
||||
// prune -- a variable generated in the current block.
|
||||
@ -921,7 +929,7 @@ protected:
|
||||
// give a hint about why...
|
||||
if (debug() >= 9) {
|
||||
V3GraphVertex* vxp = oedgep->top();
|
||||
const SplitNodeVertex* const nvxp = dynamic_cast<SplitNodeVertex*>(vxp);
|
||||
const SplitNodeVertex* const nvxp = vxp->as<const SplitNodeVertex>();
|
||||
UINFO(0, "Cannot prune if-node due to edge "
|
||||
<< oedgep << " pointing to node " << nvxp->nodep() << endl);
|
||||
nvxp->nodep()->dumpTree("- ");
|
||||
@ -935,7 +943,7 @@ protected:
|
||||
|
||||
// This if can be split; prune dependencies on it.
|
||||
for (V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
SplitEdge* const oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
SplitEdge* const oedgep = edgep->as<SplitEdge>();
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ static void selfTestString();
|
||||
// Vertex that tracks a per-vertex key
|
||||
template <typename T_Key>
|
||||
class TspVertexTmpl final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(TspVertexTmpl, V3GraphVertex)
|
||||
private:
|
||||
const T_Key m_key;
|
||||
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
};
|
||||
|
||||
class TaskEdge final : public V3GraphEdge {
|
||||
VL_RTTI_IMPL(TaskEdge, V3GraphEdge)
|
||||
public:
|
||||
TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top)
|
||||
: V3GraphEdge{graphp, fromp, top, 1, false} {}
|
||||
|
@ -93,6 +93,7 @@ private:
|
||||
// Vertex of a dependency graph of suspendable nodes, e.g. if a node (process or task) is
|
||||
// suspendable, all its dependents should also be suspendable
|
||||
class DepVtx VL_NOT_FINAL : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(DepVtx, V3GraphVertex)
|
||||
AstClass* const m_classp; // Class associated with a method
|
||||
AstNode* const m_nodep; // AST node represented by this graph vertex
|
||||
|
||||
@ -121,6 +122,7 @@ private:
|
||||
};
|
||||
|
||||
class SuspendDepVtx final : public DepVtx {
|
||||
VL_RTTI_IMPL(SuspendDepVtx, DepVtx)
|
||||
string dotColor() const override {
|
||||
if (nodep()->user2() & T_SUSPENDER) return "red";
|
||||
if (nodep()->user2() & T_SUSPENDEE) return "blue";
|
||||
@ -134,6 +136,7 @@ private:
|
||||
};
|
||||
|
||||
class NeedsProcDepVtx final : public DepVtx {
|
||||
VL_RTTI_IMPL(NeedsProcDepVtx, DepVtx)
|
||||
string dotColor() const override {
|
||||
if (nodep()->user2() & T_CALLS_PROC_SELF) return "red";
|
||||
if (nodep()->user2() & T_HAS_PROC) return "blue";
|
||||
|
@ -56,6 +56,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
// Graph vertexes
|
||||
|
||||
class TraceActivityVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(TraceActivityVertex, V3GraphVertex)
|
||||
AstNode* const m_insertp;
|
||||
int32_t m_activityCode;
|
||||
bool m_slow; // If always slow, we can use the same code
|
||||
@ -100,6 +101,7 @@ public:
|
||||
};
|
||||
|
||||
class TraceCFuncVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(TraceCFuncVertex, V3GraphVertex)
|
||||
AstCFunc* const m_nodep;
|
||||
|
||||
public:
|
||||
@ -115,6 +117,7 @@ public:
|
||||
};
|
||||
|
||||
class TraceTraceVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(TraceTraceVertex, V3GraphVertex)
|
||||
AstTraceDecl* const m_nodep; // TRACEINC this represents
|
||||
// nullptr, or other vertex with the real code() that duplicates this one
|
||||
TraceTraceVertex* m_duplicatep = nullptr;
|
||||
@ -137,6 +140,7 @@ public:
|
||||
};
|
||||
|
||||
class TraceVarVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(TraceVarVertex, V3GraphVertex)
|
||||
AstVarScope* const m_nodep;
|
||||
|
||||
public:
|
||||
@ -204,8 +208,7 @@ private:
|
||||
// Hash all of the values the traceIncs need
|
||||
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||
itp = itp->verticesNextp()) {
|
||||
if (const TraceTraceVertex* const vvertexp
|
||||
= dynamic_cast<const TraceTraceVertex*>(itp)) {
|
||||
if (const TraceTraceVertex* const vvertexp = itp->cast<const TraceTraceVertex>()) {
|
||||
const AstTraceDecl* const nodep = vvertexp->nodep();
|
||||
if (nodep->valuep()) {
|
||||
UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep,
|
||||
@ -220,7 +223,7 @@ private:
|
||||
}
|
||||
// Find if there are any duplicates
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (TraceTraceVertex* const vvertexp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
||||
if (TraceTraceVertex* const vvertexp = itp->cast<TraceTraceVertex>()) {
|
||||
const AstTraceDecl* const nodep = vvertexp->nodep();
|
||||
if (nodep->valuep() && !vvertexp->duplicatep()) {
|
||||
const auto dupit = dupFinder.findDuplicate(nodep->valuep());
|
||||
@ -229,7 +232,7 @@ private:
|
||||
= VN_AS(dupit->second->backp(), TraceDecl);
|
||||
UASSERT_OBJ(dupDeclp, nodep, "Trace duplicate of wrong type");
|
||||
TraceTraceVertex* const dupvertexp
|
||||
= dynamic_cast<TraceTraceVertex*>(dupDeclp->user1u().toGraphVertex());
|
||||
= dupDeclp->user1u().toGraphVertex()->cast<TraceTraceVertex>();
|
||||
UINFO(8, " Orig " << nodep << endl);
|
||||
UINFO(8, " dup " << dupDeclp << endl);
|
||||
// Mark the hashed node as the original and our
|
||||
@ -246,7 +249,7 @@ private:
|
||||
// Remove all variable nodes
|
||||
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
||||
nextp = itp->verticesNextp();
|
||||
if (TraceVarVertex* const vvertexp = dynamic_cast<TraceVarVertex*>(itp)) {
|
||||
if (TraceVarVertex* const vvertexp = itp->cast<TraceVarVertex>()) {
|
||||
vvertexp->rerouteEdges(&m_graph);
|
||||
vvertexp->unlinkDelete(&m_graph);
|
||||
}
|
||||
@ -258,7 +261,7 @@ private:
|
||||
// Remove all Cfunc nodes
|
||||
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
||||
nextp = itp->verticesNextp();
|
||||
if (TraceCFuncVertex* const vvertexp = dynamic_cast<TraceCFuncVertex*>(itp)) {
|
||||
if (TraceCFuncVertex* const vvertexp = itp->cast<TraceCFuncVertex>()) {
|
||||
vvertexp->rerouteEdges(&m_graph);
|
||||
vvertexp->unlinkDelete(&m_graph);
|
||||
}
|
||||
@ -271,16 +274,13 @@ private:
|
||||
// If there are any edges from a always, keep only the always
|
||||
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||
itp = itp->verticesNextp()) {
|
||||
if (const TraceTraceVertex* const vvertexp
|
||||
= dynamic_cast<const TraceTraceVertex*>(itp)) {
|
||||
if (const TraceTraceVertex* const vvertexp = itp->cast<const TraceTraceVertex>()) {
|
||||
// Search for the incoming always edge
|
||||
const V3GraphEdge* alwaysEdgep = nullptr;
|
||||
for (const V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;
|
||||
edgep = edgep->inNextp()) {
|
||||
const TraceActivityVertex* const actVtxp
|
||||
= dynamic_cast<const TraceActivityVertex*>(edgep->fromp());
|
||||
UASSERT_OBJ(actVtxp, vvertexp->nodep(),
|
||||
"Tracing a node with FROM non activity");
|
||||
= edgep->fromp()->as<const TraceActivityVertex>();
|
||||
if (actVtxp->activityAlways()) {
|
||||
alwaysEdgep = edgep;
|
||||
break;
|
||||
@ -299,7 +299,7 @@ private:
|
||||
// Activity points with no outputs can be removed
|
||||
for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) {
|
||||
nextp = itp->verticesNextp();
|
||||
if (TraceActivityVertex* const vtxp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
||||
if (TraceActivityVertex* const vtxp = itp->cast<TraceActivityVertex>()) {
|
||||
// Leave in the always vertex for later use.
|
||||
if (vtxp != m_alwaysVtxp && !vtxp->outBeginp()) vtxp->unlinkDelete(&m_graph);
|
||||
}
|
||||
@ -309,7 +309,7 @@ private:
|
||||
uint32_t assignactivityNumbers() {
|
||||
uint32_t activityNumber = 1; // Note 0 indicates "slow" only
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (TraceActivityVertex* const vvertexp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
||||
if (TraceActivityVertex* const vvertexp = itp->cast<TraceActivityVertex>()) {
|
||||
if (vvertexp != m_alwaysVtxp) {
|
||||
if (vvertexp->slow()) {
|
||||
vvertexp->activityCode(TraceActivityVertex::ACTIVITY_SLOW);
|
||||
@ -328,14 +328,14 @@ private:
|
||||
nFullCodes = 0;
|
||||
nChgCodes = 0;
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (TraceTraceVertex* const vtxp = dynamic_cast<TraceTraceVertex*>(itp)) {
|
||||
if (TraceTraceVertex* const vtxp = itp->cast<TraceTraceVertex>()) {
|
||||
ActCodeSet actSet;
|
||||
UINFO(9, " Add to sort: " << vtxp << endl);
|
||||
if (debug() >= 9) vtxp->nodep()->dumpTree("- trnode: ");
|
||||
for (const V3GraphEdge* edgep = vtxp->inBeginp(); edgep;
|
||||
edgep = edgep->inNextp()) {
|
||||
const TraceActivityVertex* const cfvertexp
|
||||
= dynamic_cast<const TraceActivityVertex*>(edgep->fromp());
|
||||
= edgep->fromp()->cast<const TraceActivityVertex>();
|
||||
UASSERT_OBJ(cfvertexp, vtxp->nodep(),
|
||||
"Should have been function pointing to this trace");
|
||||
UINFO(9, " Activity: " << cfvertexp << endl);
|
||||
@ -471,8 +471,7 @@ private:
|
||||
// Insert activity setters
|
||||
for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp;
|
||||
itp = itp->verticesNextp()) {
|
||||
if (const TraceActivityVertex* const vtxp
|
||||
= dynamic_cast<const TraceActivityVertex*>(itp)) {
|
||||
if (const TraceActivityVertex* const vtxp = itp->cast<const TraceActivityVertex>()) {
|
||||
if (vtxp->activitySlow()) {
|
||||
// Just set all flags in slow code as it should be rare.
|
||||
// This will be rolled up into a loop by V3Reloop.
|
||||
@ -787,7 +786,7 @@ private:
|
||||
|
||||
TraceCFuncVertex* getCFuncVertexp(AstCFunc* nodep) {
|
||||
TraceCFuncVertex* vertexp
|
||||
= dynamic_cast<TraceCFuncVertex*>(nodep->user1u().toGraphVertex());
|
||||
= nodep->user1() ? nodep->user1u().toGraphVertex()->cast<TraceCFuncVertex>() : nullptr;
|
||||
if (!vertexp) {
|
||||
vertexp = new TraceCFuncVertex{&m_graph, nodep};
|
||||
nodep->user1p(vertexp);
|
||||
@ -796,7 +795,8 @@ private:
|
||||
}
|
||||
TraceActivityVertex* getActivityVertexp(AstNode* nodep, bool slow) {
|
||||
TraceActivityVertex* vertexp
|
||||
= dynamic_cast<TraceActivityVertex*>(nodep->user3u().toGraphVertex());
|
||||
= nodep->user3() ? nodep->user3u().toGraphVertex()->cast<TraceActivityVertex>()
|
||||
: nullptr;
|
||||
if (!vertexp) {
|
||||
vertexp = new TraceActivityVertex{&m_graph, nodep, slow};
|
||||
nodep->user3p(vertexp);
|
||||
|
@ -142,6 +142,7 @@ public:
|
||||
// Graph support classes
|
||||
|
||||
class TristateVertex final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(TristateVertex, V3GraphVertex)
|
||||
AstNode* const m_nodep;
|
||||
bool m_isTristate = false; // Logic indicates a tristate
|
||||
bool m_feedsTri = false; // Propagates to a tristate node (on RHS)
|
||||
@ -222,7 +223,7 @@ private:
|
||||
UINFO(9, " Mark tri " << level << " " << vtxp << endl);
|
||||
if (!vtxp->varp()) { // not a var where we stop the recursion
|
||||
for (V3GraphEdge* edgep = vtxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
TristateVertex* const vvertexp = dynamic_cast<TristateVertex*>(edgep->top());
|
||||
TristateVertex* const vvertexp = edgep->top()->as<TristateVertex>();
|
||||
// Doesn't hurt to not check if already set, but by doing so when we
|
||||
// print out the debug messages, we'll see this node at level 0 instead.
|
||||
if (!vvertexp->isTristate()) {
|
||||
@ -234,7 +235,7 @@ private:
|
||||
// A variable is tristated. Find all of the LHS VARREFs that
|
||||
// drive this signal now need tristate drivers
|
||||
for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
TristateVertex* const vvertexp = dynamic_cast<TristateVertex*>(edgep->fromp());
|
||||
TristateVertex* const vvertexp = edgep->fromp()->as<TristateVertex>();
|
||||
if (const AstVarRef* const refp = VN_CAST(vvertexp->nodep(), VarRef)) {
|
||||
if (refp->access().isWriteOrRW()
|
||||
// Doesn't hurt to not check if already set, but by doing so when we
|
||||
@ -259,7 +260,7 @@ private:
|
||||
UINFO(9, " Mark feedstri " << level << " " << vtxp << endl);
|
||||
if (!vtxp->varp()) { // not a var where we stop the recursion
|
||||
for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
TristateVertex* const vvertexp = dynamic_cast<TristateVertex*>(edgep->fromp());
|
||||
TristateVertex* const vvertexp = edgep->fromp()->as<TristateVertex>();
|
||||
// Doesn't hurt to not check if already set, but by doing so when we
|
||||
// print out the debug messages, we'll see this node at level 0 instead.
|
||||
if (!vvertexp->feedsTri()) {
|
||||
|
Loading…
Reference in New Issue
Block a user