Add separate AstInitialStatic node for static initializers

Static variable initializers run before initial blocks, so use an
explicitly different procedure type for them. This also enables us to
now raise errors for assignments to const variables in initial blocks.
This commit is contained in:
Geza Lore 2022-04-23 14:44:48 +01:00
parent b22e368b25
commit 9abab2c366
9 changed files with 33 additions and 4 deletions

View File

@ -15,6 +15,7 @@ Verilator 4.221 devel
* Split --prof-threads into --prof-exec and --prof-pgo (#3365). [Geza Lore, Shunyao CAD]
* Deprecate 'vluint64_t' and similar types (#3255).
* Raise error on assignment to const in initial blocks. [Geza Lore, Shunyao CAD]
* Fix MSVC localtime_s (#3124).
* Fix Bison 3.8.2 error (#3366). [elike-ypq]
* Fix rare bug in -Oz (V3Localize) (#3286). [Geza Lore, Shunyao CAD]

View File

@ -422,6 +422,14 @@ private:
virtual void visit(AstActive* nodep) override {
// Actives are being formed, so we can ignore any already made
}
virtual void visit(AstInitialStatic* nodep) override {
// Relink to IACTIVE, unless already under it
UINFO(4, " INITIAL " << nodep << endl);
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
AstActive* const wantactivep = m_namer.getIActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstInitial* nodep) override {
// Relink to IACTIVE, unless already under it
UINFO(4, " INITIAL " << nodep << endl);

View File

@ -3407,7 +3407,7 @@ public:
};
class AstInitialAutomatic final : public AstNodeProcedure {
// initial for automatic variables
// Automatic variable initialization
// That is, it runs every function start, or class construction
public:
AstInitialAutomatic(FileLine* fl, AstNode* bodysp)
@ -3415,6 +3415,15 @@ public:
ASTNODE_NODE_FUNCS(InitialAutomatic)
};
class AstInitialStatic final : public AstNodeProcedure {
// Static variable initialization
// That is, it runs at the beginning of simulation, before 'initial' blocks
public:
AstInitialStatic(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER_InitialStatic(fl, bodysp) {}
ASTNODE_NODE_FUNCS(InitialStatic)
};
class AstAlways final : public AstNodeProcedure {
const VAlwaysKwd m_keyword;

View File

@ -716,6 +716,7 @@ private:
// Ignores
virtual void visit(AstInitial*) override {}
virtual void visit(AstInitialAutomatic*) override {}
virtual void visit(AstInitialStatic*) override {}
virtual void visit(AstTraceDecl*) override {}
virtual void visit(AstCoverToggle*) override {}
virtual void visit(AstNodeDType*) override {}

View File

@ -153,6 +153,11 @@ private:
iterateChildren(nodep);
if (m_packageScopep) { m_toScopeMoves.push_back(std::make_pair(nodep, m_packageScopep)); }
}
virtual void visit(AstInitialStatic* nodep) override {
// But not AstInitialAutomatic, which remains under the class
iterateChildren(nodep);
if (m_packageScopep) { m_toScopeMoves.push_back(std::make_pair(nodep, m_packageScopep)); }
}
virtual void visit(AstNodeMath* nodep) override {} // Short circuit
virtual void visit(AstNodeStmt* nodep) override {} // Short circuit
@ -173,7 +178,7 @@ public:
vscp->scopep(scopep);
vscp->unlinkFrBack();
scopep->addVarp(vscp);
} else if (VN_IS(nodep, Initial)) {
} else if (VN_IS(nodep, Initial) || VN_IS(nodep, InitialStatic)) {
nodep->unlinkFrBack();
scopep->addActivep(nodep);
} else {

View File

@ -99,6 +99,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
putqs(nodep, "end\n");
}
virtual void visit(AstInitialAutomatic* nodep) override { iterateChildrenConst(nodep); }
virtual void visit(AstInitialStatic* nodep) override { iterateChildrenConst(nodep); }
virtual void visit(AstAlways* nodep) override {
putfs(nodep, "always ");
if (m_sensesp) {

View File

@ -275,7 +275,7 @@ private:
if (nodep->lifetime().isAutomatic()) {
nodep->addNextHere(new AstInitialAutomatic{newfl, assp});
} else {
nodep->addNextHere(new AstInitial{newfl, assp});
nodep->addNextHere(new AstInitialStatic{newfl, assp});
}
} // 4. Under blocks, it's an initial value to be under an assign
else {

View File

@ -662,6 +662,9 @@ class OrderBuildVisitor final : public VNVisitor {
virtual void visit(AstInitialAutomatic* nodep) override { //
iterateLogic(nodep);
}
virtual void visit(AstInitialStatic* nodep) override { //
iterateLogic(nodep);
}
virtual void visit(AstAlways* nodep) override { //
iterateLogic(nodep);
}

View File

@ -2041,7 +2041,8 @@ private:
if (nodep->access().isWriteOrRW() && nodep->varp()->direction() == VDirection::CONSTREF) {
nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ());
} else if (nodep->access().isWriteOrRW() && nodep->varp()->isConst() && !m_paramsOnly
&& (!m_ftaskp || !m_ftaskp->isConstructor()) && !VN_IS(m_procedurep, Initial)) {
&& (!m_ftaskp || !m_ftaskp->isConstructor())
&& !VN_IS(m_procedurep, InitialStatic)) {
// Too loose, but need to allow our generated first assignment
// Move this to a property of the AstInitial block
nodep->v3error("Assigning to const variable: " << nodep->prettyNameQ());