1 | // Copyright (c) 2016 Google Inc. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #ifndef SOURCE_OPT_LOG_H_ |
16 | #define SOURCE_OPT_LOG_H_ |
17 | |
18 | #include <cstdio> |
19 | #include <cstdlib> |
20 | #include <utility> |
21 | #include <vector> |
22 | |
23 | #include "spirv-tools/libspirv.hpp" |
24 | |
25 | // Asserts the given condition is true. Otherwise, sends a message to the |
26 | // consumer and exits the problem with failure code. Accepts the following |
27 | // formats: |
28 | // |
29 | // SPIRV_ASSERT(<message-consumer>, <condition-expression>); |
30 | // SPIRV_ASSERT(<message-consumer>, <condition-expression>, <message>); |
31 | // SPIRV_ASSERT(<message-consumer>, <condition-expression>, |
32 | // <message-format>, <variable-arguments>); |
33 | // |
34 | // In the third format, the number of <variable-arguments> cannot exceed (5 - |
35 | // 2). If more arguments are wanted, grow PP_ARG_N and PP_NARGS in the below. |
36 | #if !defined(NDEBUG) |
37 | #define SPIRV_ASSERT(consumer, ...) SPIRV_ASSERT_IMPL(consumer, __VA_ARGS__) |
38 | #else |
39 | #define SPIRV_ASSERT(consumer, ...) |
40 | #endif |
41 | |
42 | // Logs a debug message to the consumer. Accepts the following formats: |
43 | // |
44 | // SPIRV_DEBUG(<message-consumer>, <message>); |
45 | // SPIRV_DEBUG(<message-consumer>, <message-format>, <variable-arguments>); |
46 | // |
47 | // In the second format, the number of <variable-arguments> cannot exceed (5 - |
48 | // 1). If more arguments are wanted, grow PP_ARG_N and PP_NARGS in the below. |
49 | #if !defined(NDEBUG) && defined(SPIRV_LOG_DEBUG) |
50 | #define SPIRV_DEBUG(consumer, ...) SPIRV_DEBUG_IMPL(consumer, __VA_ARGS__) |
51 | #else |
52 | #define SPIRV_DEBUG(consumer, ...) |
53 | #endif |
54 | |
55 | // Logs an error message to the consumer saying the given feature is |
56 | // unimplemented. |
57 | #define SPIRV_UNIMPLEMENTED(consumer, feature) \ |
58 | do { \ |
59 | spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ |
60 | {static_cast<size_t>(__LINE__), 0, 0}, \ |
61 | "unimplemented: " feature); \ |
62 | } while (0) |
63 | |
64 | // Logs an error message to the consumer saying the code location |
65 | // should be unreachable. |
66 | #define SPIRV_UNREACHABLE(consumer) \ |
67 | do { \ |
68 | spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ |
69 | {static_cast<size_t>(__LINE__), 0, 0}, "unreachable"); \ |
70 | } while (0) |
71 | |
72 | // Helper macros for concatenating arguments. |
73 | #define SPIRV_CONCATENATE(a, b) SPIRV_CONCATENATE_(a, b) |
74 | #define SPIRV_CONCATENATE_(a, b) a##b |
75 | |
76 | // Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler. |
77 | #define PP_EXPAND(x) x |
78 | |
79 | namespace spvtools { |
80 | |
81 | // Calls the given |consumer| by supplying the |message|. The |message| is from |
82 | // the given |source| and |location| and of the given severity |level|. |
83 | inline void Log(const MessageConsumer& consumer, spv_message_level_t level, |
84 | const char* source, const spv_position_t& position, |
85 | const char* message) { |
86 | if (consumer != nullptr) consumer(level, source, position, message); |
87 | } |
88 | |
89 | // Calls the given |consumer| by supplying the message composed according to the |
90 | // given |format|. The |message| is from the given |source| and |location| and |
91 | // of the given severity |level|. |
92 | template <typename... Args> |
93 | void Logf(const MessageConsumer& consumer, spv_message_level_t level, |
94 | const char* source, const spv_position_t& position, |
95 | const char* format, Args&&... args) { |
96 | #if defined(_MSC_VER) && _MSC_VER < 1900 |
97 | // Sadly, snprintf() is not supported until Visual Studio 2015! |
98 | #define snprintf _snprintf |
99 | #endif |
100 | |
101 | enum { kInitBufferSize = 256 }; |
102 | |
103 | char message[kInitBufferSize]; |
104 | const int size = |
105 | snprintf(message, kInitBufferSize, format, std::forward<Args>(args)...); |
106 | |
107 | if (size >= 0 && size < kInitBufferSize) { |
108 | Log(consumer, level, source, position, message); |
109 | return; |
110 | } |
111 | |
112 | if (size >= 0) { |
113 | // The initial buffer is insufficient. Allocate a buffer of a larger size, |
114 | // and write to it instead. Force the size to be unsigned to avoid a |
115 | // warning in GCC 7.1. |
116 | std::vector<char> longer_message(size + 1u); |
117 | snprintf(longer_message.data(), longer_message.size(), format, |
118 | std::forward<Args>(args)...); |
119 | Log(consumer, level, source, position, longer_message.data()); |
120 | return; |
121 | } |
122 | |
123 | Log(consumer, level, source, position, "cannot compose log message" ); |
124 | |
125 | #if defined(_MSC_VER) && _MSC_VER < 1900 |
126 | #undef snprintf |
127 | #endif |
128 | } |
129 | |
130 | // Calls the given |consumer| by supplying the given error |message|. The |
131 | // |message| is from the given |source| and |location|. |
132 | inline void Error(const MessageConsumer& consumer, const char* source, |
133 | const spv_position_t& position, const char* message) { |
134 | Log(consumer, SPV_MSG_ERROR, source, position, message); |
135 | } |
136 | |
137 | // Calls the given |consumer| by supplying the error message composed according |
138 | // to the given |format|. The |message| is from the given |source| and |
139 | // |location|. |
140 | template <typename... Args> |
141 | inline void Errorf(const MessageConsumer& consumer, const char* source, |
142 | const spv_position_t& position, const char* format, |
143 | Args&&... args) { |
144 | Logf(consumer, SPV_MSG_ERROR, source, position, format, |
145 | std::forward<Args>(args)...); |
146 | } |
147 | |
148 | } // namespace spvtools |
149 | |
150 | #define SPIRV_ASSERT_IMPL(consumer, ...) \ |
151 | PP_EXPAND(SPIRV_CONCATENATE(SPIRV_ASSERT_, PP_NARGS(__VA_ARGS__))( \ |
152 | consumer, __VA_ARGS__)) |
153 | |
154 | #define SPIRV_DEBUG_IMPL(consumer, ...) \ |
155 | PP_EXPAND(SPIRV_CONCATENATE(SPIRV_DEBUG_, PP_NARGS(__VA_ARGS__))( \ |
156 | consumer, __VA_ARGS__)) |
157 | |
158 | #define SPIRV_ASSERT_1(consumer, condition) \ |
159 | do { \ |
160 | if (!(condition)) { \ |
161 | spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ |
162 | {static_cast<size_t>(__LINE__), 0, 0}, \ |
163 | "assertion failed: " #condition); \ |
164 | std::exit(EXIT_FAILURE); \ |
165 | } \ |
166 | } while (0) |
167 | |
168 | #define SPIRV_ASSERT_2(consumer, condition, message) \ |
169 | do { \ |
170 | if (!(condition)) { \ |
171 | spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ |
172 | {static_cast<size_t>(__LINE__), 0, 0}, \ |
173 | "assertion failed: " message); \ |
174 | std::exit(EXIT_FAILURE); \ |
175 | } \ |
176 | } while (0) |
177 | |
178 | #define SPIRV_ASSERT_more(consumer, condition, format, ...) \ |
179 | do { \ |
180 | if (!(condition)) { \ |
181 | spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ |
182 | {static_cast<size_t>(__LINE__), 0, 0}, \ |
183 | "assertion failed: " format, __VA_ARGS__); \ |
184 | std::exit(EXIT_FAILURE); \ |
185 | } \ |
186 | } while (0) |
187 | |
188 | #define SPIRV_ASSERT_3(consumer, condition, format, ...) \ |
189 | SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) |
190 | |
191 | #define SPIRV_ASSERT_4(consumer, condition, format, ...) \ |
192 | SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) |
193 | |
194 | #define SPIRV_ASSERT_5(consumer, condition, format, ...) \ |
195 | SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) |
196 | |
197 | #define SPIRV_DEBUG_1(consumer, message) \ |
198 | do { \ |
199 | spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, \ |
200 | {static_cast<size_t>(__LINE__), 0, 0}, message); \ |
201 | } while (0) |
202 | |
203 | #define SPIRV_DEBUG_more(consumer, format, ...) \ |
204 | do { \ |
205 | spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, \ |
206 | {static_cast<size_t>(__LINE__), 0, 0}, format, \ |
207 | __VA_ARGS__); \ |
208 | } while (0) |
209 | |
210 | #define SPIRV_DEBUG_2(consumer, format, ...) \ |
211 | SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) |
212 | |
213 | #define SPIRV_DEBUG_3(consumer, format, ...) \ |
214 | SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) |
215 | |
216 | #define SPIRV_DEBUG_4(consumer, format, ...) \ |
217 | SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) |
218 | |
219 | #define SPIRV_DEBUG_5(consumer, format, ...) \ |
220 | SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) |
221 | |
222 | // Macros for counting the number of arguments passed in. |
223 | #define PP_NARGS(...) PP_EXPAND(PP_ARG_N(__VA_ARGS__, 5, 4, 3, 2, 1, 0)) |
224 | #define PP_ARG_N(_1, _2, _3, _4, _5, N, ...) N |
225 | |
226 | // Tests for making sure that PP_NARGS() behaves as expected. |
227 | static_assert(PP_NARGS(0) == 1, "PP_NARGS macro error" ); |
228 | static_assert(PP_NARGS(0, 0) == 2, "PP_NARGS macro error" ); |
229 | static_assert(PP_NARGS(0, 0, 0) == 3, "PP_NARGS macro error" ); |
230 | static_assert(PP_NARGS(0, 0, 0, 0) == 4, "PP_NARGS macro error" ); |
231 | static_assert(PP_NARGS(0, 0, 0, 0, 0) == 5, "PP_NARGS macro error" ); |
232 | static_assert(PP_NARGS(1 + 1, 2, 3 / 3) == 3, "PP_NARGS macro error" ); |
233 | static_assert(PP_NARGS((1, 1), 2, (3, 3)) == 3, "PP_NARGS macro error" ); |
234 | |
235 | #endif // SOURCE_OPT_LOG_H_ |
236 | |