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
29namespace 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