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 11:18:38 +01:00
parent 715f5f0c13
commit 7b45b3ee8a
2 changed files with 117 additions and 19 deletions
+100 -13
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);