Support super.new calls (#3789)

This commit is contained in:
Ryszard Rozak 2022-11-30 12:42:48 +01:00 committed by GitHub
parent 468a33b61c
commit 073dc03adc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 183 additions and 38 deletions

View File

@ -550,7 +550,7 @@ private:
string m_cname; // C name, for dpiExports
string m_rtnType; // void, bool, or other return type
string m_argTypes; // Argument types
string m_ctorInits; // Constructor sub-class inits
string m_baseCtors; // Base class constructor
string m_ifdef; // #ifdef symbol around this function
VBoolOrUnknown m_isConst; // Function is declared const (*this not changed)
bool m_isStatic : 1; // Function is static (no need for a 'this' pointer)
@ -611,7 +611,7 @@ public:
bool same(const AstNode* samep) const override {
const AstCFunc* const asamep = static_cast<const AstCFunc*>(samep);
return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid())
&& (argTypes() == asamep->argTypes()) && (ctorInits() == asamep->ctorInits())
&& (argTypes() == asamep->argTypes()) && (baseCtors() == asamep->baseCtors())
&& isLoose() == asamep->isLoose()
&& (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name()));
}
@ -644,8 +644,8 @@ public:
void funcPublic(bool flag) { m_funcPublic = flag; }
void argTypes(const string& str) { m_argTypes = str; }
string argTypes() const { return m_argTypes; }
void ctorInits(const string& str) { m_ctorInits = str; }
string ctorInits() const { return m_ctorInits; }
void baseCtors(const string& str) { m_baseCtors = str; }
string baseCtors() const { return m_baseCtors; }
void ifdef(const string& str) { m_ifdef = str; }
string ifdef() const { return m_ifdef; }
bool isConstructor() const { return m_isConstructor; }

View File

@ -422,11 +422,7 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint
puts(nodep->argTypes());
comma = true;
}
for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
if (comma) puts(", ");
iterate(subnodep);
comma = true;
}
putCommaIterateNext(nodep->argsp(), comma);
puts(")");
}

View File

@ -205,6 +205,13 @@ public:
m_emitConstInit = true;
iterate(initp);
}
void putCommaIterateNext(AstNode* nodep, bool comma = false) {
for (AstNode* subnodep = nodep; subnodep; subnodep = subnodep->nextp()) {
if (comma) puts(", ");
iterate(subnodep);
comma = true;
}
}
// VISITORS
using EmitCConstInit::visit;
@ -221,11 +228,24 @@ public:
if (nodep->isInline()) puts("VL_INLINE_OPT ");
emitCFuncHeader(nodep, m_modp, /* withScope: */ true);
// TODO perhaps better to have a new AstCCtorInit so we can pass arguments
// rather than requiring a string here
if (!nodep->ctorInits().empty()) {
if (!nodep->baseCtors().empty()) {
puts(": ");
puts(nodep->ctorInits());
puts(nodep->baseCtors());
puts("(vlSymsp");
// Find call to super.new to get the arguments
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
AstNode* exprp;
if (VN_IS(stmtp, StmtExpr)) {
exprp = VN_CAST(stmtp, StmtExpr)->exprp();
} else {
exprp = stmtp;
}
if (AstCNew* const newRefp = VN_CAST(exprp, CNew)) {
putCommaIterateNext(newRefp->argsp(), true);
break;
}
}
puts(")");
}
puts(" {\n");
@ -417,15 +437,13 @@ public:
iterate(nodep->exprp());
}
void visit(AstCNew* nodep) override {
bool comma = false;
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", ");
puts("vlSymsp"); // TODO make this part of argsp, and eliminate when unnecessary
if (nodep->argsp()) comma = true;
for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
if (comma) puts(", ");
iterate(subnodep);
comma = true;
if (VN_IS(nodep->dtypep(), VoidDType)) {
// super.new case
return;
}
// assignment case
puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", vlSymsp");
putCommaIterateNext(nodep->argsp(), true);
puts(")");
}
void visit(AstCMethodHard* nodep) override {

View File

@ -1181,8 +1181,8 @@ private:
cfuncp->isConstructor(true);
AstClass* const classp = m_statep->getClassp(nodep);
if (classp->extendsp()) {
cfuncp->ctorInits(EmitCBaseVisitor::prefixNameProtect(classp->extendsp()->classp())
+ "(vlSymsp)");
cfuncp->baseCtors(
EmitCBaseVisitor::prefixNameProtect(classp->extendsp()->classp()));
}
}
if (cfuncp->dpiExportImpl()) cfuncp->cname(nodep->cname());

