Fix extern function that returns parametrized class (#4924).
This commit is contained in:
parent
5278f42025
commit
040484cc3f
1
Changes
1
Changes
|
|
@ -41,6 +41,7 @@ Verilator 5.043 devel
|
||||||
* Optimize $past delayed variable reuse (#6689). [Geza Lore, Fractile Ltd.]
|
* Optimize $past delayed variable reuse (#6689). [Geza Lore, Fractile Ltd.]
|
||||||
* Optimize combinational loops through sign extension (#6724). [Geza Lore]
|
* Optimize combinational loops through sign extension (#6724). [Geza Lore]
|
||||||
* Optimize trace initialization code size (#6749). [Geza Lore]
|
* Optimize trace initialization code size (#6749). [Geza Lore]
|
||||||
|
* Fix extern function that returns parametrized class (#4924).
|
||||||
* Fix expression short circuiting (#6483). [Todd Strader]
|
* Fix expression short circuiting (#6483). [Todd Strader]
|
||||||
* Fix expression coverage of system calls (#6592). [Todd Strader]
|
* Fix expression coverage of system calls (#6592). [Todd Strader]
|
||||||
* Fix `--timing` with `--x-initial-edge` (#6603) (#6631). [Krzysztof Bieganski, Antmicro Ltd.]
|
* Fix `--timing` with `--x-initial-edge` (#6603) (#6631). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,16 @@
|
||||||
VL_DANGLING(var); \
|
VL_DANGLING(var); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
/// As with VL_DO_DANGLING, but two variables dangle.
|
||||||
|
#define VL_DO_DANGLING2(stmt, var, var2) \
|
||||||
|
do { \
|
||||||
|
do { \
|
||||||
|
stmt; \
|
||||||
|
} while (false); \
|
||||||
|
VL_DANGLING(var); \
|
||||||
|
VL_DANGLING(var2); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
/// Perform an e.g. delete, then set variable to nullptr as a requirement
|
/// Perform an e.g. delete, then set variable to nullptr as a requirement
|
||||||
#define VL_DO_CLEAR(stmt, stmt2) \
|
#define VL_DO_CLEAR(stmt, stmt2) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
||||||
|
|
@ -966,18 +966,17 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
|
|
||||||
void moveExternFuncDecl(AstNodeFTask* nodep, AstClass* classp) {
|
void moveExternFuncDecl(AstNodeFTask* nodep, AstClass* classp) {
|
||||||
// Move an 'extern function|task' to inside a class or, from an outer to inner-class
|
// Move an 'extern function|task' to inside a class or, from an outer to inner-class
|
||||||
if (!nodep->isExternDef()) {
|
if (nodep->isExternDef()) return;
|
||||||
// Move it to proper spot under the target class
|
// Move it to proper spot under the target class
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
classp->addStmtsp(nodep);
|
classp->addStmtsp(nodep);
|
||||||
nodep->isExternDef(true); // So we check there's a matching extern
|
nodep->isExternDef(true); // So we check there's a matching extern
|
||||||
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
||||||
// Any "Type::" reference in the function's IO are really "MovedToClass::" references
|
// Any "Type::" reference in the function's IO are really "MovedToClass::" references
|
||||||
if (nodep->fvarp()) moveExternFuncDeclRefs(nodep->fvarp(), classp);
|
if (nodep->fvarp()) moveExternFuncDeclRefs(nodep->fvarp(), classp);
|
||||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||||
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
|
||||||
if (portp->isIO()) moveExternFuncDeclRefs(portp, classp);
|
if (portp->isIO()) moveExternFuncDeclRefs(portp, classp);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -985,7 +984,14 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
nodep->foreach([this, classp](AstClassOrPackageRef* refp) { //
|
nodep->foreach([this, classp](AstClassOrPackageRef* refp) { //
|
||||||
if (refp->name() == classp->name() && !refp->paramsp()) {
|
if (refp->name() == classp->name() && !refp->paramsp()) {
|
||||||
UINFO(9, "Cleaning up external function type for class " << refp);
|
UINFO(9, "Cleaning up external function type for class " << refp);
|
||||||
pushDeletep(refp->unlinkFrBack());
|
AstDot* const dotp = VN_CAST(refp->backp(), Dot);
|
||||||
|
if (dotp && dotp->lhsp() == refp) {
|
||||||
|
// If had DOT(CLASSREF this, ...) the DOT can go away
|
||||||
|
dotp->replaceWith(dotp->rhsp()->unlinkFrBack());
|
||||||
|
VL_DO_DANGLING2(pushDeletep(dotp), dotp, refp);
|
||||||
|
} else {
|
||||||
|
VL_DO_DANGLING(pushDeletep(refp->unlinkFrBack()), refp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. 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
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class One #(
|
||||||
|
type VALUE_T = int unsigned
|
||||||
|
);
|
||||||
|
typedef One#(VALUE_T) self_t;
|
||||||
|
VALUE_T value;
|
||||||
|
extern static function self_t create(VALUE_T value);
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Two #(
|
||||||
|
type VALUE_T = int unsigned
|
||||||
|
);
|
||||||
|
VALUE_T value;
|
||||||
|
extern static function Two#(VALUE_T) create(VALUE_T value);
|
||||||
|
`ifdef NEVER
|
||||||
|
// works ok if put function directly here
|
||||||
|
static function Two#(VALUE_T) create(VALUE_T value);
|
||||||
|
Two #(VALUE_T) obj = new();
|
||||||
|
obj.value = value;
|
||||||
|
return obj;
|
||||||
|
endfunction
|
||||||
|
`endif
|
||||||
|
endclass
|
||||||
|
|
||||||
|
function One::self_t One::create(VALUE_T value);
|
||||||
|
One #(VALUE_T) obj = new();
|
||||||
|
obj.value = value;
|
||||||
|
return obj;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function Two#(Two::VALUE_T) Two::create(VALUE_T value);
|
||||||
|
Two #(VALUE_T) obj = new();
|
||||||
|
obj.value = value;
|
||||||
|
return obj;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
module t;
|
||||||
|
initial begin
|
||||||
|
One #(string) one;
|
||||||
|
Two #(string) two;
|
||||||
|
one = One#(string)::create("one");
|
||||||
|
two = Two#(string)::create("two");
|
||||||
|
if (one.value !== "one") $stop;
|
||||||
|
if (two.value !== "two") $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue