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 {__LINE__, 0, 0}, "unimplemented: " feature); \ 61 } while (0) 62 63 // Logs an error message to the consumer saying the code location 64 // should be unreachable. 65 #define SPIRV_UNREACHABLE(consumer) \ 66 do { \ 67 spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ 68 {__LINE__, 0, 0}, "unreachable"); \ 69 } while (0) 70 71 // Helper macros for concatenating arguments. 72 #define SPIRV_CONCATENATE(a, b) SPIRV_CONCATENATE_(a, b) 73 #define SPIRV_CONCATENATE_(a, b) a##b 74 75 // Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler. 76 #define PP_EXPAND(x) x 77 78 namespace spvtools { 79 80 // Calls the given |consumer| by supplying the |message|. The |message| is from 81 // the given |source| and |location| and of the given severity |level|. 82 inline void Log(const MessageConsumer& consumer, spv_message_level_t level, 83 const char* source, const spv_position_t& position, 84 const char* message) { 85 if (consumer != nullptr) consumer(level, source, position, message); 86 } 87 88 // Calls the given |consumer| by supplying the message composed according to the 89 // given |format|. The |message| is from the given |source| and |location| and 90 // of the given severity |level|. 91 template <typename... Args> 92 void Logf(const MessageConsumer& consumer, spv_message_level_t level, 93 const char* source, const spv_position_t& position, 94 const char* format, Args&&... args) { 95 #if defined(_MSC_VER) && _MSC_VER < 1900 96 // Sadly, snprintf() is not supported until Visual Studio 2015! 97 #define snprintf _snprintf 98 #endif 99 100 enum { kInitBufferSize = 256 }; 101 102 char message[kInitBufferSize]; 103 const int size = 104 snprintf(message, kInitBufferSize, format, std::forward<Args>(args)...); 105 106 if (size >= 0 && size < kInitBufferSize) { 107 Log(consumer, level, source, position, message); 108 return; 109 } 110 111 if (size >= 0) { 112 // The initial buffer is insufficient. Allocate a buffer of a larger size, 113 // and write to it instead. Force the size to be unsigned to avoid a 114 // warning in GCC 7.1. 115 std::vector<char> longer_message(size + 1u); 116 snprintf(longer_message.data(), longer_message.size(), format, 117 std::forward<Args>(args)...); 118 Log(consumer, level, source, position, longer_message.data()); 119 return; 120 } 121 122 Log(consumer, level, source, position, "cannot compose log message"); 123 124 #if defined(_MSC_VER) && _MSC_VER < 1900 125 #undef snprintf 126 #endif 127 } 128 129 // Calls the given |consumer| by supplying the given error |message|. The 130 // |message| is from the given |source| and |location|. 131 inline void Error(const MessageConsumer& consumer, const char* source, 132 const spv_position_t& position, const char* message) { 133 Log(consumer, SPV_MSG_ERROR, source, position, message); 134 } 135 136 // Calls the given |consumer| by supplying the error message composed according 137 // to the given |format|. The |message| is from the given |source| and 138 // |location|. 139 template <typename... Args> 140 inline void Errorf(const MessageConsumer& consumer, const char* source, 141 const spv_position_t& position, const char* format, 142 Args&&... args) { 143 Logf(consumer, SPV_MSG_ERROR, source, position, format, 144 std::forward<Args>(args)...); 145 } 146 147 } // namespace spvtools 148 149 #define SPIRV_ASSERT_IMPL(consumer, ...) \ 150 PP_EXPAND(SPIRV_CONCATENATE(SPIRV_ASSERT_, PP_NARGS(__VA_ARGS__))( \ 151 consumer, __VA_ARGS__)) 152 153 #define SPIRV_DEBUG_IMPL(consumer, ...) \ 154 PP_EXPAND(SPIRV_CONCATENATE(SPIRV_DEBUG_, PP_NARGS(__VA_ARGS__))( \ 155 consumer, __VA_ARGS__)) 156 157 #define SPIRV_ASSERT_1(consumer, condition) \ 158 do { \ 159 if (!(condition)) { \ 160 spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ 161 {__LINE__, 0, 0}, "assertion failed: " #condition); \ 162 std::exit(EXIT_FAILURE); \ 163 } \ 164 } while (0) 165 166 #define SPIRV_ASSERT_2(consumer, condition, message) \ 167 do { \ 168 if (!(condition)) { \ 169 spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ 170 {__LINE__, 0, 0}, "assertion failed: " message); \ 171 std::exit(EXIT_FAILURE); \ 172 } \ 173 } while (0) 174 175 #define SPIRV_ASSERT_more(consumer, condition, format, ...) \ 176 do { \ 177 if (!(condition)) { \ 178 spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ 179 {__LINE__, 0, 0}, "assertion failed: " format, \ 180 __VA_ARGS__); \ 181 std::exit(EXIT_FAILURE); \ 182 } \ 183 } while (0) 184 185 #define SPIRV_ASSERT_3(consumer, condition, format, ...) \ 186 SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) 187 188 #define SPIRV_ASSERT_4(consumer, condition, format, ...) \ 189 SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) 190 191 #define SPIRV_ASSERT_5(consumer, condition, format, ...) \ 192 SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) 193 194 #define SPIRV_DEBUG_1(consumer, message) \ 195 do { \ 196 spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \ 197 message); \ 198 } while (0) 199 200 #define SPIRV_DEBUG_more(consumer, format, ...) \ 201 do { \ 202 spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \ 203 format, __VA_ARGS__); \ 204 } while (0) 205 206 #define SPIRV_DEBUG_2(consumer, format, ...) \ 207 SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) 208 209 #define SPIRV_DEBUG_3(consumer, format, ...) \ 210 SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) 211 212 #define SPIRV_DEBUG_4(consumer, format, ...) \ 213 SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) 214 215 #define SPIRV_DEBUG_5(consumer, format, ...) \ 216 SPIRV_DEBUG_more(consumer, format, __VA_ARGS__) 217 218 // Macros for counting the number of arguments passed in. 219 #define PP_NARGS(...) PP_EXPAND(PP_ARG_N(__VA_ARGS__, 5, 4, 3, 2, 1, 0)) 220 #define PP_ARG_N(_1, _2, _3, _4, _5, N, ...) N 221 222 // Tests for making sure that PP_NARGS() behaves as expected. 223 static_assert(PP_NARGS(0) == 1, "PP_NARGS macro error"); 224 static_assert(PP_NARGS(0, 0) == 2, "PP_NARGS macro error"); 225 static_assert(PP_NARGS(0, 0, 0) == 3, "PP_NARGS macro error"); 226 static_assert(PP_NARGS(0, 0, 0, 0) == 4, "PP_NARGS macro error"); 227 static_assert(PP_NARGS(0, 0, 0, 0, 0) == 5, "PP_NARGS macro error"); 228 static_assert(PP_NARGS(1 + 1, 2, 3 / 3) == 3, "PP_NARGS macro error"); 229 static_assert(PP_NARGS((1, 1), 2, (3, 3)) == 3, "PP_NARGS macro error"); 230 231 #endif // SOURCE_OPT_LOG_H_ 232