View File

@ -3555,22 +3555,32 @@ private:
void visit(AstNew* nodep) override {
if (nodep->didWidth()) return;
AstClassRefDType* const refp
= m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr;
if (!refp) { // e.g. int a = new;
nodep->v3error("new() not expected in this context");
return;
}
nodep->dtypep(refp);
AstClass* classp = nullptr;
if (VN_IS(nodep->backp(), Assign)) { // assignment case
AstClassRefDType* const refp
= m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr;
if (!refp) { // e.g. int a = new;
nodep->v3error("new() not expected in this context");
return;
}
nodep->dtypep(refp);
AstClass* const classp = refp->classp();
UASSERT_OBJ(classp, nodep, "Unlinked");
if (AstNodeFTask* const ftaskp = VN_CAST(classp->findMember("new"), Func)) {
nodep->taskp(ftaskp);
nodep->classOrPackagep(classp);
} else {
// Either made explicitly or V3LinkDot made implicitly
classp->v3fatalSrc("Can't find class's new");
classp = refp->classp();
UASSERT_OBJ(classp, nodep, "Unlinked");
if (AstNodeFTask* const ftaskp = VN_CAST(classp->findMember("new"), Func)) {
nodep->taskp(ftaskp);
nodep->classOrPackagep(classp);
} else {
// Either made explicitly or V3LinkDot made implicitly
classp->v3fatalSrc("Can't find class's new");
}
} else { // super.new case
// in this case class and taskp() should be properly linked in V3LinkDot.cpp during
// "super" reference resolution
classp = VN_CAST(nodep->classOrPackagep(), Class);
UASSERT_OBJ(classp, nodep, "Unlinked classOrPackagep()");
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked taskp()");
nodep->dtypeFrom(nodep->taskp());
}
if (classp->isVirtual()) {
nodep->v3error(

View File

@ -0,0 +1,20 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile();
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,101 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
`define stop $stop
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
class Foo;
int x;
function new;
this.x = 10;
endfunction
endclass
class Bar extends Foo;
function new;
super.new;
endfunction
endclass
class BarUnusedArg extends Foo;
function new (int a);
super.new;
endfunction
endclass
class FooArg;
int x;
function new (int a);
this.x = a;
endfunction
endclass
class BarArg extends FooArg;
function new (int a);
super.new(a);
endfunction
endclass
class BarExpr extends FooArg;
function new (int a, string b);
super.new(a + b.len());
endfunction
endclass
class Foo2Args;
int x;
function new (int a, int b);
this.x = a + b;
endfunction
endclass
class Bar2Args extends Foo2Args;
function new (int a, int b);
super.new(a, b);
endfunction
endclass
module t (/*AUTOARG*/
);
class FooInModule;
int x;
function new;
this.x = 15;
endfunction
endclass
class BarInModule extends FooInModule;
function new;
super.new;
endfunction
endclass
Bar bar;
BarInModule barInModule;
BarUnusedArg barUnusedArg;
BarArg barArg;
BarExpr barExpr;
Bar2Args bar2Args;
initial begin
bar = new;
`checkh(bar.x, 10);
barInModule = new;
`checkh(barInModule.x, 15);
barUnusedArg = new(2);
`checkh(barUnusedArg.x, 10);
barArg = new(2);
`checkh(barArg.x, 2);
barExpr = new (7, "ABCDEFGHI");
`checkh(barExpr.x, 16);
bar2Args = new(2, 12);
`checkh(bar2Args.x, 14);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule