Internals: Refactoring (#6433 prep). No functional change intended.
This commit is contained in:
parent
5e4668c146
commit
12c524ac06
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue