From 84125d7c9244f1c2b8d454f2550087e0299f7da2 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 24 Oct 2023 15:51:46 +0200 Subject: [PATCH] Fix virtual methods (#4616) --- src/V3AstNodeExpr.h | 9 +++++++ src/V3EmitCFunc.h | 2 +- src/V3LinkDot.cpp | 13 +++++++++- src/V3Randomize.cpp | 1 + src/V3Task.cpp | 6 +++++ test_regress/t/t_class_virtual.v | 43 ++++++++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index f9de8e512..d026e5fcc 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -183,6 +183,7 @@ class AstNodeCCall VL_NOT_FINAL : public AstNodeExpr { // @astgen op2 := argsp : List[AstNodeExpr] // Note: op1 used by some sub-types only AstCFunc* m_funcp; string m_argTypes; + bool m_superReference = false; // Called with super reference protected: AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr) @@ -213,6 +214,8 @@ public: string emitVerilog() final override { V3ERROR_NA_RETURN(""); } string emitC() final override { V3ERROR_NA_RETURN(""); } bool cleanOut() const final override { return true; } + bool superReference() const { return m_superReference; } + void superReference(bool flag) { m_superReference = flag; } }; class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr { // A reference to a task (or function) @@ -4198,12 +4201,15 @@ public: // === AstNodeFTaskRef === class AstFuncRef final : public AstNodeFTaskRef { // A reference to a function + bool m_superReference = false; // Called with super reference public: AstFuncRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp) : ASTGEN_SUPER_FuncRef(fl, (AstNode*)namep, pinsp) {} AstFuncRef(FileLine* fl, const string& name, AstNodeExpr* pinsp) : ASTGEN_SUPER_FuncRef(fl, name, pinsp) {} ASTGEN_MEMBERS_AstFuncRef; + bool superReference() const { return m_superReference; } + void superReference(bool flag) { m_superReference = flag; } }; class AstMethodCall final : public AstNodeFTaskRef { // A reference to a member task (or function) @@ -4240,6 +4246,7 @@ public: }; class AstTaskRef final : public AstNodeFTaskRef { // A reference to a task + bool m_superReference = false; // Called with super reference public: AstTaskRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp) : ASTGEN_SUPER_TaskRef(fl, (AstNode*)namep, pinsp) { @@ -4250,6 +4257,8 @@ public: dtypeSetVoid(); } ASTGEN_MEMBERS_AstTaskRef; + bool superReference() const { return m_superReference; } + void superReference(bool flag) { m_superReference = flag; } }; // === AstNodePreSel === diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index a90368ace..6c7ef5fb0 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -486,7 +486,7 @@ public: // Call static method via the containing class puts(prefixNameProtect(funcModp) + "::"); puts(funcp->nameProtect()); - } else if (VN_IS(funcModp, Class) && funcModp != m_modp) { + } else if (nodep->superReference()) { // Calling superclass method puts(prefixNameProtect(funcModp) + "::"); puts(funcp->nameProtect()); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index df0028782..a3b5a350b 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2039,6 +2039,7 @@ 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_super; // Starts with super reference 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 @@ -2050,6 +2051,7 @@ private: m_dotPos = DP_NONE; m_dotSymp = curSymp; m_dotp = nullptr; + m_super = false; m_dotErr = false; m_dotText = ""; m_unresolvedCell = false; @@ -2061,6 +2063,7 @@ private: std::ostringstream sstr; sstr << "ds=" << names[m_dotPos]; sstr << " dse" << cvtToHex(m_dotSymp); + sstr << " sup=" << m_super; sstr << " txt=" << m_dotText; sstr << " unrCell=" << m_unresolvedCell; sstr << " unrClass=" << m_unresolvedClass; @@ -2462,6 +2465,7 @@ private: const auto baseClassp = cextp->classp(); UASSERT_OBJ(baseClassp, nodep, "Bad superclass"); m_ds.m_dotSymp = m_statep->getNodeSym(baseClassp); + m_ds.m_super = true; UINFO(8, " super. " << m_ds.ascii() << endl); } } @@ -2538,7 +2542,6 @@ private: // Generally resolved during Primay, but might be at param time under AstUnlinkedRef UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep, "ParseRefs should no longer exist"); - if (nodep->name() == "super") nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); const DotStates lastStates = m_ds; const bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed if (start) { @@ -3079,6 +3082,14 @@ private: iterateChildren(nodep); } + if (m_ds.m_super) { + if (AstFuncRef* const funcRefp = VN_CAST(nodep, FuncRef)) { + funcRefp->superReference(true); + } else if (AstTaskRef* const taskRefp = VN_CAST(nodep, TaskRef)) { + taskRefp->superReference(true); + } + } + bool staticAccess = false; if (m_ds.m_unresolvedClass) { // Unable to link before V3Param diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 5c39b78d2..af72b95c0 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -310,6 +310,7 @@ private: baseRandCallp->taskp(baseRandomizep); baseRandCallp->dtypeFrom(baseRandomizep->dtypep()); baseRandCallp->classOrPackagep(nodep->extendsp()->classp()); + baseRandCallp->superReference(true); beginValp = baseRandCallp; } } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index a410f06a6..9bd96ef03 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -638,6 +638,12 @@ private: beginp->addNext(ccallp->makeStmt()); } + if (const AstFuncRef* const funcRefp = VN_CAST(refp, FuncRef)) { + ccallp->superReference(funcRefp->superReference()); + } else if (const AstTaskRef* const taskRefp = VN_CAST(refp, TaskRef)) { + ccallp->superReference(taskRefp->superReference()); + } + // Convert complicated outputs to temp signals { const V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp()); diff --git a/test_regress/t/t_class_virtual.v b/test_regress/t/t_class_virtual.v index 9daf4cd65..5b2e9511d 100644 --- a/test_regress/t/t_class_virtual.v +++ b/test_regress/t/t_class_virtual.v @@ -22,12 +22,48 @@ class VB extends VBase; endfunction endclass +virtual class uvm_phase; + virtual function int exec_func; + return 0; + endfunction +endclass + +class uvm_topdown_phase extends uvm_phase; + function int get1; + return exec_func(); + endfunction +endclass + +class uvm_build_phase extends uvm_topdown_phase; + virtual function int exec_func; + return 1; + endfunction +endclass + +virtual class Cls; + uvm_phase ph; +endclass + +class ExtendsCls extends Cls; + function new; + uvm_build_phase bp = new; + ph = bp; + endfunction + + function int get1; + return super.ph.exec_func(); + endfunction +endclass + module t; initial begin VA va = new; VB vb = new; VBase b; + uvm_build_phase ph; + ExtendsCls ec; + if (va.hello() != 2) $stop; if (vb.hello() != 3) $stop; @@ -35,6 +71,13 @@ module t; if (b.hello() != 2) $stop; b = vb; if (b.hello() != 3) $stop; + + ph = new; + if (ph.get1() != 1) $stop; + + ec = new; + if (ec.get1() != 1) $stop; + $write("*-* All Finished *-*\n"); $finish; end