Cleanup V3Changed and V3GenClk

This commit is contained in:
Geza Lore 2022-02-11 10:46:02 +00:00
parent 4b79d23d00
commit 8931bd37e2
3 changed files with 41 additions and 102 deletions

View File

@ -2025,12 +2025,15 @@ public:
#include "V3Ast__gen_impl.h" // From ./astgen
// Specializations of privateMayBeUnder
template <> inline bool AstNode::mayBeUnder<AstCell>(const AstNode* nodep) {
template <> inline bool AstNode::privateMayBeUnder<AstCell>(const AstNode* nodep) {
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath);
}
template <> inline bool AstNode::mayBeUnder<AstNodeAssign>(const AstNode* nodep) {
template <> inline bool AstNode::privateMayBeUnder<AstNodeAssign>(const AstNode* nodep) {
return !VN_IS(nodep, NodeMath);
}
template <> inline bool AstNode::privateMayBeUnder<AstVarScope>(const AstNode* nodep) {
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath);
}
inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
if (!rhs) {

View File

@ -117,8 +117,8 @@ public:
class ChangedInsertVisitor final : public VNVisitor {
private:
// STATE
ChangedState* m_statep = nullptr; // Shared state across visitors
AstVarScope* m_vscp = nullptr; // Original (non-change) variable we're change-detecting
ChangedState& m_state; // Shared state across visitors
AstVarScope* const m_vscp; // Original (non-change) variable we're change-detecting
AstVarScope* m_newvscp = nullptr; // New (change detect) variable we're change-detecting
AstNode* m_varEqnp = nullptr; // Original var's equation to get var value
AstNode* m_newLvEqnp = nullptr; // New var's equation to read value
@ -126,34 +126,32 @@ private:
uint32_t m_detects = 0; // # detects created
// CONSTANTS
enum MiscConsts {
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
// Ok to increase this, but may result in much slower model
};
// How many indexes before error. Ok to increase this, but may result in much slower model
static constexpr uint32_t DETECTARRAY_MAX_INDEXES = 256;
void newChangeDet() {
if (++m_detects > DETECTARRAY_MAX_INDEXES) {
m_vscp->v3warn(E_DETECTARRAY,
"Unsupported: Can't detect more than "
<< cvtToStr(DETECTARRAY_MAX_INDEXES)
<< DETECTARRAY_MAX_INDEXES
<< " array indexes (probably with UNOPTFLAT warning suppressed): "
<< m_vscp->prettyName() << '\n'
<< m_vscp->warnMore()
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased");
return;
}
m_statep->maybeCreateChgFuncp();
m_state.maybeCreateChgFuncp();
AstChangeDet* const changep = new AstChangeDet{
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true)};
m_statep->m_chgFuncp->addStmtsp(changep);
m_state.m_chgFuncp->addStmtsp(changep);
AstAssign* const initp = new AstAssign{m_vscp->fileline(), m_newLvEqnp->cloneTree(true),
m_varEqnp->cloneTree(true)};
m_statep->m_chgFuncp->addFinalsp(initp);
m_state.m_chgFuncp->addFinalsp(initp);
// Later code will expand words which adds to GCC compile time,
// so add penalty based on word width also
m_statep->m_numStmts += initp->nodeCount() + m_varEqnp->widthWords();
m_state.m_numStmts += initp->nodeCount() + m_varEqnp->widthWords();
}
virtual void visit(AstBasicDType*) override { //
@ -202,13 +200,13 @@ private:
public:
// CONSTRUCTORS
ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) {
ChangedInsertVisitor(AstVarScope* vscp, ChangedState& state)
: m_state{state}
, m_vscp{vscp} {
// DPI export trigger should never need change detect. See similar assertions in V3Order
// (OrderVisitor::nodeMarkCircular), and V3GenClk (GenClkRenameVisitor::genInpClk).
UASSERT_OBJ(vscp != v3Global.rootp()->dpiExportTriggerp(), vscp,
"DPI export trigger should not need change detect");
m_statep = statep;
m_vscp = vscp;
{
AstVar* const varp = m_vscp->varp();
const string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
@ -219,9 +217,9 @@ public:
// CHANGEDET(VARREF(_last), VARREF(var))
AstVar* const newvarp
= new AstVar{varp->fileline(), VVarType::MODULETEMP, newvarname, varp};
m_statep->m_topModp->addStmtp(newvarp);
m_newvscp = new AstVarScope{m_vscp->fileline(), m_statep->m_scopetopp, newvarp};
m_statep->m_scopetopp->addVarp(m_newvscp);
m_state.m_topModp->addStmtp(newvarp);
m_newvscp = new AstVarScope{m_vscp->fileline(), m_state.m_scopetopp, newvarp};
m_state.m_scopetopp->addVarp(m_newvscp);
m_varEqnp = new AstVarRef{m_vscp->fileline(), m_vscp, VAccess::READ};
m_newLvEqnp = new AstVarRef{m_vscp->fileline(), m_newvscp, VAccess::WRITE};
@ -236,72 +234,22 @@ public:
VL_UNCOPYABLE(ChangedInsertVisitor);
};
//######################################################################
// Changed state, as a visitor of each AstNode
class ChangedVisitor final : public VNVisitor {
private:
// NODE STATE
// Entire netlist:
// AstVarScope::user1() -> bool. True indicates processed
const VNUser1InUse m_inuser1;
// STATE
ChangedState* const m_statep; // Shared state across visitors
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void genChangeDet(AstVarScope* vscp) {
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ());
{ ChangedInsertVisitor{vscp, m_statep}; }
}
// VISITORS
virtual void visit(AstNodeModule* nodep) override {
UINFO(4, " MOD " << nodep << endl);
if (nodep->isTop()) m_statep->m_topModp = nodep;
iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) override {
UINFO(4, " TS " << nodep << endl);
// Clearing
AstNode::user1ClearTree();
// Prep for if make change detection function
AstScope* const scopep = nodep->scopep();
UASSERT_OBJ(scopep, nodep, "No scope found on top level, perhaps you have no statements?");
m_statep->m_scopetopp = scopep;
iterateChildren(nodep);
}
virtual void visit(AstVarScope* nodep) override {
if (nodep->isCircular()) {
UINFO(8, " CIRC " << nodep << endl);
if (!nodep->user1SetOnce()) genChangeDet(nodep);
}
}
//--------------------
virtual void visit(AstNodeMath*) override {} // Accelerate
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
ChangedVisitor(AstNetlist* nodep, ChangedState* statep)
: m_statep{statep} {
iterate(nodep);
}
virtual ~ChangedVisitor() override = default;
};
//######################################################################
// Changed class functions
void V3Changed::changedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{
ChangedState state;
ChangedVisitor{nodep, &state};
} // Destruct before checking
ChangedState state;
state.m_scopetopp = nodep->topScopep()->scopep();
state.m_topModp = nodep->topModulep();
nodep->foreach<AstVarScope>([&state](AstVarScope* vscp) {
if (vscp->isCircular()) {
vscp->v3warn(IMPERFECTSCH,
"Imperfect scheduling of variable: " << vscp->prettyNameQ());
ChangedInsertVisitor{vscp, state};
}
});
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -53,9 +53,7 @@ private:
// METHODS
AstVarScope* genInpClk(AstVarScope* vscp) {
if (vscp->user2p()) {
return VN_AS(vscp->user2p(), VarScope);
} else {
if (!vscp->user2p()) {
// In order to create a __VinpClk* for a signal, it needs to be marked circular.
// The DPI export trigger is never marked circular by V3Order (see comments in
// OrderVisitor::nodeMarkCircular). The only other place where one might mark
@ -86,22 +84,15 @@ private:
m_scopetopp->addFinalClkp(asninitp);
//
vscp->user2p(newvscp);
return newvscp;
}
return VN_AS(vscp->user2p(), VarScope);
}
// VISITORS
virtual void visit(AstTopScope* nodep) override {
AstNode::user2ClearTree(); // user2p() used on entire tree
iterateChildren(nodep);
}
//----
virtual void visit(AstVarRef* nodep) override {
// Consumption/generation of a variable,
AstVarScope* const vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (m_activep && !nodep->user3()) {
nodep->user3(true);
if (m_activep && !nodep->user3SetOnce()) {
AstVarScope* const vscp = nodep->varScopep();
if (vscp->isCircular()) {
UINFO(8, " VarActReplace " << nodep << endl);
// Replace with the new variable
@ -115,10 +106,8 @@ private:
}
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterate(nodep->sensesp());
m_activep = nullptr;
iterateChildren(nodep);
}
//-----
@ -141,7 +130,6 @@ private:
// NODE STATE
// Cleared on top scope
// AstVarScope::user() -> bool. Set when the var has been used as clock
const VNUser1InUse m_inuser1;
// STATE
bool m_tracingCall = false; // Iterating into a call to a cfunc
@ -151,13 +139,13 @@ private:
// VISITORS
virtual void visit(AstTopScope* nodep) override {
AstNode::user1ClearTree(); // user1p() used on entire tree
iterateChildren(nodep);
{
// Make the new clock signals and replace any activate references
// See rename, it does some AstNode::userClearTree()'s
GenClkRenameVisitor{nodep, m_topModp};
const VNUser1InUse user1InUse;
iterateChildren(nodep);
}
// Make the new clock signals and replace any activate references
// See rename, it does some AstNode::userClearTree()'s
GenClkRenameVisitor{nodep, m_topModp};
}
virtual void visit(AstNodeModule* nodep) override {
// Only track the top scopes, not lower level functions