3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-08-03 18:00:24 +00:00

Replace stringf() with a templated function which does compile-time format string checking.

Checking only happens at compile time if -std=c++20 (or greater) is enabled. Otherwise
the checking happens at run time.

This requires the format string to be a compile-time constant (when compiling with
C++20), so fix a few places where that isn't true.

The format string behavior is a bit more lenient than C printf. For %d/%u
you can pass any integer type and it will be converted and output without
truncating bits, i.e. any length specifier is ignored and the conversion is
always treated as 'll'. Any truncation needs to be done by casting the argument itself.
For %f/%g you can pass anything that converts to double, including integers.

Performance results with clang 19 -O3 on Linux:
```
hyperfine './yosys -dp "read_rtlil /usr/local/google/home/rocallahan/Downloads/jpeg.synth.il; dump"'
```
C++17 before: Time (mean ± σ):     101.3 ms ±   0.8 ms    [User: 85.6 ms, System: 15.6 ms]
C++17 after:  Time (mean ± σ):      98.4 ms ±   1.2 ms    [User: 82.1 ms, System: 16.1 ms]
C++20 before: Time (mean ± σ):     100.9 ms ±   1.1 ms    [User: 87.0 ms, System: 13.8 ms]
C++20 after:  Time (mean ± σ):      97.8 ms ±   1.4 ms    [User: 83.1 ms, System: 14.7 ms]

The generated code is reasonably efficient. E.g. with clang 19, `stringf()` with a format
with no %% escapes and no other parameters (a weirdly common case) often compiles to a fully
inlined `std::string` construction. In general the format string parsing is often (not always)
compiled away.
This commit is contained in:
Robert O'Callahan 2025-07-09 02:31:33 +00:00
parent 8f6d7a3043
commit 6ee3cd8ffd
4 changed files with 551 additions and 19 deletions

View file

@ -1163,9 +1163,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
dump_sigspec(f, cell->getPort(ID::Y));
f << stringf(" = ~((");
dump_cell_expr_port(f, cell, "A", false);
f << stringf(cell->type == ID($_AOI3_) ? " & " : " | ");
f << (cell->type == ID($_AOI3_) ? " & " : " | ");
dump_cell_expr_port(f, cell, "B", false);
f << stringf(cell->type == ID($_AOI3_) ? ") |" : ") &");
f << (cell->type == ID($_AOI3_) ? ") |" : ") &");
dump_attributes(f, "", cell->attributes, " ");
f << stringf(" ");
dump_cell_expr_port(f, cell, "C", false);
@ -1178,13 +1178,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
dump_sigspec(f, cell->getPort(ID::Y));
f << stringf(" = ~((");
dump_cell_expr_port(f, cell, "A", false);
f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
f << (cell->type == ID($_AOI4_) ? " & " : " | ");
dump_cell_expr_port(f, cell, "B", false);
f << stringf(cell->type == ID($_AOI4_) ? ") |" : ") &");
f << (cell->type == ID($_AOI4_) ? ") |" : ") &");
dump_attributes(f, "", cell->attributes, " ");
f << stringf(" (");
dump_cell_expr_port(f, cell, "C", false);
f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
f << (cell->type == ID($_AOI4_) ? " & " : " | ");
dump_cell_expr_port(f, cell, "D", false);
f << stringf("));\n");
return true;
@ -1395,10 +1395,10 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
int s_width = cell->getPort(ID::S).size();
std::string func_name = cellname(cell);
f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
f << stringf("%s" "function [%d:0] %s;\n", indent, width-1, func_name);
f << stringf("%s" " input [%d:0] a;\n", indent, width-1);
f << stringf("%s" " input [%d:0] b;\n", indent, s_width*width-1);
f << stringf("%s" " input [%d:0] s;\n", indent, s_width-1);
dump_attributes(f, indent + " ", cell->attributes);
if (noparallelcase)
@ -1407,7 +1407,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (!noattr)
f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
f << stringf("%s" " casez (s)", indent.c_str());
f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
f << (noattr ? " // synopsys parallel_case\n" : "\n");
}
for (int i = 0; i < s_width; i++)