| 1 | // Copyright 2019 The SwiftShader Authors. All Rights Reserved. |
| 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 rr_Print_hpp |
| 16 | #define rr_Print_hpp |
| 17 | |
| 18 | #if !defined(NDEBUG) |
| 19 | #define ENABLE_RR_PRINT 1 // Enables RR_PRINT(), RR_WATCH() |
| 20 | #endif // !defined(NDEBUG) |
| 21 | |
| 22 | #ifdef ENABLE_RR_PRINT |
| 23 | |
| 24 | #include "Reactor.hpp" |
| 25 | |
| 26 | #include <string> |
| 27 | #include <vector> |
| 28 | |
| 29 | namespace rr { |
| 30 | |
| 31 | // PrintValue holds the printf format and value(s) for a single argument |
| 32 | // to Print(). A single argument can be expanded into multiple printf |
| 33 | // values - for example a Float4 will expand to "%f %f %f %f" and four |
| 34 | // scalar values. |
| 35 | // The PrintValue constructor accepts the following: |
| 36 | // * Reactor LValues, RValues, Pointers. |
| 37 | // * Standard Plain-Old-Value types (int, float, bool, etc) |
| 38 | // * Custom types that specialize the PrintValue::Ty template struct. |
| 39 | // * Static arrays in the form T[N] where T can be any of the above. |
| 40 | class PrintValue |
| 41 | { |
| 42 | // Ty is a template that can be specialized for printing type T. |
| 43 | // Each specialization must expose: |
| 44 | // * A 'static std::string fmt(const T& v)' method that provides the |
| 45 | // printf format specifier. |
| 46 | // * A 'static std::vector<rr::Value*> val(const T& v)' method that |
| 47 | // returns all the printf format values. |
| 48 | template <typename T> struct Ty |
| 49 | { |
| 50 | // static std::string fmt(const T& v); |
| 51 | // static std::vector<rr::Value*> val(const T& v); |
| 52 | }; |
| 53 | |
| 54 | // returns the printf values for all the values in the given array. |
| 55 | template <typename T> |
| 56 | static std::vector<Value*> val(const T* list, int count) { |
| 57 | std::vector<Value*> values; |
| 58 | values.reserve(count); |
| 59 | for (int i = 0; i < count; i++) |
| 60 | { |
| 61 | auto v = val(list[i]); |
| 62 | values.insert(values.end(), v.begin(), v.end()); |
| 63 | } |
| 64 | return values; |
| 65 | } |
| 66 | |
| 67 | // fmt returns the comma-delimited list of printf format strings for |
| 68 | // every element in the provided list, all enclosed in square brackets. |
| 69 | template <typename T> |
| 70 | static std::string fmt(const T* list, int count) |
| 71 | { |
| 72 | std::string out = "[" ; |
| 73 | for (int i = 0; i < count; i++) |
| 74 | { |
| 75 | if (i > 0) { out += ", " ; } |
| 76 | out += fmt(list[i]); |
| 77 | } |
| 78 | return out + "]" ; |
| 79 | } |
| 80 | |
| 81 | static std::string addr(const void* ptr) |
| 82 | { |
| 83 | char buf[32]; |
| 84 | snprintf(buf, sizeof(buf), "%p" , ptr); |
| 85 | return buf; |
| 86 | } |
| 87 | |
| 88 | public: |
| 89 | const std::string format; |
| 90 | const std::vector<Value*> values; |
| 91 | |
| 92 | // Constructs a PrintValue for the given value. |
| 93 | template <typename T> |
| 94 | PrintValue(const T& v) : format(fmt(v)), values(val(v)) {} |
| 95 | |
| 96 | // Constructs a PrintValue for the given static array. |
| 97 | template <typename T, int N> |
| 98 | PrintValue(const T (&v)[N]) : format(fmt(&v[0], N)), values(val(&v[0], N)) {} |
| 99 | |
| 100 | // Constructs a PrintValue for the given array starting at arr of length |
| 101 | // len. |
| 102 | template <typename T> |
| 103 | PrintValue(const T* arr, int len) : format(fmt(arr, len)), values(val(arr, len)) {} |
| 104 | |
| 105 | // PrintValue constructors for plain-old-data values. |
| 106 | PrintValue(bool v) : format(v ? "true" : "false" ) {} |
| 107 | PrintValue(int8_t v) : format(std::to_string(v)) {} |
| 108 | PrintValue(uint8_t v) : format(std::to_string(v)) {} |
| 109 | PrintValue(int16_t v) : format(std::to_string(v)) {} |
| 110 | PrintValue(uint16_t v) : format(std::to_string(v)) {} |
| 111 | PrintValue(int32_t v) : format(std::to_string(v)) {} |
| 112 | PrintValue(uint32_t v) : format(std::to_string(v)) {} |
| 113 | PrintValue(int64_t v) : format(std::to_string(v)) {} |
| 114 | PrintValue(uint64_t v) : format(std::to_string(v)) {} |
| 115 | PrintValue(float v) : format(std::to_string(v)) {} |
| 116 | PrintValue(double v) : format(std::to_string(v)) {} |
| 117 | |
| 118 | template <typename T> |
| 119 | PrintValue(const T* v) : format(addr(v)) {} |
| 120 | |
| 121 | // vals is a helper to build composite value lists. |
| 122 | // vals returns the full, sequential list of printf argument values used |
| 123 | // to print all the provided variadic values. |
| 124 | // vals() is intended to be used by implementations of |
| 125 | // PrintValue::Ty<>::vals() to help declare aggregate types. |
| 126 | // For example, if you were declaring a PrintValue::Ty<> specialization |
| 127 | // for a custom Mat4x4 matrix formed from four Vector4 values, you'd |
| 128 | // write: |
| 129 | // |
| 130 | // namespace rr |
| 131 | // { |
| 132 | // template <> struct PrintValue::Ty<Mat4x4> |
| 133 | // { |
| 134 | // static std::string fmt(const Mat4x4& v) |
| 135 | // { |
| 136 | // return "[a: <%f, %f, %f, %f>," |
| 137 | // " b: <%f, %f, %f, %f>," |
| 138 | // " c: <%f, %f, %f, %f>," |
| 139 | // " d: <%f, %f, %f, %f>]"; |
| 140 | // } |
| 141 | // static std::vector<rr::Value*> val(const Mat4x4& v) |
| 142 | // { |
| 143 | // return PrintValue::vals(v.a, v.b, v.c, v.d); |
| 144 | // } |
| 145 | // }; |
| 146 | // } |
| 147 | template<typename ... ARGS> |
| 148 | static std::vector<Value*> vals(ARGS... v) |
| 149 | { |
| 150 | std::vector< std::vector<Value*> > lists = {val(v)...}; |
| 151 | std::vector<Value*> joined; |
| 152 | for (const auto& list : lists) |
| 153 | { |
| 154 | joined.insert(joined.end(), list.begin(), list.end()); |
| 155 | } |
| 156 | return joined; |
| 157 | } |
| 158 | |
| 159 | // returns the printf format specifier for the given type via the |
| 160 | // PrintValue::Ty<T> specialization. |
| 161 | template <typename T> |
| 162 | static std::string fmt(const T& v) { return Ty<T>::fmt(v); } |
| 163 | |
| 164 | // returns the printf value for the given type with a |
| 165 | // PrintValue::Ty<T> specialization. |
| 166 | template <typename T> |
| 167 | static std::vector<Value*> val(const T& v) { return Ty<T>::val(v); } |
| 168 | }; |
| 169 | |
| 170 | // PrintValue::Ty<T> specializations for basic types. |
| 171 | template <> struct PrintValue::Ty<const char*> |
| 172 | { |
| 173 | static std::string fmt(const char* v) { return "%s" ; } |
| 174 | static std::vector<Value*> val(const char* v); |
| 175 | }; |
| 176 | template <> struct PrintValue::Ty<std::string> |
| 177 | { |
| 178 | static std::string fmt(const std::string& v) { return PrintValue::Ty<const char*>::fmt(v.c_str()); } |
| 179 | static std::vector<Value*> val(const std::string& v) { return PrintValue::Ty<const char*>::val(v.c_str()); } |
| 180 | }; |
| 181 | |
| 182 | // PrintValue::Ty<T> specializations for standard Reactor types. |
| 183 | template <> struct PrintValue::Ty<Bool> |
| 184 | { |
| 185 | static std::string fmt(const RValue<Bool>& v) { return "%d" ; } |
| 186 | static std::vector<Value*> val(const RValue<Bool>& v) { return {v.value}; } |
| 187 | }; |
| 188 | template <> struct PrintValue::Ty<Byte> |
| 189 | { |
| 190 | static std::string fmt(const RValue<Byte>& v) { return "%d" ; } |
| 191 | static std::vector<Value*> val(const RValue<Byte>& v); |
| 192 | }; |
| 193 | template <> struct PrintValue::Ty<Byte4> |
| 194 | { |
| 195 | static std::string fmt(const RValue<Byte4>& v) { return "[%d, %d, %d, %d]" ; } |
| 196 | static std::vector<Value*> val(const RValue<Byte4>& v); |
| 197 | }; |
| 198 | template <> struct PrintValue::Ty<Int> |
| 199 | { |
| 200 | static std::string fmt(const RValue<Int>& v) { return "%d" ; } |
| 201 | static std::vector<Value*> val(const RValue<Int>& v); |
| 202 | }; |
| 203 | template <> struct PrintValue::Ty<Int2> |
| 204 | { |
| 205 | static std::string fmt(const RValue<Int>& v) { return "[%d, %d]" ; } |
| 206 | static std::vector<Value*> val(const RValue<Int2>& v); |
| 207 | }; |
| 208 | template <> struct PrintValue::Ty<Int4> |
| 209 | { |
| 210 | static std::string fmt(const RValue<Int4>& v) { return "[%d, %d, %d, %d]" ; } |
| 211 | static std::vector<Value*> val(const RValue<Int4>& v); |
| 212 | }; |
| 213 | template <> struct PrintValue::Ty<UInt> |
| 214 | { |
| 215 | static std::string fmt(const RValue<UInt>& v) { return "%u" ; } |
| 216 | static std::vector<Value*> val(const RValue<UInt>& v); |
| 217 | }; |
| 218 | template <> struct PrintValue::Ty<UInt2> |
| 219 | { |
| 220 | static std::string fmt(const RValue<UInt>& v) { return "[%u, %u]" ; } |
| 221 | static std::vector<Value*> val(const RValue<UInt2>& v); |
| 222 | }; |
| 223 | template <> struct PrintValue::Ty<UInt4> |
| 224 | { |
| 225 | static std::string fmt(const RValue<UInt4>& v) { return "[%u, %u, %u, %u]" ; } |
| 226 | static std::vector<Value*> val(const RValue<UInt4>& v); |
| 227 | }; |
| 228 | template <> struct PrintValue::Ty<Short> |
| 229 | { |
| 230 | static std::string fmt(const RValue<Short>& v) { return "%d" ; } |
| 231 | static std::vector<Value*> val(const RValue<Short>& v); |
| 232 | }; |
| 233 | template <> struct PrintValue::Ty<Short4> |
| 234 | { |
| 235 | static std::string fmt(const RValue<Short4>& v) { return "[%d, %d, %d, %d]" ; } |
| 236 | static std::vector<Value*> val(const RValue<Short4>& v); |
| 237 | }; |
| 238 | template <> struct PrintValue::Ty<UShort> |
| 239 | { |
| 240 | static std::string fmt(const RValue<UShort>& v) { return "%u" ; } |
| 241 | static std::vector<Value*> val(const RValue<UShort>& v); |
| 242 | }; |
| 243 | template <> struct PrintValue::Ty<UShort4> |
| 244 | { |
| 245 | static std::string fmt(const RValue<UShort4>& v) { return "[%u, %u, %u, %u]" ; } |
| 246 | static std::vector<Value*> val(const RValue<UShort4>& v); |
| 247 | }; |
| 248 | template <> struct PrintValue::Ty<Float> |
| 249 | { |
| 250 | static std::string fmt(const RValue<Float>& v) { return "[%f]" ; } |
| 251 | static std::vector<Value*> val(const RValue<Float>& v); |
| 252 | }; |
| 253 | template <> struct PrintValue::Ty<Float4> |
| 254 | { |
| 255 | static std::string fmt(const RValue<Float4>& v) { return "[%f, %f, %f, %f]" ; } |
| 256 | static std::vector<Value*> val(const RValue<Float4>& v); |
| 257 | }; |
| 258 | template <> struct PrintValue::Ty<Long> |
| 259 | { |
| 260 | static std::string fmt(const RValue<Long>& v) { return "%lld" ; } |
| 261 | static std::vector<Value*> val(const RValue<Long>& v) { return {v.value}; } |
| 262 | }; |
| 263 | template <typename T> struct PrintValue::Ty< Pointer<T> > |
| 264 | { |
| 265 | static std::string fmt(const RValue<Pointer<T>>& v) { return "%p" ; } |
| 266 | static std::vector<Value*> val(const RValue<Pointer<T>>& v) { return {v.value}; } |
| 267 | }; |
| 268 | template <typename T> struct PrintValue::Ty< Reference<T> > |
| 269 | { |
| 270 | static std::string fmt(const Reference<T>& v) { return PrintValue::Ty<T>::fmt(v); } |
| 271 | static std::vector<Value*> val(const Reference<T>& v) { return PrintValue::Ty<T>::val(v); } |
| 272 | }; |
| 273 | template <typename T> struct PrintValue::Ty< RValue<T> > |
| 274 | { |
| 275 | static std::string fmt(const RValue<T>& v) { return PrintValue::Ty<T>::fmt(v); } |
| 276 | static std::vector<Value*> val(const RValue<T>& v) { return PrintValue::Ty<T>::val(v); } |
| 277 | }; |
| 278 | |
| 279 | // Printv emits a call to printf() using the function, file and line, |
| 280 | // message and optional values. |
| 281 | // See Printv below. |
| 282 | void Printv(const char* function, const char* file, int line, const char* msg, std::initializer_list<PrintValue> vals); |
| 283 | |
| 284 | // Printv emits a call to printf() using the provided message and optional |
| 285 | // values. |
| 286 | // Printf replaces any bracketed indices in the message with string |
| 287 | // representations of the corresponding value in vals. |
| 288 | // For example: |
| 289 | // Printv("{0} and {1}", "red", "green"); |
| 290 | // Would print the string: |
| 291 | // "red and green" |
| 292 | // Arguments can be indexed in any order. |
| 293 | // Invalid indices are not substituted. |
| 294 | inline void Printv(const char* msg, std::initializer_list<PrintValue> vals) |
| 295 | { |
| 296 | Printv(nullptr, nullptr, 0, msg, vals); |
| 297 | } |
| 298 | |
| 299 | // Print is a wrapper over Printv that wraps the variadic arguments into an |
| 300 | // initializer_list before calling Printv. |
| 301 | template <typename ... ARGS> |
| 302 | void Print(const char* msg, const ARGS& ... vals) { Printv(msg, {vals...}); } |
| 303 | |
| 304 | // Print is a wrapper over Printv that wraps the variadic arguments into an |
| 305 | // initializer_list before calling Printv. |
| 306 | template <typename ... ARGS> |
| 307 | void Print(const char* function, const char* file, int line, const char* msg, const ARGS& ... vals) |
| 308 | { |
| 309 | Printv(function, file, line, msg, {vals...}); |
| 310 | } |
| 311 | |
| 312 | // RR_LOG is a macro that calls Print(), automatically populating the |
| 313 | // function, file and line parameters and appending a newline to the string. |
| 314 | // |
| 315 | // RR_LOG() is intended to be used for debugging JIT compiled code, and is |
| 316 | // not intended for production use. |
| 317 | #if defined(_WIN32) |
| 318 | #define RR_LOG(msg, ...) Print(__FUNCSIG__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__) |
| 319 | #else |
| 320 | #define RR_LOG(msg, ...) Print(__PRETTY_FUNCTION__, __FILE__, static_cast<int>(__LINE__), msg "\n", ##__VA_ARGS__) |
| 321 | #endif |
| 322 | |
| 323 | // Macro magic to perform variadic dispatch. |
| 324 | // See: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments |
| 325 | // Note, this doesn't attempt to use the ##__VA_ARGS__ trick to handle 0 |
| 326 | #define RR_MSVC_EXPAND_BUG(X) X // Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler. |
| 327 | #define RR_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N |
| 328 | #define RR_COUNT_ARGUMENTS(...) RR_MSVC_EXPAND_BUG(RR_GET_NTH_ARG(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) |
| 329 | static_assert(1 == RR_COUNT_ARGUMENTS(a), "RR_COUNT_ARGUMENTS broken" ); // Sanity checks. |
| 330 | static_assert(2 == RR_COUNT_ARGUMENTS(a, b), "RR_COUNT_ARGUMENTS broken" ); |
| 331 | static_assert(3 == RR_COUNT_ARGUMENTS(a, b, c), "RR_COUNT_ARGUMENTS broken" ); |
| 332 | |
| 333 | // RR_WATCH_FMT(...) resolves to a string literal that lists all the |
| 334 | // arguments by name. This string can be passed to LOG() to print each of |
| 335 | // the arguments with their name and value. |
| 336 | // |
| 337 | // RR_WATCH_FMT(...) uses the RR_COUNT_ARGUMENTS helper macro to delegate to a |
| 338 | // corresponding RR_WATCH_FMT_n specialization macro below. |
| 339 | #define RR_WATCH_CONCAT(a, b) a ## b |
| 340 | #define RR_WATCH_CONCAT2(a, b) RR_WATCH_CONCAT(a, b) |
| 341 | #define RR_WATCH_FMT(...) RR_MSVC_EXPAND_BUG(RR_WATCH_CONCAT2(RR_WATCH_FMT_, RR_COUNT_ARGUMENTS(__VA_ARGS__))(__VA_ARGS__)) |
| 342 | #define RR_WATCH_FMT_1(_1) "\n " #_1 ": {0}" |
| 343 | #define RR_WATCH_FMT_2(_1, _2) RR_WATCH_FMT_1(_1) "\n " #_2 ": {1}" |
| 344 | #define RR_WATCH_FMT_3(_1, _2, _3) RR_WATCH_FMT_2(_1, _2) "\n " #_3 ": {2}" |
| 345 | #define RR_WATCH_FMT_4(_1, _2, _3, _4) RR_WATCH_FMT_3(_1, _2, _3) "\n " #_4 ": {3}" |
| 346 | #define RR_WATCH_FMT_5(_1, _2, _3, _4, _5) RR_WATCH_FMT_4(_1, _2, _3, _4) "\n " #_5 ": {4}" |
| 347 | #define RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) RR_WATCH_FMT_5(_1, _2, _3, _4, _5) "\n " #_6 ": {5}" |
| 348 | #define RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) RR_WATCH_FMT_6(_1, _2, _3, _4, _5, _6) "\n " #_7 ": {6}" |
| 349 | #define RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) RR_WATCH_FMT_7(_1, _2, _3, _4, _5, _6, _7) "\n " #_8 ": {7}" |
| 350 | #define RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) RR_WATCH_FMT_8(_1, _2, _3, _4, _5, _6, _7, _8) "\n " #_9 ": {8}" |
| 351 | #define RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) RR_WATCH_FMT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) "\n " #_10 ": {9}" |
| 352 | #define RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) RR_WATCH_FMT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) "\n " #_11 ": {10}" |
| 353 | #define RR_WATCH_FMT_12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) RR_WATCH_FMT_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) "\n " #_12 ": {11}" |
| 354 | |
| 355 | // RR_WATCH() is a helper that prints the name and value of all the supplied |
| 356 | // arguments. |
| 357 | // For example, if you had the Int and bool variables 'foo' and 'bar' that |
| 358 | // you want to print, you can simply write: |
| 359 | // RR_WATCH(foo, bar) |
| 360 | // When this JIT compiled code is executed, it will print the string |
| 361 | // "foo: 1, bar: true" to stdout. |
| 362 | // |
| 363 | // RR_WATCH() is intended to be used for debugging JIT compiled code, and |
| 364 | // is not intended for production use. |
| 365 | #define RR_WATCH(...) RR_LOG(RR_WATCH_FMT(__VA_ARGS__), __VA_ARGS__) |
| 366 | |
| 367 | } // namespace rr |
| 368 | |
| 369 | #endif // ENABLE_RR_PRINT |
| 370 | |
| 371 | #endif // rr_Print_hpp |
| 372 | |