forked from github/verilator
Handle references of static members of type aliases of a parametrized class (#3922)
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
This commit is contained in:
parent
18e317fb78
commit
0e955d503e
@ -2028,7 +2028,8 @@ private:
|
||||
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||
VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup
|
||||
const AstDot* m_dotp; // Current dot
|
||||
bool m_unresolved; // Unresolved, needs help from V3Param
|
||||
bool m_unresolvedCell; // Unresolved cell, needs help from V3Param
|
||||
bool m_unresolvedClass; // Unresolved class reference, needs help from V3Param
|
||||
AstNode* m_unlinkedScopep; // Unresolved scope, needs corresponding VarXRef
|
||||
bool m_dotErr; // Error found in dotted resolution, ignore upwards
|
||||
string m_dotText; // String of dotted names found in below parseref
|
||||
@ -2040,7 +2041,8 @@ private:
|
||||
m_dotp = nullptr;
|
||||
m_dotErr = false;
|
||||
m_dotText = "";
|
||||
m_unresolved = false;
|
||||
m_unresolvedCell = false;
|
||||
m_unresolvedClass = false;
|
||||
m_unlinkedScopep = nullptr;
|
||||
}
|
||||
string ascii() const {
|
||||
@ -2049,7 +2051,8 @@ private:
|
||||
sstr << "ds=" << names[m_dotPos];
|
||||
sstr << " dse" << cvtToHex(m_dotSymp);
|
||||
sstr << " txt=" << m_dotText;
|
||||
sstr << " unr=" << m_unresolved;
|
||||
sstr << " unrCell=" << m_unresolvedCell;
|
||||
sstr << " unrClass=" << m_unresolvedClass;
|
||||
return sstr.str();
|
||||
}
|
||||
} m_ds; // State to preserve across recursions
|
||||
@ -2350,7 +2353,6 @@ private:
|
||||
// Dot(Dot(Dot(ParseRef(text), ...
|
||||
if (nodep->user3SetOnce()) return;
|
||||
UINFO(8, " " << nodep << endl);
|
||||
bool replaceWithRhs = true;
|
||||
const DotStates lastStates = m_ds;
|
||||
const bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
|
||||
{
|
||||
@ -2402,10 +2404,9 @@ private:
|
||||
}
|
||||
if (m_statep->forPrimary() && isParamedClassRef(nodep->lhsp())) {
|
||||
// Dots of paramed classes will be linked after deparameterization
|
||||
m_ds.m_unresolved = true;
|
||||
replaceWithRhs = false;
|
||||
m_ds.m_unresolvedClass = true;
|
||||
}
|
||||
if (m_ds.m_unresolved
|
||||
if (m_ds.m_unresolvedCell
|
||||
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
|
||||
m_ds.m_unlinkedScopep = nodep->lhsp();
|
||||
}
|
||||
@ -2416,8 +2417,8 @@ private:
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
// if (debug() >= 9) nodep->dumpTree("- dot-rho: ");
|
||||
}
|
||||
if (start) {
|
||||
if (replaceWithRhs) {
|
||||
if (!m_ds.m_unresolvedClass) {
|
||||
if (start) {
|
||||
AstNode* newp;
|
||||
if (m_ds.m_dotErr) {
|
||||
newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
|
||||
@ -2427,23 +2428,25 @@ private:
|
||||
if (debug() >= 9) newp->dumpTree("- dot-out: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // Dot midpoint
|
||||
AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack();
|
||||
if (m_ds.m_unresolvedCell) {
|
||||
AstCellRef* const crp = new AstCellRef{
|
||||
nodep->fileline(), nodep->name(), nodep->lhsp()->unlinkFrBack(), newp};
|
||||
newp = crp;
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
} else { // Dot midpoint
|
||||
AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack();
|
||||
if (m_ds.m_unresolved) {
|
||||
AstCellRef* const crp = new AstCellRef{nodep->fileline(), nodep->name(),
|
||||
nodep->lhsp()->unlinkFrBack(), newp};
|
||||
newp = crp;
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
const bool unresolvedClass = m_ds.m_unresolvedClass;
|
||||
if (start) {
|
||||
m_ds = lastStates;
|
||||
} else {
|
||||
m_ds.m_dotp = lastStates.m_dotp;
|
||||
}
|
||||
m_ds.m_unresolvedClass |= unresolvedClass;
|
||||
}
|
||||
void visit(AstSenItem* nodep) override {
|
||||
VL_RESTORER(m_inSens);
|
||||
@ -2453,7 +2456,7 @@ private:
|
||||
void visit(AstParseRef* nodep) override {
|
||||
if (nodep->user3SetOnce()) return;
|
||||
UINFO(9, " linkPARSEREF " << m_ds.ascii() << " n=" << nodep << endl);
|
||||
if (m_ds.m_unresolved && !m_ds.m_unlinkedScopep) return;
|
||||
if (m_ds.m_unresolvedClass) return;
|
||||
// m_curSymp is symbol table of outer expression
|
||||
// m_ds.m_dotSymp is symbol table relative to "."'s above now
|
||||
UASSERT_OBJ(m_ds.m_dotSymp, nodep, "nullptr lookup symbol table");
|
||||
@ -2629,7 +2632,7 @@ private:
|
||||
varp->attrSplitVar(false);
|
||||
}
|
||||
m_ds.m_dotText = "";
|
||||
if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) {
|
||||
if (m_ds.m_unresolvedCell && m_ds.m_unlinkedScopep) {
|
||||
const string dotted = refp->dotted();
|
||||
const size_t pos = dotted.find("__BRA__??__KET__");
|
||||
// Arrays of interfaces all have the same parameters
|
||||
@ -2641,7 +2644,7 @@ private:
|
||||
newp = new AstUnlinkedRef{nodep->fileline(), refp, refp->name(),
|
||||
m_ds.m_unlinkedScopep->unlinkFrBack()};
|
||||
m_ds.m_unlinkedScopep = nullptr;
|
||||
m_ds.m_unresolved = false;
|
||||
m_ds.m_unresolvedCell = false;
|
||||
}
|
||||
} else {
|
||||
newp = refp;
|
||||
@ -2951,19 +2954,17 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
if (m_ds.m_unresolved) {
|
||||
if (m_ds.m_unresolvedClass) {
|
||||
// Unable to link before V3Param
|
||||
if (m_ds.m_dotPos == DP_FINAL && m_ds.m_unlinkedScopep) {
|
||||
AstNodeFTaskRef* const newftaskp = nodep->cloneTree(false);
|
||||
newftaskp->dotted(m_ds.m_dotText);
|
||||
AstNode* const newp
|
||||
= new AstUnlinkedRef{nodep->fileline(), newftaskp, nodep->name(),
|
||||
m_ds.m_unlinkedScopep->unlinkFrBack()};
|
||||
m_ds.m_unlinkedScopep = nullptr;
|
||||
m_ds.m_unresolved = false;
|
||||
nodep->replaceWith(newp);
|
||||
}
|
||||
// else: AstDot wasn't replaced and it will be linked after V3Param
|
||||
return;
|
||||
} else if (m_ds.m_unresolvedCell && m_ds.m_dotPos == DP_FINAL && m_ds.m_unlinkedScopep) {
|
||||
AstNodeFTaskRef* const newftaskp = nodep->cloneTree(false);
|
||||
newftaskp->dotted(m_ds.m_dotText);
|
||||
AstNode* const newp = new AstUnlinkedRef{nodep->fileline(), newftaskp, nodep->name(),
|
||||
m_ds.m_unlinkedScopep->unlinkFrBack()};
|
||||
m_ds.m_unlinkedScopep = nullptr;
|
||||
m_ds.m_unresolvedCell = false;
|
||||
nodep->replaceWith(newp);
|
||||
return;
|
||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
|
||||
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
|
||||
@ -3118,7 +3119,7 @@ private:
|
||||
== DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
UINFO(9, " deferring until after a V3Param pass: " << nodep << endl);
|
||||
m_ds.m_dotText += "__BRA__??__KET__";
|
||||
m_ds.m_unresolved = true;
|
||||
m_ds.m_unresolvedCell = true;
|
||||
// And pass up m_ds.m_dotText
|
||||
}
|
||||
// Pass dot state down to fromp()
|
||||
@ -3131,7 +3132,7 @@ private:
|
||||
iterateAndNextNull(nodep->attrp());
|
||||
}
|
||||
}
|
||||
if (m_ds.m_unresolved && m_ds.m_dotPos == DP_SCOPE) {
|
||||
if (m_ds.m_unresolvedCell && m_ds.m_dotPos == DP_SCOPE) {
|
||||
AstNodeExpr* const exprp = nodep->bitp()->unlinkFrBack();
|
||||
AstCellArrayRef* const newp
|
||||
= new AstCellArrayRef{nodep->fileline(), nodep->fromp()->name(), exprp};
|
||||
|
@ -911,6 +911,7 @@ class ParamVisitor final : public VNVisitor {
|
||||
bool m_iterateModule = false; // Iterating module body
|
||||
string m_generateHierName; // Generate portion of hierarchy name
|
||||
string m_unlinkedTxt; // Text for AstUnlinkedRef
|
||||
std::vector<AstDot*> m_dots; // Dot references to process
|
||||
std::multimap<bool, AstNode*> m_cellps; // Cells left to process (in current module)
|
||||
std::multimap<int, AstNodeModule*> m_workQueue; // Modules left to process
|
||||
|
||||
@ -1007,6 +1008,21 @@ class ParamVisitor final : public VNVisitor {
|
||||
m_cellps.emplace(!isIface, nodep);
|
||||
}
|
||||
|
||||
// RHSs of AstDots need a relink when LHS is a parametrized class reference
|
||||
void relinkDots() {
|
||||
for (AstDot* const dotp : m_dots) {
|
||||
const AstClassOrPackageRef* const classRefp = VN_AS(dotp->lhsp(), ClassOrPackageRef);
|
||||
const AstClass* const lhsClassp = VN_AS(classRefp->classOrPackageNodep(), Class);
|
||||
AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef);
|
||||
for (auto* itemp = lhsClassp->membersp(); itemp; itemp = itemp->nextp()) {
|
||||
if (itemp->name() == rhsp->name()) {
|
||||
rhsp->classOrPackageNodep(itemp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination
|
||||
@ -1113,6 +1129,25 @@ class ParamVisitor final : public VNVisitor {
|
||||
nodep->varp(nullptr); // Needs relink, as may remove pointed-to var
|
||||
}
|
||||
|
||||
void visit(AstDot* nodep) override {
|
||||
iterate(nodep->lhsp());
|
||||
// Check if it is a reference to a field of a parameterized class.
|
||||
// If so, the RHS should be updated, when the LHS is replaced
|
||||
// by a class with actual parameter values.
|
||||
const AstClass* lhsClassp = nullptr;
|
||||
const AstClassOrPackageRef* const classRefp = VN_CAST(nodep->lhsp(), ClassOrPackageRef);
|
||||
if (classRefp) lhsClassp = VN_CAST(classRefp->classOrPackageNodep(), Class);
|
||||
AstNode* rhsDefp = nullptr;
|
||||
AstClassOrPackageRef* const rhsp = VN_CAST(nodep->rhsp(), ClassOrPackageRef);
|
||||
if (rhsp) rhsDefp = rhsp->classOrPackageNodep();
|
||||
if (lhsClassp && rhsDefp) {
|
||||
m_dots.push_back(nodep);
|
||||
// No need to iterate into rhsp, because there should be nothing to do
|
||||
} else {
|
||||
iterate(nodep->rhsp());
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstUnlinkedRef* nodep) override {
|
||||
AstVarXRef* const varxrefp = VN_CAST(nodep->refp(), VarXRef);
|
||||
AstNodeFTaskRef* const taskrefp = VN_CAST(nodep->refp(), NodeFTaskRef);
|
||||
@ -1273,6 +1308,8 @@ public:
|
||||
// Relies on modules already being in top-down-order
|
||||
iterate(netlistp);
|
||||
|
||||
relinkDots();
|
||||
|
||||
// Re-sort module list to be in topological order and fix-up incorrect levels. We need to
|
||||
// do this globally at the end due to the presence of recursive modules, which might be
|
||||
// expanded in orders that reuse earlier specializations later at a lower level.
|
||||
|
@ -70,6 +70,17 @@ class IntQueue;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class ClsStatic;
|
||||
static int x = 1;
|
||||
static function int get_2;
|
||||
return 2;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class ClsParam #(type T);
|
||||
typedef T param_t;
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
Cls c12;
|
||||
@ -139,6 +150,9 @@ module t (/*AUTOARG*/);
|
||||
if(Sum#(int)::sum != 16) $stop;
|
||||
if(Sum#(real)::sum != 0) $stop;
|
||||
|
||||
if (ClsParam#(ClsStatic)::param_t::x != 1) $stop;
|
||||
if (ClsParam#(ClsStatic)::param_t::get_2() != 2) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user