Internals: Refactoring (#6433 prep). No functional change intended.

This commit is contained in:
Wilson Snyder 2025-09-14 21:50:19 -04:00
parent 5e4668c146
commit 12c524ac06
3 changed files with 121 additions and 120 deletions

View File

@ -2230,9 +2230,12 @@ void AstRefDType::dump(std::ostream& str) const {
static bool s_recursing = false;
if (!s_recursing) { // Prevent infinite dump if circular typedefs
s_recursing = true;
if (classOrPackagep()) str << " cpkg=" << nodeAddr(classOrPackagep());
if (refDTypep()) str << " refDTypep=" << nodeAddr(refDTypep());
if (typedefp()) str << " typedefp=" << nodeAddr(typedefp());
str << " -> ";
if (const AstNodeDType* const subp = subDTypep()) {
if (typedefp()) str << "typedef=" << static_cast<void*>(typedefp()) << " -> ";
subp->dump(str);
} else if (const AstTypedef* const subp = typedefp()) {
subp->dump(str);

View File

@ -909,6 +909,17 @@ class LinkDotFindVisitor final : public VNVisitor {
return hierBlocks.find(name) != hierBlocks.end();
}
void moveExternFuncDecl(AstNodeFTask* nodep, AstClass* classp) {
// Move an 'extern function|task' to inside a class or, from an outer to inner-class
if (!nodep->isExternDef()) {
// Move it to proper spot under the target class
nodep->unlinkFrBack();
classp->addStmtsp(nodep);
nodep->isExternDef(true); // So we check there's a matching extern
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
}
}
// VISITORS
void visit(AstNetlist* nodep) override { // FindVisitor::
// Process $unit or other packages
@ -1238,114 +1249,100 @@ class LinkDotFindVisitor final : public VNVisitor {
VL_RESTORER(m_classOrPackagep);
VL_RESTORER(m_curSymp);
VSymEnt* upSymp = m_curSymp;
{
if (VN_IS(m_curSymp->nodep(), Class)) {
if (VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual()
&& !nodep->isConstructor()) {
nodep->v3error("Interface class functions must be pure virtual"
<< " (IEEE 1800-2023 8.26): " << nodep->prettyNameQ());
}
if (m_statep->forPrimary()
&& (nodep->name() == "randomize" || nodep->name() == "srandom")) {
nodep->v3error(nodep->prettyNameQ()
<< " is a predefined class method; redefinition not allowed"
" (IEEE 1800-2023 18.6.3)");
}
if (VN_IS(m_curSymp->nodep(), Class)) {
if (VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual()
&& !nodep->isConstructor()) {
nodep->v3error("Interface class functions must be pure virtual"
<< " (IEEE 1800-2023 8.26): " << nodep->prettyNameQ());
}
// Change to appropriate package if extern declaration (vs definition)
if (nodep->classOrPackagep()) {
// class-in-class
AstDot* const dotp = VN_CAST(nodep->classOrPackagep(), Dot);
AstClassOrPackageRef* const cpackagerefp
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
if (dotp) {
AstClassOrPackageRef* const lhsp = VN_AS(dotp->lhsp(), ClassOrPackageRef);
m_statep->resolveClassOrPackage(m_curSymp, lhsp, true, false,
"External definition :: reference");
AstClass* const lhsclassp = VN_CAST(lhsp->classOrPackageSkipp(), Class);
if (!lhsclassp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(lhsclassp);
upSymp = m_curSymp;
AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef);
m_statep->resolveClassOrPackage(m_curSymp, rhsp, true, false,
"External definition :: reference");
AstClass* const rhsclassp = VN_CAST(rhsp->classOrPackageSkipp(), Class);
if (!rhsclassp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(rhsclassp);
upSymp = m_curSymp;
if (!nodep->isExternDef()) {
// Move it to proper spot under the target class
nodep->unlinkFrBack();
rhsclassp->addStmtsp(nodep);
nodep->isExternDef(true); // So we check there's a matching extern
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
}
}
}
} else if (cpackagerefp) {
if (!cpackagerefp->classOrPackageSkipp()) {
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, true, false,
"External definition :: reference");
}
AstClass* const classp = VN_CAST(cpackagerefp->classOrPackageSkipp(), Class);
if (!classp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(classp);
upSymp = m_curSymp;
if (!nodep->isExternDef()) {
// Move it to proper spot under the target class
nodep->unlinkFrBack();
classp->addStmtsp(nodep);
nodep->isExternDef(true); // So we check there's a matching extern
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
}
}
} else {
v3fatalSrc("Unhandled extern function definition package");
}
if (m_statep->forPrimary()
&& (nodep->name() == "randomize" || nodep->name() == "srandom")) {
nodep->v3error(nodep->prettyNameQ()
<< " is a predefined class method; redefinition not allowed"
" (IEEE 1800-2023 18.6.3)");
}
// Set the class as package for iteration
if (VN_IS(m_curSymp->nodep(), Class)) {
m_classOrPackagep = VN_AS(m_curSymp->nodep(), Class);
}
// Create symbol table for the task's vars
const string name = (nodep->isExternProto() ? "extern "s : ""s) + nodep->name();
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_classOrPackagep);
m_curSymp->fallbackp(upSymp);
// Convert the func's range to the output variable
// This should probably be done in the Parser instead, as then we could
// just attach normal signal attributes to it.
if (!nodep->isExternProto() && nodep->fvarp() && !VN_IS(nodep->fvarp(), Var)) {
AstNodeDType* dtypep = VN_CAST(nodep->fvarp(), NodeDType);
// If unspecified, function returns one bit; however when we
// support NEW() it could also return the class reference.
if (dtypep) {
dtypep->unlinkFrBack();
} else {
dtypep = new AstBasicDType{nodep->fileline(), VBasicDTypeKwd::LOGIC};
}
AstVar* const newvarp
= new AstVar{nodep->fileline(), VVarType::VAR, nodep->name(),
VFlagChildDType{}, dtypep}; // Not dtype resolved yet
newvarp->direction(VDirection::OUTPUT);
newvarp->lifetime(VLifetime::AUTOMATIC);
newvarp->funcReturn(true);
newvarp->trace(false); // Not user visible
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
nodep->fvarp(newvarp);
// Explicit insert required, as the var name shadows the upper level's task name
m_statep->insertSym(m_curSymp, newvarp->name(), newvarp,
nullptr /*classOrPackagep*/);
}
VL_RESTORER(m_ftaskp);
m_ftaskp = nodep;
iterateChildren(nodep);
}
// Change to appropriate package if extern declaration (vs definition)
if (nodep->classOrPackagep()) {
// class-in-class
AstDot* const dotp = VN_CAST(nodep->classOrPackagep(), Dot);
AstClassOrPackageRef* const cpackagerefp
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
if (dotp) {
AstClassOrPackageRef* const lhsp = VN_AS(dotp->lhsp(), ClassOrPackageRef);
m_statep->resolveClassOrPackage(m_curSymp, lhsp, true, false,
"External definition :: reference");
AstClass* const lhsclassp = VN_CAST(lhsp->classOrPackageSkipp(), Class);
if (!lhsclassp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(lhsclassp);
upSymp = m_curSymp;
AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef);
m_statep->resolveClassOrPackage(m_curSymp, rhsp, true, false,
"External definition :: reference");
AstClass* const rhsclassp = VN_CAST(rhsp->classOrPackageSkipp(), Class);
if (!rhsclassp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(rhsclassp);
upSymp = m_curSymp;
moveExternFuncDecl(nodep, rhsclassp);
}
}
} else if (cpackagerefp) {
if (!cpackagerefp->classOrPackageSkipp()) {
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, true, false,
"External definition :: reference");
}
AstClass* const classp = VN_CAST(cpackagerefp->classOrPackageSkipp(), Class);
if (!classp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(classp);
upSymp = m_curSymp;
moveExternFuncDecl(nodep, classp);
}
} else {
v3fatalSrc("Unhandled extern function definition package");
}
}
// Set the class as package for iteration
if (VN_IS(m_curSymp->nodep(), Class)) {
m_classOrPackagep = VN_AS(m_curSymp->nodep(), Class);
}
// Create symbol table for the task's vars
const string name = (nodep->isExternProto() ? "extern "s : ""s) + nodep->name();
m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_classOrPackagep);
m_curSymp->fallbackp(upSymp);
// Convert the func's range to the output variable
// This should probably be done in the Parser instead, as then we could
// just attach normal signal attributes to it.
if (!nodep->isExternProto() && nodep->fvarp() && !VN_IS(nodep->fvarp(), Var)) {
AstNodeDType* dtypep = VN_CAST(nodep->fvarp(), NodeDType);
// If unspecified, function returns one bit; however when we
// support NEW() it could also return the class reference.
if (dtypep) {
dtypep->unlinkFrBack();
} else {
dtypep = new AstBasicDType{nodep->fileline(), VBasicDTypeKwd::LOGIC};
}
AstVar* const newvarp
= new AstVar{nodep->fileline(), VVarType::VAR, nodep->name(), VFlagChildDType{},
dtypep}; // Not dtype resolved yet
newvarp->direction(VDirection::OUTPUT);
newvarp->lifetime(VLifetime::AUTOMATIC);
newvarp->funcReturn(true);
newvarp->trace(false); // Not user visible
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
nodep->fvarp(newvarp);
// Explicit insert required, as the var name shadows the upper level's task name
m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, nullptr /*classOrPackagep*/);
}
VL_RESTORER(m_ftaskp);
m_ftaskp = nodep;
iterateChildren(nodep);
}
void visit(AstClocking* nodep) override { // FindVisitor::
VL_RESTORER(m_clockingp);

View File

@ -1004,32 +1004,32 @@ class ParamProcessor final {
for (size_t paramIdx = pinsByIndex.size(); paramIdx < m_classParams.size(); paramIdx++) {
const int sourceParamIdx = m_classParams[paramIdx].second;
AstPin* newPin = nullptr;
AstPin* newPinp = nullptr;
// Case 1: Dependent default -> clone the source pin's type
if (sourceParamIdx >= 0) { newPin = pinsByIndex[sourceParamIdx]->cloneTree(false); }
if (sourceParamIdx >= 0) newPinp = pinsByIndex[sourceParamIdx]->cloneTree(false);
// Case 2: Direct default type (e.g., int), create a new pin with that dtype
if (!newPin && defaultTypeNodes[paramIdx]) {
if (!newPinp && defaultTypeNodes[paramIdx]) {
AstNodeDType* const dtypep = defaultTypeNodes[paramIdx];
newPin = new AstPin{dtypep->fileline(), static_cast<int>(paramIdx) + 1,
"__paramNumber" + cvtToStr(paramIdx + 1),
dtypep->cloneTree(false)};
newPinp = new AstPin{dtypep->fileline(), static_cast<int>(paramIdx) + 1,
"__paramNumber" + cvtToStr(paramIdx + 1),
dtypep->cloneTree(false)};
}
if (newPin) {
newPin->name("__paramNumber" + cvtToStr(paramIdx + 1));
newPin->param(true);
newPin->modPTypep(m_classParams[paramIdx].first);
if (newPinp) {
newPinp->name("__paramNumber" + cvtToStr(paramIdx + 1));
newPinp->param(true);
newPinp->modPTypep(m_classParams[paramIdx].first);
if (classOrPackageRef) {
classOrPackageRef->addParamsp(newPin);
classOrPackageRef->addParamsp(newPinp);
} else if (classRefDType) {
classRefDType->addParamsp(newPin);
classRefDType->addParamsp(newPinp);
}
// Update local tracking so future dependent defaults can find it
pinsByIndex.resize(paramIdx + 1, nullptr);
pinsByIndex[paramIdx] = newPin;
if (!paramsp) paramsp = newPin;
pinsByIndex[paramIdx] = newPinp;
if (!paramsp) paramsp = newPinp;
}
}
}
@ -1083,6 +1083,7 @@ class ParamProcessor final {
AstNodeModule* nodeCopyp = srcModp->cloneTree(false);
// It is a temporary copy of the original class node, stored in order to create
// another instances. It is needed only during class instantiation.
UINFO(8, " Created clone " << nodeCopyp);
m_deleter.pushDeletep(nodeCopyp);
srcModp->user3p(nodeCopyp);
storeOriginalParams(nodeCopyp);