From ccf140f2efcf916a6e17ecb03dde1c758b75ec56 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 4 Sep 2025 14:47:45 +0200 Subject: [PATCH 01/17] hashlib: don't build an unused hash for expired value in do_insert --- kernel/hashlib.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 9c53e6687..bef54b500 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -509,12 +509,11 @@ class dict { return do_lookup_internal(key, hash); } - int do_insert(const K &key, Hasher::hash_t &hash) + int do_insert(const K &key, const Hasher::hash_t &hash) { if (hashtable.empty()) { entries.emplace_back(std::pair(key, T()), -1); do_rehash(); - hash = do_hash(key); } else { entries.emplace_back(std::pair(key, T()), hashtable[hash]); hashtable[hash] = entries.size() - 1; @@ -522,12 +521,11 @@ class dict { return entries.size() - 1; } - int do_insert(const std::pair &value, Hasher::hash_t &hash) + int do_insert(const std::pair &value, const Hasher::hash_t &hash) { if (hashtable.empty()) { entries.emplace_back(value, -1); do_rehash(); - hash = do_hash(value.first); } else { entries.emplace_back(value, hashtable[hash]); hashtable[hash] = entries.size() - 1; @@ -535,13 +533,11 @@ class dict { return entries.size() - 1; } - int do_insert(std::pair &&rvalue, Hasher::hash_t &hash) + int do_insert(std::pair &&rvalue, const Hasher::hash_t &hash) { if (hashtable.empty()) { - auto key = rvalue.first; entries.emplace_back(std::forward>(rvalue), -1); do_rehash(); - hash = do_hash(key); } else { entries.emplace_back(std::forward>(rvalue), hashtable[hash]); hashtable[hash] = entries.size() - 1; From 75316e8c496c93ec048682463d24f8ea28f0cab9 Mon Sep 17 00:00:00 2001 From: Michael Kupfer Date: Wed, 14 May 2025 20:23:29 +0200 Subject: [PATCH 02/17] Add state_dependent_path_declaration so that `ifnone` can be parsed --- frontends/verilog/verilog_lexer.l | 1 + frontends/verilog/verilog_parser.y | 56 ++++++++++++++++++++++++++---- tests/verilog/specify-ifnone.ys | 27 ++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 tests/verilog/specify-ifnone.ys diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 8280c0067..686e9853f 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -377,6 +377,7 @@ TIME_SCALE_SUFFIX [munpf]?s "begin" { return parser::make_TOK_BEGIN(out_loc); } "end" { return parser::make_TOK_END(out_loc); } "if" { return parser::make_TOK_IF(out_loc); } +"ifnone" { return parser::make_TOK_IFNONE(out_loc); } "else" { return parser::make_TOK_ELSE(out_loc); } "for" { return parser::make_TOK_FOR(out_loc); } "posedge" { return parser::make_TOK_POSEDGE(out_loc); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index c77d0a7cf..238d39254 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -493,7 +493,7 @@ %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH -%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT +%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_IFNONE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY @@ -1581,18 +1581,60 @@ list_of_specparam_assignments: specparam_assignment: ignspec_id TOK_EQ ignspec_expr ; -ignspec_opt_cond: - TOK_IF TOK_LPAREN ignspec_expr TOK_RPAREN | %empty; - path_declaration : simple_path_declaration TOK_SEMICOL // | edge_sensitive_path_declaration - // | state_dependent_path_declaration + | state_dependent_path_declaration TOK_SEMICOL ; simple_path_declaration : - ignspec_opt_cond parallel_path_description TOK_EQ path_delay_value | - ignspec_opt_cond full_path_description TOK_EQ path_delay_value + parallel_path_description TOK_EQ path_delay_value | + full_path_description TOK_EQ path_delay_value + ; + +state_dependent_path_declaration: + TOK_IF TOK_LPAREN module_path_expression TOK_RPAREN simple_path_declaration + // | TOK_IF TOK_LPAREN module_path_expression TOK_RPAREN edge_sensitive_path_declaration + | TOK_IFNONE simple_path_declaration + ; + +module_path_expression: + module_path_primary + // Flatten out unary_operator to avoid shift/reduce conflict + | TOK_EXCL attr module_path_primary { free_attr($2); } + | TOK_TILDE attr module_path_primary { free_attr($2); } + | TOK_AMP attr module_path_primary { free_attr($2); } + | OP_NAND attr module_path_primary { free_attr($2); } + | TOK_PIPE attr module_path_primary { free_attr($2); } + | OP_NOR attr module_path_primary { free_attr($2); } + | TOK_CARET attr module_path_primary { free_attr($2); } + | OP_XNOR attr module_path_primary { free_attr($2); } + // Flatten out binary_operator to avoid shift/reduce conflict + | module_path_expression OP_EQ attr module_path_expression { free_attr($3); } + | module_path_expression OP_NE attr module_path_expression { free_attr($3); } + | module_path_expression OP_LAND attr module_path_expression { free_attr($3); } + | module_path_expression OP_LOR attr module_path_expression { free_attr($3); } + | module_path_expression TOK_AMP attr module_path_expression { free_attr($3); } + | module_path_expression TOK_PIPE attr module_path_expression { free_attr($3); } + | module_path_expression TOK_CARET attr module_path_expression { free_attr($3); } + | module_path_expression OP_XNOR attr module_path_expression { free_attr($3); } + // | module_path_conditional_expression + ; + +module_path_primary: + number + | TOK_ID + // Deviate from specification: Normally string would not be allowed, however they are necessary for the ecp5 tests + | TOK_STRING + // | module_path_concatenation + // | module_path_multiple_concatenation + // | function_subroutine_call + // | TOK_LPAREN module_path_minmax_expression TOK_RPAREN + ; + +number: + integral_number + | TOK_REALVAL ; path_delay_value : diff --git a/tests/verilog/specify-ifnone.ys b/tests/verilog/specify-ifnone.ys new file mode 100644 index 000000000..50b11d487 --- /dev/null +++ b/tests/verilog/specify-ifnone.ys @@ -0,0 +1,27 @@ +# ifnone gets parsed and ignored without -specify +logger -expect-no-warnings +read_verilog << EOF +module dut1 (i, o); + output o; + input i; + specify + if (a ^ (* meow *) 1 == 1'b0) + (i => o) = 1; + ifnone (i => o) = 0; + endspecify +endmodule +EOF + +# ifnone is still an error with -specify +logger -expect error "syntax error" 1 +read_verilog -specify << EOF +module dut2 (i, o); + output o; + input i; + specify + if (a ^ (* meow *) 1 == 1'b0) + (i => o) = 1; + ifnone (i => o) = 0; + endspecify +endmodule +EOF From 3f69a768f4aac3e1b95f830b13c866e20a0f073e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 02:30:12 +0000 Subject: [PATCH 03/17] Hide public `logv_` variant declarations that don't need to be public --- kernel/log.cc | 11 ++++++----- kernel/log.h | 5 ----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 3203ed3cf..1cd4a5449 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -102,7 +102,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) } #endif -void logv(const char *format, va_list ap) +static void logv(const char *format, va_list ap) { while (format[0] == '\n' && format[1] != 0) { log("\n"); @@ -204,7 +204,7 @@ void logv(const char *format, va_list ap) } } -void logv_header(RTLIL::Design *design, const char *format, va_list ap) +static void logv_header(RTLIL::Design *design, const char *format, va_list ap) { bool pop_errfile = false; @@ -305,12 +305,12 @@ static void logv_warning_with_prefix(const char *prefix, } } -void logv_warning(const char *format, va_list ap) +static void logv_warning(const char *format, va_list ap) { logv_warning_with_prefix("Warning: ", format, ap); } -void logv_warning_noprefix(const char *format, va_list ap) +static void logv_warning_noprefix(const char *format, va_list ap) { logv_warning_with_prefix("", format, ap); } @@ -390,7 +390,8 @@ static void logv_error_with_prefix(const char *prefix, #endif } -void logv_error(const char *format, va_list ap) +[[noreturn]] +static void logv_error(const char *format, va_list ap) { logv_error_with_prefix("ERROR: ", format, ap); } diff --git a/kernel/log.h b/kernel/log.h index 48997d250..27ee49d8f 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -119,11 +119,6 @@ extern int log_make_debug; extern int log_force_debug; extern int log_debug_suppressed; -void logv(const char *format, va_list ap); -void logv_header(RTLIL::Design *design, const char *format, va_list ap); -void logv_warning(const char *format, va_list ap); -void logv_warning_noprefix(const char *format, va_list ap); -[[noreturn]] void logv_error(const char *format, va_list ap); [[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap); void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); From d34ac0c87d5a31eacfe9c8ae0ad350f72ba90349 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 10 Jul 2025 05:24:59 +0000 Subject: [PATCH 04/17] Make `log()` use the `FmtString` infrastructure. Now `log()` supports `std::string`. We have to fix a few places where the format parameter was not a compile time constant. This is mostly trivial. --- backends/cxxrtl/cxxrtl_backend.cc | 4 +-- kernel/io.h | 1 + kernel/log.cc | 45 +++++++++++++++++-------------- kernel/log.h | 35 +++++++++++++++++++----- passes/cmds/logcmd.cc | 10 +++---- passes/cmds/stat.cc | 2 +- passes/equiv/equiv_simple.cc | 2 +- passes/sat/sat.cc | 4 +-- passes/techmap/dfflibmap.cc | 14 +++++----- passes/tests/test_cell.cc | 2 +- 10 files changed, 74 insertions(+), 45 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 7080f54d5..0c9f6c054 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -3478,8 +3478,8 @@ struct CxxrtlWorker { }; struct CxxrtlBackend : public Backend { - static const int DEFAULT_OPT_LEVEL = 6; - static const int DEFAULT_DEBUG_LEVEL = 4; + static constexpr int DEFAULT_OPT_LEVEL = 6; + static constexpr int DEFAULT_DEBUG_LEVEL = 4; CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { } void help() override diff --git a/kernel/io.h b/kernel/io.h index 08c234d6e..2ad0a6466 100644 --- a/kernel/io.h +++ b/kernel/io.h @@ -437,6 +437,7 @@ public: { return format_emit_toplevel(fmt, has_escapes, specs, args...); } + std::string_view format_string() const { return fmt; } private: std::string_view fmt; bool has_escapes = false; diff --git a/kernel/log.cc b/kernel/log.cc index 1cd4a5449..0afc98cd0 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -102,17 +102,16 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) } #endif -static void logv(const char *format, va_list ap) -{ - while (format[0] == '\n' && format[1] != 0) { - log("\n"); - format++; +static void logv_string(std::string_view format, std::string str) { + size_t remove_leading = 0; + while (format.size() > 1 && format[0] == '\n') { + logv_string("\n", "\n"); + format = format.substr(1); + ++remove_leading; + } + if (remove_leading > 0) { + str = str.substr(remove_leading); } - - if (log_make_debug && !ys_debug(1)) - return; - - std::string str = vstringf(format, ap); if (str.empty()) return; @@ -145,13 +144,13 @@ static void logv(const char *format, va_list ap) time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec)); } - if (format[0] && format[strlen(format)-1] == '\n') + if (!format.empty() && format[format.size() - 1] == '\n') next_print_log = true; // Special case to detect newlines in Python log output, since // the binding always calls `log("%s", payload)` and the newline // is then in the first formatted argument - if (!strcmp(format, "%s") && str.back() == '\n') + if (format == "%s" && str.back() == '\n') next_print_log = true; for (auto f : log_files) @@ -204,6 +203,20 @@ static void logv(const char *format, va_list ap) } } +static void logv(const char *format, va_list ap) +{ + if (log_make_debug && !ys_debug(1)) + return; + logv_string(format, vstringf(format, ap)); +} + +void log_formatted_string(std::string_view format, std::string str) +{ + if (log_make_debug && !ys_debug(1)) + return; + logv_string(format, std::move(str)); +} + static void logv_header(RTLIL::Design *design, const char *format, va_list ap) { bool pop_errfile = false; @@ -412,14 +425,6 @@ void log_file_error(const string &filename, int lineno, logv_file_error(filename, lineno, format, ap); } -void log(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv(format, ap); - va_end(ap); -} - void log_header(RTLIL::Design *design, const char *format, ...) { va_list ap; diff --git a/kernel/log.h b/kernel/log.h index 27ee49d8f..f58bf3afe 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -121,7 +121,7 @@ extern int log_debug_suppressed; [[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap); -void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); + void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3)); void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); @@ -145,6 +145,15 @@ static inline bool ys_debug(int = 0) { return false; } #endif # define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) +void log_formatted_string(std::string_view format, std::string str); +template +inline void log(FmtString...> fmt, const Args &... args) +{ + if (log_make_debug && !ys_debug(1)) + return; + log_formatted_string(fmt.format_string(), fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); @@ -346,8 +355,22 @@ static inline void log_dump_val_worker(unsigned long int v) { log("%lu", v); } static inline void log_dump_val_worker(long long int v) { log("%lld", v); } static inline void log_dump_val_worker(unsigned long long int v) { log("%lld", v); } #endif -static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); } -static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); } +static inline void log_dump_val_worker(char c) +{ + if (c >= 32 && c < 127) { + log("'%c'", c); + } else { + log("'\\x%02x'", c); + } +} +static inline void log_dump_val_worker(unsigned char c) +{ + if (c >= 32 && c < 127) { + log("'%c'", c); + } else { + log("'\\x%02x'", c); + } +} static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); } static inline void log_dump_val_worker(double v) { log("%f", v); } static inline void log_dump_val_worker(char *v) { log("%s", v); } @@ -369,7 +392,7 @@ static inline void log_dump_val_worker(dict &v) { log("{"); bool first = true; for (auto &it : v) { - log(first ? " " : ", "); + log("%s ", first ? "" : ","); log_dump_val_worker(it.first); log(": "); log_dump_val_worker(it.second); @@ -383,7 +406,7 @@ static inline void log_dump_val_worker(pool &v) { log("{"); bool first = true; for (auto &it : v) { - log(first ? " " : ", "); + log("%s ", first ? "" : ","); log_dump_val_worker(it); first = false; } @@ -395,7 +418,7 @@ static inline void log_dump_val_worker(std::vector &v) { log("{"); bool first = true; for (auto &it : v) { - log(first ? " " : ", "); + log("%s ", first ? "" : ","); log_dump_val_worker(it); first = false; } diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc index 0238627d1..391eaea2e 100644 --- a/passes/cmds/logcmd.cc +++ b/passes/cmds/logcmd.cc @@ -101,13 +101,13 @@ struct LogPass : public Pass { text += args[argidx] + ' '; if (!text.empty()) text.resize(text.size()-1); - const char *fmtline = newline ? "%s\n" : "%s"; + const char *line_end = newline ? "\n" : ""; - if (to_stdout) fprintf(stdout, fmtline, text.c_str()); - if (to_stderr) fprintf(stderr, fmtline, text.c_str()); + if (to_stdout) fprintf(stdout, "%s%s", text.c_str(), line_end); + if (to_stderr) fprintf(stderr, "%s%s", text.c_str(), line_end); if (to_log) { - if (!header) log(fmtline, text.c_str()); - else log_header(design, fmtline, text.c_str()); + if (!header) log("%s%s", text.c_str(), line_end); + else log_header(design, "%s%s", text.c_str(), line_end); } } } LogPass; diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index ebbd10b5c..9281f3327 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -1017,7 +1017,7 @@ struct StatPass : public Pass { if (json_mode) { log("\n"); - log(top_mod == nullptr ? " }\n" : " },\n"); + log("%s", top_mod == nullptr ? " }\n" : " },\n"); } if (top_mod != nullptr) { diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc index 8ba42595e..9e3076077 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -331,7 +331,7 @@ struct EquivSimpleWorker construct_ezsat(input_bits, step); if (!ez->solve(ez_context)) { - log(cfg.verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n"); + log("%s", cfg.verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n"); // Replace $equiv cell with a short cell->setPort(ID::B, cell->getPort(ID::A)); ez->assume(ez->NOT(ez_context)); diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 2f20880cb..60e099097 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -634,10 +634,10 @@ struct SatHelper "---------------------------------------------------------------------------------------------------" "---------------------------------------------------------------------------------------------------"; if (last_timestep == -2) { - log(max_timestep > 0 ? " Time " : " "); + log("%s", max_timestep > 0 ? " Time " : " "); log("%-*s %11s %9s %*s\n", maxModelName+5, "Signal Name", "Dec", "Hex", maxModelWidth+3, "Bin"); } - log(max_timestep > 0 ? " ---- " : " "); + log("%s", max_timestep > 0 ? " ---- " : " "); log("%*.*s %11.11s %9.9s %*.*s\n", maxModelName+5, maxModelName+5, hline, hline, hline, maxModelWidth+3, maxModelWidth+3, hline); last_timestep = info.timestep; diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index a2b9c3bff..70d0f4ef5 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -135,7 +135,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std if (ff == nullptr || ff->args.size() != 2) return false; auto ff_output = ff->args.at(0); - + // This test is redundant with the one in enable_pin, but we're in a // position that gives better diagnostics here. if (!pin_names.count(ff_output)) { @@ -166,23 +166,23 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std // the ff output Q is in a known bit location, so we now just have to compare the LUT mask to known values to find the enable pin and polarity. if (lut == 0xD8) { data_name = pins[1]; - enable_name = pins[0]; + enable_name = pins[0]; return true; } if (lut == 0xB8) { data_name = pins[0]; - enable_name = pins[1]; + enable_name = pins[1]; return true; } enable_not_inverted = false; if (lut == 0xE4) { data_name = pins[1]; - enable_name = pins[0]; + enable_name = pins[0]; return true; } if (lut == 0xE2) { data_name = pins[0]; - enable_name = pins[1]; + enable_name = pins[1]; return true; } // this does not match an enable flop. @@ -553,11 +553,11 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) new_cell->setPort("\\" + port.first, sig); } - stats[stringf(" mapped %%d %s cells to %s cells.\n", cell_type, new_cell->type)]++; + stats[stringf("%s cells to %s cells", cell_type, new_cell->type)]++; } for (auto &stat: stats) - log(stat.first.c_str(), stat.second); + log(" mapped %d %s.\n", stat.second, stat.first); } struct DfflibmapPass : public Pass { diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 87e0a00f8..a08a6ec29 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -620,7 +620,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std:: for (int i = 0; i < 64; i++) { - log(verbose ? "\n" : "."); + log("%s", verbose ? "\n" : "."); gold_ce.clear(); gate_ce.clear(); From 66d2c2af08447ce1d4f80e91579a7348d1c65381 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 02:26:50 +0000 Subject: [PATCH 05/17] Make `log_header()` use variadic templates. --- kernel/log.cc | 12 ++---------- kernel/log.h | 8 +++++++- passes/opt/opt.cc | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 0afc98cd0..bef3efb99 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -217,7 +217,7 @@ void log_formatted_string(std::string_view format, std::string str) logv_string(format, std::move(str)); } -static void logv_header(RTLIL::Design *design, const char *format, va_list ap) +void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str) { bool pop_errfile = false; @@ -236,7 +236,7 @@ static void logv_header(RTLIL::Design *design, const char *format, va_list ap) header_id += stringf("%s%d", header_id.empty() ? "" : ".", c); log("%s. ", header_id.c_str()); - logv(format, ap); + log_formatted_string(format, std::move(str)); log_flush(); if (log_hdump_all) @@ -425,14 +425,6 @@ void log_file_error(const string &filename, int lineno, logv_file_error(filename, lineno, format, ap); } -void log_header(RTLIL::Design *design, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_header(design, format, ap); - va_end(ap); -} - void log_warning(const char *format, ...) { va_list ap; diff --git a/kernel/log.h b/kernel/log.h index f58bf3afe..55fa58a34 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -122,7 +122,6 @@ extern int log_debug_suppressed; [[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap); -void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3)); void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); @@ -154,6 +153,13 @@ inline void log(FmtString...> fmt, const Args &... args) log_formatted_string(fmt.format_string(), fmt.format(args...)); } +void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str); +template +inline void log_header(RTLIL::Design *design, FmtString...> fmt, const Args &... args) +{ + log_formatted_header(design, fmt.format_string(), fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc index 146c21cce..ec5760cd9 100644 --- a/passes/opt/opt.cc +++ b/passes/opt/opt.cc @@ -196,7 +196,7 @@ struct OptPass : public Pass { design->sort(); design->check(); - log_header(design, fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n"); + log_header(design, "Finished fast OPT passes.%s\n", fast_mode ? "" : " (There is nothing left to do.)"); log_pop(); } } OptPass; From 25cba6181e533f41474e7e87f465b13616931651 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 03:14:15 +0000 Subject: [PATCH 06/17] Make log_warning()/log_warning_noprefix() use variadic templates. --- kernel/log.cc | 38 +++++--------------------------------- kernel/log.h | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index bef3efb99..18de1296a 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -256,10 +256,8 @@ void log_formatted_header(RTLIL::Design *design, std::string_view format, std::s log_files.pop_back(); } -static void logv_warning_with_prefix(const char *prefix, - const char *format, va_list ap) +void log_formatted_warning(std::string_view prefix, std::string message) { - std::string message = vstringf(format, ap); bool suppressed = false; for (auto &re : log_nowarn_regexes) @@ -268,7 +266,7 @@ static void logv_warning_with_prefix(const char *prefix, if (suppressed) { - log("Suppressed %s%s", prefix, message.c_str()); + log("Suppressed %s%s", prefix, message); } else { @@ -294,7 +292,7 @@ static void logv_warning_with_prefix(const char *prefix, if (log_warnings.count(message)) { - log("%s%s", prefix, message.c_str()); + log("%s%s", prefix, message); log_flush(); } else @@ -302,7 +300,7 @@ static void logv_warning_with_prefix(const char *prefix, if (log_errfile != NULL && !log_quiet_warnings) log_files.push_back(log_errfile); - log("%s%s", prefix, message.c_str()); + log("%s%s", prefix, message); log_flush(); if (log_errfile != NULL && !log_quiet_warnings) @@ -318,16 +316,6 @@ static void logv_warning_with_prefix(const char *prefix, } } -static void logv_warning(const char *format, va_list ap) -{ - logv_warning_with_prefix("Warning: ", format, ap); -} - -static void logv_warning_noprefix(const char *format, va_list ap) -{ - logv_warning_with_prefix("", format, ap); -} - void log_file_warning(const std::string &filename, int lineno, const char *format, ...) { @@ -335,7 +323,7 @@ void log_file_warning(const std::string &filename, int lineno, va_start(ap, format); std::string prefix = stringf("%s:%d: Warning: ", filename.c_str(), lineno); - logv_warning_with_prefix(prefix.c_str(), format, ap); + log_formatted_warning(prefix, vstringf(format, ap)); va_end(ap); } @@ -425,14 +413,6 @@ void log_file_error(const string &filename, int lineno, logv_file_error(filename, lineno, format, ap); } -void log_warning(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_warning(format, ap); - va_end(ap); -} - void log_experimental(const char *format, ...) { va_list ap; @@ -446,14 +426,6 @@ void log_experimental(const char *format, ...) } } -void log_warning_noprefix(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_warning_noprefix(format, ap); - va_end(ap); -} - void log_error(const char *format, ...) { va_list ap; diff --git a/kernel/log.h b/kernel/log.h index 55fa58a34..c8277f365 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -122,7 +122,6 @@ extern int log_debug_suppressed; [[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap); -void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); @@ -132,7 +131,6 @@ extern void (*log_verific_callback)(int msg_type, const char *message_id, const void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); -void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); [[noreturn]] void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); [[noreturn]] void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); [[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); @@ -160,6 +158,18 @@ inline void log_header(RTLIL::Design *design, FmtString...> f log_formatted_header(design, fmt.format_string(), fmt.format(args...)); } +void log_formatted_warning(std::string_view prefix, std::string str); +template +inline void log_warning(FmtString...> fmt, const Args &... args) +{ + log_formatted_warning("Warning: ", fmt.format(args...)); +} +template +inline void log_warning_noprefix(FmtString...> fmt, const Args &... args) +{ + log_formatted_warning("", fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); From 2a2c586e2c6ff1d1cca63aefc6df3ba337fa87a7 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 03:51:29 +0000 Subject: [PATCH 07/17] Make log_experimental() just take an std::string, since it doesn't need to be varargs. --- kernel/log.cc | 13 ++++--------- kernel/log.h | 5 ++--- kernel/register.cc | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 18de1296a..e5715425a 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -413,16 +413,11 @@ void log_file_error(const string &filename, int lineno, logv_file_error(filename, lineno, format, ap); } -void log_experimental(const char *format, ...) +void log_experimental(const std::string &str) { - va_list ap; - va_start(ap, format); - string s = vstringf(format, ap); - va_end(ap); - - if (log_experimentals_ignored.count(s) == 0 && log_experimentals.count(s) == 0) { - log_warning("Feature '%s' is experimental.\n", s.c_str()); - log_experimentals.insert(s); + if (log_experimentals_ignored.count(str) == 0 && log_experimentals.count(str) == 0) { + log_warning("Feature '%s' is experimental.\n", str); + log_experimentals.insert(str); } } diff --git a/kernel/log.h b/kernel/log.h index c8277f365..af30d9cfa 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -121,9 +121,6 @@ extern int log_debug_suppressed; [[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap); - -void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); - void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg); @@ -170,6 +167,8 @@ inline void log_warning_noprefix(FmtString...> fmt, const Arg log_formatted_warning("", fmt.format(args...)); } +void log_experimental(const std::string &str); + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); diff --git a/kernel/register.cc b/kernel/register.cc index 0b02a6aa5..c82620f40 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -265,7 +265,7 @@ void Pass::call(RTLIL::Design *design, std::vector args) log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str()); if (pass_register[args[0]]->experimental_flag) - log_experimental("%s", args[0].c_str()); + log_experimental(args[0]); size_t orig_sel_stack_pos = design->selection_stack.size(); auto state = pass_register[args[0]]->pre_execute(); From 9764fa5c41c39d704762c961fbba3db4008d41e2 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 04:01:02 +0000 Subject: [PATCH 08/17] Remove superfluous/wasteful .c_str()s in log_file_warning() filename parameter --- frontends/verilog/verilog_lexer.l | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 8280c0067..fbc9fca07 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -162,7 +162,7 @@ static bool is_hex_dig(char c, int *val, parser::location_type loc) *val = c - 'A' + 0xA; return true; } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c); + log_file_warning(*loc.begin.filename, loc.begin.line, "'%c' not a valid digit in hex escape sequence.\n", c); *val = 0; // not semantically valid in hex escape... return true; // ...but still processed as part of hex token } @@ -176,7 +176,7 @@ static bool is_oct_dig(char c, int *val, parser::location_type loc) *val = c - '0'; return true; } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c); + log_file_warning(*loc.begin.filename, loc.begin.line, "'%c' not a valid digit in octal escape sequence.\n", c); *val = 0; // not semantically valid in octal escape... return true; // ...but still processed as part of octal token } @@ -196,7 +196,7 @@ static parser::symbol_type process_str(char *str, int len, bool triple, parser:: if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) in++; if (!triple) - log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n"); + log_file_warning(*loc.begin.filename, loc.begin.line, "Multi-line string literals should be triple-quoted or escaped.\n"); *out++ = '\n'; break; case '\\': @@ -233,7 +233,7 @@ static parser::symbol_type process_str(char *str, int len, bool triple, parser:: } out++; } else - log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "ignoring invalid hex escape.\n"); + log_file_warning(*loc.begin.filename, loc.begin.line, "ignoring invalid hex escape.\n"); break; case '\\': *out++ = '\\'; @@ -256,7 +256,7 @@ static parser::symbol_type process_str(char *str, int len, bool triple, parser:: in++; if (in + 1 < str + len && is_oct_dig(in[1], &val, loc)) { if (*out >= 040) - log_file_warning(loc.begin.filename->c_str(), loc.begin.line, "octal escape exceeds \\377\n"); + log_file_warning(*loc.begin.filename, loc.begin.line, "octal escape exceeds \\377\n"); *out = *out * 010 + val; in++; } From ec5f62e6d4b3a4a207935ff6d94bbb9c0508cc75 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 04:03:43 +0000 Subject: [PATCH 09/17] Make log_file_warning() use variadic templates. --- kernel/log.cc | 11 +++-------- kernel/log.h | 10 ++++++++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index e5715425a..911afbe9d 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -316,15 +316,10 @@ void log_formatted_warning(std::string_view prefix, std::string message) } } -void log_file_warning(const std::string &filename, int lineno, - const char *format, ...) +void log_formatted_file_warning(std::string_view filename, int lineno, std::string str) { - va_list ap; - va_start(ap, format); - std::string prefix = stringf("%s:%d: Warning: ", - filename.c_str(), lineno); - log_formatted_warning(prefix, vstringf(format, ap)); - va_end(ap); + std::string prefix = stringf("%s:%d: Warning: ", filename, lineno); + log_formatted_warning(prefix, std::move(str)); } void log_file_info(const std::string &filename, int lineno, diff --git a/kernel/log.h b/kernel/log.h index af30d9cfa..694b238df 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -124,8 +124,6 @@ extern int log_debug_suppressed; void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg); -// Log with filename to report a problem in a source file. -void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); [[noreturn]] void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); @@ -169,6 +167,14 @@ inline void log_warning_noprefix(FmtString...> fmt, const Arg void log_experimental(const std::string &str); +// Log with filename to report a problem in a source file. +void log_formatted_file_warning(std::string_view filename, int lineno, std::string str); +template +void log_file_warning(std::string_view filename, int lineno, FmtString...> fmt, const Args &... args) +{ + log_formatted_file_warning(filename, lineno, fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); From ea2bb5b79aac400f473035e16094d664405477f2 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 04:15:30 +0000 Subject: [PATCH 10/17] Make log_file_info() use variadic templates. --- kernel/log.cc | 17 ++--------------- kernel/log.h | 11 +++++++++-- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 911afbe9d..27d58b45b 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -203,13 +203,6 @@ static void logv_string(std::string_view format, std::string str) { } } -static void logv(const char *format, va_list ap) -{ - if (log_make_debug && !ys_debug(1)) - return; - logv_string(format, vstringf(format, ap)); -} - void log_formatted_string(std::string_view format, std::string str) { if (log_make_debug && !ys_debug(1)) @@ -322,15 +315,9 @@ void log_formatted_file_warning(std::string_view filename, int lineno, std::stri log_formatted_warning(prefix, std::move(str)); } -void log_file_info(const std::string &filename, int lineno, - const char *format, ...) +void log_formatted_file_info(std::string_view filename, int lineno, std::string str) { - va_list ap; - va_start(ap, format); - std::string fmt = stringf("%s:%d: Info: %s", - filename.c_str(), lineno, format); - logv(fmt.c_str(), ap); - va_end(ap); + log("%s:%d: Info: %s", filename, lineno, str); } [[noreturn]] diff --git a/kernel/log.h b/kernel/log.h index 694b238df..c3cbbc04a 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -124,8 +124,6 @@ extern int log_debug_suppressed; void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg); -void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); - [[noreturn]] void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); [[noreturn]] void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); [[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); @@ -175,6 +173,15 @@ void log_file_warning(std::string_view filename, int lineno, FmtString +void log_file_info(std::string_view filename, int lineno, FmtString...> fmt, const Args &... args) +{ + if (log_make_debug && !ys_debug(1)) + return; + log_formatted_file_info(filename, lineno, fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); From 1b5373de0d4137c671c298cbf6e5530178a10ab8 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sat, 23 Aug 2025 18:21:33 +1200 Subject: [PATCH 11/17] Move log_assert_worker()'s call to log_error() into an out-of-line non-varags function --- kernel/log.cc | 5 +++++ kernel/log.h | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/log.cc b/kernel/log.cc index 27d58b45b..1e95ea5c5 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -410,6 +410,11 @@ void log_error(const char *format, ...) logv_error(format, ap); } +void log_assert_failure(const char *expr, const char *file, int line) +{ + log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); +} + void log_cmd_error(const char *format, ...) { va_list ap; diff --git a/kernel/log.h b/kernel/log.h index c3cbbc04a..40e1f02ff 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -252,9 +252,11 @@ void log_module(RTLIL::Module *module, std::string indent = ""); void log_cell(RTLIL::Cell *cell, std::string indent = ""); void log_wire(RTLIL::Wire *wire, std::string indent = ""); +[[noreturn]] +void log_assert_failure(const char *expr, const char *file, int line); #ifndef NDEBUG static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) { - if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); + if (!cond) log_assert_failure(expr, file, line); } # define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) #else From c3924d06169d4172a336c4ac39766f2bb969c6af Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sat, 23 Aug 2025 18:30:07 +1200 Subject: [PATCH 12/17] Move log_abort()'s call to log_error() into an out-of-line non-varargs function --- kernel/log.cc | 5 +++++ kernel/log.h | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/log.cc b/kernel/log.cc index 1e95ea5c5..6bab033de 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -415,6 +415,11 @@ void log_assert_failure(const char *expr, const char *file, int line) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); } +void log_abort_internal(const char *file, int line) +{ + log_error("Abort in %s:%d.\n", file, line); +} + void log_cmd_error(const char *format, ...) { va_list ap; diff --git a/kernel/log.h b/kernel/log.h index 40e1f02ff..653a73ba3 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -263,7 +263,9 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi # define log_assert(_assert_expr_) do { if (0) { (void)(_assert_expr_); } } while(0) #endif -#define log_abort() YOSYS_NAMESPACE_PREFIX log_error("Abort in %s:%d.\n", __FILE__, __LINE__) +[[noreturn]] +void log_abort_internal(const char *file, int line); +#define log_abort() YOSYS_NAMESPACE_PREFIX log_abort_internal(__FILE__, __LINE__) #define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) From 974455378b14e0aa71a7fc55517209bf1cdd0a6c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 04:28:32 +0000 Subject: [PATCH 13/17] Make log_error() use variadic templates. --- kernel/log.cc | 25 ++++++++----------------- kernel/log.h | 8 +++++++- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 6bab033de..55e721768 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -268,7 +268,7 @@ void log_formatted_warning(std::string_view prefix, std::string message) for (auto &re : log_werror_regexes) if (std::regex_search(message, re)) - log_error("%s", message.c_str()); + log_error("%s", message); bool warning_match = false; for (auto &[_, item] : log_expect_warning) @@ -321,8 +321,7 @@ void log_formatted_file_info(std::string_view filename, int lineno, std::string } [[noreturn]] -static void logv_error_with_prefix(const char *prefix, - const char *format, va_list ap) +static void log_error_with_prefix(std::string_view prefix, std::string str) { #ifdef EMSCRIPTEN auto backup_log_files = log_files; @@ -339,8 +338,8 @@ static void logv_error_with_prefix(const char *prefix, if (f == stdout) f = stderr; - log_last_error = vstringf(format, ap); - log("%s%s", prefix, log_last_error.c_str()); + log_last_error = std::move(str); + log("%s%s", prefix, log_last_error); log_flush(); log_make_debug = bak_log_make_debug; @@ -373,18 +372,12 @@ static void logv_error_with_prefix(const char *prefix, #endif } -[[noreturn]] -static void logv_error(const char *format, va_list ap) -{ - logv_error_with_prefix("ERROR: ", format, ap); -} - void logv_file_error(const string &filename, int lineno, const char *format, va_list ap) { std::string prefix = stringf("%s:%d: ERROR: ", filename.c_str(), lineno); - logv_error_with_prefix(prefix.c_str(), format, ap); + log_error_with_prefix(prefix, vstringf(format, ap)); } void log_file_error(const string &filename, int lineno, @@ -403,11 +396,9 @@ void log_experimental(const std::string &str) } } -void log_error(const char *format, ...) +void log_formatted_error(std::string str) { - va_list ap; - va_start(ap, format); - logv_error(format, ap); + log_error_with_prefix("ERROR: ", std::move(str)); } void log_assert_failure(const char *expr, const char *file, int line) @@ -445,7 +436,7 @@ void log_cmd_error(const char *format, ...) throw log_cmd_error_exception(); } - logv_error(format, ap); + log_formatted_error(vstringf(format, ap)); } void log_spacer() diff --git a/kernel/log.h b/kernel/log.h index 653a73ba3..396a24efa 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -124,7 +124,6 @@ extern int log_debug_suppressed; void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg); -[[noreturn]] void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); [[noreturn]] void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); [[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); @@ -182,6 +181,13 @@ void log_file_info(std::string_view filename, int lineno, FmtString +[[noreturn]] void log_error(FmtString...> fmt, const Args &... args) +{ + log_formatted_error(fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); From 243f5f52013a4dd7efcb44b564d916c2c094435c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 04:35:30 +0000 Subject: [PATCH 14/17] Make log_file_error() use variadic templates. --- kernel/log.cc | 18 +++++++----------- kernel/log.h | 8 +++++++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index 55e721768..ceebc3a86 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -372,20 +372,16 @@ static void log_error_with_prefix(std::string_view prefix, std::string str) #endif } +void log_formatted_file_error(std::string_view filename, int lineno, std::string str) +{ + std::string prefix = stringf("%s:%d: ERROR: ", filename, lineno); + log_error_with_prefix(prefix, str); +} + void logv_file_error(const string &filename, int lineno, const char *format, va_list ap) { - std::string prefix = stringf("%s:%d: ERROR: ", - filename.c_str(), lineno); - log_error_with_prefix(prefix, vstringf(format, ap)); -} - -void log_file_error(const string &filename, int lineno, - const char *format, ...) -{ - va_list ap; - va_start(ap, format); - logv_file_error(filename, lineno, format, ap); + log_formatted_file_error(filename, lineno, vstringf(format, ap)); } void log_experimental(const std::string &str) diff --git a/kernel/log.h b/kernel/log.h index 396a24efa..6cd97ce11 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -124,7 +124,6 @@ extern int log_debug_suppressed; void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg); -[[noreturn]] void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); [[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); #ifndef NDEBUG @@ -188,6 +187,13 @@ template log_formatted_error(fmt.format(args...)); } +[[noreturn]] void log_formatted_file_error(std::string_view filename, int lineno, std::string str); +template +[[noreturn]] void log_file_error(std::string_view filename, int lineno, FmtString...> fmt, const Args &... args) +{ + log_formatted_file_error(filename, lineno, fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); From a137d03c329393397ea42f342efa44002f5a6f9f Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 22 Jul 2025 04:42:43 +0000 Subject: [PATCH 15/17] Make log_cmd_error() use variadic templates. --- kernel/log.cc | 11 ++++------- kernel/log.h | 9 +++++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index ceebc3a86..0dd56a04f 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -407,13 +407,10 @@ void log_abort_internal(const char *file, int line) log_error("Abort in %s:%d.\n", file, line); } -void log_cmd_error(const char *format, ...) +void log_formatted_cmd_error(std::string str) { - va_list ap; - va_start(ap, format); - if (log_cmd_error_throw) { - log_last_error = vstringf(format, ap); + log_last_error = str; // Make sure the error message gets through any selective silencing // of log output @@ -423,7 +420,7 @@ void log_cmd_error(const char *format, ...) pop_errfile = true; } - log("ERROR: %s", log_last_error.c_str()); + log("ERROR: %s", log_last_error); log_flush(); if (pop_errfile) @@ -432,7 +429,7 @@ void log_cmd_error(const char *format, ...) throw log_cmd_error_exception(); } - log_formatted_error(vstringf(format, ap)); + log_formatted_error(str); } void log_spacer() diff --git a/kernel/log.h b/kernel/log.h index 6cd97ce11..5143524bf 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -124,8 +124,6 @@ extern int log_debug_suppressed; void set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg)); extern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg); -[[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); - #ifndef NDEBUG static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } #else @@ -194,6 +192,13 @@ template log_formatted_file_error(filename, lineno, fmt.format(args...)); } +[[noreturn]] void log_formatted_cmd_error(std::string str); +template +[[noreturn]] void log_cmd_error(FmtString...> fmt, const Args &... args) +{ + log_formatted_cmd_error(fmt.format(args...)); +} + static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { log("\n", log_debug_suppressed); From 75a97241fabeb898e0c801349350912cd03cf7d0 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 9 Sep 2025 10:23:15 +0200 Subject: [PATCH 16/17] Maintain logging ABI compatiblity with YosysHQ Verific Extensions The YosysHQ Verific Extensions are compiled separately using their own stripped-down version of the Yosys headers. To maintain ABI compatibility with older extension builds post C++-ification of Yosys's logging APIs, which are backwards compatible on the API but not ABI level, this commit adds ABI compatible versions of a subset of the old logging API used by the extensions. --- Makefile | 3 ++ kernel/log_compat.cc | 86 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 kernel/log_compat.cc diff --git a/Makefile b/Makefile index aedcd4d3b..fc8d361e6 100644 --- a/Makefile +++ b/Makefile @@ -633,6 +633,9 @@ $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h)) OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/io.o kernel/gzip.o OBJS += kernel/log_help.o +ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1) +OBJS += kernel/log_compat.o +endif OBJS += kernel/binding.o kernel/tclapi.o OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o kernel/sexpr.o OBJS += kernel/drivertools.o kernel/functional.o diff --git a/kernel/log_compat.cc b/kernel/log_compat.cc new file mode 100644 index 000000000..e93714873 --- /dev/null +++ b/kernel/log_compat.cc @@ -0,0 +1,86 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + + +#include "kernel/log.h" + +YOSYS_NAMESPACE_BEGIN + +// ABI compatibility for the YosysHQ Verific Extensions + +// The YosysHQ Verific Extensions are compiled separately using their own +// stripped-down version of the Yosys headers. To maintain ABI compatibility +// with older extension builds post C++-ification of Yosys's logging APIs, +// which are backwards compatible on the API but not ABI level, this file +// provides ABI compatible versions of a subset of the old logging API used by +// the extensions. + +void log_cmd_error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string formatted = vstringf(format, ap); + va_end(ap); + log_formatted_cmd_error(formatted); +} + +void log_warning(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string formatted = vstringf(format, ap); + va_end(ap); + log_formatted_warning("Warning: ", formatted); +} + +void log_warning_noprefix(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string formatted = vstringf(format, ap); + va_end(ap); + log_formatted_warning("", formatted); +} + +void log_error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string formatted = vstringf(format, ap); + va_end(ap); + log_formatted_error(formatted); +} + +static inline void log_formatted(std::string const &str) +{ + // We use this inline wrapper as the following becomes ambiguous as soon as + // the `log` function below is declared. + return log("%s", str); +} + +void log(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string formatted = vstringf(format, ap); + va_end(ap); + log_formatted(formatted); +} + +YOSYS_NAMESPACE_END From c2291c10a6f27142bc376d8aa62c66cf856fcab9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 00:22:30 +0000 Subject: [PATCH 17/17] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fc8d361e6..5da8066db 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.57+30 +YOSYS_VER := 0.57+52 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)