parent
06263ec724
commit
716b404256
|
|
@ -997,6 +997,48 @@ inline std::ostream& operator<<(std::ostream& os, const VCMethod& rhs) {
|
|||
|
||||
// ######################################################################
|
||||
|
||||
class VCStmtType final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
NONE, // Unknown or not applicable
|
||||
CTOR_VAR_RESET_CALL,
|
||||
_ENUM_MAX // Leave last
|
||||
};
|
||||
|
||||
private:
|
||||
struct Item final {
|
||||
enum en m_e; // Statement's enum mnemonic, for checking
|
||||
const char* m_name; // Statements name, for debugging
|
||||
};
|
||||
static Item s_itemData[];
|
||||
|
||||
public:
|
||||
enum en m_e;
|
||||
VCStmtType()
|
||||
: m_e{NONE} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VCStmtType(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit VCStmtType(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const VL_PURE {
|
||||
static const char* const names[] = {"none", "ctor_var_reset_call"};
|
||||
return names[m_e];
|
||||
}
|
||||
bool isNone() const { return m_e == NONE; }
|
||||
};
|
||||
constexpr bool operator==(const VCStmtType& lhs, const VCStmtType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VCStmtType& lhs, VCStmtType::en rhs) { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VCStmtType::en lhs, const VCStmtType& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VCStmtType& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VCaseType final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
|
|||
bool m_modPublic : 1; // Module has public references
|
||||
bool m_modTrace : 1; // Tracing this module
|
||||
bool m_inLibrary : 1; // From a library, no error if not used, never top level
|
||||
bool m_ctorVarReset : 1; // Ctor needs to call ctor_var_reset
|
||||
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
|
||||
bool m_hasGParam : 1; // Has global parameter (for link)
|
||||
bool m_hasParameterList : 1; // Has #() for parameter declaration
|
||||
|
|
@ -301,6 +302,7 @@ protected:
|
|||
, m_modPublic{false}
|
||||
, m_modTrace{false}
|
||||
, m_inLibrary{false}
|
||||
, m_ctorVarReset{false}
|
||||
, m_dead{false}
|
||||
, m_hasGParam{false}
|
||||
, m_hasParameterList{false}
|
||||
|
|
@ -336,6 +338,8 @@ public:
|
|||
void modPublic(bool flag) { m_modPublic = flag; }
|
||||
bool modTrace() const { return m_modTrace; }
|
||||
void modTrace(bool flag) { m_modTrace = flag; }
|
||||
bool ctorVarReset() const { return m_ctorVarReset; }
|
||||
void ctorVarReset(bool flag) { m_ctorVarReset = flag; }
|
||||
bool dead() const { return m_dead; }
|
||||
void dead(bool flag) { m_dead = flag; }
|
||||
bool hasGParam() const { return m_hasGParam; }
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ public:
|
|||
class AstCStmt final : public AstNodeStmt {
|
||||
// C statement emitted into output, with some arbitrary nodes interspersed
|
||||
// @astgen op1 := nodesp : List[AstNode<AstNodeStmt|AstNodeExpr|AstText>]
|
||||
const VCStmtType m_stmtType; // Special statement (instead of comparing name())
|
||||
|
||||
static AstCStmt* profExecSection(FileLine* flp, const std::string& section, bool push) {
|
||||
// Compute the label
|
||||
|
|
@ -337,8 +338,10 @@ class AstCStmt final : public AstNodeStmt {
|
|||
}
|
||||
|
||||
public:
|
||||
explicit AstCStmt(FileLine* fl, const std::string& text = "")
|
||||
: ASTGEN_SUPER_CStmt(fl) {
|
||||
explicit AstCStmt(FileLine* fl, const std::string& text = "",
|
||||
const VCStmtType& stmtType = VCStmtType::NONE)
|
||||
: ASTGEN_SUPER_CStmt(fl)
|
||||
, m_stmtType{stmtType} {
|
||||
if (!text.empty()) add(text);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCStmt;
|
||||
|
|
@ -347,6 +350,9 @@ public:
|
|||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() override { return false; }
|
||||
bool sameNode(const AstNode*) const override { return true; }
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
VCStmtType stmtType() const { return m_stmtType; }
|
||||
// Add some text, or a node to this statement
|
||||
void add(const std::string& text) { addNodesp(new AstText{fileline(), text}); }
|
||||
void add(AstNode* nodep) { addNodesp(nodep); }
|
||||
|
|
|
|||
|
|
@ -2633,6 +2633,7 @@ void AstNodeModule::dump(std::ostream& str) const {
|
|||
str << " D" << depth();
|
||||
if (modPublic()) str << " [P]";
|
||||
if (inLibrary()) str << " [LIB]";
|
||||
if (ctorVarReset()) str << " [CVRESET]";
|
||||
if (dead()) str << " [DEAD]";
|
||||
if (recursiveClone()) {
|
||||
str << " [RECURSIVE-CLONE]";
|
||||
|
|
@ -2650,6 +2651,7 @@ void AstNodeModule::dumpJson(std::ostream& str) const {
|
|||
dumpJsonNumFunc(str, level);
|
||||
dumpJsonBoolFuncIf(str, modPublic);
|
||||
dumpJsonBoolFuncIf(str, inLibrary);
|
||||
dumpJsonBoolFuncIf(str, ctorVarReset);
|
||||
dumpJsonBoolFuncIf(str, dead);
|
||||
dumpJsonBoolFuncIf(str, recursiveClone);
|
||||
dumpJsonBoolFuncIf(str, recursive);
|
||||
|
|
@ -3398,6 +3400,14 @@ void AstCMethodHard::setPurity() {
|
|||
}
|
||||
}
|
||||
|
||||
void AstCStmt::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (!stmtType().isNone()) str << " [" << stmtType().ascii() << "]";
|
||||
}
|
||||
void AstCStmt::dumpJson(std::ostream& str) const {
|
||||
dumpJsonGen(str);
|
||||
if (!stmtType().isNone()) dumpJsonStr(str, "stmtType", stmtType().ascii());
|
||||
}
|
||||
void AstCUse::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [" << useType() << "]";
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ class V3CCtorsBuilder final {
|
|||
funcp->keepIfEmpty(true); // TODO relax
|
||||
funcp->declPrivate(true);
|
||||
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
|
||||
if (!m_type.isCoverage()) m_modp->ctorVarReset(true);
|
||||
string preventUnusedStmt;
|
||||
if (m_type.isClass()) {
|
||||
funcp->argTypes(EmitCUtil::symClassVar());
|
||||
|
|
@ -83,6 +84,7 @@ class V3CCtorsBuilder final {
|
|||
|
||||
public:
|
||||
void add(AstNode* nodep) {
|
||||
if (m_newFunctions.empty()) m_newFunctions.push_back(makeNewFunc());
|
||||
if (v3Global.opt.outputSplitCFuncs() && m_numStmts > v3Global.opt.outputSplitCFuncs()) {
|
||||
m_newFunctions.push_back(makeNewFunc());
|
||||
}
|
||||
|
|
@ -94,13 +96,13 @@ public:
|
|||
: m_modp{nodep}
|
||||
, m_basename{basename}
|
||||
, m_type{type} {
|
||||
// Note: The constructor is always called, even if empty, so we must always create at least
|
||||
// one.
|
||||
m_newFunctions.push_back(makeNewFunc());
|
||||
// Expect coverage function to always exist, so must always create at least one.
|
||||
if (m_type.isCoverage()) m_newFunctions.push_back(makeNewFunc());
|
||||
}
|
||||
|
||||
~V3CCtorsBuilder() {
|
||||
if (m_newFunctions.size() == 1) {
|
||||
if (m_newFunctions.size() == 0) {
|
||||
} else if (m_newFunctions.size() == 1) {
|
||||
// No split was necessary, rename the one function to the basename
|
||||
m_newFunctions.front()->name(m_basename);
|
||||
} else {
|
||||
|
|
@ -136,6 +138,7 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
AstCFunc* m_cfuncp = nullptr; // Current function
|
||||
V3CCtorsBuilder* m_varResetp = nullptr; // Builder of _ctor_var_reset
|
||||
std::map<AstCStmt*, const AstNodeModule*> m_ctorCalls; // Calls to _ctor_var_reset
|
||||
|
||||
// METHODS
|
||||
static void insertSc(AstCFunc* cfuncp, const AstNodeModule* modp, VSystemCSectionType type) {
|
||||
|
|
@ -194,6 +197,13 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
if (nodep->name() == "new") insertSc(nodep, m_modp, VSystemCSectionType::CTOR);
|
||||
}
|
||||
void visit(AstCStmt* nodep) override {
|
||||
if (nodep->stmtType() == VCStmtType::CTOR_VAR_RESET_CALL) {
|
||||
UASSERT_OBJ(m_modp, nodep, "ctor_var_reset call not under module");
|
||||
m_ctorCalls.emplace(nodep, m_modp);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
if (nodep->needsCReset()) {
|
||||
AstNode* const crstp = new AstAssign{
|
||||
|
|
@ -215,7 +225,14 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CCtorsVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
~CCtorsVisitor() override = default;
|
||||
~CCtorsVisitor() override {
|
||||
// Remove CStmts to ctor_var_resets that are no longer needed
|
||||
for (auto& itr : m_ctorCalls) {
|
||||
AstCStmt* const nodep = itr.first;
|
||||
const AstNodeModule* const modp = itr.second;
|
||||
if (!modp->ctorVarReset()) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -92,8 +92,9 @@ class EmitCImp final : public EmitCFunc {
|
|||
const std::string modName = EmitCUtil::prefixNameProtect(modp);
|
||||
|
||||
puts("\n");
|
||||
m_lazyDecls.emit("void " + modName + "__", protect("_ctor_var_reset"),
|
||||
"(" + modName + "* vlSelf);");
|
||||
if (modp->ctorVarReset())
|
||||
m_lazyDecls.emit("void " + modName + "__", protect("_ctor_var_reset"),
|
||||
"(" + modName + "* vlSelf);");
|
||||
puts("\n");
|
||||
|
||||
const std::string ctorArgs = EmitCUtil::symClassName() + "* symsp, const char* namep";
|
||||
|
|
@ -148,7 +149,7 @@ class EmitCImp final : public EmitCFunc {
|
|||
}
|
||||
|
||||
putsDecoration(modp, "// Reset structure values\n");
|
||||
puts(modName + "__" + protect("_ctor_var_reset") + "(this);\n");
|
||||
if (modp->ctorVarReset()) puts(modName + "__" + protect("_ctor_var_reset") + "(this);\n");
|
||||
emitSystemCSection(modp, VSystemCSectionType::CTOR);
|
||||
|
||||
puts("}\n");
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ private:
|
|||
if (m_logp) *m_logp << "Buckets assigned to Work Lists:\n";
|
||||
int availableBuckets = v3Global.opt.outputGroups();
|
||||
for (WorkList* listp : m_concatenableListsByDescSize) {
|
||||
if (availableBuckets > 0) {
|
||||
if (availableBuckets > 0 && idealBucketScore > 0) {
|
||||
listp->m_bucketsNum = std::min(
|
||||
availableBuckets, std::max<int>(1, listp->m_totalScore / idealBucketScore));
|
||||
availableBuckets -= listp->m_bucketsNum;
|
||||
|
|
|
|||
|
|
@ -1345,7 +1345,8 @@ class TaskVisitor final : public VNVisitor {
|
|||
}
|
||||
if (!isInterfaceClass) {
|
||||
const string stmt = VIdProtect::protect("_ctor_var_reset") + "(vlSymsp);";
|
||||
cfuncp->addStmtsp(new AstCStmt{nodep->fileline(), stmt});
|
||||
cfuncp->addStmtsp(
|
||||
new AstCStmt{nodep->fileline(), stmt, VCStmtType::CTOR_VAR_RESET_CALL});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,7 @@ test.compile(verilator_flags2=["--output-groups", "2"])
|
|||
test.execute()
|
||||
|
||||
# Check that only vm_classes_*.cpp are to be compiled
|
||||
test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "Foo")
|
||||
test.file_grep(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_classes_Slow_1")
|
||||
test.file_grep(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_classes_1")
|
||||
test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_classes_Slow_2")
|
||||
test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_classes_2")
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,14 @@
|
|||
// SPDX-FileCopyrightText: 2024 Antmicro Ltd
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`ifdef verilator
|
||||
`define no_optimize(v) $c(v)
|
||||
`else
|
||||
`define no_optimize(v) (v)
|
||||
`endif
|
||||
// verilog_format: on
|
||||
|
||||
virtual class Base;
|
||||
pure virtual function int get_param;
|
||||
endclass
|
||||
|
|
@ -11,7 +19,7 @@ class Foo #(
|
|||
int N = 17
|
||||
) extends Base;
|
||||
function int get_param;
|
||||
return N;
|
||||
return `no_optimize(N);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
|
|
|
|||
|
|
@ -1,55 +1,22 @@
|
|||
-V{t#,#}- Verilated::debug is on. Message prefix indicates {<thread>,<sequence_number>}.
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions
|
||||
-V{t#,#}+ Initial
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_static
|
||||
-V{t#,#}+ Vt_timing_debug2_t___eval_static__TOP__t
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_ready
|
||||
|
|
@ -68,7 +35,6 @@
|
|||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::__VnoInFunc_do_delay
|
||||
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__7
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::_ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork____Vfork_1__0
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork____Vfork_1__1
|
||||
|
|
@ -395,8 +361,6 @@
|
|||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:123
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_wake
|
||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:261
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::new
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::_ctor_var_reset
|
||||
-V{t#,#} Process forked at t/t_timing_class.v:260 finished
|
||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:135
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
|
||||
|
|
|
|||
Loading…
Reference in New Issue