1/* @title: Assertions */
2#include <compiler.h>
3#include <console/crash.h>
4#include <console/panic.h>
5
6#define _kassert_pick(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, NAME, ...) \
7 NAME
8
9#define _kassert_dispatch(default, name, prefix, ...) \
10 _kassert_pick(__VA_ARGS__, name##_n, name##_n, name##_n, name##_n, \
11 name##_n, name##_n, name##_n, name##_n, name##_n, name##_2, \
12 name##_1)(default, prefix, __VA_ARGS__)
13
14#define _kassert_as_code(x) __comptime_as_type(enum crash_code, x)
15#define _kassert_msg(x) "Assertion \"" #x "\" failed"
16
17#define _kassert_debug_off_dispatch(first, ...) ({ first; })
18
19#define _kassert_eval(prefix, x, msg_stmt) \
20 __builtin_choose_expr( \
21 __builtin_types_compatible_p(__comptime_decay(x), void), ({ (x); }), \
22 ({ \
23 __comptime_decay(x) _kassert_res = (x); \
24 if (unlikely(!(_kassert_res))) { \
25 msg_stmt; \
26 __builtin_unreachable(); \
27 } \
28 _kassert_res; \
29 }))
30/*
31 * kassert(x)
32 */
33#define _kassert_1(default, prefix, x) \
34 _kassert_eval(prefix, x, \
35 assert_impl_assertion(CRASH_CODE_TO_PAYLOAD(default), \
36 __FILE__, __LINE__, __func__, prefix, \
37 _kassert_msg(x), NULL))
38
39/*
40 * kassert(x, CODE)
41 * kassert(x, "msg")
42 */
43#define _kassert_2(default, prefix, x, a) \
44 __builtin_choose_expr( \
45 __comptime_is_str(a), \
46 _kassert_eval(prefix, x, \
47 assert_impl_assertion(CRASH_CODE_TO_PAYLOAD(default), \
48 __FILE__, __LINE__, __func__, \
49 prefix, _kassert_msg(x), \
50 __comptime_as_str(a))), \
51 _kassert_eval( \
52 prefix, x, \
53 assert_impl_assertion(CRASH_CODE_TO_PAYLOAD(_kassert_as_code(a)), \
54 __FILE__, __LINE__, __func__, prefix, \
55 _kassert_msg(x), NULL)))
56
57/*
58 * kassert(x, "msg %d", 12)
59 * kassert(x, CODE, "msg %d", 12)
60 */
61#define _kassert_n(default, prefix, x, a, b, ...) \
62 __builtin_choose_expr( \
63 __comptime_is_str(a), /* a is format, b is first vararg */ \
64 _kassert_eval(prefix, x, \
65 assert_impl_assertion( \
66 CRASH_CODE_TO_PAYLOAD(default), __FILE__, __LINE__, \
67 __func__, prefix, _kassert_msg(x), \
68 __comptime_as_str(a), b, \
69 ##__VA_ARGS__)), /* a is code, b is format */ \
70 _kassert_eval( \
71 prefix, x, \
72 assert_impl_assertion(CRASH_CODE_TO_PAYLOAD(_kassert_as_code(a)), \
73 __FILE__, __LINE__, __func__, prefix, \
74 _kassert_msg(x), __comptime_as_str(b), \
75 ##__VA_ARGS__)))
76
77#define _kassert_fail(c, prefix, ...) \
78 assert_impl_default(CRASH_CODE_TO_PAYLOAD(c), __FILE__, __LINE__, \
79 __func__, prefix __VA_ARGS__)
80
81#define kassert_with_default(default, ...) \
82 _kassert_dispatch(default, "", __VA_ARGS__)
83#define kassert(...) \
84 _kassert_dispatch(CRASH_CODE_GENERIC, _kassert, "", __VA_ARGS__)
85
86#define kassert_with(x, payload, fmt, ...) \
87 __builtin_choose_expr( \
88 __builtin_types_compatible_p(__comptime_decay(x), void), ({ (x); }), \
89 ({ \
90 __comptime_decay(x) _kassert_res = (x); \
91 if (unlikely(!(_kassert_res))) { \
92 assert_impl_default(payload, __FILE__, __LINE__, __func__, \
93 _kassert_msg(x) ": " fmt, ##__VA_ARGS__); \
94 __builtin_unreachable(); \
95 } \
96 _kassert_res; \
97 }))
98
99#define unreachable(...) \
100 _kassert_fail(CRASH_CODE_GENERIC, "unreachable! ", ##__VA_ARGS__)
101#define unimplemented(...) \
102 _kassert_fail(CRASH_CODE_GENERIC, "unimplemented! ", ##__VA_ARGS__)
103#define todo(...) _kassert_fail(CRASH_CODE_GENERIC, "TODO: ", ##__VA_ARGS__)
104
105#ifdef DEBUG_ASSERT
106
107#define kassert_debug_with_default(default, ...) \
108 _kassert_dispatch(default, _kassert, "DEBUG ", __VA_ARGS__)
109
110#define kassert_debug(...) \
111 _kassert_dispatch(CRASH_CODE_GENERIC, _kassert, "DEBUG ", __VA_ARGS__)
112
113#define unreachable_debug(...) \
114 _kassert_fail(CRASH_CODE_GENERIC, "DEBUG unreachable! ", ##__VA_ARGS__)
115#define unimplemented_debug(...) \
116 _kassert_fail(CRASH_CODE_GENERIC, "DEBUG unimplemented! ", ##__VA_ARGS__)
117#define todo_debug(...) \
118 _kassert_fail(CRASH_CODE_GENERIC, "DEBUG TODO: ", ##__VA_ARGS__)
119
120#else
121
122#define kassert_debug(...) _kassert_debug_off_dispatch(__VA_ARGS__)
123#define unreachable_debug(...) _kassert_debug_off_dispatch(__VA_ARGS__)
124#define unimplemented_debug(...) _kassert_debug_off_dispatch(__VA_ARGS__)
125#define todo_debug(...) _kassert_debug_off_dispatch(__VA_ARGS__)
126
127#endif
128