X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=kernel%2Flog.h;h=ea14028dd1fa5d504c115bfd8028cc6dc2103a63;hb=3c0f3504c60198a52148f023498acbd5472db632;hp=5478482ac4f0952874d16464fa458a4b9748103c;hpb=c2804a68c2d4d198e72be7a8c0164093c1e62fce;p=yosys.git diff --git a/kernel/log.h b/kernel/log.h index 5478482ac..ea14028dd 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * 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 @@ -24,9 +24,29 @@ #include -// In GCC 4.8 std::regex is not working correctlty, in order to make features -// using regular expressions to work replacement regex library is used -#if defined(__GNUC__) && !defined( __clang__) && ( __GNUC__ == 4 && __GNUC_MINOR__ <= 8) +// In the libstdc++ headers that are provided by GCC 4.8, std::regex is not +// working correctly. In order to make features using regular expressions +// work, a replacement regex library is used. Just checking for GCC version +// is not enough though, because at least on RHEL7/CentOS7 even when compiling +// with Clang instead of GCC, the GCC 4.8 headers are still used for std::regex. +// We have to check the version of the libstdc++ headers specifically, not the +// compiler version. GCC headers of libstdc++ before version 3.4 define +// __GLIBCPP__, later versions define __GLIBCXX__. GCC 7 and newer additionaly +// define _GLIBCXX_RELEASE with a version number. +// Include limits std C++ header, so we get the version macros defined: +#if defined(__cplusplus) +# include +#endif +// Check if libstdc++ is from GCC +#if defined(__GLIBCPP__) || defined(__GLIBCXX__) +// Check if version could be 4.8 or lower (this also matches for some 4.9 and +// 5.0 releases). See: +// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning +# if !defined(_GLIBCXX_RELEASE) && (defined(__GLIBCPP__) || __GLIBCXX__ <= 20150623) +# define YS_HAS_BAD_STD_REGEX +# endif +#endif +#if defined(YS_HAS_BAD_STD_REGEX) #include #define YS_REGEX_TYPE boost::xpressive::sregex #define YS_REGEX_MATCH_TYPE boost::xpressive::smatch @@ -50,9 +70,14 @@ std::regex_constants::egrep) #endif -#ifndef _WIN32 +#if defined(_WIN32) +# include +#else # include # include +# if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# include +# endif #endif #if defined(_MSC_VER) @@ -69,6 +94,41 @@ YOSYS_NAMESPACE_BEGIN #define S__LINE__sub1(x) S__LINE__sub2(x) #define S__LINE__ S__LINE__sub1(__LINE__) +// YS_DEBUGTRAP is a macro that is functionally equivalent to a breakpoint +// if the platform provides such functionality, and does nothing otherwise. +// If no debugger is attached, it starts a just-in-time debugger if available, +// and crashes the process otherwise. +#if defined(_WIN32) +# define YS_DEBUGTRAP __debugbreak() +#else +# ifndef __has_builtin +// __has_builtin is a GCC/Clang extension; on a different compiler (or old enough GCC/Clang) +// that does not have it, using __has_builtin(...) is a syntax error. +# define __has_builtin(x) 0 +# endif +# if __has_builtin(__builtin_debugtrap) +# define YS_DEBUGTRAP __builtin_debugtrap() +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# define YS_DEBUGTRAP raise(SIGTRAP) +# else +# define YS_DEBUGTRAP do {} while(0) +# endif +#endif + +// YS_DEBUGTRAP_IF_DEBUGGING is a macro that is functionally equivalent to a breakpoint +// if a debugger is attached, and does nothing otherwise. +#if defined(_WIN32) +# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0) +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However, +// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore. +# define YS_DEBUGTRAP_IF_DEBUGGING do { \ + auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ + } while(0) +#else +# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) +#endif + struct log_cmd_error_exception { }; extern std::vector log_files; @@ -99,7 +159,7 @@ 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); -YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn); +[[noreturn]] void logv_error(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)); @@ -111,17 +171,16 @@ void log_file_warning(const std::string &filename, int lineno, const char *forma 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)); -YS_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); -YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); +[[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; } -# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) #else static inline bool ys_debug(int = 0) { return false; } -# define log_debug(_fmt, ...) do { } while (0) #endif +# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) static inline void log_suppressed() { if (log_debug_suppressed && !log_make_debug) { @@ -164,19 +223,16 @@ void log_flush(); struct LogExpectedItem { - LogExpectedItem(std::string pattern, int expected) : - expected_count(expected), - current_count(0), - pattern(pattern) - { - } + LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) : + pattern(pat), expected_count(expected), current_count(0) {} + LogExpectedItem() : expected_count(0), current_count(0) {} + YS_REGEX_TYPE pattern; int expected_count; int current_count; - std::string pattern; }; -extern std::vector> log_expect_log, log_expect_warning, log_expect_error; +extern dict log_expect_log, log_expect_warning, log_expect_error; void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); @@ -199,7 +255,7 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi } # define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) #else -# define log_assert(_assert_expr_) +# 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__) @@ -271,19 +327,17 @@ struct PerformanceTimer static int64_t query() { # ifdef _WIN32 return 0; -# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) - struct timespec ts; - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); - return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec; # elif defined(RUSAGE_SELF) struct rusage rusage; - int64_t t; - if (getrusage(RUSAGE_SELF, &rusage) == -1) { - log_cmd_error("getrusage failed!\n"); - log_abort(); + int64_t t = 0; + for (int who : {RUSAGE_SELF, RUSAGE_CHILDREN}) { + if (getrusage(who, &rusage) == -1) { + log_cmd_error("getrusage failed!\n"); + log_abort(); + } + t += 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL; + t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; } - t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL; - t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; return t; # else # error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)." @@ -334,7 +388,7 @@ static inline void log_dump_val_worker(char *v) { log("%s", v); } static inline void log_dump_val_worker(const char *v) { log("%s", v); } static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); } static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); } -static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { log_assert(*p == 0); } +static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); } void log_dump_val_worker(RTLIL::IdString v); void log_dump_val_worker(RTLIL::SigSpec v); void log_dump_val_worker(RTLIL::State v);