Optimize empty function definition bodies (#5750).

This commit is contained in:
Wilson Snyder 2025-01-25 12:13:25 -05:00
parent 98e40c847c
commit 001c098e5a
8 changed files with 19 additions and 27 deletions

View File

@ -26,6 +26,7 @@ Verilator 5.033 devel
* Improve VPI write errors (#5712). [Andrew Nolte]
* Improve `resetall support (#5728) (#5730). [Ethan Sifferman]
* Optimize labels as final `if` block statements (#5744).
* Optimize empty function definition bodies (#5750).
* Fix error message when call task as a function (#3089). [Matthew Ballance]
* Fix VPI iteration over hierarchy (#5314) (#5731). [Natan Kreimer]
* Fix constrained random for > 64-bit associative arrays (#5670) (#5682). [Yilou Wang]

View File

@ -625,6 +625,7 @@ class AstCFunc final : public AstNode {
bool m_isTrace : 1; // Function is related to tracing
bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special
bool m_declPrivate : 1; // Declare it private
bool m_keepIfEmpty : 1; // Keep declaration and definition separate, even if empty
bool m_slow : 1; // Slow routine, called once or just at init time
bool m_funcPublic : 1; // From user public task/function
bool m_isConstructor : 1; // Is C class constructor
@ -655,6 +656,7 @@ public:
m_isTrace = false;
m_dontCombine = false;
m_declPrivate = false;
m_keepIfEmpty = false;
m_slow = false;
m_funcPublic = false;
m_isConstructor = false;
@ -706,6 +708,8 @@ public:
bool dontInline() const { return dontCombine() || slow() || funcPublic(); }
bool declPrivate() const { return m_declPrivate; }
void declPrivate(bool flag) { m_declPrivate = flag; }
bool keepIfEmpty() const VL_MT_SAFE { return m_keepIfEmpty; }
void keepIfEmpty(bool flag) { m_keepIfEmpty = flag; }
bool slow() const VL_MT_SAFE { return m_slow; }
void slow(bool flag) { m_slow = flag; }
bool funcPublic() const { return m_funcPublic; }
@ -749,8 +753,7 @@ public:
void cost(int cost) { m_cost = cost; }
// Special methods
bool emptyBody() const {
return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr
&& finalsp() == nullptr;
return !keepIfEmpty() && !argsp() && !initsp() && !stmtsp() && !finalsp();
}
};
class AstCLocalScope final : public AstNode {

View File

@ -2865,15 +2865,17 @@ void AstCFile::dumpJson(std::ostream& str) const {
void AstCFunc::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (slow()) str << " [SLOW]";
if (dpiPure()) str << " [DPIPURE]";
if (isStatic()) str << " [STATIC]";
if (dpiContext()) str << " [DPICTX]";
if (dpiExportDispatcher()) str << " [DPIED]";
if (dpiExportImpl()) str << " [DPIEI]";
if (dpiImportPrototype()) str << " [DPIIP]";
if (dpiImportWrapper()) str << " [DPIIW]";
if (dpiContext()) str << " [DPICTX]";
if (dpiPure()) str << " [DPIPURE]";
if (isConstructor()) str << " [CTOR]";
if (isDestructor()) str << " [DTOR]";
if (isMethod()) str << " [METHOD]";
if (isLoose()) str << " [LOOSE]";
if (isVirtual()) str << " [VIRT]";
if (isCoroutine()) str << " [CORO]";
if (needProcess()) str << " [NPRC]";

View File

@ -62,6 +62,7 @@ class V3CCtorsBuilder final {
AstCFunc* const funcp = new AstCFunc{m_modp->fileline(), funcName, nullptr, "void"};
funcp->isStatic(false);
funcp->isLoose(!m_type.isClass());
funcp->keepIfEmpty(true); // TODO relax
funcp->declPrivate(true);
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
string preventUnusedStmt;
@ -210,6 +211,7 @@ void V3CCtors::evalAsserts() {
funcp->declPrivate(true);
funcp->isStatic(false);
funcp->isLoose(true);
funcp->keepIfEmpty(true);
funcp->slow(false);
funcp->ifdef("VL_DEBUG");
modp->addStmtsp(funcp);

View File

@ -171,7 +171,11 @@ void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeMo
putns(funcp, "virtual ");
}
emitCFuncHeader(funcp, modp, /* withScope: */ false);
putns(funcp, ";\n");
if (funcp->emptyBody() && !funcp->isLoose() && !cLinkage) {
putns(funcp, " {}\n");
} else {
putns(funcp, ";\n");
}
if (!funcp->ifdef().empty()) putns(funcp, "#endif // " + funcp->ifdef() + "\n");
}

View File

@ -280,6 +280,7 @@ public:
// VISITORS
using EmitCConstInit::visit;
void visit(AstCFunc* nodep) override {
if (nodep->emptyBody() && !nodep->isLoose()) return;
VL_RESTORER(m_useSelfForThis);
VL_RESTORER(m_cfuncp);
VL_RESTORER(m_instantiatesOwnProcess)

View File

@ -70,6 +70,7 @@ AstCFunc* makeSubFunction(AstNetlist* netlistp, const string& name, bool slow) {
AstCFunc* makeTopFunction(AstNetlist* netlistp, const string& name, bool slow) {
AstCFunc* const funcp = makeSubFunction(netlistp, name, slow);
funcp->entryPoint(true);
funcp->keepIfEmpty(true);
return funcp;
}

View File

@ -185,7 +185,6 @@
-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274
-V{t#,#} Resuming delayed processes
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:173
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::__VnoInFunc_do_sth_else
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_delay
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:247
-V{t#,#} Process forked at t/t_timing_class.v:246 finished
@ -499,7 +498,6 @@
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:257
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::__VnoInFunc_do_delay
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:174
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_sth_else
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_delay
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
@ -1038,9 +1036,7 @@
-V{t#,#} Process forked at t/t_timing_class.v:250 finished
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:245
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:175
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_sth_else
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_delay
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_sth_else
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__6____Vfork_1__0
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76
@ -1082,8 +1078,6 @@
-V{t#,#}End-of-eval cleanup
-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::~
-V{t#,#}+ Eval
-V{t#,#}+ Vt_timing_debug2___024root___eval
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
@ -1236,7 +1230,6 @@
-V{t#,#}End-of-eval cleanup
-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step
-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::~
-V{t#,#}+ Eval
-V{t#,#}+ Vt_timing_debug2___024root___eval
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
@ -1308,18 +1301,3 @@
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__nba
-V{t#,#}End-of-eval cleanup
-V{t#,#}+ Vt_timing_debug2___024root___eval_final
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::~
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::~
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::~
-V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::~
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::~