Make _ctror_var_reset and _configure_coverage static. (#2977)

Another step towards #2958/#2140. Make the mentioned generated functions
static for modules (but not for classes).
This commit is contained in:
Geza Lore 2021-05-22 18:50:55 +01:00 committed by GitHub
parent 2dd5ef5e8b
commit ef9f477df2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 78 deletions

View File

@ -32,63 +32,99 @@
#include "V3CCtors.h" #include "V3CCtors.h"
#include <algorithm> #include <algorithm>
#include <map> #include <list>
class VCtorType final {
public:
enum en : uint8_t { MODULE, CLASS, COVERAGE };
class V3CCtorsVisitor final {
private: private:
string m_basename; enum en m_e;
string m_argsp;
string m_callargsp; public:
AstNodeModule* m_modp; // Current module // cppcheck-suppress noExplicitConstructor
AstCFunc* m_tlFuncp; // Top level function being built inline VCtorType(en _e)
AstCFunc* m_funcp; // Current function : m_e{_e} {}
bool isClass() const { return m_e == CLASS; }
bool isCoverage() const { return m_e == COVERAGE; }
};
class V3CCtorsBuilder final {
private:
AstNodeModule* const m_modp; // Current module/class
const string m_basename;
const VCtorType m_type; // What kind of constructor are we creating
std::list<AstCFunc*> m_newFunctions; // Created functions, latest is at back
int m_numStmts = 0; // Number of statements output int m_numStmts = 0; // Number of statements output
int m_funcNum = 0; // Function number being built
AstCFunc* makeNewFunc() {
const int funcNum = m_newFunctions.size();
const string funcName = m_basename + "_" + cvtToStr(funcNum);
AstCFunc* const funcp = new AstCFunc(m_modp->fileline(), funcName, nullptr, "void");
funcp->isStatic(!m_type.isClass()); // Class constructors are non static
funcp->declPrivate(true);
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
string preventUnusedStmt;
if (m_type.isClass()) {
funcp->argTypes(EmitCBaseVisitor::symClassVar());
preventUnusedStmt = "if (false && vlSymsp) {}";
} else if (m_type.isCoverage()) {
funcp->argTypes(EmitCBaseVisitor::prefixNameProtect(m_modp) + "* self, "
+ EmitCBaseVisitor::symClassVar() + ", bool first");
preventUnusedStmt = "if (false && self && vlSymsp && first) {}";
} else { // Module
funcp->argTypes(EmitCBaseVisitor::prefixNameProtect(m_modp) + "* self");
preventUnusedStmt = "if (false && self) {}";
}
preventUnusedStmt += " // Prevent unused\n";
funcp->addStmtsp(new AstCStmt(m_modp->fileline(), preventUnusedStmt));
m_modp->addStmtp(funcp);
m_numStmts = 0;
return funcp;
}
public: public:
void add(AstNode* nodep) { void add(AstNode* nodep) {
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) { if (v3Global.opt.outputSplitCFuncs() && m_numStmts > v3Global.opt.outputSplitCFuncs()) {
m_funcp = nullptr; m_newFunctions.push_back(makeNewFunc());
} }
if (!m_funcp) { m_newFunctions.back()->addStmtsp(nodep);
m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum),
nullptr, "void");
m_funcp->isStatic(false);
m_funcp->declPrivate(true);
m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
m_funcp->argTypes(m_argsp);
m_modp->addStmtp(m_funcp);
// Add a top call to it
AstCCall* callp = new AstCCall(m_modp->fileline(), m_funcp);
callp->argTypes(m_callargsp);
m_tlFuncp->addStmtsp(callp);
m_numStmts = 0;
}
m_funcp->addStmtsp(nodep);
m_numStmts += 1; m_numStmts += 1;
} }
V3CCtorsVisitor(AstNodeModule* nodep, const string& basename, const string& argsp = "", V3CCtorsBuilder(AstNodeModule* nodep, const string& basename, VCtorType type)
const string& callargsp = "", const string& stmt = "") { : m_modp(nodep)
m_basename = basename; , m_basename{basename}
m_argsp = argsp; , m_type(type) {
m_callargsp = callargsp; // Note: The constructor is always called, even if empty, so we must always create at least
m_modp = nodep; // one.
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void"); m_newFunctions.push_back(makeNewFunc());
m_tlFuncp->declPrivate(true);
m_tlFuncp->isStatic(false);
m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
m_tlFuncp->argTypes(m_argsp);
if (stmt != "") m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
m_funcp = m_tlFuncp;
m_modp->addStmtp(m_tlFuncp);
} }
~V3CCtorsVisitor() = default;
~V3CCtorsBuilder() {
if (m_newFunctions.size() == 1) {
// No split was necessary, rename the one function to the basename
m_newFunctions.front()->name(m_basename);
} else {
// Split was necessary, create root function and call all others from that
AstCFunc* const rootFuncp = makeNewFunc();
rootFuncp->name(m_basename);
for (AstCFunc* const funcp : m_newFunctions) {
AstCCall* const callp = new AstCCall(m_modp->fileline(), funcp);
if (m_type.isClass()) {
callp->argTypes("vlSymsp");
} else if (m_type.isCoverage()) {
callp->argTypes("self, vlSymsp, first");
} else { // Module
callp->argTypes("self");
}
rootFuncp->addStmtsp(callp);
}
}
};
private: private:
VL_UNCOPYABLE(V3CCtorsVisitor); VL_UNCOPYABLE(V3CCtorsBuilder);
}; };
//###################################################################### //######################################################################
@ -140,32 +176,24 @@ void V3CCtors::cctorsAll() {
modp = VN_CAST(modp->nextp(), NodeModule)) { modp = VN_CAST(modp->nextp(), NodeModule)) {
// Process each module in turn // Process each module in turn
{ {
V3CCtorsVisitor var_reset( V3CCtorsBuilder var_reset(modp, "_ctor_var_reset",
modp, "_ctor_var_reset", VN_IS(modp, Class) ? VCtorType::CLASS : VCtorType::MODULE);
(VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""),
(VN_IS(modp, Class) ? "vlSymsp" : ""),
(VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : ""));
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) { if (AstVar* const varp = VN_CAST(np, Var)) {
if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) { if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) {
var_reset.add( const auto vrefp = new AstVarRef(varp->fileline(), varp, VAccess::WRITE);
new AstCReset(varp->fileline(), var_reset.add(new AstCReset(varp->fileline(), vrefp));
new AstVarRef(varp->fileline(), varp, VAccess::WRITE)));
} }
} }
} }
} }
if (v3Global.opt.coverage()) { if (v3Global.opt.coverage()) {
V3CCtorsVisitor configure_coverage( V3CCtorsBuilder configure_coverage(modp, "_configure_coverage", VCtorType::COVERAGE);
modp, "_configure_coverage", EmitCBaseVisitor::symClassVar() + ", bool first",
"vlSymsp, first", "if (false && vlSymsp && first) {} // Prevent unused\n");
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) { if (AstCoverDecl* const coverp = VN_CAST(np, CoverDecl)) {
AstNode* backp = coverp->backp(); np = coverp->backp();
coverp->unlinkFrBack(); configure_coverage.add(coverp->unlinkFrBack());
configure_coverage.add(coverp);
np = backp;
} }
} }
} }

