Internals: Move wrapTop before V3Coverage (#8291)

This commit is contained in:
Geza Lore
2026-09-06 17:34:40 -04:00
committed by GitHub
parent 8213c0ea98
commit 849cc5aeca
24 changed files with 892 additions and 873 deletions
+4 -4
View File
@@ -433,20 +433,20 @@ class AssertVisitor final : public VNVisitor {
if (!m_monitorNumVarp) {
m_monitorNumVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorNum",
nodep->findUInt64DType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorNumVarp);
v3Global.rootp()->dollarUnitPkgp()->addStmtsp(m_monitorNumVarp);
}
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), m_monitorNumVarp, access};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgp());
return varrefp;
}
AstVarRef* newMonitorOffVarRefp(const AstNode* nodep, VAccess access) {
if (!m_monitorOffVarp) {
m_monitorOffVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorOff",
nodep->findBitDType()};
v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorOffVarp);
v3Global.rootp()->dollarUnitPkgp()->addStmtsp(m_monitorOffVarp);
}
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), m_monitorOffVarp, access};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgp());
return varrefp;
}
static AstIf* newIfAssertOn(AstNode* bodyp, VAssertDirectiveType directiveType,
+1 -5
View File
@@ -313,7 +313,6 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
bool m_hasParameterList : 1; // Has #() for parameter declaration
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
bool m_hierParams : 1; // Block containing params for parameterized hier blocks
bool m_internal : 1; // Internally created
bool m_recursive : 1; // Recursive module
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
bool m_parameterizedTemplate : 1; // True when at least one specialized clone exists;
@@ -335,7 +334,6 @@ protected:
, m_hasParameterList{false}
, m_hierBlock{false}
, m_hierParams{false}
, m_internal{false}
, m_recursive{false}
, m_recursiveClone{false}
, m_parameterizedTemplate{false}
@@ -379,8 +377,6 @@ public:
void hierBlock(bool flag) { m_hierBlock = flag; }
bool hierParams() const { return m_hierParams; }
void hierParams(bool flag) { m_hierParams = flag; }
bool internal() const { return m_internal; }
void internal(bool flag) { m_internal = flag; }
bool recursive() const { return m_recursive; }
void recursive(bool flag) { m_recursive = flag; }
void recursiveClone(bool flag) { m_recursiveClone = flag; }
@@ -1492,7 +1488,7 @@ public:
void astConstOrigParamName(const AstConst* nodep, const string& name);
void astConstOrigParamNameErase(const AstConst* nodep);
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
AstPackage* dollarUnitPkgAddp();
void dollarUnitPkgp(AstPackage* const packagep) { m_dollarUnitPkgp = packagep; }
AstCFunc* evalFuncp(VEval eval) const { return m_evalFuncps[eval]; }
void evalFuncp(VEval eval, AstCFunc* funcp) { m_evalFuncps[eval] = funcp; }
AstCFunc* dumpTriggersFuncp(VEval eval) const { return m_dumpTriggersFuncps[eval]; }
+7 -13
View File
@@ -1863,9 +1863,15 @@ AstNodeBiop* AstNeq::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp
AstNetlist::AstNetlist()
: ASTGEN_SUPER_Netlist(new FileLine{FileLine::builtInFilename()})
, m_typeTablep{new AstTypeTable{fileline()}}
, m_constPoolp{new AstConstPool{fileline()}} {
, m_constPoolp{new AstConstPool{fileline()}}
, m_dollarUnitPkgp{new AstPackage{fileline(), AstPackage::dollarUnitName(), "work"}} {
addMiscsp(m_typeTablep);
addMiscsp(m_constPoolp);
// packages are always libraries; don't want to make them a "top"
m_dollarUnitPkgp->level(1);
m_dollarUnitPkgp->inLibrary(true);
m_dollarUnitPkgp->modTrace(false); // may reconsider later
addModulesp(m_dollarUnitPkgp);
}
void AstNetlist::addEvalStats(const std::string& phase) {
if (!v3Global.opt.stats()) return;
@@ -1932,18 +1938,6 @@ void AstNetlist::deleteContents() {
if (op4p()) op4p()->unlinkFrBackWithNext()->deleteTree();
#undef VN_DELETE_ONE
}
AstPackage* AstNetlist::dollarUnitPkgAddp() {
if (!m_dollarUnitPkgp) {
m_dollarUnitPkgp = new AstPackage{fileline(), AstPackage::dollarUnitName(), "work"};
// packages are always libraries; don't want to make them a "top"
m_dollarUnitPkgp->level(1);
m_dollarUnitPkgp->inLibrary(true);
m_dollarUnitPkgp->modTrace(false); // may reconsider later
m_dollarUnitPkgp->internal(true);
addModulesp(m_dollarUnitPkgp);
}
return m_dollarUnitPkgp;
}
void AstNetlist::dump(std::ostream& str) const {
Super::dump(str);
if (timescaleSpecified()) str << " [TIMESCALES]";
+1 -1
View File
@@ -283,7 +283,7 @@ class CoverageVisitor final : public VNVisitor {
VL_RESTORER_COPY(m_funcTemps);
createHandle(nodep);
m_modp = nodep;
m_state.m_inModOff = false; // Haven't made top shell, so tops are real tops
m_state.m_inModOff = nodep->isTop(); // Already made top shell, no coverage for it
if (!origModp) {
// No blocks cross (non-nested) modules, so save some memory
m_varnames.clear();
+7 -1
View File
@@ -400,7 +400,10 @@ class DeadVisitor final : public VNVisitor {
AstNodeModule* nextmodp;
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = nextmodp) {
nextmodp = VN_AS(modp->nextp(), NodeModule);
if (modp->dead() || (!modp->isTop() && modp->user1() == 0 && !modp->internal())) {
// Keep $unit until m_elimCells stages. Note v3Global.opt.serializeOnly()
// won't reach this stage, and will always have an empty $unit. That's ok.
const bool keep = !m_elimCells && modp == v3Global.rootp()->dollarUnitPkgp();
if (modp->dead() || (!modp->isTop() && modp->user1() == 0 && !keep)) {
// > 2 because L1 is the wrapper, L2 is the top user module
UINFO(4, " Dead module " << modp);
// And its children may now be killable too; correct counts
@@ -410,6 +413,9 @@ class DeadVisitor final : public VNVisitor {
cellp->modp()->user1Inc(-1);
});
}
if (modp == v3Global.rootp()->dollarUnitPkgp()) {
v3Global.rootp()->dollarUnitPkgp(nullptr);
}
deleting(modp);
retry = true;
}
+1 -1
View File
@@ -467,7 +467,7 @@ class LinkCellsVisitor final : public VNVisitor {
if (nodep->fileline()->filebasenameNoExt() != nodep->prettyName()
&& !v3Global.opt.isLibraryFile(nodep->fileline()->filename(), nodep->libname())
&& !VN_IS(nodep, NotFoundModule) && !nodep->recursiveClone()
&& !nodep->internal()) {
&& nodep != v3Global.rootp()->dollarUnitPkgp()) {
// We only complain once per file, otherwise library-like files
// have a huge mess of warnings
const auto itFoundPair = m_declfnWarned.insert(nodep->fileline()->filename());
+9 -2
View File
@@ -1216,7 +1216,14 @@ class LinkDotFindVisitor final : public VNVisitor {
// (sorted before this is called).
// This may not be the module with isTop() set, as early in the steps,
// wrapTop may have not been created yet.
if (!nodep->modulesp()) nodep->v3error("No top level module found");
// $unit always exists, so nothing else, and nothing in it, means nothing was given
AstNodeModule* const modulesp = nodep->modulesp();
UASSERT_OBJ(modulesp, nodep, "$unit should always be in the netlist");
if (!modulesp->nextp()) {
UASSERT_OBJ(modulesp == v3Global.rootp()->dollarUnitPkgp(), modulesp,
"Sole module should be $unit");
if (!modulesp->stmtsp()) nodep->v3error("No top level module found");
}
for (AstNodeModule* modp = nodep->modulesp(); modp && modp->isTop();
modp = VN_AS(modp->nextp(), NodeModule)) {
UINFO(8, "Top Module: " << modp);
@@ -1405,7 +1412,7 @@ class LinkDotFindVisitor final : public VNVisitor {
}
void visit(AstClassOrPackageRef* nodep) override { // FindVisitor::
if (!nodep->classOrPackageNodep() && nodep->name() == "$unit") {
nodep->classOrPackageNodep(v3Global.rootp()->dollarUnitPkgAddp());
nodep->classOrPackageNodep(v3Global.rootp()->dollarUnitPkgp());
}
iterateChildren(nodep);
}
+2 -2
View File
@@ -211,7 +211,7 @@ class LinkJumpVisitor final : public VNVisitor {
if (!processQueuep->lifetime().isStatic() || processQueuep->isTemp()) {
return new AstVarRef{fl, processQueuep, access};
}
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgAddp();
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgp();
return new AstVarRef{fl, topPkgp, processQueuep, access};
}
static AstStmtExpr* getQueuePushProcessSelfp(FileLine* const fl, AstVar* const processQueuep) {
@@ -275,7 +275,7 @@ class LinkJumpVisitor final : public VNVisitor {
AstNodeModule* const ownerp = findOwnerModulep(nodep);
if (VN_IS(ownerp, Package) || VN_IS(ownerp, Class)) {
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgAddp();
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgp();
AstVar* const processQueuep = newProcessQueuep(nodep, fl, VVarType::VAR);
processQueuep->lifetime(VLifetime::STATIC_EXPLICIT);
topPkgp->addStmtsp(processQueuep);
+1 -1
View File
@@ -291,7 +291,7 @@ public:
size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf, max_size); }
//==== Symbol tables
AstPackage* unitPackage(FileLine* /*fl*/) { return parsep()->rootp()->dollarUnitPkgAddp(); }
AstPackage* unitPackage(FileLine* /*fl*/) { return parsep()->rootp()->dollarUnitPkgp(); }
// CONSTRUCTORS
V3ParseImp(AstNetlist* rootp, VInFilter* filterp)
+2 -2
View File
@@ -4006,7 +4006,7 @@ class RandomizeVisitor final : public VNVisitor {
varp->isStatic(true);
varp->valuep(initp);
// Add to root, as don't know module we are in, and aids later structure sharing
v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(varp);
v3Global.rootp()->dollarUnitPkgp()->addStmtsp(varp);
UASSERT_OBJ(nodep->itemsp(), nodep, "Enum without items");
for (AstEnumItem* itemp = nodep->itemsp(); itemp;
@@ -4179,7 +4179,7 @@ class RandomizeVisitor final : public VNVisitor {
EnumDType)) {
AstVarRef* const tabRefp
= new AstVarRef{fl, enumValueTabp(enumDtp), VAccess::READ};
tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgp());
AstNodeExpr* const randp
= newRandValue(fl, randcVarp, exprp->findBasicDType(VBasicDTypeKwd::UINT32));
AstNodeExpr* const moddivp = new AstModDiv{
+3 -3
View File
@@ -9928,7 +9928,7 @@ class WidthVisitor final : public VNVisitor {
varp->isStatic(true);
varp->valuep(initp);
// Add to root, as don't know module we are in, and aids later structure sharing
v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(varp);
v3Global.rootp()->dollarUnitPkgp()->addStmtsp(varp);
// Element 0 is a non-index and has speced values
initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, 0));
for (unsigned i = 1; i < msbdim + 1; ++i) {
@@ -9997,7 +9997,7 @@ class WidthVisitor final : public VNVisitor {
varp->isStatic(true);
varp->valuep(initp);
// Add to root, as don't know module we are in, and aids later structure sharing
v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(varp);
v3Global.rootp()->dollarUnitPkgp()->addStmtsp(varp);
// Default for all unspecified values
if (attrType == VAttrType::ENUM_NAME) {
@@ -10294,7 +10294,7 @@ class WidthVisitor final : public VNVisitor {
}
static AstVarRef* newVarRefDollarUnit(AstVar* nodep) {
AstVarRef* const varrefp = new AstVarRef{nodep->fileline(), nodep, VAccess::READ};
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgp());
return varrefp;
}
AstNode* nodeForUnsizedWarning(AstNode* nodep) {
+16 -14
View File
@@ -233,11 +233,22 @@ static void process() {
v3Global.vlExit(0);
}
// Insert generic non-FSM coverage before dead code elimination and
// inlining, or those opportunities may be optimized away. FSM
// coverage is handled later in V3FsmDetect, after scoping has created
// the AST context needed to recover and lower FSMs reliably.
if (v3Global.opt.coverageNonFsm()) V3Coverage::coverage(v3Global.rootp());
if (!v3Global.opt.serializeOnly() || v3Global.opt.flatten()) {
// Add top level wrapper with instance pointing to old top
// Move packages to under new top
// Must do this after we know parameters and dtypes (as don't clone dtype decls)
V3LinkLevel::wrapTop(v3Global.rootp());
} else {
V3LinkLevel::nonWrapTop(v3Global.rootp());
}
if (!v3Global.opt.serializeOnly()) {
// Insert generic code coverage before dead code elimination and
// inlining, or those opportunities may be optimized away. FSM
// coverage is handled later in V3FsmDetect, after scoping has created
// the AST context needed to recover and lower FSMs reliably.
if (v3Global.opt.coverageNonFsm()) V3Coverage::coverage(v3Global.rootp());
}
// Functional coverage code generation
// Generate code for covergroups/coverpoints
@@ -268,15 +279,6 @@ static void process() {
//
V3Assert::assertAll(v3Global.rootp());
if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) {
// Add top level wrapper with instance pointing to old top
// Move packages to under new top
// Must do this after we know parameters and dtypes (as don't clone dtype decls)
V3LinkLevel::wrapTop(v3Global.rootp());
} else {
V3LinkLevel::nonWrapTop(v3Global.rootp());
}
// Propagate constants into expressions
if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLint(v3Global.rootp());