From 794247450fb59fd30a2695e7651cc20b8d34b91b Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 14 Oct 2025 12:08:35 +0100 Subject: [PATCH] Internals: Simplify AstScopeName (#6280) Reduce reliance on AstText where not necessary. --- src/V3AstNodeExpr.h | 42 +++++++++++++++++++++++------------------- src/V3AstNodes.cpp | 24 +++++++++++------------- src/V3Begin.cpp | 11 +++-------- src/V3Inline.cpp | 12 +++--------- src/V3Scope.cpp | 12 +++--------- src/V3Task.cpp | 4 ++-- 6 files changed, 45 insertions(+), 60 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 9c068f6c6..5dec976dd 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -2060,13 +2060,13 @@ public: }; class AstScopeName final : public AstNodeExpr { // For display %m and DPI context imports - // Parents: DISPLAY - // @astgen op1 := scopeAttrp : List[AstText] - // @astgen op2 := scopeEntrp : List[AstText] + // Parents: AstSFormatF, AstNodeFTaskRef, AstNodeFTask + std::string m_scopeAttr; + std::string m_scopeEntr; bool m_dpiExport = false; // Is for dpiExport const bool m_forFormat; // Is for a format %m - string scopeNameFormatter(AstText* scopeTextp) const; - string scopePrettyNameFormatter(AstText* scopeTextp) const; + static std::string scopeNameFormatter(const std::string& text); + static std::string scopePrettyNameFormatter(const std::string& text); public: class ForFormat {}; @@ -2078,28 +2078,32 @@ public: ASTGEN_MEMBERS_AstScopeName; bool sameNode(const AstNode* samep) const override { const AstScopeName* const sp = VN_DBG_AS(samep, ScopeName); - return (m_dpiExport == sp->m_dpiExport && m_forFormat == sp->m_forFormat); + return m_scopeAttr == sp->m_scopeAttr // + && m_scopeEntr == sp->m_scopeEntr // + && m_dpiExport == sp->m_dpiExport // + && m_forFormat == sp->m_forFormat; } - string emitVerilog() override { return ""; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } void dump(std::ostream& str = std::cout) const override; void dumpJson(std::ostream& str = std::cout) const override; - string scopeSymName() const { // Name for __Vscope variable including children - return scopeNameFormatter(scopeAttrp()); - } - string scopeDpiName() const { // Name for DPI import scope - return scopeNameFormatter(scopeEntrp()); - } - string scopePrettySymName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeAttrp()); - } - string scopePrettyDpiName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeEntrp()); - } + // ACCESSORS + const std::string& scopeAttr() const { return m_scopeAttr; } + void scopeAttr(const std::string& val) { m_scopeAttr = val; } + const std::string& scopeEntr() const { return m_scopeEntr; } + void scopeEntr(const std::string& val) { m_scopeEntr = val; } bool dpiExport() const { return m_dpiExport; } void dpiExport(bool flag) { m_dpiExport = flag; } bool forFormat() const { return m_forFormat; } + // Name for __Vscope variable including children + string scopeSymName() const { return scopeNameFormatter(m_scopeAttr); } + // Name for DPI import scope + string scopeDpiName() const { return scopeNameFormatter(m_scopeEntr); } + // Name for __Vscope variable including children + string scopePrettySymName() const { return scopePrettyNameFormatter(m_scopeAttr); } + // Name for __Vscope variable including children + string scopePrettyDpiName() const { return scopePrettyNameFormatter(m_scopeEntr); } }; class AstSelLoopVars final : public AstNodeExpr { // Parser only concept "[id, id, id]" for a foreach statement diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index dee3bfbe1..a9c927b5a 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1211,28 +1211,22 @@ AstVarScope* AstScope::createTempLike(const string& name, const AstVarScope* vsc return createTemp(name, vscp->dtypep()); } -string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const { - string out; - for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) { - out += textp->text(); - } +std::string AstScopeName::scopePrettyNameFormatter(const std::string& text) { + std::string out = text; // TOP will be replaced by top->name() if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, ""); if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, ""); if (out.substr(0, 1) == ".") out.replace(0, 1, ""); return AstNode::prettyName(out); } -string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const { - string out; - for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) { - out += textp->text(); - } +std::string AstScopeName::scopeNameFormatter(const std::string& text) { + std::string out = text; if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, ""); if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, ""); if (out.substr(0, 1) == ".") out.replace(0, 1, ""); - string::size_type pos; - while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__"); - while ((pos = out.find("__DOT__")) != string::npos) out.replace(pos, 7, "__"); + std::string::size_type pos; + while ((pos = out.find('.')) != std::string::npos) out.replace(pos, 1, "__"); + while ((pos = out.find("__DOT__")) != std::string::npos) out.replace(pos, 7, "__"); return out; } @@ -2813,10 +2807,14 @@ void AstScopeName::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); if (dpiExport()) str << " [DPIEX]"; if (forFormat()) str << " [FMT]"; + str << " scopeAttr=\"" << m_scopeAttr << "\""; + str << " scopeEntr=\"" << m_scopeEntr << "\""; } void AstScopeName::dumpJson(std::ostream& str) const { dumpJsonBoolFunc(str, dpiExport); dumpJsonBoolFunc(str, forFormat); + dumpJsonStr(str, "scopeAttr", m_scopeAttr); + dumpJsonStr(str, "scopeEntr", m_scopeEntr); dumpJsonGen(str); } void AstSenTree::dump(std::ostream& str) const { diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 21f3cdaad..4f007d6ff 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -293,14 +293,9 @@ class BeginVisitor final : public VNVisitor { // Similar code in V3Inline if (nodep->user1SetOnce()) return; // Don't double-add text's // DPI svGetScope doesn't include function name, but %m does - const string scname = nodep->forFormat() ? m_displayScope : m_namedScope; - if (!scname.empty()) { - // To keep correct visual order, must add before other Text's - AstText* const afterp = nodep->scopeAttrp(); - if (afterp) afterp->unlinkFrBackWithNext(); - nodep->addScopeAttrp(new AstText{nodep->fileline(), "__DOT__"s + scname}); - if (afterp) nodep->addScopeAttrp(afterp); - } + const std::string scname = nodep->forFormat() ? m_displayScope : m_namedScope; + // To keep correct visual order, must add before exising + if (!scname.empty()) nodep->scopeAttr("__DOT__"s + scname + nodep->scopeAttr()); iterateChildren(nodep); } void visit(AstNodeCoverDecl* nodep) override { diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 7eb1d1f9d..03649a5ce 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -393,15 +393,9 @@ class InlineRelinkVisitor final : public VNVisitor { void visit(AstScopeName* nodep) override { // If there's a %m in the display text, we add a special node that will contain the name() // Similar code in V3Begin - // To keep correct visual order, must add before other Text's - AstText* afterp = nodep->scopeAttrp(); - if (afterp) afterp->unlinkFrBackWithNext(); - nodep->addScopeAttrp(new AstText{nodep->fileline(), "__DOT__"s + m_cellp->name()}); - if (afterp) nodep->addScopeAttrp(afterp); - afterp = nodep->scopeEntrp(); - if (afterp) afterp->unlinkFrBackWithNext(); - nodep->addScopeEntrp(new AstText{nodep->fileline(), "__DOT__"s + m_cellp->name()}); - if (afterp) nodep->addScopeEntrp(afterp); + // To keep correct visual order, must add before exising + nodep->scopeAttr("__DOT__" + m_cellp->name() + nodep->scopeAttr()); + nodep->scopeEntr("__DOT__" + m_cellp->name() + nodep->scopeEntr()); iterateChildren(nodep); } void visit(AstNodeCoverDecl* nodep) override { diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index b866fe8b2..16a3d8014 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -291,15 +291,9 @@ class ScopeVisitor final : public VNVisitor { const string prefix = "__DOT__"s + m_scopep->name(); // TOP and above will be the user's name(). // Note 'TOP.' is stripped by scopePrettyName - // To keep correct visual order, must add before other Text's - AstText* afterp = nodep->scopeAttrp(); - if (afterp) afterp->unlinkFrBackWithNext(); - nodep->addScopeAttrp(new AstText{nodep->fileline(), prefix}); - if (afterp) nodep->addScopeAttrp(afterp); - afterp = nodep->scopeEntrp(); - if (afterp) afterp->unlinkFrBackWithNext(); - nodep->addScopeEntrp(new AstText{nodep->fileline(), prefix}); - if (afterp) nodep->addScopeEntrp(afterp); + // To keep correct visual order, must add before existing + nodep->scopeAttr(prefix + nodep->scopeAttr()); + nodep->scopeEntr(prefix + nodep->scopeEntr()); iterateChildren(nodep); } void visit(AstScope* nodep) override { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 307220cf4..aaa20eb54 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1303,8 +1303,8 @@ class TaskVisitor final : public VNVisitor { if (nodep->dpiExport()) { AstScopeName* const snp = nodep->scopeNamep(); UASSERT_OBJ(snp, nodep, "Missing scoping context"); - snp->dpiExport( - true); // The AstScopeName is really a statement(ish) for tracking, not a function + // The AstScopeName is really a statement(ish) for tracking, not a function + snp->dpiExport(true); snp->unlinkFrBack(); cfuncp->addInitsp(snp); }