Optimize emitting to_string() for compiler speedup (#7468)
Signed-off-by: Jakub Michalski <jmichalski@antmicro.com>
This commit is contained in:
parent
a5a1ed55d3
commit
05f6db7970
|
|
@ -239,6 +239,7 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
|
|||
bool m_packed;
|
||||
bool m_isFourstate = false; // V3Width computes; true if any member is 4-state
|
||||
bool m_constrainedRand = false; // True if struct has constraint expression
|
||||
bool m_emitToString = false; // Generate to_string() for this struct/union if set
|
||||
|
||||
protected:
|
||||
AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack)
|
||||
|
|
@ -293,6 +294,8 @@ public:
|
|||
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||
bool isConstrainedRand() const { return m_constrainedRand; }
|
||||
void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
|
||||
bool emitToString() const { return m_emitToString; }
|
||||
void setEmitToString() { m_emitToString = true; }
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
|
|
|
|||
|
|
@ -2663,6 +2663,7 @@ class AstClass final : public AstNodeModule {
|
|||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||
bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
|
||||
bool m_virtual = false; // Virtual class
|
||||
bool m_printedFrom = false; // This class is printed from i.e. is used as format arg.
|
||||
|
||||
public:
|
||||
AstClass(FileLine* fl, const string& name, const string& libname)
|
||||
|
|
@ -2690,6 +2691,8 @@ public:
|
|||
void needRNG(bool flag) { m_needRNG = flag; }
|
||||
bool useVirtualPublic() const { return m_useVirtualPublic; }
|
||||
void useVirtualPublic(bool flag) { m_useVirtualPublic = flag; }
|
||||
void markPrintedFrom() { m_printedFrom = true; }
|
||||
bool isPrintedFrom() const { return m_printedFrom; }
|
||||
// Return true if this class is an extension of base class (SLOW)
|
||||
// Accepts nullptrs
|
||||
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
||||
|
|
|
|||
|
|
@ -2003,6 +2003,7 @@ void AstClass::dump(std::ostream& str) const {
|
|||
if (isInterfaceClass()) str << " [IFCCLS]";
|
||||
if (isVirtual()) str << " [VIRT]";
|
||||
if (useVirtualPublic()) str << " [VIRPUB]";
|
||||
if (isPrintedFrom()) str << " [PRINTED]";
|
||||
}
|
||||
void AstClass::dumpJson(std::ostream& str) const {
|
||||
// dumpJsonNumFunc(str, declTokenNum); // Not dumped as adding token changes whole file
|
||||
|
|
@ -2010,6 +2011,7 @@ void AstClass::dumpJson(std::ostream& str) const {
|
|||
dumpJsonBoolFuncIf(str, isExtended);
|
||||
dumpJsonBoolFuncIf(str, isInterfaceClass);
|
||||
dumpJsonBoolFuncIf(str, isVirtual);
|
||||
dumpJsonBoolFuncIf(str, isPrintedFrom);
|
||||
if (baseOverride().isAny()) dumpJsonStr(str, "baseOverride", baseOverride().ascii());
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
|
|
@ -2608,10 +2610,12 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
|||
if (packed()) str << " [PACKED]";
|
||||
if (isFourstate()) str << " [4STATE]";
|
||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||
if (emitToString()) str << " [EMITSTR]";
|
||||
}
|
||||
void AstNodeUOrStructDType::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFuncIf(str, packed);
|
||||
dumpJsonBoolFuncIf(str, isFourstate);
|
||||
dumpJsonBoolFuncIf(str, emitToString);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstUnionDType::dump(std::ostream& str) const {
|
||||
|
|
|
|||
213
src/V3Common.cpp
213
src/V3Common.cpp
|
|
@ -16,7 +16,16 @@
|
|||
// V3Common's Transformations:
|
||||
//
|
||||
// Each class:
|
||||
// Create string access functions
|
||||
// Emit to_string() if given class is printed from (used as format arg), or any of its
|
||||
// parents/children is printed from, or if any of its children has another parent that is
|
||||
// printed from. If class emits to_string(), emit to_string() for its struct/union/interface
|
||||
// fields.
|
||||
// Each struct/union:
|
||||
// Emit to_string() if given struct/union is used as format arg or is a field of a
|
||||
// class/struct/union that emits to_string(). If struct/union emits to_string(), emit
|
||||
// to_string() for its struct/union fields.
|
||||
// Each interface:
|
||||
// Emit to_string() if given interface is a field of a class that emits to_string()
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
|
@ -150,30 +159,192 @@ static void makeToStringMiddle(AstClass* nodep) {
|
|||
nodep->addStmtsp(funcp);
|
||||
}
|
||||
|
||||
class ToStringVisitor final : public VNVisitorConst {
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> bool. to_string() was emitted
|
||||
// AstClass::user2() -> PrintedFromParent. Used to propagate emission of to_string() from
|
||||
// parent to child
|
||||
const VNUser1InUse m_inuser1;
|
||||
const VNUser2InUse m_inuser2;
|
||||
size_t m_emitTowardsRoot
|
||||
= 0; // class that require its ancestors to emit to_string() sets this
|
||||
size_t m_emitForMembers = 0; // class/struct that requires its members (and their members
|
||||
// recursively) to emit to_string() sets this
|
||||
enum class PrintedFromParent : uint8_t {
|
||||
UNRESOLVED,
|
||||
PRINTED_FROM_PARENT,
|
||||
NO_PRINTED_FROM_PARENT
|
||||
};
|
||||
|
||||
VDouble0 m_statClassToString;
|
||||
VDouble0 m_statInterfaceToString;
|
||||
VDouble0 m_statStructUnionToString;
|
||||
|
||||
void markClassIterate(AstClass* classp) {
|
||||
if (classp->user1SetOnce()) return;
|
||||
VL_RESTORER(m_emitForMembers);
|
||||
++m_emitForMembers;
|
||||
for (AstNode* stmtp = classp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* const varp = VN_CAST(stmtp, Var)) {
|
||||
AstNodeDType* nodeDtypep = varp->dtypep();
|
||||
if (AstIfaceRefDType* const ifaceRedDTypep = VN_CAST(nodeDtypep, IfaceRefDType)) {
|
||||
if (ifaceRedDTypep->ifacep()) iterateConst(ifaceRedDTypep->ifacep());
|
||||
} else {
|
||||
while (nodeDtypep && nodeDtypep->subDTypep()
|
||||
&& nodeDtypep->subDTypep()->skipRefp()) {
|
||||
nodeDtypep = nodeDtypep->subDTypep()->skipRefp();
|
||||
if (AstIfaceRefDType* const ifaceRedDTypep
|
||||
= VN_CAST(nodeDtypep, IfaceRefDType)) {
|
||||
if (ifaceRedDTypep->ifacep()) {
|
||||
iterateConst(ifaceRedDTypep->ifacep());
|
||||
}
|
||||
} else if (AstNodeUOrStructDType* const uOrStructDTypep
|
||||
= VN_CAST(nodeDtypep, NodeUOrStructDType)) {
|
||||
iterateConst(uOrStructDTypep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
makeToString(classp);
|
||||
makeToStringMiddle(classp);
|
||||
++m_statClassToString;
|
||||
}
|
||||
void visit(AstNodeUOrStructDType* structp) override {
|
||||
if (structp->user1())
|
||||
return; // if to_string() was already emitted skip the rest of the function
|
||||
if (structp->emitToString()) ++m_emitForMembers;
|
||||
if (m_emitForMembers
|
||||
> 0) { // either this struct directly requires emission of to_string() or the
|
||||
// class/struct that has this struct as a field requires it to emit to_string()
|
||||
for (AstMemberDType* memberp = structp->membersp(); memberp;
|
||||
memberp = VN_AS(memberp->nextp(), MemberDType)) {
|
||||
AstNodeDType* nodeDtypep = memberp->dtypep();
|
||||
if (AstNodeUOrStructDType* const uOrStructDTypep
|
||||
= VN_CAST(nodeDtypep, NodeUOrStructDType)) {
|
||||
iterateConst(uOrStructDTypep);
|
||||
} else {
|
||||
while (nodeDtypep && nodeDtypep->subDTypep()) {
|
||||
nodeDtypep = nodeDtypep->subDTypep()->skipRefp();
|
||||
if (AstNodeUOrStructDType* const uOrStructDTypep
|
||||
= VN_CAST(nodeDtypep, NodeUOrStructDType)) {
|
||||
iterateConst(uOrStructDTypep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (structp->emitToString()) --m_emitForMembers;
|
||||
|
||||
if (!structp->packed()) {
|
||||
makeVlToString(structp);
|
||||
++m_statStructUnionToString;
|
||||
}
|
||||
|
||||
structp->user1(true); // mark that to_string() was emitted to not emit it twice (if
|
||||
// e.g two printed classes have this struct as a field)
|
||||
}
|
||||
}
|
||||
void visit(AstIface* ifacep) override {
|
||||
if (ifacep->user1())
|
||||
return; // if to_string() was already emitted skip the rest of the function
|
||||
if (m_emitForMembers
|
||||
> 0) { // class that has this iface as a field requires it to emit to_string()
|
||||
makeVlToString(ifacep);
|
||||
++m_statInterfaceToString;
|
||||
ifacep->user1(true); // mark that to_string() was emitted to not emit it twice (if e.g
|
||||
// two printed classes have this interface as a field)
|
||||
}
|
||||
}
|
||||
// go towards class hierarchy root, if there is any printed from class on the way, mark its
|
||||
// ancestors, and mark everything on the return path from the printed from class
|
||||
void visit(AstClass* classp) override {
|
||||
if (classp->user1()) return;
|
||||
if (classp->isPrintedFrom()) {
|
||||
markClassIterate(classp);
|
||||
VL_RESTORER(m_emitTowardsRoot);
|
||||
++m_emitTowardsRoot;
|
||||
for (const AstClassExtends* extendp = classp->extendsp(); extendp;
|
||||
extendp = VN_AS(extendp->nextp(), ClassExtends)) {
|
||||
if (extendp->classp() && !extendp->classp()->user1()) {
|
||||
iterateConst(extendp->classp());
|
||||
}
|
||||
}
|
||||
classp->user2(static_cast<int>(PrintedFromParent::PRINTED_FROM_PARENT));
|
||||
} else {
|
||||
PrintedFromParent printed_parent = static_cast<PrintedFromParent>(classp->user2());
|
||||
if (printed_parent != PrintedFromParent::UNRESOLVED && m_emitTowardsRoot == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_emitTowardsRoot > 0) markClassIterate(classp);
|
||||
|
||||
bool is_root = true;
|
||||
for (const AstClassExtends* extendp = classp->extendsp(); extendp;
|
||||
extendp = VN_AS(extendp->nextp(), ClassExtends)) {
|
||||
if (extendp->classp()) {
|
||||
if (static_cast<PrintedFromParent>(extendp->classp()->user2())
|
||||
== PrintedFromParent::UNRESOLVED
|
||||
|| (m_emitTowardsRoot > 0 && !extendp->classp()->user1())) {
|
||||
iterateConst(extendp->classp());
|
||||
}
|
||||
if (printed_parent != PrintedFromParent::PRINTED_FROM_PARENT) {
|
||||
printed_parent
|
||||
= static_cast<PrintedFromParent>(extendp->classp()->user2());
|
||||
}
|
||||
is_root = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_root) printed_parent = PrintedFromParent::NO_PRINTED_FROM_PARENT;
|
||||
|
||||
classp->user2(static_cast<int>(printed_parent));
|
||||
if (printed_parent == PrintedFromParent::PRINTED_FROM_PARENT) {
|
||||
markClassIterate(classp);
|
||||
|
||||
// If one parent is printed from, other parent also has to emit to_string() to
|
||||
// handle cases like:
|
||||
// Base IFaceClass (printed from)
|
||||
// V V
|
||||
// Derived (this class)
|
||||
VL_RESTORER(m_emitTowardsRoot);
|
||||
++m_emitTowardsRoot;
|
||||
for (const AstClassExtends* extendp = classp->extendsp(); extendp;
|
||||
extendp = VN_AS(extendp->nextp(), ClassExtends)) {
|
||||
if (extendp->classp() && !extendp->classp()->user1()) {
|
||||
iterateConst(extendp->classp());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void visit(AstConstPool*) override {} // Accelerate
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
explicit ToStringVisitor(AstNode* nodep) {
|
||||
if (v3Global.hasPrintedObjects()) {
|
||||
AstNode::user1ClearTree();
|
||||
AstNode::user2ClearTree();
|
||||
|
||||
iterateConst(nodep);
|
||||
}
|
||||
|
||||
V3Stats::addStat("Optimizations, Class ToString emitted", m_statClassToString);
|
||||
V3Stats::addStat("Optimizations, Interface ToString emitted", m_statInterfaceToString);
|
||||
V3Stats::addStat("Optimizations, Struct/union ToString emitted",
|
||||
m_statStructUnionToString);
|
||||
}
|
||||
~ToStringVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// V3Common class functions
|
||||
|
||||
void V3Common::commonAll() {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstClass::user1() -> bool. True if class needs to_string dumper
|
||||
const VNUser1InUse m_inuser1;
|
||||
// Create common contents for each module
|
||||
for (AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) {
|
||||
if (AstClass* const classp = VN_CAST(nodep, Class)) {
|
||||
// Create ToString methods
|
||||
makeToString(classp);
|
||||
makeToStringMiddle(classp);
|
||||
} else if (AstIface* const ifacep = VN_CAST(nodep, Iface)) {
|
||||
makeVlToString(ifacep);
|
||||
}
|
||||
}
|
||||
for (AstNode* nodep = v3Global.rootp()->typeTablep()->typesp(); nodep;
|
||||
nodep = nodep->nextp()) {
|
||||
if (AstNodeUOrStructDType* const dtypep = VN_CAST(nodep, NodeUOrStructDType)) {
|
||||
if (!dtypep->packed()) makeVlToString(dtypep);
|
||||
}
|
||||
}
|
||||
|
||||
ToStringVisitor{v3Global.rootp()};
|
||||
|
||||
V3Global::dumpCheckGlobalTree("common", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ class V3Global final {
|
|||
bool m_useParallelBuild = false; // Use parallel build for model
|
||||
bool m_useRandSequence = false; // Has `randsequence`
|
||||
bool m_useRandomizeMethods = false; // Need to define randomize() class methods
|
||||
bool m_hasPrintedObjects = false; // Design has format args printed with to_string()
|
||||
uint64_t m_currentHierBlockCost = 0; // Total cost of this hier block, used for scheduling
|
||||
|
||||
// Memory address to short string mapping (for debug)
|
||||
|
|
@ -221,6 +222,8 @@ public:
|
|||
void useRandSequence(bool flag) { m_useRandSequence = flag; }
|
||||
bool useRandomizeMethods() const { return m_useRandomizeMethods; }
|
||||
void useRandomizeMethods(bool flag) { m_useRandomizeMethods = flag; }
|
||||
bool hasPrintedObjects() const { return m_hasPrintedObjects; }
|
||||
void hasPrintedObjects(bool flag) { m_hasPrintedObjects = flag; }
|
||||
void saveJsonPtrFieldName(const std::string& fieldName);
|
||||
void ptrNamesDumpJson(std::ostream& os);
|
||||
void idPtrMapDumpJson(std::ostream& os);
|
||||
|
|
|
|||
|
|
@ -6415,6 +6415,26 @@ class WidthVisitor final : public VNVisitor {
|
|||
} else if (dtypep->isString()) {
|
||||
formatAttr = VFormatAttr::STRING;
|
||||
} else if (isFormatNonNumericArg(dtypep)) {
|
||||
if (AstVarRef* const varRefp = VN_CAST(argp, VarRef)) {
|
||||
if (AstClassRefDType* const classRefp
|
||||
= VN_CAST(varRefp->dtypep(), ClassRefDType)) {
|
||||
if (classRefp->classp()) {
|
||||
classRefp->classp()->markPrintedFrom();
|
||||
v3Global.hasPrintedObjects(true);
|
||||
}
|
||||
} else {
|
||||
AstNodeDType* nodeDtypep = varRefp->dtypep();
|
||||
while (nodeDtypep && nodeDtypep->subDTypep()
|
||||
&& nodeDtypep->subDTypep()->skipRefp()) {
|
||||
nodeDtypep = nodeDtypep->subDTypep()->skipRefp();
|
||||
if (AstNodeUOrStructDType* const uOrStructDTypep
|
||||
= VN_CAST(nodeDtypep, NodeUOrStructDType)) {
|
||||
uOrStructDTypep->setEmitToString();
|
||||
v3Global.hasPrintedObjects(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AstNodeExpr* const newp = new AstToStringN{argp->fileline(), argp};
|
||||
formatAttr = VFormatAttr::COMPLEX;
|
||||
argp = newp;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
struct: ''{s1:'{a:'h0}, s2:'{'{'{b:'h0}, '{b:'h0}, '{b:'h0}}, '{'{b:'h0}, '{b:'h0}, '{b:'h0}}}, x:'h0}'
|
||||
class: ''{z:'h0, i1:top.t.i1, i2:'{'{top.t.i2}}, s1:'{a:'h0}, s2:'{'{'{b:'h0}, '{b:'h0}, '{b:'h0}}, '{'{b:'h0}, '{b:'h0}, '{b:'h0}}}}'
|
||||
class from subclass: ''{derived_a:'h0, base_a:'h0}'
|
||||
class from superclass: ''{derived2_a:'h0, c2:$unit::Class2, base2_a:'h0}'
|
||||
class from interface: ''{derived3_a:'h0, base3_a:'h0}'
|
||||
class from interface 2: ''{derived4_a:'h0, }'
|
||||
nested class: ''{nested_class_field:'h0}'
|
||||
classes with shared field types: ''{s1:'{x:'h0}, s2:'{x:'h0}, i:top.t.i3}', ''{s:'{x:'h0}, i:top.t.i3}'
|
||||
*-* All Finished *-*
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--stats", "-DDISPLAY_OBJECTS"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.file_grep(test.stats, r"Optimizations, Struct/union ToString emitted\s+(\d+)", 6)
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)", 13)
|
||||
test.file_grep(test.stats, r"Optimizations, Interface ToString emitted\s+(\d+)", 3)
|
||||
|
||||
test.files_identical(test.obj_dir + "/vlt_sim.log", test.golden_filename, "logfile")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
int a;
|
||||
} s1;
|
||||
struct {
|
||||
int b;
|
||||
} s2[2][3];
|
||||
int x;
|
||||
} struct_t;
|
||||
|
||||
interface iface;
|
||||
int y1;
|
||||
endinterface
|
||||
|
||||
interface iface2;
|
||||
int y2;
|
||||
endinterface
|
||||
|
||||
class Class;
|
||||
int z;
|
||||
virtual iface i1;
|
||||
virtual iface2 i2[1][1];
|
||||
struct {
|
||||
int a;
|
||||
} s1;
|
||||
struct {
|
||||
int b;
|
||||
} s2[2][3];
|
||||
endclass
|
||||
|
||||
class Class2;
|
||||
int x;
|
||||
endclass;
|
||||
|
||||
class Base;
|
||||
int base_a;
|
||||
endclass
|
||||
|
||||
class Derived extends Base;
|
||||
int derived_a;
|
||||
endclass
|
||||
|
||||
class Base2;
|
||||
int base2_a;
|
||||
endclass
|
||||
|
||||
class Derived2 extends Base2;
|
||||
int derived2_a;
|
||||
Class2 c2;
|
||||
endclass;
|
||||
|
||||
class Base3;
|
||||
int base3_a;
|
||||
endclass
|
||||
|
||||
interface class Iclass;
|
||||
endclass
|
||||
|
||||
class Derived3 extends Base3 implements Iclass;
|
||||
int derived3_a;
|
||||
endclass
|
||||
|
||||
interface class Iclass2;
|
||||
endclass
|
||||
|
||||
class Derived4 implements Iclass2;
|
||||
int derived4_a;
|
||||
endclass
|
||||
|
||||
class OuterClass;
|
||||
class NestedClass;
|
||||
int nested_class_field;
|
||||
endclass
|
||||
endclass
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
} struct2_t;
|
||||
|
||||
interface iface3;
|
||||
int i;
|
||||
endinterface
|
||||
|
||||
class Class3;
|
||||
struct2_t s1;
|
||||
struct2_t s2;
|
||||
virtual iface3 i;
|
||||
endclass
|
||||
|
||||
class Class4;
|
||||
struct2_t s;
|
||||
virtual iface3 i;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
struct_t s;
|
||||
iface i1();
|
||||
iface2 i2();
|
||||
Class c;
|
||||
Derived d;
|
||||
Derived2 d2;
|
||||
Base2 b2;
|
||||
Derived3 d3;
|
||||
Iclass iclass;
|
||||
Derived4 d4;
|
||||
Iclass2 iclass2;
|
||||
OuterClass::NestedClass nc;
|
||||
Class3 c3;
|
||||
Class4 c4;
|
||||
iface3 i3();
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.i1 = i1;
|
||||
c.i2[0][0] = i2;
|
||||
d = new;
|
||||
d2 = new;
|
||||
d2.c2 = new;
|
||||
b2 = d2;
|
||||
d3 = new;
|
||||
iclass = d3;
|
||||
d4 = new;
|
||||
iclass2 = d4;
|
||||
nc = new;
|
||||
c3 = new;
|
||||
c3.i = i3;
|
||||
c4 = new;
|
||||
c4.i = i3;
|
||||
|
||||
`ifdef DISPLAY_OBJECTS
|
||||
$display("struct: '%p'", s);
|
||||
$display("class: '%p'", c);
|
||||
$display("class from subclass: '%p'", d);
|
||||
$display("class from superclass: '%p'", b2);
|
||||
$display("class from interface: '%p'", iclass);
|
||||
$display("class from interface 2: '%p'", d4);
|
||||
$display("nested class: '%p'", nc);
|
||||
$display("classes with shared field types: '%p', '%p'", c3, c4);
|
||||
`endif
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Base
|
||||
// V
|
||||
// Derived1---------------- IClass1
|
||||
// V V V
|
||||
// Derived2------ Derived7
|
||||
// V V V
|
||||
// Derived3 Derived5 Derived8
|
||||
// V V V
|
||||
// Derived4 Derived6 Derived9
|
||||
|
||||
interface class IClass1;
|
||||
endclass
|
||||
|
||||
class Base;
|
||||
int base_field;
|
||||
endclass
|
||||
|
||||
class Derived1 extends Base;
|
||||
int derived1_field;
|
||||
endclass
|
||||
|
||||
class Derived2 extends Derived1;
|
||||
int derived2_field;
|
||||
endclass
|
||||
|
||||
class Derived3 extends Derived2;
|
||||
int derived3_field;
|
||||
endclass
|
||||
|
||||
class Derived4 extends Derived3;
|
||||
int derived4_field;
|
||||
endclass
|
||||
|
||||
class Derived5 extends Derived2;
|
||||
int derived5_field;
|
||||
endclass
|
||||
|
||||
class Derived6 extends Derived5;
|
||||
int derived6_field;
|
||||
endclass
|
||||
|
||||
class Derived7 extends Derived1 implements IClass1;
|
||||
int derived7_field;
|
||||
endclass
|
||||
|
||||
class Derived8 extends Derived7;
|
||||
int derived8_field;
|
||||
endclass
|
||||
|
||||
class Derived9 extends Derived8;
|
||||
int derived9_field;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
`OBJ_TYPE obj = new;
|
||||
`PRINTED_FROM_TYPE printed_obj = obj;
|
||||
`ifdef OBJ_TYPE2
|
||||
`OBJ_TYPE2 obj2 = new;
|
||||
`PRINTED_FROM_TYPE2 printed_obj2 = obj2;
|
||||
`endif
|
||||
|
||||
initial begin
|
||||
$display("'%p'", printed_obj);
|
||||
`ifdef OBJ_TYPE2
|
||||
$display("'%p'", printed_obj2);
|
||||
`endif
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
''{derived9_field:'h0, derived8_field:'h0, derived7_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
*-* All Finished *-*
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_to_string_emitted_class_hierarchy.v"
|
||||
|
||||
obj_type = "Derived9"
|
||||
printed_from_type = "IClass1"
|
||||
expected_to_string_classes = ["Base", "Derived1", "IClass1", "Derived7", "Derived8", "Derived9"]
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats", f"-DOBJ_TYPE={obj_type}", f"-DPRINTED_FROM_TYPE={printed_from_type}"
|
||||
])
|
||||
for class_name in expected_to_string_classes:
|
||||
test.file_grep(
|
||||
f"{test.obj_dir}/{test.vm_prefix}___024unit__03a__03a{class_name}__Vclpkg__0.cpp",
|
||||
f"std::string {test.vm_prefix}___024unit__03a__03a{class_name}::to_string()")
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)",
|
||||
len(expected_to_string_classes))
|
||||
test.execute()
|
||||
test.files_identical(test.obj_dir + "/vlt_sim.log", test.golden_filename, "logfile")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
''{derived2_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
*-* All Finished *-*
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_to_string_emitted_class_hierarchy.v"
|
||||
|
||||
obj_type = "Derived2"
|
||||
printed_from_type = "Derived2"
|
||||
expected_to_string_classes = [
|
||||
"Base", "Derived1", "Derived2", "Derived3", "Derived4", "Derived5", "Derived6"
|
||||
]
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats", f"-DOBJ_TYPE={obj_type}", f"-DPRINTED_FROM_TYPE={printed_from_type}"
|
||||
])
|
||||
for class_name in expected_to_string_classes:
|
||||
test.file_grep(
|
||||
f"{test.obj_dir}/{test.vm_prefix}___024unit__03a__03a{class_name}__Vclpkg__0.cpp",
|
||||
f"std::string {test.vm_prefix}___024unit__03a__03a{class_name}::to_string()")
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)",
|
||||
len(expected_to_string_classes))
|
||||
test.execute()
|
||||
test.files_identical(test.obj_dir + "/vlt_sim.log", test.golden_filename, "logfile")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
''{derived3_field:'h0, derived2_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
*-* All Finished *-*
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_to_string_emitted_class_hierarchy.v"
|
||||
|
||||
obj_type = "Derived3"
|
||||
printed_from_type = "Derived3"
|
||||
expected_to_string_classes = ["Base", "Derived1", "Derived2", "Derived3", "Derived4"]
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats", f"-DOBJ_TYPE={obj_type}", f"-DPRINTED_FROM_TYPE={printed_from_type}"
|
||||
])
|
||||
for class_name in expected_to_string_classes:
|
||||
test.file_grep(
|
||||
f"{test.obj_dir}/{test.vm_prefix}___024unit__03a__03a{class_name}__Vclpkg__0.cpp",
|
||||
f"std::string {test.vm_prefix}___024unit__03a__03a{class_name}::to_string()")
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)",
|
||||
len(expected_to_string_classes))
|
||||
test.execute()
|
||||
test.files_identical(test.obj_dir + "/vlt_sim.log", test.golden_filename, "logfile")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
''{derived6_field:'h0, derived5_field:'h0, derived2_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
*-* All Finished *-*
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_to_string_emitted_class_hierarchy.v"
|
||||
|
||||
obj_type = "Derived6"
|
||||
printed_from_type = "Derived6"
|
||||
expected_to_string_classes = ["Base", "Derived1", "Derived2", "Derived5", "Derived6"]
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats", f"-DOBJ_TYPE={obj_type}", f"-DPRINTED_FROM_TYPE={printed_from_type}"
|
||||
])
|
||||
for class_name in expected_to_string_classes:
|
||||
test.file_grep(
|
||||
f"{test.obj_dir}/{test.vm_prefix}___024unit__03a__03a{class_name}__Vclpkg__0.cpp",
|
||||
f"std::string {test.vm_prefix}___024unit__03a__03a{class_name}::to_string()")
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)",
|
||||
len(expected_to_string_classes))
|
||||
test.execute()
|
||||
test.files_identical(test.obj_dir + "/vlt_sim.log", test.golden_filename, "logfile")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
''{derived7_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
''{derived9_field:'h0, derived8_field:'h0, derived7_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
*-* All Finished *-*
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_to_string_emitted_class_hierarchy.v"
|
||||
|
||||
obj_type = "Derived7"
|
||||
printed_from_type = "Derived7"
|
||||
obj_type2 = "Derived9"
|
||||
printed_from_type2 = "Derived9"
|
||||
expected_to_string_classes = ["Base", "Derived1", "IClass1", "Derived7", "Derived8", "Derived9"]
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats", f"-DOBJ_TYPE={obj_type}", f"-DPRINTED_FROM_TYPE={printed_from_type}",
|
||||
f"-DOBJ_TYPE2={obj_type2}", f"-DPRINTED_FROM_TYPE2={printed_from_type2}"
|
||||
])
|
||||
for class_name in expected_to_string_classes:
|
||||
test.file_grep(
|
||||
f"{test.obj_dir}/{test.vm_prefix}___024unit__03a__03a{class_name}__Vclpkg__0.cpp",
|
||||
f"std::string {test.vm_prefix}___024unit__03a__03a{class_name}::to_string()")
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)",
|
||||
len(expected_to_string_classes))
|
||||
test.execute()
|
||||
test.files_identical(test.obj_dir + "/vlt_sim.log", test.golden_filename, "logfile")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
''{derived4_field:'h0, derived3_field:'h0, derived2_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
''{derived9_field:'h0, derived8_field:'h0, derived7_field:'h0, derived1_field:'h0, base_field:'h0}'
|
||||
*-* All Finished *-*
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_to_string_emitted_class_hierarchy.v"
|
||||
|
||||
obj_type = "Derived4"
|
||||
printed_from_type = "Derived4"
|
||||
obj_type2 = "Derived9"
|
||||
printed_from_type2 = "Derived9"
|
||||
expected_to_string_classes = [
|
||||
"Base", "Derived1", "Derived2", "Derived3", "Derived4", "IClass1", "Derived7", "Derived8",
|
||||
"Derived9"
|
||||
]
|
||||
|
||||
test.compile(verilator_flags2=[
|
||||
"--stats", f"-DOBJ_TYPE={obj_type}", f"-DPRINTED_FROM_TYPE={printed_from_type}",
|
||||
f"-DOBJ_TYPE2={obj_type2}", f"-DPRINTED_FROM_TYPE2={printed_from_type2}"
|
||||
])
|
||||
for class_name in expected_to_string_classes:
|
||||
test.file_grep(
|
||||
f"{test.obj_dir}/{test.vm_prefix}___024unit__03a__03a{class_name}__Vclpkg__0.cpp",
|
||||
f"std::string {test.vm_prefix}___024unit__03a__03a{class_name}::to_string()")
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)",
|
||||
len(expected_to_string_classes))
|
||||
test.execute()
|
||||
test.files_identical(test.obj_dir + "/vlt_sim.log", test.golden_filename, "logfile")
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.top_filename = "t_to_string_emitted.v"
|
||||
|
||||
test.compile(verilator_flags2=["--stats"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.file_grep(test.stats, r"Optimizations, Struct/union ToString emitted\s+(\d+)", 0)
|
||||
test.file_grep(test.stats, r"Optimizations, Class ToString emitted\s+(\d+)", 0)
|
||||
test.file_grep(test.stats, r"Optimizations, Interface ToString emitted\s+(\d+)", 0)
|
||||
|
||||
test.passes()
|
||||
Loading…
Reference in New Issue