Internals: Cleanup some V3LinkParse code; ignore whitespace if diff. No functional change.

This commit is contained in:
Wilson Snyder 2025-09-21 15:30:49 -04:00
parent ad6379b762
commit 9e664a3921
1 changed files with 85 additions and 85 deletions

View File

@ -44,13 +44,14 @@ class LinkParseVisitor final : public VNVisitor {
// TYPES // TYPES
using ImplTypedefMap = std::map<std::string, AstTypedef*>; using ImplTypedefMap = std::map<std::string, AstTypedef*>;
// STATE // STATE - across all visitors
AstVar* m_varp = nullptr; // Variable we're under
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
std::unordered_set<FileLine*> m_filelines; // Filelines that have been seen std::unordered_set<FileLine*> m_filelines; // Filelines that have been seen
bool m_inAlways = false; // Inside an always
AstNodeModule* m_valueModp // STATE - for current visit position (use VL_RESTORER)
= nullptr; // If set, move AstVar->valuep() initial values to this module // If set, move AstVar->valuep() initial values to this module
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
AstVar* m_varp = nullptr; // Variable we're under
AstNodeModule* m_valueModp = nullptr;
AstNodeModule* m_modp = nullptr; // Current module AstNodeModule* m_modp = nullptr; // Current module
AstNodeFTask* m_ftaskp = nullptr; // Current task AstNodeFTask* m_ftaskp = nullptr; // Current task
AstNodeDType* m_dtypep = nullptr; // Current data type AstNodeDType* m_dtypep = nullptr; // Current data type
@ -61,27 +62,29 @@ class LinkParseVisitor final : public VNVisitor {
int m_genblkNum = 0; // Begin block number, 0=none seen int m_genblkNum = 0; // Begin block number, 0=none seen
int m_beginDepth = 0; // How many begin blocks above current node within current AstNodeModule int m_beginDepth = 0; // How many begin blocks above current node within current AstNodeModule
VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime
bool m_inAlways = false; // Inside an always
bool m_insideLoop = false; // True if the node is inside a loop bool m_insideLoop = false; // True if the node is inside a loop
bool m_lifetimeAllowed = false; // True to allow lifetime settings bool m_lifetimeAllowed = false; // True to allow lifetime settings
VDouble0 m_statModules; // Number of modules seen
bool m_moduleWithGenericIface = false; // If current module contains generic interface bool m_moduleWithGenericIface = false; // If current module contains generic interface
// STATE - Statistic tracking
VDouble0 m_statModules; // Number of modules seen
// METHODS // METHODS
void cleanFileline(AstNode* nodep) { void cleanFileline(AstNode* nodep) {
if (!nodep->user2SetOnce()) { // Process once if (nodep->user2SetOnce()) return; // Process once
// We make all filelines unique per AstNode. This allows us to // We make all filelines unique per AstNode. This allows us to
// later turn off messages on a fileline when an issue is found // later turn off messages on a fileline when an issue is found
// so that messages on replicated blocks occur only once, // so that messages on replicated blocks occur only once,
// without suppressing other token's messages as a side effect. // without suppressing other token's messages as a side effect.
// We could have verilog.l create a new one on every token, // We could have verilog.l create a new one on every token,
// but that's a lot more structures than only doing AST nodes. // but that's a lot more structures than only doing AST nodes.
// TODO: Many places copy the filename when suppressing warnings, // TODO: Many places copy the filename when suppressing warnings,
// perhaps audit to make consistent and this is no longer needed // perhaps audit to make consistent and this is no longer needed
if (m_filelines.find(nodep->fileline()) != m_filelines.end()) { if (m_filelines.find(nodep->fileline()) != m_filelines.end()) {
nodep->fileline(new FileLine{nodep->fileline()}); nodep->fileline(new FileLine{nodep->fileline()});
}
m_filelines.insert(nodep->fileline());
} }
m_filelines.insert(nodep->fileline());
} }
string nameFromTypedef(AstNode* nodep) { string nameFromTypedef(AstNode* nodep) {
@ -101,12 +104,11 @@ class LinkParseVisitor final : public VNVisitor {
} }
void visitIterateNodeDType(AstNodeDType* nodep) { void visitIterateNodeDType(AstNodeDType* nodep) {
if (!nodep->user1SetOnce()) { // Process only once. if (nodep->user1SetOnce()) return; // Process only once.
cleanFileline(nodep); cleanFileline(nodep);
VL_RESTORER(m_dtypep); VL_RESTORER(m_dtypep);
m_dtypep = nodep; m_dtypep = nodep;
iterateChildren(nodep); iterateChildren(nodep);
}
} }
bool nestedIfBegin(AstBegin* nodep) { // Point at begin inside the GenIf bool nestedIfBegin(AstBegin* nodep) { // Point at begin inside the GenIf
@ -178,71 +180,69 @@ class LinkParseVisitor final : public VNVisitor {
// VISITORS // VISITORS
void visit(AstNodeFTask* nodep) override { void visit(AstNodeFTask* nodep) override {
if (!nodep->user1SetOnce()) { // Process only once. if (nodep->user1SetOnce()) return; // Process only once.
// Mark class methods // Mark class methods
if (VN_IS(m_modp, Class)) nodep->classMethod(true); if (VN_IS(m_modp, Class)) nodep->classMethod(true);
V3Control::applyFTask(m_modp, nodep); V3Control::applyFTask(m_modp, nodep);
cleanFileline(nodep); cleanFileline(nodep);
VL_RESTORER(m_ftaskp); VL_RESTORER(m_ftaskp);
VL_RESTORER(m_lifetime); VL_RESTORER(m_lifetime);
m_ftaskp = nodep; m_ftaskp = nodep;
VL_RESTORER(m_lifetimeAllowed); VL_RESTORER(m_lifetimeAllowed);
m_lifetimeAllowed = true; m_lifetimeAllowed = true;
if (!nodep->lifetime().isNone()) { if (!nodep->lifetime().isNone()) {
m_lifetime = nodep->lifetime(); m_lifetime = nodep->lifetime();
} else { } else {
if (nodep->classMethod()) { if (nodep->classMethod()) {
// Class methods are automatic by default // Class methods are automatic by default
m_lifetime = VLifetime::AUTOMATIC; m_lifetime = VLifetime::AUTOMATIC;
} else if (nodep->dpiImport() || VN_IS(nodep, Property)) { } else if (nodep->dpiImport() || VN_IS(nodep, Property)) {
// DPI-imported functions and properties don't have lifetime specifiers // DPI-imported functions and properties don't have lifetime specifiers
m_lifetime = VLifetime::NONE; m_lifetime = VLifetime::NONE;
} }
nodep->lifetime(m_lifetime); nodep->lifetime(m_lifetime);
for (AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) { for (AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) {
AstVar* const varp = VN_CAST(itemp, Var); AstVar* const varp = VN_CAST(itemp, Var);
if (varp && varp->valuep() && varp->lifetime().isNone() if (varp && varp->valuep() && varp->lifetime().isNone()
&& nodep->lifetime().isStatic() && !varp->isIO()) { && nodep->lifetime().isStatic() && !varp->isIO()) {
if (VN_IS(m_modp, Module)) { if (VN_IS(m_modp, Module)) {
nodep->v3warn(IMPLICITSTATIC, nodep->v3warn(IMPLICITSTATIC,
"Function/task's lifetime implicitly set to static\n" "Function/task's lifetime implicitly set to static\n"
<< nodep->warnMore() << nodep->warnMore()
<< "... Suggest use 'function automatic' or " << "... Suggest use 'function automatic' or "
"'function static'\n" "'function static'\n"
<< nodep->warnContextPrimary() << '\n' << nodep->warnContextPrimary() << '\n'
<< varp->warnOther() << varp->warnOther()
<< "... Location of implicit static variable\n" << "... Location of implicit static variable\n"
<< varp->warnContextSecondary() << '\n' << varp->warnContextSecondary() << '\n'
<< "... Suggest use 'function automatic' or " << "... Suggest use 'function automatic' or "
"'function static'"); "'function static'");
} else { } else {
varp->v3warn(IMPLICITSTATIC, varp->v3warn(IMPLICITSTATIC,
"Variable's lifetime implicitly set to static\n" "Variable's lifetime implicitly set to static\n"
<< nodep->warnMore() << nodep->warnMore()
<< "... Suggest use 'static' before " << "... Suggest use 'static' before "
"variable declaration'"); "variable declaration'");
}
} }
} }
} }
if (nodep->classMethod() && nodep->lifetime().isStatic()) {
nodep->v3error("Class function/task cannot be static lifetime ('"
<< nodep->verilogKwd() << " static') (IEEE 1800-2023 6.21)\n"
<< nodep->warnMore() << "... May have intended 'static "
<< nodep->verilogKwd() << "'");
}
iterateChildren(nodep);
} }
if (nodep->classMethod() && nodep->lifetime().isStatic()) {
nodep->v3error("Class function/task cannot be static lifetime ('"
<< nodep->verilogKwd() << " static') (IEEE 1800-2023 6.21)\n"
<< nodep->warnMore() << "... May have intended 'static "
<< nodep->verilogKwd() << "'");
}
iterateChildren(nodep);
} }
void visit(AstNodeFTaskRef* nodep) override { void visit(AstNodeFTaskRef* nodep) override {
if (!nodep->user1SetOnce()) { // Process only once. if (nodep->user1SetOnce()) return; // Process only once.
cleanFileline(nodep); cleanFileline(nodep);
UINFO(5, " " << nodep); UINFO(5, " " << nodep);
VL_RESTORER(m_valueModp); VL_RESTORER(m_valueModp);
m_valueModp = nullptr; m_valueModp = nullptr;
iterateChildren(nodep); iterateChildren(nodep);
}
} }
void visit(AstNodeDType* nodep) override { visitIterateNodeDType(nodep); } void visit(AstNodeDType* nodep) override { visitIterateNodeDType(nodep); }
void visit(AstConstraint* nodep) override { void visit(AstConstraint* nodep) override {
@ -673,7 +673,7 @@ class LinkParseVisitor final : public VNVisitor {
V3Control::applyCoverageBlock(m_modp, nodep); V3Control::applyCoverageBlock(m_modp, nodep);
cleanFileline(nodep); cleanFileline(nodep);
VL_RESTORER(m_beginDepth); VL_RESTORER(m_beginDepth);
m_beginDepth++; ++m_beginDepth;
const AstNode* const backp = nodep->backp(); const AstNode* const backp = nodep->backp();
// IEEE says directly nested item is not a new block // IEEE says directly nested item is not a new block
// The genblk name will get attached to the if true/false LOWER begin block(s) // The genblk name will get attached to the if true/false LOWER begin block(s)