From 9273fafbbf61a18e7b72800bfea55671145eb340 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Tue, 20 Jul 2021 16:40:38 +0100 Subject: [PATCH] Internals: Split parts of V3CUse into V3Common Apart from adding required AstCUse, V3CUse also used to create some standard methods for classes. This is now done in a separate pass V3Common. Note that this is not a performance issue, as V3Common just iterates through each module, which are stored in a simple linked list under the netlist, and does not need to traverse the whole netlist. --- src/Makefile_obj.in | 1 + src/V3CUse.cpp | 78 ---------------------------- src/V3Common.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++ src/V3Common.h | 30 +++++++++++ src/Verilator.cpp | 13 +++-- 5 files changed, 160 insertions(+), 82 deletions(-) create mode 100644 src/V3Common.cpp create mode 100644 src/V3Common.h diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 95e860637..abb5f1a36 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -169,6 +169,7 @@ RAW_OBJS = \ V3Clean.o \ V3Clock.o \ V3Combine.o \ + V3Common.o \ V3Config.o \ V3Const__gen.o \ V3Coverage.o \ diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index c4da89455..d997256f3 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -44,9 +44,6 @@ private: std::map m_didUse; // What we already used // NODE STATE - // Entire netlist: - // AstClass::user1() -> bool. True if class needs to_string dumper - AstUser1InUse m_inuser1; // AstClass::user2() -> bool. True if iterated AstUser2InUse m_inuser2; @@ -129,85 +126,10 @@ class CUseVisitor final : public AstNVisitor { } } } - void makeVlToString(AstClass* nodep) { - AstCFunc* const funcp - = new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"}; - funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep) - + ">& obj"); - funcp->isMethod(false); - funcp->isConst(false); - funcp->isStatic(false); - funcp->protect(false); - AstNode* const exprp - = new AstCMath{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0}; - exprp->dtypeSetString(); - funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); - nodep->addStmtp(funcp); - } - void makeToString(AstClass* nodep) { - AstCFunc* const funcp - = new AstCFunc{nodep->fileline(), "to_string", nullptr, "std::string"}; - funcp->isConst(true); - funcp->isStatic(false); - funcp->protect(false); - AstNode* const exprp = new AstCMath{nodep->fileline(), - R"(std::string("'{") + to_string_middle() + "}")", 0}; - exprp->dtypeSetString(); - funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); - nodep->addStmtp(funcp); - } - void makeToStringMiddle(AstClass* nodep) { - AstCFunc* const funcp - = new AstCFunc{nodep->fileline(), "to_string_middle", nullptr, "std::string"}; - funcp->isConst(true); - funcp->isStatic(false); - funcp->protect(false); - funcp->addStmtsp(new AstCStmt{nodep->fileline(), "std::string out;\n"}); - std::string comma; - for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) { - if (auto* const varp = VN_CAST(itemp, Var)) { - if (!varp->isParam()) { - string stmt = "out += \""; - stmt += comma; - comma = ", "; - stmt += itemp->origNameProtect(); - stmt += ":\" + "; - if (itemp->isWide()) { - stmt += "VL_TO_STRING_W("; - stmt += cvtToStr(itemp->widthWords()); - stmt += ", "; - } else { - stmt += "VL_TO_STRING("; - } - stmt += itemp->nameProtect(); - stmt += ");\n"; - nodep->user1(true); // So what we extend dumps this - funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); - } - } - } - if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) { - string stmt = "out += \""; - if (!comma.empty()) stmt += "\", \"+ "; - // comma = ", "; // Nothing further so not needed - stmt += nodep->extendsp()->dtypep()->nameProtect(); - stmt += "::to_string_middle();\n"; - nodep->user1(true); // So what we extend dumps this - funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); - } - funcp->addStmtsp(new AstCStmt{nodep->fileline(), "return out;\n"}); - nodep->addStmtp(funcp); - } - // VISITORS virtual void visit(AstNodeModule* nodep) override { makeUseCells(nodep); { CUseDTypeVisitor dtypeVisitor{nodep, m_state}; } - if (AstClass* const classp = VN_CAST(nodep, Class)) { - makeVlToString(classp); - makeToString(classp); - makeToStringMiddle(classp); - } } virtual void visit(AstNode*) override {} // All in AstNodeModule diff --git a/src/V3Common.cpp b/src/V3Common.cpp new file mode 100644 index 000000000..0cb564a5d --- /dev/null +++ b/src/V3Common.cpp @@ -0,0 +1,120 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Add common contents to modules +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 +// +//************************************************************************* +// V3Common's Transformations: +// +// Each class: +// Create string access functions +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Common.h" +#include "V3Ast.h" +#include "V3Global.h" +#include "V3EmitCBase.h" + +//###################################################################### +// Common component builders + +static void makeVlToString(AstClass* nodep) { + AstCFunc* const funcp + = new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"}; + funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep) + ">& obj"); + funcp->isMethod(false); + funcp->isConst(false); + funcp->isStatic(false); + funcp->protect(false); + AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0}; + exprp->dtypeSetString(); + funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); + nodep->addStmtp(funcp); +} +static void makeToString(AstClass* nodep) { + AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "to_string", nullptr, "std::string"}; + funcp->isConst(true); + funcp->isStatic(false); + funcp->protect(false); + AstNode* const exprp + = new AstCMath{nodep->fileline(), R"(std::string("'{") + to_string_middle() + "}")", 0}; + exprp->dtypeSetString(); + funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); + nodep->addStmtp(funcp); +} +static void makeToStringMiddle(AstClass* nodep) { + AstCFunc* const funcp + = new AstCFunc{nodep->fileline(), "to_string_middle", nullptr, "std::string"}; + funcp->isConst(true); + funcp->isStatic(false); + funcp->protect(false); + funcp->addStmtsp(new AstCStmt{nodep->fileline(), "std::string out;\n"}); + std::string comma; + for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) { + if (auto* const varp = VN_CAST(itemp, Var)) { + if (!varp->isParam()) { + string stmt = "out += \""; + stmt += comma; + comma = ", "; + stmt += itemp->origNameProtect(); + stmt += ":\" + "; + if (itemp->isWide()) { + stmt += "VL_TO_STRING_W("; + stmt += cvtToStr(itemp->widthWords()); + stmt += ", "; + } else { + stmt += "VL_TO_STRING("; + } + stmt += itemp->nameProtect(); + stmt += ");\n"; + nodep->user1(true); // So what we extend dumps this + funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); + } + } + } + if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) { + string stmt = "out += \""; + if (!comma.empty()) stmt += "\", \"+ "; + // comma = ", "; // Nothing further so not needed + stmt += nodep->extendsp()->dtypep()->nameProtect(); + stmt += "::to_string_middle();\n"; + nodep->user1(true); // So what we extend dumps this + funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); + } + funcp->addStmtsp(new AstCStmt{nodep->fileline(), "return out;\n"}); + nodep->addStmtp(funcp); +} + +//###################################################################### +// V3Common class functions + +void V3Common::commonAll() { + UINFO(2, __FUNCTION__ << ": " << endl); + // Create common contents for each module + for (AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) { + if (AstClass* const classp = VN_CAST(nodep, Class)) { + // NODE STATE + // Entire netlist: + // AstClass::user1() -> bool. True if class needs to_string dumper + AstUser1InUse m_inuser1; + // Create ToString methods + makeVlToString(classp); + makeToString(classp); + makeToStringMiddle(classp); + } + } + V3Global::dumpCheckGlobalTree("common", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); +} diff --git a/src/V3Common.h b/src/V3Common.h new file mode 100644 index 000000000..408507e77 --- /dev/null +++ b/src/V3Common.h @@ -0,0 +1,30 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Add common contents to modules +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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_V3COMMON_H_ +#define VERILATOR_V3COMMON_H_ + +#include "config_build.h" +#include "verilatedos.h" + +//============================================================================ + +class V3Common final { +public: + static void commonAll(); +}; + +#endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 65b75c2bb..28400d9e4 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -34,6 +34,7 @@ #include "V3Clean.h" #include "V3Clock.h" #include "V3Combine.h" +#include "V3Common.h" #include "V3Const.h" #include "V3Coverage.h" #include "V3CoverageJoin.h" @@ -502,15 +503,19 @@ static void process() { V3Partition::finalize(); } - // Output the text if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { - // Create AstCUse to determine what class forward declarations/#includes needed in C - // Must be before V3EmitC - V3CUse::cUseAll(); + // Add common methods/etc to modules + V3Common::commonAll(); // Order variables V3VariableOrder::orderAll(); + // Create AstCUse to determine what class forward declarations/#includes needed in C + V3CUse::cUseAll(); + } + + // Output the text + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { // emitcInlines is first, as it may set needHInlines which other emitters read V3EmitC::emitcInlines(); V3EmitC::emitcSyms();