diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e2d7a2cd9..de74f595f 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -124,7 +124,7 @@ static bool is_hex_dig(char c, int *val) *val = c - 'A' + 0xA; return true; } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in hex escape sequence.\n", c); + log_file_warning(AST::current_filename, frontend_verilog_yyget_lineno(), "'%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 } @@ -138,7 +138,7 @@ static bool is_oct_dig(char c, int *val) *val = c - '0'; return true; } else if (c == 'x' || c == 'X' || c == 'z' || c == 'Z' || c == '?') { - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "'%c' not a valid digit in octal escape sequence.\n", c); + log_file_warning(AST::current_filename, frontend_verilog_yyget_lineno(), "'%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 } @@ -158,7 +158,7 @@ static std::string *process_str(char *str, int len, bool triple) if (in + 1 < str + len && (in[1] ^ *in) == ('\n' ^ '\r')) in++; if (!triple) - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n"); + log_file_warning(AST::current_filename, frontend_verilog_yyget_lineno(), "Multi-line string literals should be triple-quoted or escaped.\n"); *out++ = '\n'; break; case '\\': @@ -195,7 +195,7 @@ static std::string *process_str(char *str, int len, bool triple) } out++; } else - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n"); + log_file_warning(AST::current_filename, frontend_verilog_yyget_lineno(), "ignoring invalid hex escape.\n"); break; case '\\': *out++ = '\\'; @@ -218,7 +218,7 @@ static std::string *process_str(char *str, int len, bool triple) in++; if (in + 1 < str + len && is_oct_dig(in[1], &val)) { if (*out >= 040) - log_file_warning(AST::current_filename.c_str(), frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n"); + log_file_warning(AST::current_filename, frontend_verilog_yyget_lineno(), "octal escape exceeds \\377\n"); *out = *out * 010 + val; in++; } diff --git a/kernel/io.h b/kernel/io.h index ea2499e43..a05ed731e 100644 --- a/kernel/io.h +++ b/kernel/io.h @@ -423,6 +423,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 679a55562..8ba20d64d 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -101,17 +101,16 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) } #endif -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; @@ -144,13 +143,13 @@ 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) @@ -203,7 +202,14 @@ void logv(const char *format, va_list ap) } } -void logv_header(RTLIL::Design *design, const char *format, va_list 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)); +} + +void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str) { bool pop_errfile = false; @@ -222,7 +228,7 @@ 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) @@ -242,10 +248,8 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap) 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) @@ -254,7 +258,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 { @@ -263,7 +267,7 @@ static void logv_warning_with_prefix(const char *prefix, 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) @@ -274,7 +278,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 @@ -282,7 +286,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) @@ -298,41 +302,19 @@ static void logv_warning_with_prefix(const char *prefix, } } -void logv_warning(const char *format, va_list ap) +void log_formatted_file_warning(std::string_view filename, int lineno, std::string str) { - logv_warning_with_prefix("Warning: ", format, ap); + std::string prefix = stringf("%s:%d: Warning: ", filename, lineno); + log_formatted_warning(prefix, std::move(str)); } -void logv_warning_noprefix(const char *format, va_list ap) +void log_formatted_file_info(std::string_view filename, int lineno, std::string str) { - logv_warning_with_prefix("", format, ap); -} - -void log_file_warning(const std::string &filename, int lineno, - const char *format, ...) -{ - va_list ap; - va_start(ap, format); - std::string prefix = stringf("%s:%d: Warning: ", - filename.c_str(), lineno); - logv_warning_with_prefix(prefix.c_str(), format, ap); - va_end(ap); -} - -void log_file_info(const std::string &filename, int lineno, - const char *format, ...) -{ - 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]] -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; @@ -349,8 +331,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; @@ -379,86 +361,35 @@ static void logv_error_with_prefix(const char *prefix, #endif } -void logv_error(const char *format, va_list ap) +void log_formatted_file_error(std::string_view filename, int lineno, std::string str) { - logv_error_with_prefix("ERROR: ", format, ap); + 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); - logv_error_with_prefix(prefix.c_str(), format, ap); + log_formatted_file_error(filename, lineno, vstringf(format, ap)); } -void log_file_error(const string &filename, int lineno, - const char *format, ...) +void log_experimental(const std::string &str) { - va_list ap; - va_start(ap, format); - 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; - va_start(ap, format); - logv_header(design, format, ap); - va_end(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; - 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); } } -void log_warning_noprefix(const char *format, ...) +void log_formatted_error(std::string str) { - va_list ap; - va_start(ap, format); - logv_warning_noprefix(format, ap); - va_end(ap); + log_error_with_prefix("ERROR: ", std::move(str)); } -void log_error(const char *format, ...) +void log_formatted_cmd_error(std::string str) { - va_list ap; - va_start(ap, format); - logv_error(format, ap); -} - -void log_cmd_error(const char *format, ...) -{ - 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 @@ -468,7 +399,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) @@ -477,7 +408,7 @@ void log_cmd_error(const char *format, ...) throw log_cmd_error_exception(); } - logv_error(format, ap); + log_formatted_error(str); } void log_spacer() diff --git a/kernel/log.h b/kernel/log.h index e26ef072c..6bfc0b421 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -119,30 +119,11 @@ 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)); -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)); - 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)); - -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)); - #ifndef NDEBUG static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } #else @@ -150,6 +131,74 @@ 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, Args... args) +{ + if (log_make_debug && !ys_debug(1)) + return; + 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, Args... args) +{ + 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, Args... args) +{ + log_formatted_warning("Warning: ", fmt.format(args...)); +} +template +inline void log_warning_noprefix(FmtString...> fmt, Args... args) +{ + log_formatted_warning("", fmt.format(args...)); +} + +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, Args... args) +{ + log_formatted_file_warning(filename, lineno, fmt.format(args...)); +} + +void log_formatted_file_info(std::string_view filename, int lineno, std::string str); +template +void log_file_info(std::string_view filename, int lineno, FmtString...> fmt, Args... args) +{ + if (log_make_debug && !ys_debug(1)) + return; + log_formatted_file_info(filename, lineno, fmt.format(args...)); +} + +[[noreturn]] void log_formatted_error(std::string str); +template +[[noreturn]] void log_error(FmtString...> fmt, Args... args) +{ + 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, Args... args) +{ + 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, 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); @@ -350,8 +399,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); } @@ -373,7 +436,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); @@ -387,7 +450,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; } @@ -399,7 +462,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/kernel/register.cc b/kernel/register.cc index af1823b5b..38b8c8dc8 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -253,7 +253,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(); diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc index 3b82ac48c..9f57eb455 100644 --- a/passes/cmds/logcmd.cc +++ b/passes/cmds/logcmd.cc @@ -97,13 +97,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 6b93621f1..bb12b237b 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -474,7 +474,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 59974a1e6..ff5f04fed 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -202,7 +202,7 @@ struct EquivSimpleWorker log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses()); if (!ez->solve(ez_context)) { - log(verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n"); + log("%s", verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n"); equiv_cell->setPort(ID::B, equiv_cell->getPort(ID::A)); ez->assume(ez->NOT(ez_context)); return true; 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; diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 0c2143fc9..215aac21b 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -639,10 +639,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 409ac7865..e68620260 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -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.c_str(), new_cell->type.c_str())]++; + stats[stringf("%s cells to %s cells", cell_type.c_str(), new_cell->type.c_str())]++; } 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 a34eafc2f..ded0398c7 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -522,7 +522,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();