From 2e113f5eff87f083544d1820eb0521edf291eca5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 19 Aug 2026 15:59:46 +0200 Subject: [PATCH] log: create LogManager singleton and move implementation --- frontends/ast/ast.cc | 14 +- frontends/ast/genrtlil.cc | 12 +- frontends/ast/simplify.cc | 27 +- kernel/driver.cc | 54 ++-- kernel/log.cc | 184 ++++++------ kernel/log.h | 459 ++++++++++++++++++++++------- kernel/log_compat.cc | 8 +- kernel/register.cc | 18 +- kernel/satgen.cc | 4 +- kernel/tclapi.cc | 7 +- kernel/yosys.cc | 5 +- passes/cmds/logger.cc | 40 +-- passes/cmds/tee.cc | 28 +- passes/cmds/trace.cc | 18 +- passes/techmap/libparse.cc | 2 +- passes/techmap/techmap.cc | 2 +- pyosys/generator.py | 10 +- pyosys/wrappers_tpl.cc | 27 +- tests/unit/kernel/cellTypesTest.cc | 2 +- tests/unit/kernel/modindexTest.cc | 2 +- tests/unit/kernel/rtlilTest.cc | 2 +- tests/unit/kernel/threadingTest.cc | 2 +- tests/unit/techmap/libparseTest.cc | 2 +- 23 files changed, 561 insertions(+), 368 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 470cdcb3d..626ef014c 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -321,11 +321,11 @@ AstNode::~AstNode() void AstNode::dumpAst(FILE *f, std::string indent) const { if (f == NULL) { - for (auto &s : log_sinks) { - f = s->file_handle(); + logger().for_each_sink([&](LogSink &sink) { + FILE *f = sink.file_handle(); if (f) dumpAst(f, indent); - } + }); return; } @@ -428,11 +428,11 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const std::vector rem_children1, rem_children2; if (f == NULL) { - for (auto &s : log_sinks) { - f = s->file_handle(); + logger().for_each_sink([&](LogSink &sink) { + FILE *f = sink.file_handle(); if (f) dumpVlog(f, indent); - } + }); return; } @@ -1944,7 +1944,7 @@ void AstModule::loadconfig() const void AstNode::formatted_input_error(std::string str) const { - log_formatted_file_error(*location.begin.filename, location.begin.line, std::move(str)); + log_file_error(*location.begin.filename, location.begin.line, "%s", std::move(str)); } YOSYS_NAMESPACE_END diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 56b3dc5c7..dcaf1c99d 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1386,11 +1386,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun // everything should have been handled above -> print error if not. default: AstNode *current_scope_ast = current_ast_mod == nullptr ? current_ast : current_ast_mod; - for (auto &s : log_sinks) { - auto f = s->file_handle(); + logger().for_each_sink([&](LogSink &sink) { + FILE *f = sink.file_handle(); if (f) current_scope_ast->dumpAst(f, "verilog-ast> "); - } + }); input_error("Don't know how to detect sign and width for %s node!\n", type2str(type)); } @@ -2365,11 +2365,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // everything should have been handled above -> print error if not. default: - for (auto &s : log_sinks) { - auto f = s->file_handle(); + logger().for_each_sink([&](LogSink &sink) { + FILE *f = sink.file_handle(); if (f) current_ast_mod->dumpAst(f, "verilog-ast> "); - } + }); input_error("Don't know how to generate RTLIL code for %s node!\n", type2str(type)); } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index a8411b2ec..43a83a66f 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2791,10 +2791,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { - // for (auto &s : log_sinks) { - // auto f = s->file_handle(); - // if (f) - // dumpAst(f, "verilog-ast> "); + //logger().for_each_sink([&](LogSink &sink) { + // FILE *f = sink.file_handle(); + // if (f) + // dumpAst(f, "verilog-ast> "); + //}); input_error("Condition for generate if is not constant!\n"); } if (buf->asBool() != 0) { @@ -2830,10 +2831,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin auto buf = children[0]->clone(); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { - // for (auto &s : log_sinks) { - // auto f = s->file_handle(); - // if (f) - // dumpAst(f, "verilog-ast> "); + //logger().for_each_sink([&](LogSink &sink) { + // FILE *f = sink.file_handle(); + // if (f) + // dumpAst(f, "verilog-ast> "); + //}); input_error("Condition for generate case is not constant!\n"); } @@ -2866,10 +2868,11 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin buf->set_in_param_flag(true); while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { - // for (auto &s : log_sinks) { - // auto f = s->file_handle(); - // if (f) - // dumpAst(f, "verilog-ast> "); + //logger().for_each_sink([&](LogSink &sink) { + // FILE *f = sink.file_handle(); + // if (f) + // dumpAst(f, "verilog-ast> "); + //}); input_error("Expression in generate case is not constant!\n"); } diff --git a/kernel/driver.cc b/kernel/driver.cc index 04ae3f658..b98e7aa69 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -19,7 +19,6 @@ #include "kernel/yosys.h" #include "kernel/hashlib.h" -#include "libs/sha1/sha1.h" #define CXXOPTS_VECTOR_DELIMITER '\0' #include "libs/cxxopts/include/cxxopts.hpp" #include @@ -287,7 +286,7 @@ int main(int argc, char **argv) run_shell = false; } if (result.count("C")) run_tcl_shell = true; - if (result.count("g")) log_force_debug++; + if (result.count("g")) logger().force_debug_on(); if (result.count("m")) plugin_filenames = result["m"].as>(); if (result.count("f")) frontend_command = result["f"].as(); if (result.count("H")) { @@ -316,7 +315,7 @@ int main(int argc, char **argv) if (result.count(key)) { for (const auto& filename : result[key].as>()) { try { - log_sinks.push_back(std::make_unique(filename, key[0] == 'L', false)); + logger().add_sink(filename, key[0] == 'L', false); } catch (const std::runtime_error &e) { std::cerr << e.what(); exit(1); @@ -326,15 +325,15 @@ int main(int argc, char **argv) } if (result.count("q")) { mode_q = true; - if (log_errfile == stderr) log_quiet_warnings = true; + if (log_errfile == stderr) logger().set_quiet_warnings(true); log_errfile = stderr; } if (result.count("v")) { mode_v = true; log_errfile = stderr; - log_verbose_level = result["v"].as(); + logger().set_verbose_level(result["v"].as()); } - if (result.count("t")) log_time = true; + if (result.count("t")) logger().set_log_time(true); if (result.count("d")) timing_details = true; for (const auto& key : {"s", "c"}) { if (result.count(key)) { @@ -353,11 +352,11 @@ int main(int argc, char **argv) auto regexes = result[key].as>(); for (const auto& regex : regexes) { if (std::string(key) == "W") - log_warn_regexes.push_back(std::regex(regex)); + logger().add_warn(regex); if (std::string(key) == "w") - log_nowarn_regexes.push_back(std::regex(regex)); + logger().add_nowarn(regex); if (std::string(key) == "e") - log_werror_regexes.push_back(std::regex(regex)); + logger().add_werror(regex); } } } @@ -372,7 +371,7 @@ int main(int argc, char **argv) std::cerr << "Invalid number of tokens in -P ALL." << std::endl; exit(1); } - log_hdump_all = true; + logger().set_hdump_all(true); } else { if (!tokens.empty() && !tokens[0].empty() && tokens[0].back() == '.') tokens[0].pop_back(); @@ -382,14 +381,14 @@ int main(int argc, char **argv) std::cerr << "Invalid number of tokens in -P." << std::endl; exit(1); } - log_hdump[tokens[0]].insert(tokens[1]); + logger().add_hdump(tokens[0],tokens[1]); } } } if (result.count("E")) depsfile = result["E"].as(); if (result.count("x")) { - auto ignores = result["x"].as>(); - log_experimentals_ignored.insert(ignores.begin(), ignores.end()); + for (const auto &ignore : result["x"].as>()) + logger().add_experimental_ignore(ignore); } if (result.count("perffile")) perffile = result["perffile"].as(); if (result.count("infile")) { @@ -405,10 +404,10 @@ int main(int argc, char **argv) } if (log_errfile == NULL) { - log_sinks.push_back(std::make_unique()); - log_error_stderr = true; + logger().add_sink(); + logger().set_error_stderr(true); } else { - log_sinks.push_back(std::make_unique()); + logger().add_sink(); } if (print_banner) @@ -452,7 +451,7 @@ int main(int argc, char **argv) #endif if (print_stats) - log_hasher = new SHA1; + logger().start_hasher(); #if defined(__OpenBSD__) // save the executable origin for proc_self_dirname() @@ -596,28 +595,19 @@ int main(int argc, char **argv) fprintf(f, "\n"); } - if (log_expect_no_warnings && log_warnings_count_noexpect) - log_error("Unexpected warnings found: %d unique messages, %d total, %d expected\n", GetSize(log_warnings), - log_warnings_count, log_warnings_count - log_warnings_count_noexpect); + logger().report_unexpected_error(); if (print_stats) { - std::string hash = log_hasher->final().substr(0, 10); - delete log_hasher; - log_hasher = nullptr; - - log_time = false; + std::string hash = logger().finish_hasher(); + logger().set_log_time(false); yosys_xtrace = 0; log_spacer(); if (mode_v && !mode_q) - log_stderr_force = true; + logger().set_stderr_force(true); - if (log_warnings_count) - log("Warnings: %d unique messages, %d total\n", GetSize(log_warnings), log_warnings_count); - - if (!log_experimentals.empty()) - log("Warnings: %d experimental features used (not excluded with -x).\n", GetSize(log_experimentals)); + logger().report_warning_stats(); #ifdef _WIN32 log("End of script. Logfile hash: %s\n", hash); @@ -719,7 +709,7 @@ int main(int argc, char **argv) } } - log_check_expected(); + logger().check_expected(); yosys_atexit(); diff --git a/kernel/log.cc b/kernel/log.cc index f201ebabb..2f1d7a85e 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -38,40 +38,19 @@ YOSYS_NAMESPACE_BEGIN -std::vector> log_sinks; - -std::map> log_hdump; -std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -dict log_expect_log, log_expect_warning, log_expect_error; -dict log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error; -std::set log_warnings, log_experimentals, log_experimentals_ignored; -int log_warnings_count = 0; -int log_warnings_count_noexpect = 0; -bool log_expect_no_warnings = false; -bool log_hdump_all = false; -SHA1 *log_hasher = NULL; - -bool log_time = false; -bool log_error_stderr = false; -bool log_cmd_error_throw = false; -bool log_quiet_warnings = false; -int log_verbose_level; +LogManager &logger() +{ + static LogManager instance; + return instance; +} void (*log_error_atexit)() = NULL; 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) = NULL; -int log_make_debug = 0; -int log_force_debug = 0; -int log_debug_suppressed = 0; - -bool log_stderr_force = false; - -vector header_count; +// TODO: remove when log_id is removed vector log_id_cache; -static std::optional initial_time; static bool next_print_log = false; -static int log_newline_count = 0; FileLogSink::FileLogSink(const std::string &filename, bool line_buffered, bool append) : file(fopen(filename.c_str(), append ? "at" : "wt")) @@ -92,7 +71,7 @@ FileLogSink::~FileLogSink() void FileLogSink::log(const LogMessage &msg) { - fputs(msg.legacy_msg.c_str(), file); + fputs(msg.cached_msg.c_str(), file); } void FileLogSink::flush() @@ -102,8 +81,8 @@ void FileLogSink::flush() void ConsoleLogSink::log(const LogMessage &msg) { - FILE *file = (msg.severity == LogSeverity::LOG_ERROR && log_error_stderr) ? stderr : stdout; - fputs(msg.legacy_msg.c_str(), file); + FILE *file = (msg.severity == LogSeverity::LOG_ERROR && logger().get_error_stderr()) ? stderr : stdout; + fputs(msg.cached_msg.c_str(), file); } void ConsoleLogSink::flush() @@ -115,14 +94,13 @@ void ConsoleLogSink::flush() bool StderrLogSink::should_log(const LogMessage &msg) const { return msg.severity == LogSeverity::LOG_ERROR || - (msg.severity == LogSeverity::LOG_WARNING && !log_quiet_warnings) || - /* (msg.severity == LogSeverity::LOG_HEADER && int(header_count.size()) <= log_verbose_level) || */ - log_stderr_force; + (msg.severity == LogSeverity::LOG_WARNING && !logger().get_quiet_warnings()) || + logger().get_stderr_force(); } void StderrLogSink::log(const LogMessage &msg) { - fputs(msg.legacy_msg.c_str(), stderr); + fputs(msg.cached_msg.c_str(), stderr); } void StderrLogSink::flush() @@ -131,7 +109,7 @@ void StderrLogSink::flush() } ScratchPadLogSink::ScratchPadLogSink(std::string scratchpad) - : scratchpad(std::move(scratchpad)) + : scratchpad(std::move(scratchpad)) { } @@ -141,7 +119,7 @@ void ScratchPadLogSink::log(const LogMessage &msg) if (!design) return; - design->scratchpad[scratchpad].append(msg.legacy_msg); + design->scratchpad[scratchpad].append(msg.cached_msg); } LogMessage::LogMessage(LogSeverity severity, std::string_view prefix, std::string_view format, std::string_view message) : @@ -152,13 +130,11 @@ LogMessage::LogMessage(LogSeverity severity, std::string_view prefix, std::strin timestamp(std::chrono::steady_clock::now()) { std::string time_str; - if (log_time) + if (logger().get_log_time()) { - if (next_print_log || !initial_time) { + if (next_print_log) { next_print_log = false; - if (!initial_time) - initial_time = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::steady_clock::now() - *initial_time; + auto elapsed = std::chrono::steady_clock::now() - logger().get_initial_time(); auto us = std::chrono::duration_cast(elapsed); time_str += stringf("[%05d.%06d] ", int(us.count() / 1'000'000),int(us.count() % 1'000'000)); } @@ -172,7 +148,7 @@ LogMessage::LogMessage(LogSeverity severity, std::string_view prefix, std::strin if (format == "%s" && message.back() == '\n') next_print_log = true; } - legacy_msg = stringf("%s%s%s", time_str, prefix, message); + cached_msg = stringf("%s%s%s", time_str, prefix, message); } static void log_id_cache_clear() @@ -182,7 +158,7 @@ static void log_id_cache_clear() log_id_cache.clear(); } -static void logv_string(std::string_view prefix, std::string_view format, std::string str_in, LogSeverity severity) { +void LogManager::logv_string(std::string_view prefix, std::string_view format, std::string str_in, LogSeverity severity) { size_t remove_leading = 0; while (format.size() > 1 && format[0] == '\n') { logv_string(prefix, "\n", "\n", severity); @@ -208,10 +184,7 @@ static void logv_string(std::string_view prefix, std::string_view format, std::s log_hasher->update(str); auto msg = LogMessage(severity, prefix, format, str_in); - for (auto &sink : log_sinks) { - if (sink->should_log(msg)) - sink->log(msg); - } + log(msg); static std::string linebuffer; static bool log_warn_regex_recusion_guard = false; @@ -245,16 +218,16 @@ static void logv_string(std::string_view prefix, std::string_view format, std::s } } -void log_formatted_string(std::string_view prefix, std::string_view format, std::string str, LogSeverity severity) +void LogManager::log_formatted_string(std::string_view prefix, std::string_view format, std::string str, LogSeverity severity) { log_assert(!Multithreading::active()); - if (log_make_debug && !ys_debug(1)) + if (log_make_debug && !is_debug(1)) return; logv_string(prefix, format, std::move(str), severity); } -void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str) +void LogManager::log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str) { log_assert(!Multithreading::active()); @@ -273,24 +246,24 @@ void log_formatted_header(RTLIL::Design *design, std::string_view format, std::s log_formatted_string(stringf("%s. ", header_id), {}, {}, LogSeverity::LOG_HEADER); log_formatted_string({}, format, std::move(str), LogSeverity::LOG_HEADER); - log_flush(); + flush(); if (log_hdump_all) log_hdump[header_id].insert("yosys_dump_" + header_id + ".il"); if (log_hdump.count(header_id) && design != nullptr) for (auto &filename : log_hdump.at(header_id)) { - log("Dumping current design to '%s'.\n", filename); + YOSYS_NAMESPACE_PREFIX log("Dumping current design to '%s'.\n", filename); if (yosys_xtrace) IdString::xtrace_db_dump(); Pass::call(design, {"dump", "-o", filename}); if (yosys_xtrace) - log("#X# -- end of dump --\n"); + YOSYS_NAMESPACE_PREFIX log("#X# -- end of dump --\n"); } log_stderr_force = false; } -void log_formatted_warning(std::string_view prefix, std::string message) +void LogManager::log_formatted_warning(std::string_view prefix, std::string message) { log_assert(!Multithreading::active()); @@ -302,7 +275,7 @@ void log_formatted_warning(std::string_view prefix, std::string message) if (suppressed) { - log("Suppressed %s%s", prefix, message); + YOSYS_NAMESPACE_PREFIX log("Suppressed %s%s", prefix, message); } else { @@ -329,12 +302,12 @@ void log_formatted_warning(std::string_view prefix, std::string message) if (log_warnings.count(message)) { log_formatted_string(prefix, "%s", message, LogSeverity::LOG_INFO); - log_flush(); + flush(); } else { log_formatted_string(prefix, "%s", message, LogSeverity::LOG_WARNING); - log_flush(); + flush(); log_warnings.insert(message); } @@ -345,18 +318,18 @@ void log_formatted_warning(std::string_view prefix, std::string message) } } -void log_formatted_file_warning(std::string_view filename, int lineno, std::string str) +void LogManager::log_formatted_file_warning(std::string_view filename, int lineno, std::string str) { std::string prefix = stringf("%s:%d: Warning: ", filename, lineno); log_formatted_warning(prefix, std::move(str)); } -void log_formatted_file_info(std::string_view filename, int lineno, std::string str) +void LogManager::log_formatted_file_info(std::string_view filename, int lineno, std::string str) { - log("%s:%d: Info: %s", filename, lineno, str); + YOSYS_NAMESPACE_PREFIX log("%s:%d: Info: %s", filename, lineno, str); } -void log_suppressed() { +void LogManager::log_suppressed() { if (log_debug_suppressed && !log_make_debug) { constexpr const char* format = "\n"; logv_string({}, format, stringf(format, log_debug_suppressed),LogSeverity::LOG_INFO); @@ -365,14 +338,14 @@ void log_suppressed() { } [[noreturn]] -static void log_error_with_prefix(std::string_view prefix, std::string message) +void LogManager::log_error_with_prefix(std::string_view prefix, std::string message) { int bak_log_make_debug = log_make_debug; log_make_debug = 0; log_suppressed(); log_formatted_string(prefix, "%s", message, LogSeverity::LOG_ERROR); - log_flush(); + flush(); log_make_debug = bak_log_make_debug; @@ -384,7 +357,7 @@ static void log_error_with_prefix(std::string_view prefix, std::string message) if (std::regex_search(string(prefix) + message, item.pattern)) item.current_count++; - log_check_expected(); + check_expected(); if (log_error_atexit) log_error_atexit(); @@ -401,13 +374,13 @@ static void log_error_with_prefix(std::string_view prefix, std::string message) #endif } -void log_formatted_file_error(std::string_view filename, int lineno, std::string str) +void LogManager::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 log_experimental(const std::string &str) +void LogManager::log_experimental(const std::string &str) { if (log_experimentals_ignored.count(str) == 0 && log_experimentals.count(str) == 0) { log_warning("Feature '%s' is experimental.\n", str); @@ -415,7 +388,7 @@ void log_experimental(const std::string &str) } } -void log_formatted_error(std::string str) +void LogManager::log_formatted_error(std::string str) { log_error_with_prefix("ERROR: ", std::move(str)); } @@ -435,11 +408,11 @@ void log_yosys_abort_message(std::string_view file, int line, std::string_view f log_error("Abort in %s:%d (%s): %s\n", file, line, func, message); } -void log_formatted_cmd_error(std::string message) +void LogManager::log_formatted_cmd_error(std::string message) { if (log_cmd_error_throw) { log_formatted_string("ERROR: ", "%s", message, LogSeverity::LOG_ERROR); - log_flush(); + flush(); throw log_cmd_error_exception(); } @@ -447,22 +420,22 @@ void log_formatted_cmd_error(std::string message) log_formatted_error(message); } -void log_spacer() +void LogManager::log_spacer() { - if (log_newline_count < 2) log("\n"); - if (log_newline_count < 2) log("\n"); + if (log_newline_count < 2) YOSYS_NAMESPACE_PREFIX log("\n"); + if (log_newline_count < 2) YOSYS_NAMESPACE_PREFIX log("\n"); } -void log_push() +void LogManager::log_push() { header_count.push_back(0); } -void log_pop() +void LogManager::log_pop() { header_count.pop_back(); log_id_cache_clear(); - log_flush(); + flush(); } #if defined(YOSYS_ENABLE_DLOPEN) @@ -562,18 +535,12 @@ void log_backtrace(const char *prefix, int levels) void log_backtrace(const char*, int) { } #endif -void log_reset_stack() +void LogManager::log_reset_stack() { while (header_count.size() > 1) header_count.pop_back(); log_id_cache_clear(); - log_flush(); -} - -void log_flush() -{ - for (auto &sink : log_sinks) - sink->flush(); + flush(); } void log_dump_val_worker(RTLIL::IdString v) { @@ -631,7 +598,7 @@ void log_wire(RTLIL::Wire *wire, std::string indent) log("%s", buf.str()); } -void log_check_expected() +void LogManager::check_expected() { // copy out all of the expected logs so that they cannot be re-checked // or match against themselves @@ -668,7 +635,7 @@ void log_check_expected() auto check_err = [&](const std::string kind, std::string pattern, LogExpectedItem item) { if (item.current_count == item.expected_count) { log_warn_regexes.clear(); - log("Expected %s pattern '%s' found !!!\n", kind, pattern); + YOSYS_NAMESPACE_PREFIX log("Expected %s pattern '%s' found !!!\n", kind, pattern); yosys_shutdown(); #if defined(_MSC_VER) _exit(0); @@ -686,4 +653,51 @@ void log_check_expected() check_err("prefixed error", pattern, item); } +void LogManager::report_unexpected_error() +{ + if (log_expect_no_warnings && log_warnings_count_noexpect) + log_error("Unexpected warnings found: %d unique messages, %d total, %d expected\n", GetSize(log_warnings), + log_warnings_count, log_warnings_count - log_warnings_count_noexpect); +} + + +void LogManager::report_warning_stats() +{ + if (log_warnings_count) + YOSYS_NAMESPACE_PREFIX log("Warnings: %d unique messages, %d total\n", GetSize(log_warnings), log_warnings_count); + + if (!log_experimentals.empty()) + YOSYS_NAMESPACE_PREFIX log("Warnings: %d experimental features used (not excluded with -x).\n", GetSize(log_experimentals)); +} + +void LogManager::add_expect(std::string type, std::string pattern, int count) +{ + if (type == "error") + log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "prefix-error") + log_expect_prefix_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "warning") + log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "prefix-warning") + log_expect_prefix_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "log") + log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "prefix-log") + log_expect_prefix_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else log_abort(); +} +void LogManager::start_hasher() +{ + log_hasher = std::make_unique(); +} + +std::string LogManager::finish_hasher() +{ + if (!log_hasher) + return {}; + + std::string hash = log_hasher->final().substr(0, 10); + log_hasher.reset(); + return hash; +} YOSYS_NAMESPACE_END diff --git a/kernel/log.h b/kernel/log.h index e1dbc42fd..1e5f34dc4 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -102,237 +102,470 @@ struct LogMessage { std::string format; std::string message; std::chrono::steady_clock::time_point timestamp; - //TODO: remove - std::string legacy_msg; + + std::string cached_msg; }; class LogSink { public: - virtual ~LogSink() = default; + virtual ~LogSink() = default; - virtual bool should_log(const LogMessage &) const { return true; } - virtual void log(const LogMessage &msg) = 0; + virtual bool should_log(const LogMessage &) const { return true; } + virtual void log(const LogMessage &msg) = 0; virtual void flush() {} // TODO: Remove when AST/read_verilog removed virtual FILE *file_handle() { return nullptr; } }; -extern std::vector> log_sinks; - class LogSinkRef : public LogSink { public: - explicit LogSinkRef(LogSink *sink) : sink(sink) {} - bool should_log(const LogMessage &msg) const override { return sink->should_log(msg); } - void log(const LogMessage &msg) override { sink->log(msg); } - void flush() override { sink->flush(); } + explicit LogSinkRef(LogSink *sink) : sink(sink) {} + bool should_log(const LogMessage &msg) const override { return sink->should_log(msg); } + void log(const LogMessage &msg) override { sink->log(msg); } + void flush() override { sink->flush(); } FILE *file_handle() override { return sink->file_handle(); } private: - LogSink *sink; + LogSink *sink; }; class FileLogSink : public LogSink { public: - explicit FileLogSink(const std::string &filename, bool line_buffered, bool append); - ~FileLogSink() override; - void log(const LogMessage &msg) override; + explicit FileLogSink(const std::string &filename, bool line_buffered, bool append); + ~FileLogSink() override; + void log(const LogMessage &msg) override; void flush() override; FILE *file_handle() override { return file; } private: - FILE *file; + FILE *file; }; class ConsoleLogSink : public LogSink { public: - void log(const LogMessage &msg) override; - void flush() override; + void log(const LogMessage &msg) override; + void flush() override; FILE *file_handle() override { return stdout; }; }; class StderrLogSink : public LogSink { public: - bool should_log(const LogMessage &msg) const override; - void log(const LogMessage &msg) override; - void flush() override; + bool should_log(const LogMessage &msg) const override; + void log(const LogMessage &msg) override; + void flush() override; +}; + +class StreamLogSink : public LogSink +{ +public: + explicit StreamLogSink(std::ostream &stream) : stream(stream) {} + void log(const LogMessage &msg) override { stream << msg.message; } + void flush() override { stream.flush(); } + +private: + std::ostream &stream; }; class ScratchPadLogSink : public LogSink { public: - explicit ScratchPadLogSink(std::string scratchpad); - void log(const LogMessage &msg) override; + explicit ScratchPadLogSink(std::string scratchpad); + void log(const LogMessage &msg) override; - private: - std::string scratchpad; +private: + std::string scratchpad; }; -extern bool log_stderr_force; +class LogManager +{ +private: + struct LogExpectedItem + { + LogExpectedItem(const std::regex &pat, int expected) : + pattern(pat), expected_count(expected), current_count(0) {} + LogExpectedItem() : expected_count(0), current_count(0) {} -extern std::map> log_hdump; -extern std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -extern std::set log_warnings, log_experimentals, log_experimentals_ignored; -extern int log_warnings_count; -extern int log_warnings_count_noexpect; -extern bool log_expect_no_warnings; -extern bool log_hdump_all; -extern SHA1 *log_hasher; + std::regex pattern; + int expected_count; + int current_count; + }; + +public: + LogManager() = default; + + LogManager(const LogManager &) = delete; + LogManager &operator=(const LogManager &) = delete; + + LogManager(LogManager &&) = default; + LogManager &operator=(LogManager &&) = default; + + template + T &add_sink(Args&&... args) + { + auto sink = std::make_unique(std::forward(args)...); + T &ref = *sink; + log_sinks.push_back(std::move(sink)); + return ref; + } + + template + void for_each_sink(F &&func) + { + for (auto &sink : log_sinks) + func(*sink); + } + + void log(const LogMessage &msg) + { + for (auto &sink : log_sinks) { + if (sink->should_log(msg)) + sink->log(msg); + } + } + + bool empty() { return log_sinks.empty(); } + void clear() { log_sinks.clear(); } + void flush() { for (auto &sink : log_sinks) sink->flush(); } + + class Scoped + { + public: + explicit Scoped(LogManager &manager) : + manager(manager), + backup_log_sinks(std::move(manager.log_sinks)), + backup_log_verbose_level(manager.log_verbose_level) + { + manager.log_sinks.reserve(backup_log_sinks.size()); + + for (const auto &sink : backup_log_sinks) + manager.log_sinks.push_back(std::make_unique(sink.get())); + } + + ~Scoped() + { + manager.log_sinks.clear(); + manager.log_sinks = std::move(backup_log_sinks); + manager.log_verbose_level = backup_log_verbose_level; + } + + Scoped(const Scoped &) = delete; + Scoped &operator=(const Scoped &) = delete; + + private: + LogManager &manager; + std::vector> backup_log_sinks; + int backup_log_verbose_level; + }; + + Scoped scoped() + { + return Scoped(*this); + } + + class ScopedCmdErrorThrow + { + public: + explicit ScopedCmdErrorThrow(LogManager &manager) + : manager(manager), previous(manager.log_cmd_error_throw) + { + manager.log_cmd_error_throw = true; + } + + ~ScopedCmdErrorThrow() + { + manager.log_cmd_error_throw = previous; + } + + private: + LogManager &manager; + bool previous; + }; + + ScopedCmdErrorThrow scoped_cmd_error_throw() + { + return ScopedCmdErrorThrow(*this); + } + + class LogMakeDebugHdl + { + public: + explicit LogMakeDebugHdl(LogManager &manager, bool start_on = false) + : manager(manager) + { + if (start_on) + on(); + } + + ~LogMakeDebugHdl() + { + off(); + } + + void on() + { + if (status) + return; + status = true; + manager.log_make_debug++; + } + + void off_silent() + { + if (!status) + return; + status = false; + manager.log_make_debug--; + } + + void off() + { + off_silent(); + } + private: + LogManager &manager; + bool status = false; + }; + + LogMakeDebugHdl make_debug(bool start_on = false) + { + return LogMakeDebugHdl(*this, start_on); + } + + class ForceDebug + { + public: + explicit ForceDebug(LogManager &manager, bool start_on = false) + : manager(manager) + { + if (start_on) + on(); + } + + ~ForceDebug() + { + off(); + } + + void on() + { + if (active) + return; + + active = true; + manager.log_force_debug++; + } + + void off() + { + if (!active) + return; + + active = false; + manager.log_force_debug--; + } + private: + LogManager &manager; + bool active = false; + }; + + ForceDebug force_debug(bool start_on = false) + { + return ForceDebug(*this, start_on); + } + + void force_debug_on() { log_force_debug++; } + void force_debug_off() { if (log_force_debug > 0) log_force_debug--; } + void set_force_debug(bool enabled) { log_force_debug = enabled ? 1 : 0; } + + void report_unexpected_error(); + void report_warning_stats(); + + void add_experimental_ignore(std::string name) { log_experimentals_ignored.insert(name); } + void add_warn(std::string pattern) { log_warn_regexes.push_back(YS_REGEX_COMPILE(pattern)); } + void add_nowarn(std::string pattern) { log_nowarn_regexes.push_back(YS_REGEX_COMPILE(pattern)); } + void add_werror(std::string pattern) { log_werror_regexes.push_back(YS_REGEX_COMPILE(pattern)); } + void add_expect(std::string type, std::string pattern, int count); + + void set_verbose_level(int level) { log_verbose_level = level; } + void add_verbose_level(int level) { log_verbose_level += level; } + void set_expect_no_warnings(bool value) { log_expect_no_warnings = value; } + void set_log_time(bool value) { log_time = value; } + void set_error_stderr(bool value) { log_error_stderr = value; } + void set_cmd_error_throw(bool value) { log_cmd_error_throw = value; } + void set_quiet_warnings(bool value) { log_quiet_warnings = value; } + void set_stderr_force(bool value) { log_stderr_force = value; } + void set_hdump_all(bool value) { log_hdump_all = value; } + int get_verbose_level() const { return log_verbose_level; } + bool get_log_time() const { return log_time; } + bool get_error_stderr() const { return log_error_stderr; } + bool get_quiet_warnings() const { return log_quiet_warnings; } + bool get_stderr_force() const { return log_stderr_force; } + std::chrono::steady_clock::time_point get_initial_time() const { return initial_time; } + + void add_hdump(std::string name, std::string value) { log_hdump[name].insert(value); } + + void log_formatted_string(std::string_view prefix, std::string_view format, std::string str, LogSeverity severity); + void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str); + void log_formatted_warning(std::string_view prefix, std::string message); + void log_formatted_file_warning(std::string_view filename, int lineno, std::string str); + void log_formatted_file_info(std::string_view filename, int lineno, std::string str); + void log_suppressed(); + [[noreturn]] void log_formatted_file_error(std::string_view filename, int lineno, std::string str); + void log_experimental(const std::string &str); + [[noreturn]] void log_formatted_error(std::string str); + [[noreturn]] void log_formatted_cmd_error(std::string message); + void log_spacer(); + void log_push(); + void log_pop(); + + void log_reset_stack(); + + void check_expected(); + bool expects_error() { return (log_expect_error.size() + log_expect_prefix_error.size())>0; } +#ifndef NDEBUG + bool is_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } +#else + bool is_debug(int = 0) { return false; } +#endif + void start_hasher(); + std::string finish_hasher(); + +private: + void logv_string(std::string_view prefix, std::string_view format, std::string str_in, LogSeverity severity); + [[noreturn]] void log_error_with_prefix(std::string_view prefix, std::string message); + + std::chrono::steady_clock::time_point initial_time = std::chrono::steady_clock::now(); + std::vector> log_sinks; + int log_verbose_level = 0; + int log_newline_count = 0; + vector header_count; + int log_warnings_count = 0; + int log_warnings_count_noexpect = 0; + std::set log_warnings, log_experimentals, log_experimentals_ignored; + + std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; + dict log_expect_log, log_expect_warning, log_expect_error; + dict log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error; + bool log_expect_no_warnings = false; + bool log_time = false; + bool log_error_stderr = false; + bool log_cmd_error_throw = false; + bool log_quiet_warnings = false; + bool log_stderr_force = false; + std::map> log_hdump; + bool log_hdump_all = false; + + int log_debug_suppressed = 0; + int log_make_debug = 0; + int log_force_debug = 0; + std::unique_ptr log_hasher; +}; + +LogManager &logger(); -extern bool log_time; -extern bool log_error_stderr; -extern bool log_cmd_error_throw; -extern bool log_quiet_warnings; -extern int log_verbose_level; extern void (*log_error_atexit)(); -extern int log_make_debug; -extern int log_force_debug; -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); #ifndef NDEBUG -static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } +static inline bool ys_debug(int n = 0) { return logger().is_debug(n); } #else static inline bool ys_debug(int = 0) { return false; } #endif -void log_formatted_string(std::string_view prefix, std::string_view format, std::string str, LogSeverity severity); template inline void log(FmtString...> fmt, const Args &... args) { - log_formatted_string({}, fmt.format_string(), fmt.format(args...), LogSeverity::LOG_INFO); + logger().log_formatted_string({}, fmt.format_string(), fmt.format(args...), LogSeverity::LOG_INFO); } template inline void log_comment(FmtString...> fmt, const Args &... args) { - log_formatted_string({}, fmt.format_string(), fmt.format(args...), LogSeverity::LOG_COMMENT); + logger().log_formatted_string({}, fmt.format_string(), fmt.format(args...), LogSeverity::LOG_COMMENT); } template inline void log_debug(FmtString...> fmt, const Args &... args) { - if (!ys_debug(1)) - return; - log_formatted_string({}, fmt.format_string(), fmt.format(args...), LogSeverity::LOG_DEBUG); + if (!ys_debug(1)) + return; + logger().log_formatted_string({}, fmt.format_string(), fmt.format(args...), LogSeverity::LOG_DEBUG); } -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...)); + logger().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...)); + logger().log_formatted_warning("Warning: ", fmt.format(args...)); } -inline void log_formatted_warning_noprefix(std::string str) -{ - log_formatted_warning({}, str); -} template inline void log_warning_noprefix(FmtString...> fmt, const Args &... args) { - log_formatted_warning({}, fmt.format(args...)); + logger().log_formatted_warning({}, fmt.format(args...)); } -void log_experimental(const std::string &str); +inline void log_experimental(const std::string &str) +{ + logger().log_experimental(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...)); + logger().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, const Args &... args) { - log_formatted_file_info(filename, lineno, fmt.format(args...)); + logger().log_formatted_file_info(filename, lineno, fmt.format(args...)); } -[[noreturn]] void log_formatted_error(std::string str); template [[noreturn]] void log_error(FmtString...> fmt, const Args &... args) { - log_formatted_error(fmt.format(args...)); + logger().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...)); + logger().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...)); + logger().log_formatted_cmd_error(fmt.format(args...)); } -void log_suppressed(); +inline void log_suppressed() +{ + logger().log_suppressed(); +} -struct LogMakeDebugHdl { - bool status = false; - LogMakeDebugHdl(bool start_on = false) { - if (start_on) - on(); - } - ~LogMakeDebugHdl() { - off(); - } - void on() { - if (status) return; - status=true; - log_make_debug++; - } - void off_silent() { - if (!status) return; - status=false; - log_make_debug--; - } - void off() { - off_silent(); - } -}; +inline void log_spacer() { logger().log_spacer(); } +inline void log_push() { logger().log_push(); } +inline void log_pop() { logger().log_pop(); } -void log_spacer(); -void log_push(); -void log_pop(); +inline void log_reset_stack() { logger().log_reset_stack(); } +inline void log_flush() { logger().flush(); } void log_backtrace(const char *prefix, int levels); -void log_reset_stack(); -void log_flush(); -struct LogExpectedItem -{ - LogExpectedItem(const std::regex &pat, int expected) : - pattern(pat), expected_count(expected), current_count(0) {} - LogExpectedItem() : expected_count(0), current_count(0) {} - - std::regex pattern; - int expected_count; - int current_count; -}; - -extern dict log_expect_log, log_expect_warning, log_expect_error; -extern dict log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error; -void log_check_expected(); std::string log_signal(const RTLIL::SigSpec &sig, bool autoint = true); std::string log_const(const RTLIL::Const &value, bool autoint = true); diff --git a/kernel/log_compat.cc b/kernel/log_compat.cc index e512fc086..badfa5dfb 100644 --- a/kernel/log_compat.cc +++ b/kernel/log_compat.cc @@ -37,7 +37,7 @@ void log_cmd_error(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - log_formatted_cmd_error(formatted); + logger().log_formatted_cmd_error(formatted); } void log_warning(const char *format, ...) @@ -46,7 +46,7 @@ void log_warning(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - log_formatted_warning("Warning: ", formatted); + logger().log_formatted_warning("Warning: ", formatted); } void log_warning_noprefix(const char *format, ...) @@ -55,7 +55,7 @@ void log_warning_noprefix(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - log_formatted_warning("", formatted); + logger().log_formatted_warning("", formatted); } void log_error(const char *format, ...) @@ -64,7 +64,7 @@ void log_error(const char *format, ...) va_start(ap, format); std::string formatted = vstringf(format, ap); va_end(ap); - log_formatted_error(formatted); + logger().log_formatted_error(formatted); } static inline void log_formatted(std::string const &str) diff --git a/kernel/register.cc b/kernel/register.cc index 0f7448e8d..d9dbc34c9 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -753,16 +753,6 @@ static struct CellHelpMessages { SimHelper get(string name) { return cell_help[get_cell_name(name)]; } } cell_help_messages; -class HelpMsgLogSink : public LogSink -{ -public: - explicit HelpMsgLogSink(std::ostream *buf) : buf(buf) {} - void log(const LogMessage &msg) override { *buf << msg.message; } - void flush() override { buf->flush(); } -private: - std::ostream *buf; -}; - struct HelpPass : public Pass { HelpPass() : Pass("help", "display help messages") { } void help() override @@ -815,9 +805,11 @@ struct HelpPass : public Pass { // dump command help std::ostringstream buf; - log_sinks.push_back(std::make_unique(&buf)); - pass->help(); - log_sinks.pop_back(); + { + auto log_scope = logger().scoped(); + logger().add_sink(buf); + pass->help(); + } std::stringstream ss; ss << buf.str(); diff --git a/kernel/satgen.cc b/kernel/satgen.cc index 9fddc303e..437332613 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -1400,9 +1400,9 @@ void report_missing_model(bool warn_only, RTLIL::Cell* cell) s = stringf("No SAT model available for cell %s (%s).\n", cell, cell->type.unescape()); if (warn_only) { - log_formatted_warning_noprefix(s); + log_warning_noprefix("%s", s); } else { - log_formatted_error(s); + log_error("%s", s); } } diff --git a/kernel/tclapi.cc b/kernel/tclapi.cc index 70d587904..bcc65cc9e 100644 --- a/kernel/tclapi.cc +++ b/kernel/tclapi.cc @@ -100,10 +100,7 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a yosys_get_design()->scratchpad_unset("result.string"); bool in_repl = yosys_tcl_repl_active; - bool restore_log_cmd_error_throw = log_cmd_error_throw; - - log_cmd_error_throw = true; - + auto guard = logger().scoped_cmd_error_throw(); try { if (args.size() == 1) { Pass::call(yosys_get_design(), args[0]); @@ -120,14 +117,12 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a Tcl_SetResult(interp, (char *)"Yosys command produced an error", TCL_STATIC); yosys_tcl_repl_active = in_repl; - log_cmd_error_throw = restore_log_cmd_error_throw; return TCL_ERROR; } catch (...) { log_error("uncaught exception during Yosys command invoked from TCL\n"); } yosys_tcl_repl_active = in_repl; - log_cmd_error_throw = restore_log_cmd_error_throw; auto &scratchpad = yosys_get_design()->scratchpad; auto result = scratchpad.find("result.json"); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 02781399f..6fa7fd4fc 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -286,7 +286,7 @@ void yosys_shutdown() yosys_design = NULL; RTLIL::OwningIdString::collect_garbage(); - log_sinks.clear(); + logger().clear(); #ifdef YOSYS_ENABLE_TCL if (yosys_tcl_interp != NULL) { @@ -995,7 +995,7 @@ void shell(RTLIL::Design *design) static int recursion_counter = 0; recursion_counter++; - log_cmd_error_throw = true; + auto guard = logger().scoped_cmd_error_throw(); #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) rl_readline_name = (char*)"yosys"; @@ -1055,7 +1055,6 @@ void shell(RTLIL::Design *design) free(command); #endif recursion_counter--; - log_cmd_error_throw = false; } struct ShellPass : public Pass { diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 4d75b3872..2f71cdc8c 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -85,22 +85,22 @@ struct LoggerPass : public Pass { { if (args[argidx] == "-time") { - log_time = true; + logger().set_log_time(true); log("Enabled timestamp in logs.\n"); continue; } if (args[argidx] == "-notime") { - log_time = false; + logger().set_log_time(false); log("Disabled timestamp in logs.\n"); continue; } if (args[argidx] == "-stderr") { - log_error_stderr = true; + logger().set_error_stderr(true); log("Enabled loggint errors to stderr.\n"); continue; } if (args[argidx] == "-nostderr") { - log_error_stderr = false; + logger().set_error_stderr(false); log("Disabled loggint errors to stderr.\n"); continue; } @@ -109,7 +109,7 @@ struct LoggerPass : public Pass { if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); try { log("Added regex '%s' for warnings to warn list.\n", pattern); - log_warn_regexes.push_back(YS_REGEX_COMPILE(pattern)); + logger().add_warn(pattern); } catch (const std::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern); @@ -121,7 +121,7 @@ struct LoggerPass : public Pass { if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); try { log("Added regex '%s' for warnings to nowarn list.\n", pattern); - log_nowarn_regexes.push_back(YS_REGEX_COMPILE(pattern)); + logger().add_nowarn(pattern); } catch (const std::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern); @@ -133,7 +133,7 @@ struct LoggerPass : public Pass { if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); try { log("Added regex '%s' for warnings to werror list.\n", pattern); - log_werror_regexes.push_back(YS_REGEX_COMPILE(pattern)); + logger().add_werror(pattern); } catch (const std::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern); @@ -141,19 +141,19 @@ struct LoggerPass : public Pass { continue; } if (args[argidx] == "-debug") { - log_force_debug = 1; + logger().set_force_debug(true); log("Enabled debug log messages.\n"); continue; } if (args[argidx] == "-nodebug") { - log_force_debug = 0; + logger().set_force_debug(false); log("Disabled debug log messages.\n"); continue; } if (args[argidx] == "-experimental" && argidx+1 < args.size()) { std::string value = args[++argidx]; log("Added '%s' experimental ignore list.\n", value); - log_experimentals_ignored.insert(value); + logger().add_experimental_ignore(value); continue; } if (args[argidx] == "-expect" && argidx+3 < args.size()) { @@ -161,7 +161,7 @@ struct LoggerPass : public Pass { if (type!="error" && type!="warning" && type!="log" && type!="prefix-error" && type!="prefix-warning" && type!="prefix-log") log_cmd_error("Expect command require type to be 'log', 'warning' or 'error' !\n"); - if ((type=="error" || type=="prefix-error") && log_expect_error.size()>0) + if ((type=="error" || type=="prefix-error") && logger().expects_error()) log_cmd_error("Only single error message can be expected !\n"); std::string pattern = args[++argidx]; if (pattern.front() == '\"' && pattern.back() == '\"') pattern = pattern.substr(1, pattern.size() - 2); @@ -173,19 +173,7 @@ struct LoggerPass : public Pass { log("Added regex '%s' to expected %s messages list.\n", pattern.c_str(), type.c_str()); try { - if (type == "error") - log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); - else if (type == "prefix-error") - log_expect_prefix_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); - else if (type == "warning") - log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); - else if (type == "prefix-warning") - log_expect_prefix_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); - else if (type == "log") - log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); - else if (type == "prefix-log") - log_expect_prefix_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); - else log_abort(); + logger().add_expect(type, pattern, count); } catch (const std::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern); @@ -193,11 +181,11 @@ struct LoggerPass : public Pass { continue; } if (args[argidx] == "-expect-no-warnings") { - log_expect_no_warnings = true; + logger().set_expect_no_warnings(true); continue; } if (args[argidx] == "-check-expected") { - log_check_expected(); + logger().check_expected(); continue; } break; diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc index 474c35474..cf39fb0ac 100644 --- a/passes/cmds/tee.cc +++ b/passes/cmds/tee.cc @@ -58,17 +58,13 @@ struct TeePass : public Pass { } void execute(std::vector args, RTLIL::Design *design) override { - int backup_log_verbose_level = log_verbose_level; - auto backup_log_sinks = std::move(log_sinks); - log_sinks.reserve(backup_log_sinks.size()); - for (const auto &sink : backup_log_sinks) - log_sinks.push_back(std::make_unique(sink.get())); + auto log_scope = logger().scoped(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-q") { - log_sinks.clear(); + logger().clear(); continue; } if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) { @@ -76,7 +72,7 @@ struct TeePass : public Pass { auto path = args[++argidx]; rewrite_filename(path); try { - log_sinks.push_back(std::make_unique(path.c_str(), false, is_append)); + logger().add_sink(path.c_str(), false, is_append); } catch (const std::runtime_error &e) { std::cerr << e.what(); exit(1); @@ -86,28 +82,18 @@ struct TeePass : public Pass { if (args[argidx] == "-s" && argidx+1 < args.size()) { auto name = args[++argidx]; design->scratchpad[name] = ""; - log_sinks.push_back(std::make_unique(name)); + logger().add_sink(name); continue; } if (GetSize(args[argidx]) >= 2 && (args[argidx][0] == '-' || args[argidx][0] == '+') && args[argidx][1] >= '0' && args[argidx][1] <= '9') { - log_verbose_level += atoi(args[argidx].c_str()); + logger().add_verbose_level(atoi(args[argidx].c_str())); continue; } break; } - try { - std::vector new_args(args.begin() + argidx, args.end()); - Pass::call(design, new_args); - } catch (...) { - log_sinks.clear(); - log_sinks = std::move(backup_log_sinks); - throw; - } - - log_verbose_level = backup_log_verbose_level; - log_sinks.clear(); - log_sinks = std::move(backup_log_sinks); + std::vector new_args(args.begin() + argidx, args.end()); + Pass::call(design, new_args); } } TeePass; diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc index 37f7da89b..7b4e82ec3 100644 --- a/passes/cmds/trace.cc +++ b/passes/cmds/trace.cc @@ -144,27 +144,19 @@ struct DebugPass : public Pass { log_cmd_error("Cannot specify both -on and -off\n"); if (mode_on) { - log_force_debug++; + logger().force_debug_on(); return; } if (mode_off) { - if (log_force_debug > 0) - log_force_debug--; + logger().force_debug_off(); return; } - log_force_debug++; + auto force_debug = logger().force_debug(true); - try { - std::vector new_args(args.begin() + argidx, args.end()); - Pass::call(design, new_args); - } catch (...) { - log_force_debug--; - throw; - } - - log_force_debug--; + std::vector new_args(args.begin() + argidx, args.end()); + Pass::call(design, new_args); } } DebugPass; diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index fe3815cd1..509e5a0f1 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -39,7 +39,7 @@ void warn(std::string str) { #else #include "kernel/log.h" void warn(std::string str) { - Yosys::log_formatted_warning("", str); + Yosys::log_warning_noprefix("%s", str); } #endif diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 1cc95f2c4..a919b2f2a 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -419,7 +419,7 @@ struct TechmapWorker bool log_continue = false; bool did_something = false; - LogMakeDebugHdl mkdebug; + auto mkdebug = logger().make_debug(); SigMap sigmap(module); FfInitVals initvals(&sigmap, module); diff --git a/pyosys/generator.py b/pyosys/generator.py index 27ebea624..d402dcd89 100644 --- a/pyosys/generator.py +++ b/pyosys/generator.py @@ -119,21 +119,15 @@ global_denylist = frozenset( { # deprecated "builtin_ff_cell_types", - "logv_file_error", # no implementation "set_verific_logging", - # can't bridge to python cleanly - ## std::regex - "log_warn_regexes", - "log_nowarn_regexes", - "log_werror_regexes", ## function pointers "log_error_atexit", "log_verific_callback", # incomplete type "yosys_get_tcl_interp", - # unique ptr vector - "log_sinks", + # manually added later + "logger", } ) pyosys_headers = [ diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc index 406ef26c6..502dc655d 100644 --- a/pyosys/wrappers_tpl.cc +++ b/pyosys/wrappers_tpl.cc @@ -168,8 +168,8 @@ namespace pyosys { m.doc() = "python access to libyosys"; if (!yosys_already_setup()) { - log_sinks.push_back(std::make_unique()); - log_error_stderr = true; + logger().add_sink(); + logger().set_error_stderr(true); yosys_setup(); // Cleanup @@ -179,17 +179,24 @@ namespace pyosys { } // Logging Methods - m.def("log_header", [](Design *d, std::string s) { log_formatted_header(d, "%s", s); }); - m.def("log", [](std::string s) { log_formatted_string({}, "%s", s, LogSeverity::LOG_INFO); }); - m.def("log_file_info", [](std::string_view file, int line, std::string s) { log_formatted_file_info(file, line, s); }); - m.def("log_warning", [](std::string s) { log_formatted_warning("Warning: ", s); }); - m.def("log_warning_noprefix", [](std::string s) { log_formatted_warning("", s); }); - m.def("log_file_warning", [](std::string_view file, int line, std::string s) { log_formatted_file_warning(file, line, s); }); - m.def("log_error", [](std::string s) { log_formatted_error(s); }); - m.def("log_file_error", [](std::string_view file, int line, std::string s) { log_formatted_file_error(file, line, s); }); + m.def("log_header", [](Design *d, std::string s) { logger().log_formatted_header(d, "%s", s); }); + m.def("log", [](std::string s) { logger().log_formatted_string({}, "%s", s, LogSeverity::LOG_INFO); }); + m.def("log_file_info", [](std::string_view file, int line, std::string s) { logger().log_formatted_file_info(file, line, s); }); + m.def("log_warning", [](std::string s) { logger().log_formatted_warning("Warning: ", s); }); + m.def("log_warning_noprefix", [](std::string s) { logger().log_formatted_warning("", s); }); + m.def("log_file_warning", [](std::string_view file, int line, std::string s) { logger().log_formatted_file_warning(file, line, s); }); + m.def("log_error", [](std::string s) { logger().log_formatted_error(s); }); + m.def("log_file_error", [](std::string_view file, int line, std::string s) { logger().log_formatted_file_error(file, line, s); }); // Namespace to host global objects auto global_variables = py::class_(m, "Globals"); + global_variables.def_property_readonly_static( + "logger", + [](const pyosys::Globals &) -> Yosys::LogManager & { + return logger(); + }, + pybind11::return_value_policy::reference + ); // Trampoline Classes py::class_>(m, "Pass") diff --git a/tests/unit/kernel/cellTypesTest.cc b/tests/unit/kernel/cellTypesTest.cc index 0b49713ce..4515a11a6 100644 --- a/tests/unit/kernel/cellTypesTest.cc +++ b/tests/unit/kernel/cellTypesTest.cc @@ -11,7 +11,7 @@ YOSYS_NAMESPACE_BEGIN TEST(CellTypesTest, basic) { yosys_setup(); - if (log_sinks.empty()) log_sinks.push_back(std::make_unique()); + if (logger().empty()) logger().add_sink(); CellTypes older; NewCellTypes newer; older.setup(nullptr); diff --git a/tests/unit/kernel/modindexTest.cc b/tests/unit/kernel/modindexTest.cc index 9868d0a36..868aa9796 100644 --- a/tests/unit/kernel/modindexTest.cc +++ b/tests/unit/kernel/modindexTest.cc @@ -28,7 +28,7 @@ TEST(ModIndexSwapTest, has) TEST(ModIndexDeleteTest, has) { - if (log_sinks.empty()) log_sinks.push_back(std::make_unique()); + if (logger().empty()) logger().add_sink(); Design* d = new Design; Module* m = d->addModule("$m"); Wire* w = m->addWire("$w"); diff --git a/tests/unit/kernel/rtlilTest.cc b/tests/unit/kernel/rtlilTest.cc index f53d12a48..9ecccc5a1 100644 --- a/tests/unit/kernel/rtlilTest.cc +++ b/tests/unit/kernel/rtlilTest.cc @@ -19,7 +19,7 @@ namespace RTLIL { class KernelRtlilTest : public testing::Test { protected: KernelRtlilTest() { - if (log_sinks.empty()) log_sinks.push_back(std::make_unique()); + if (logger().empty()) logger().add_sink(); } virtual void SetUp() override { IdString::ensure_prepopulated(); diff --git a/tests/unit/kernel/threadingTest.cc b/tests/unit/kernel/threadingTest.cc index ec69ff343..3ce827666 100644 --- a/tests/unit/kernel/threadingTest.cc +++ b/tests/unit/kernel/threadingTest.cc @@ -7,7 +7,7 @@ YOSYS_NAMESPACE_BEGIN class ThreadingTest : public testing::Test { protected: ThreadingTest() { - if (log_sinks.empty()) log_sinks.push_back(std::make_unique()); + if (logger().empty()) logger().add_sink(); } }; diff --git a/tests/unit/techmap/libparseTest.cc b/tests/unit/techmap/libparseTest.cc index 249b0ad9a..71d67aa49 100644 --- a/tests/unit/techmap/libparseTest.cc +++ b/tests/unit/techmap/libparseTest.cc @@ -8,7 +8,7 @@ namespace RTLIL { class TechmapLibparseTest : public testing::Test { protected: TechmapLibparseTest() { - if (log_sinks.empty()) log_sinks.push_back(std::make_unique()); + if (logger().empty()) logger().add_sink(); } void checkAll(std::initializer_list expressions, std::string expected) { for (const auto& e : expressions) {