View File

@ -459,7 +459,7 @@ public:
iterateChildren(nodep); iterateChildren(nodep);
} }
virtual void visit(AstCoverDecl* nodep) override { virtual void visit(AstCoverDecl* nodep) override {
puts("__vlCoverInsert("); // As Declared in emitCoverageDecl puts("self->__vlCoverInsert("); // As Declared in emitCoverageDecl
puts("&(vlSymsp->__Vcoverage["); puts("&(vlSymsp->__Vcoverage[");
puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts(cvtToStr(nodep->dataDeclThisp()->binNum()));
puts("])"); puts("])");
@ -1753,7 +1753,9 @@ class EmitCImp final : EmitCStmts {
} }
void emitVarReset(AstVar* varp) { void emitVarReset(AstVar* varp) {
AstNodeDType* dtypep = varp->dtypep()->skipRefp(); AstNodeDType* const dtypep = varp->dtypep()->skipRefp();
const string varNameProtected
= VN_IS(m_modp, Class) ? varp->nameProtect() : "self->" + varp->nameProtect();
if (varp->isIO() && m_modp->isTop() && optSystemC()) { if (varp->isIO() && m_modp->isTop() && optSystemC()) {
// System C top I/O doesn't need loading, as the lower level subinst code does it.} // System C top I/O doesn't need loading, as the lower level subinst code does it.}
} else if (varp->isParam()) { } else if (varp->isParam()) {
@ -1766,44 +1768,44 @@ class EmitCImp final : EmitCStmts {
if (initarp->defaultp()) { if (initarp->defaultp()) {
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst())); puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("; ++__Vi) {\n"); puts("; ++__Vi) {\n");
emitSetVarConstant(varp->nameProtect() + "[__Vi]", emitSetVarConstant(varNameProtected + "[__Vi]",
VN_CAST(initarp->defaultp(), Const)); VN_CAST(initarp->defaultp(), Const));
puts("}\n"); puts("}\n");
} }
const AstInitArray::KeyItemMap& mapr = initarp->map(); const AstInitArray::KeyItemMap& mapr = initarp->map();
for (const auto& itr : mapr) { for (const auto& itr : mapr) {
AstNode* valuep = itr.second->valuep(); AstNode* valuep = itr.second->valuep();
emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(itr.first) + "]", emitSetVarConstant(varNameProtected + "[" + cvtToStr(itr.first) + "]",
VN_CAST(valuep, Const)); VN_CAST(valuep, Const));
} }
} else { } else {
varp->v3fatalSrc("InitArray under non-arrayed var"); varp->v3fatalSrc("InitArray under non-arrayed var");
} }
} else { } else {
puts(emitVarResetRecurse(varp, dtypep, 0, "")); puts(emitVarResetRecurse(varp, varNameProtected, dtypep, 0, ""));
} }
} }
string emitVarResetRecurse(AstVar* varp, AstNodeDType* dtypep, int depth, string emitVarResetRecurse(const AstVar* varp, const string& varNameProtected,
const string& suffix) { AstNodeDType* dtypep, int depth, const string& suffix) {
dtypep = dtypep->skipRefp(); dtypep = dtypep->skipRefp();
AstBasicDType* basicp = dtypep->basicp(); AstBasicDType* basicp = dtypep->basicp();
// Returns string to do resetting, empty to do nothing (which caller should handle) // Returns string to do resetting, empty to do nothing (which caller should handle)
if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) { if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) {
// Access std::array as C array // Access std::array as C array
string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray); suffix + ".atDefault()" + cvtarray);
} else if (VN_IS(dtypep, ClassRefDType)) { } else if (VN_IS(dtypep, ClassRefDType)) {
return ""; // Constructor does it return ""; // Constructor does it
} else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { } else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
// Access std::array as C array // Access std::array as C array
string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray); suffix + ".atDefault()" + cvtarray);
} else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) {
// Access std::array as C array // Access std::array as C array
string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray); suffix + ".atDefault()" + cvtarray);
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { } else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp, UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp,
@ -1811,8 +1813,8 @@ class EmitCImp final : EmitCStmts {
string ivar = string("__Vi") + cvtToStr(depth); string ivar = string("__Vi") + cvtToStr(depth);
string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<" string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<"
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n"); + cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, string below = emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(),
suffix + "[" + ivar + "]"); depth + 1, suffix + "[" + ivar + "]");
string post = "}\n"; string post = "}\n";
return below.empty() ? "" : pre + below + post; return below.empty() ? "" : pre + below + post;
} else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) { } else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) {
@ -1832,17 +1834,17 @@ class EmitCImp final : EmitCStmts {
AstConst* const constp = VN_CAST(varp->valuep(), Const); AstConst* const constp = VN_CAST(varp->valuep(), Const);
if (!constp) varp->v3fatalSrc("non-const initializer for variable"); if (!constp) varp->v3fatalSrc("non-const initializer for variable");
for (int w = 0; w < varp->widthWords(); ++w) { for (int w = 0; w < varp->widthWords(); ++w) {
out += varp->nameProtect() + suffix + "[" + cvtToStr(w) + "] = "; out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
out += cvtToStr(constp->num().edataWord(w)) + "U;\n"; out += cvtToStr(constp->num().edataWord(w)) + "U;\n";
} }
} else { } else {
out += zeroit ? "VL_ZERO_RESET_W(" : "VL_RAND_RESET_W("; out += zeroit ? "VL_ZERO_RESET_W(" : "VL_RAND_RESET_W(";
out += cvtToStr(dtypep->widthMin()); out += cvtToStr(dtypep->widthMin());
out += ", " + varp->nameProtect() + suffix + ");\n"; out += ", " + varNameProtected + suffix + ");\n";
} }
return out; return out;
} else { } else {
string out = varp->nameProtect() + suffix; string out = varNameProtected + suffix;
// If --x-initial-edge is set, we want to force an initial // If --x-initial-edge is set, we want to force an initial
// edge on uninitialized clocks (from 'X' to whatever the // edge on uninitialized clocks (from 'X' to whatever the
// first value is). Since the class is instantiated before // first value is). Since the class is instantiated before
@ -2481,7 +2483,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
puts("\n"); puts("\n");
} }
putsDecoration("// Reset structure values\n"); putsDecoration("// Reset structure values\n");
puts(protect("_ctor_var_reset") + "();\n"); puts(protect("_ctor_var_reset") + "(this);\n");
emitTextSection(AstType::atScCtor); emitTextSection(AstType::atScCtor);
if (modp->isTop() && v3Global.opt.mtasks()) { if (modp->isTop() && v3Global.opt.mtasks()) {
@ -2524,7 +2526,9 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
puts("if (false && first) {} // Prevent unused\n"); puts("if (false && first) {} // Prevent unused\n");
puts("this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. puts("this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it.
puts("if (false && this->__VlSymsp) {} // Prevent unused\n"); puts("if (false && this->__VlSymsp) {} // Prevent unused\n");
if (v3Global.opt.coverage()) { puts(protect("_configure_coverage") + "(vlSymsp, first);\n"); } if (v3Global.opt.coverage()) {
puts(protect("_configure_coverage") + "(this, vlSymsp, first);\n");
}
if (modp->isTop() && !v3Global.rootp()->timeunit().isNone()) { if (modp->isTop() && !v3Global.rootp()->timeunit().isNone()) {
puts("vlSymsp->_vm_contextp__->timeunit(" puts("vlSymsp->_vm_contextp__->timeunit("
+ cvtToStr(v3Global.rootp()->timeunit().powerOfTen()) + ");\n"); + cvtToStr(v3Global.rootp()->timeunit().powerOfTen()) + ");\n");