Merge pull request #2188 from antmicro/missing-operators
[yosys.git] / kernel / log.h
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21
22 #ifndef LOG_H
23 #define LOG_H
24
25 #include <time.h>
26
27 // In GCC 4.8 std::regex is not working correctlty, in order to make features
28 // using regular expressions to work replacement regex library is used
29 #if defined(__GNUC__) && !defined( __clang__) && ( __GNUC__ == 4 && __GNUC_MINOR__ <= 8)
30 #include <boost/xpressive/xpressive.hpp>
31 #define YS_REGEX_TYPE boost::xpressive::sregex
32 #define YS_REGEX_MATCH_TYPE boost::xpressive::smatch
33 #define YS_REGEX_NS boost::xpressive
34 #define YS_REGEX_COMPILE(param) boost::xpressive::sregex::compile(param, \
35 boost::xpressive::regex_constants::nosubs | \
36 boost::xpressive::regex_constants::optimize)
37 #define YS_REGEX_COMPILE_WITH_SUBS(param) boost::xpressive::sregex::compile(param, \
38 boost::xpressive::regex_constants::optimize)
39 # else
40 #include <regex>
41 #define YS_REGEX_TYPE std::regex
42 #define YS_REGEX_MATCH_TYPE std::smatch
43 #define YS_REGEX_NS std
44 #define YS_REGEX_COMPILE(param) std::regex(param, \
45 std::regex_constants::nosubs | \
46 std::regex_constants::optimize | \
47 std::regex_constants::egrep)
48 #define YS_REGEX_COMPILE_WITH_SUBS(param) std::regex(param, \
49 std::regex_constants::optimize | \
50 std::regex_constants::egrep)
51 #endif
52
53 #if defined(_WIN32)
54 # include <intrin.h>
55 #else
56 # include <sys/time.h>
57 # include <sys/resource.h>
58 # if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
59 # include <signal.h>
60 # endif
61 #endif
62
63 #if defined(_MSC_VER)
64 // At least this is not in MSVC++ 2013.
65 # define __PRETTY_FUNCTION__ __FUNCTION__
66 #endif
67
68 // from libs/sha1/sha1.h
69 class SHA1;
70
71 YOSYS_NAMESPACE_BEGIN
72
73 #define S__LINE__sub2(x) #x
74 #define S__LINE__sub1(x) S__LINE__sub2(x)
75 #define S__LINE__ S__LINE__sub1(__LINE__)
76
77 // YS_DEBUGTRAP is a macro that is functionally equivalent to a breakpoint
78 // if the platform provides such functionality, and does nothing otherwise.
79 // If no debugger is attached, it starts a just-in-time debugger if available,
80 // and crashes the process otherwise.
81 #if defined(_WIN32)
82 # define YS_DEBUGTRAP __debugbreak()
83 #else
84 # ifndef __has_builtin
85 // __has_builtin is a GCC/Clang extension; on a different compiler (or old enough GCC/Clang)
86 // that does not have it, using __has_builtin(...) is a syntax error.
87 # define __has_builtin(x) 0
88 # endif
89 # if __has_builtin(__builtin_debugtrap)
90 # define YS_DEBUGTRAP __builtin_debugtrap()
91 # elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
92 # define YS_DEBUGTRAP raise(SIGTRAP)
93 # else
94 # define YS_DEBUGTRAP do {} while(0)
95 # endif
96 #endif
97
98 // YS_DEBUGTRAP_IF_DEBUGGING is a macro that is functionally equivalent to a breakpoint
99 // if a debugger is attached, and does nothing otherwise.
100 #if defined(_WIN32)
101 # define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0)
102 # elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
103 // There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However,
104 // debuggers will stop when SIGTRAP is raised, even if the action is set to ignore.
105 # define YS_DEBUGTRAP_IF_DEBUGGING do { \
106 auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \
107 } while(0)
108 #else
109 # define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0)
110 #endif
111
112 struct log_cmd_error_exception { };
113
114 extern std::vector<FILE*> log_files;
115 extern std::vector<std::ostream*> log_streams;
116 extern std::map<std::string, std::set<std::string>> log_hdump;
117 extern std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
118 extern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
119 extern int log_warnings_count;
120 extern int log_warnings_count_noexpect;
121 extern bool log_expect_no_warnings;
122 extern bool log_hdump_all;
123 extern FILE *log_errfile;
124 extern SHA1 *log_hasher;
125
126 extern bool log_time;
127 extern bool log_error_stderr;
128 extern bool log_cmd_error_throw;
129 extern bool log_quiet_warnings;
130 extern int log_verbose_level;
131 extern string log_last_error;
132 extern void (*log_error_atexit)();
133
134 extern int log_make_debug;
135 extern int log_force_debug;
136 extern int log_debug_suppressed;
137
138 void logv(const char *format, va_list ap);
139 void logv_header(RTLIL::Design *design, const char *format, va_list ap);
140 void logv_warning(const char *format, va_list ap);
141 void logv_warning_noprefix(const char *format, va_list ap);
142 [[noreturn]] void logv_error(const char *format, va_list ap);
143
144 void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
145 void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));
146 void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
147 void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
148
149 // Log with filename to report a problem in a source file.
150 void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
151 void log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
152
153 void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
154 [[noreturn]] void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
155 [[noreturn]] void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
156 [[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
157
158 #ifndef NDEBUG
159 static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }
160 #else
161 static inline bool ys_debug(int = 0) { return false; }
162 #endif
163 # define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
164
165 static inline void log_suppressed() {
166 if (log_debug_suppressed && !log_make_debug) {
167 log("<suppressed ~%d debug messages>\n", log_debug_suppressed);
168 log_debug_suppressed = 0;
169 }
170 }
171
172 struct LogMakeDebugHdl {
173 bool status = false;
174 LogMakeDebugHdl(bool start_on = false) {
175 if (start_on)
176 on();
177 }
178 ~LogMakeDebugHdl() {
179 off();
180 }
181 void on() {
182 if (status) return;
183 status=true;
184 log_make_debug++;
185 }
186 void off_silent() {
187 if (!status) return;
188 status=false;
189 log_make_debug--;
190 }
191 void off() {
192 off_silent();
193 }
194 };
195
196 void log_spacer();
197 void log_push();
198 void log_pop();
199
200 void log_backtrace(const char *prefix, int levels);
201 void log_reset_stack();
202 void log_flush();
203
204 struct LogExpectedItem
205 {
206 LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) :
207 pattern(pat), expected_count(expected), current_count(0) {}
208 LogExpectedItem() : expected_count(0), current_count(0) {}
209
210 YS_REGEX_TYPE pattern;
211 int expected_count;
212 int current_count;
213 };
214
215 extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
216 void log_check_expected();
217
218 const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
219 const char *log_const(const RTLIL::Const &value, bool autoint = true);
220 const char *log_id(RTLIL::IdString id);
221
222 template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
223 if (nullstr && obj == nullptr)
224 return nullstr;
225 return log_id(obj->name);
226 }
227
228 void log_module(RTLIL::Module *module, std::string indent = "");
229 void log_cell(RTLIL::Cell *cell, std::string indent = "");
230 void log_wire(RTLIL::Wire *wire, std::string indent = "");
231
232 #ifndef NDEBUG
233 static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {
234 if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line);
235 }
236 # define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)
237 #else
238 # define log_assert(_assert_expr_) do { if (0) { (void)(_assert_expr_); } } while(0)
239 #endif
240
241 #define log_abort() YOSYS_NAMESPACE_PREFIX log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
242 #define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
243
244
245 // ---------------------------------------------------
246 // This is the magic behind the code coverage counters
247 // ---------------------------------------------------
248
249 #if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
250
251 #define cover(_id) do { \
252 static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
253 __d.counter++; \
254 } while (0)
255
256 struct CoverData {
257 const char *file, *func, *id;
258 int line, counter;
259 } YS_ATTRIBUTE(packed);
260
261 // this two symbols are created by the linker for the "yosys_cover_list" ELF section
262 extern "C" struct CoverData __start_yosys_cover_list[];
263 extern "C" struct CoverData __stop_yosys_cover_list[];
264
265 extern dict<std::string, std::pair<std::string, int>> extra_coverage_data;
266
267 void cover_extra(std::string parent, std::string id, bool increment = true);
268 dict<std::string, std::pair<std::string, int>> get_coverage_data();
269
270 #define cover_list(_id, ...) do { cover(_id); \
271 std::string r = cover_list_worker(_id, __VA_ARGS__); \
272 log_assert(r.empty()); \
273 } while (0)
274
275 static inline std::string cover_list_worker(std::string, std::string last) {
276 return last;
277 }
278
279 template<typename... T>
280 std::string cover_list_worker(std::string prefix, std::string first, T... rest) {
281 std::string selected = cover_list_worker(prefix, rest...);
282 cover_extra(prefix, prefix + "." + first, first == selected);
283 return first == selected ? "" : selected;
284 }
285
286 #else
287 # define cover(...) do { } while (0)
288 # define cover_list(...) do { } while (0)
289 #endif
290
291
292 // ------------------------------------------------------------
293 // everything below this line are utilities for troubleshooting
294 // ------------------------------------------------------------
295
296 // simple timer for performance measurements
297 // toggle the '#if 1' to get a baseline for the performance penalty added by the measurement
298 struct PerformanceTimer
299 {
300 #if 1
301 int64_t total_ns;
302
303 PerformanceTimer() {
304 total_ns = 0;
305 }
306
307 static int64_t query() {
308 # ifdef _WIN32
309 return 0;
310 # elif defined(RUSAGE_SELF)
311 struct rusage rusage;
312 int64_t t = 0;
313 for (int who : {RUSAGE_SELF, RUSAGE_CHILDREN}) {
314 if (getrusage(who, &rusage) == -1) {
315 log_cmd_error("getrusage failed!\n");
316 log_abort();
317 }
318 t += 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;
319 t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
320 }
321 return t;
322 # else
323 # error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)."
324 # endif
325 }
326
327 void reset() {
328 total_ns = 0;
329 }
330
331 void begin() {
332 total_ns -= query();
333 }
334
335 void end() {
336 total_ns += query();
337 }
338
339 float sec() const {
340 return total_ns * 1e-9f;
341 }
342 #else
343 static int64_t query() { return 0; }
344 void reset() { }
345 void begin() { }
346 void end() { }
347 float sec() const { return 0; }
348 #endif
349 };
350
351 // simple API for quickly dumping values when debugging
352
353 static inline void log_dump_val_worker(short v) { log("%d", v); }
354 static inline void log_dump_val_worker(unsigned short v) { log("%u", v); }
355 static inline void log_dump_val_worker(int v) { log("%d", v); }
356 static inline void log_dump_val_worker(unsigned int v) { log("%u", v); }
357 static inline void log_dump_val_worker(long int v) { log("%ld", v); }
358 static inline void log_dump_val_worker(unsigned long int v) { log("%lu", v); }
359 #ifndef _WIN32
360 static inline void log_dump_val_worker(long long int v) { log("%lld", v); }
361 static inline void log_dump_val_worker(unsigned long long int v) { log("%lld", v); }
362 #endif
363 static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
364 static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
365 static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); }
366 static inline void log_dump_val_worker(double v) { log("%f", v); }
367 static inline void log_dump_val_worker(char *v) { log("%s", v); }
368 static inline void log_dump_val_worker(const char *v) { log("%s", v); }
369 static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); }
370 static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); }
371 static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }
372 void log_dump_val_worker(RTLIL::IdString v);
373 void log_dump_val_worker(RTLIL::SigSpec v);
374 void log_dump_val_worker(RTLIL::State v);
375
376 template<typename K, typename T, typename OPS>
377 static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
378 log("{");
379 bool first = true;
380 for (auto &it : v) {
381 log(first ? " " : ", ");
382 log_dump_val_worker(it.first);
383 log(": ");
384 log_dump_val_worker(it.second);
385 first = false;
386 }
387 log(" }");
388 }
389
390 template<typename K, typename OPS>
391 static inline void log_dump_val_worker(pool<K, OPS> &v) {
392 log("{");
393 bool first = true;
394 for (auto &it : v) {
395 log(first ? " " : ", ");
396 log_dump_val_worker(it);
397 first = false;
398 }
399 log(" }");
400 }
401
402 template<typename T>
403 static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); }
404
405 template<typename T, typename ... Args>
406 void log_dump_args_worker(const char *p, T first, Args ... args)
407 {
408 int next_p_state = 0;
409 const char *next_p = p;
410 while (*next_p && (next_p_state != 0 || *next_p != ',')) {
411 if (*next_p == '"')
412 do {
413 next_p++;
414 while (*next_p == '\\' && *(next_p + 1))
415 next_p += 2;
416 } while (*next_p && *next_p != '"');
417 if (*next_p == '\'') {
418 next_p++;
419 if (*next_p == '\\')
420 next_p++;
421 if (*next_p)
422 next_p++;
423 }
424 if (*next_p == '(' || *next_p == '[' || *next_p == '{')
425 next_p_state++;
426 if ((*next_p == ')' || *next_p == ']' || *next_p == '}') && next_p_state > 0)
427 next_p_state--;
428 next_p++;
429 }
430 log("\n\t%.*s => ", int(next_p - p), p);
431 if (*next_p == ',')
432 next_p++;
433 while (*next_p == ' ' || *next_p == '\t' || *next_p == '\r' || *next_p == '\n')
434 next_p++;
435 log_dump_val_worker(first);
436 log_dump_args_worker(next_p, args ...);
437 }
438
439 #define log_dump(...) do { \
440 log("DEBUG DUMP IN %s AT %s:%d:", __PRETTY_FUNCTION__, __FILE__, __LINE__); \
441 log_dump_args_worker(#__VA_ARGS__, __VA_ARGS__); \
442 log("\n"); \
443 } while (0)
444
445 YOSYS_NAMESPACE_END
446
447 #endif