Optimize string formatting runtime functions

Add an overload that takes `const char*` format string. This avoids
having to construct/destruct a temporary `std::string` at the call site
when calling these functions with a string literal, which is fairly
common. This is worth 25% code size on some assertion heavy design.

Also use `std::string::clear()` instead of assigning an empty string
which is more efficient.
This commit is contained in:
Geza Lore 2026-06-03 09:54:02 +01:00
parent 715f5f0c13
commit 7b45b3ee8a
2 changed files with 117 additions and 19 deletions

View File

@ -998,7 +998,7 @@ void _vl_vsformat(std::string& output, const std::string& format, int argc,
bool widthSet = false;
bool left = false;
size_t width = 0;
output = "";
output.clear();
output.reserve(format.length());
for (std::string::const_iterator pos = format.cbegin(); pos != format.cend(); ++pos) {
if (!inPct && pos[0] == '%') {
@ -1833,9 +1833,11 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
Verilated::threadContextp()->impp()->fdClose(fdi);
}
//===========================================================================
// String formatting functions taking const std::string& as format string
void VL_SFORMAT_NX(int obits, CData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
@ -1846,7 +1848,6 @@ void VL_SFORMAT_NX(int obits, CData& destr, const std::string& format, int argc,
void VL_SFORMAT_NX(int obits, SData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
@ -1857,7 +1858,6 @@ void VL_SFORMAT_NX(int obits, SData& destr, const std::string& format, int argc,
void VL_SFORMAT_NX(int obits, IData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
@ -1868,7 +1868,6 @@ void VL_SFORMAT_NX(int obits, IData& destr, const std::string& format, int argc,
void VL_SFORMAT_NX(int obits, QData& destr, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
@ -1879,7 +1878,6 @@ void VL_SFORMAT_NX(int obits, QData& destr, const std::string& format, int argc,
void VL_SFORMAT_NX(int obits, EData* destp, const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
@ -1898,19 +1896,17 @@ void VL_SFORMAT_NX(std::string& output, const std::string& format, int argc, ...
}
std::string VL_SFORMATF_N_NX(const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
std::string output;
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
_vl_vsformat(output, format, argc, ap);
va_end(ap);
return t_output;
return output;
}
void VL_WRITEF_NX(const std::string& format, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
@ -1922,8 +1918,6 @@ void VL_WRITEF_NX(const std::string& format, int argc, ...) VL_MT_SAFE {
void VL_FWRITEF_NX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, format, argc, ap);
@ -1932,6 +1926,99 @@ void VL_FWRITEF_NX(IData fpi, const std::string& format, int argc, ...) VL_MT_SA
Verilated::threadContextp()->impp()->fdWrite(fpi, t_output);
}
//===========================================================================
// String formatting functions taking const char* as format string
void VL_SFORMAT_NX(int obits, CData& destr, const char* formatp, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, formatp, argc, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_NX(int obits, SData& destr, const char* formatp, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, formatp, argc, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_NX(int obits, IData& destr, const char* formatp, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, formatp, argc, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_NX(int obits, QData& destr, const char* formatp, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, formatp, argc, ap);
va_end(ap);
_vl_string_to_vint(obits, &destr, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_NX(int obits, EData* destp, const char* formatp, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, formatp, argc, ap);
va_end(ap);
_vl_string_to_vint(obits, destp, t_output.length(), t_output.c_str());
}
void VL_SFORMAT_NX(std::string& output, const char* formatp, int argc, ...) VL_MT_SAFE {
std::string temp_output;
va_list ap;
va_start(ap, argc);
_vl_vsformat(temp_output, formatp, argc, ap);
va_end(ap);
output = temp_output;
}
std::string VL_SFORMATF_N_NX(const char* formatp, int argc, ...) VL_MT_SAFE {
std::string output;
va_list ap;
va_start(ap, argc);
_vl_vsformat(output, formatp, argc, ap);
va_end(ap);
return output;
}
void VL_WRITEF_NX(const char* formatp, int argc, ...) VL_MT_SAFE {
static thread_local std::string t_output; // static only for speed
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, formatp, argc, ap);
va_end(ap);
VL_PRINTF_MT("%s", t_output.c_str());
}
void VL_FWRITEF_NX(IData fpi, const char* formatp, int argc, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
static thread_local std::string t_output; // static only for speed
va_list ap;
va_start(ap, argc);
_vl_vsformat(t_output, formatp, argc, ap);
va_end(ap);
Verilated::threadContextp()->impp()->fdWrite(fpi, t_output);
}
IData VL_FSCANF_INX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
FILE* const fp = VL_CVT_I_FP(fpi);

View File

@ -150,9 +150,6 @@ extern void VL_FCLOSE_I(IData fdi) VL_MT_SAFE;
extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi,
IData start, IData count) VL_MT_SAFE;
extern void VL_WRITEF_NX(const std::string& format, int argc, ...) VL_MT_SAFE;
extern void VL_FWRITEF_NX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE;
extern IData VL_FSCANF_INX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IINX(int lbits, IData ld, const std::string& format, int argc,
...) VL_MT_SAFE;
@ -161,6 +158,7 @@ extern IData VL_SSCANF_IQNX(int lbits, QData ld, const std::string& format, int
extern IData VL_SSCANF_IWNX(int lbits, WDataInP const lwp, const std::string& format, int argc,
...) VL_MT_SAFE;
// String formatting functions taking const std::string& as format string
extern void VL_SFORMAT_NX(int obits, CData& destr, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, SData& destr, const std::string& format, int argc,
@ -171,6 +169,22 @@ extern void VL_SFORMAT_NX(int obits, QData& destr, const std::string& format, in
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, EData* destp, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(std::string& output, const std::string& format, int argc,
...) VL_MT_SAFE;
extern std::string VL_SFORMATF_N_NX(const std::string& format, int argc, ...) VL_MT_SAFE;
extern void VL_WRITEF_NX(const std::string& format, int argc, ...) VL_MT_SAFE;
extern void VL_FWRITEF_NX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE;
// String formatting functions taking const char* format string
extern void VL_SFORMAT_NX(int obits, CData& destr, const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, SData& destr, const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, IData& destr, const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, QData& destr, const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(int obits, EData* destp, const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(std::string& output, const char* formatp, int argc, ...) VL_MT_SAFE;
extern std::string VL_SFORMATF_N_NX(const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_WRITEF_NX(const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_FWRITEF_NX(IData fpi, const char* formatp, int argc, ...) VL_MT_SAFE;
extern void VL_STACKTRACE() VL_MT_SAFE;
extern std::string VL_STACKTRACE_N() VL_MT_SAFE;
@ -3668,9 +3682,6 @@ extern void VL_WRITEMEM_N(bool hex, int bits, QData depth, int array_lsb,
QData end) VL_MT_SAFE;
extern IData VL_SSCANF_INNX(int lbits, const std::string& ld, const std::string& format, int argc,
...) VL_MT_SAFE;
extern void VL_SFORMAT_NX(std::string& output, const std::string& format, int argc,
...) VL_MT_SAFE;
extern std::string VL_SFORMATF_N_NX(const std::string& format, int argc, ...) VL_MT_SAFE;
extern void VL_TIMEFORMAT_IINI(bool hasUnits, int units, bool hasPrecision, int precision,
bool hasSuffix, const std::string& suffix, bool hasWidth, int width,
VerilatedContext* contextp) VL_MT_SAFE;