Halide  12.0.1
Halide compiler and libraries
Util.h
Go to the documentation of this file.
1 // Always use assert, even if llvm-config defines NDEBUG
2 #ifdef NDEBUG
3 #undef NDEBUG
4 #include <assert.h>
5 #define NDEBUG
6 #else
7 #include <cassert>
8 #endif
9 
10 #ifndef HALIDE_UTIL_H
11 #define HALIDE_UTIL_H
12 
13 /** \file
14  * Various utility functions used internally Halide. */
15 
16 #include <cstdint>
17 #include <cstring>
18 #include <functional>
19 #include <limits>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "runtime/HalideRuntime.h"
25 
26 #ifdef Halide_STATIC_DEFINE
27 #define HALIDE_EXPORT
28 #else
29 #if defined(_MSC_VER)
30 // Halide_EXPORTS is quietly defined by CMake when building a shared library
31 #ifdef Halide_EXPORTS
32 #define HALIDE_EXPORT __declspec(dllexport)
33 #else
34 #define HALIDE_EXPORT __declspec(dllimport)
35 #endif
36 #else
37 #define HALIDE_EXPORT __attribute__((visibility("default")))
38 #endif
39 #endif
40 
41 // If we're in user code, we don't want certain functions to be inlined.
42 #if defined(COMPILING_HALIDE) || defined(BUILDING_PYTHON)
43 #define HALIDE_NO_USER_CODE_INLINE
44 #else
45 #define HALIDE_NO_USER_CODE_INLINE HALIDE_NEVER_INLINE
46 #endif
47 
48 namespace Halide {
49 
50 /** Load a plugin in the form of a dynamic library (e.g. for custom autoschedulers).
51  * If the string doesn't contain any . characters, the proper prefix and/or suffix
52  * for the platform will be added:
53  *
54  * foo -> libfoo.so (Linux/OSX/etc -- note that .dylib is not supported)
55  * foo -> foo.dll (Windows)
56  *
57  * otherwise, it is assumed to be an appropriate pathname.
58  *
59  * Any error in loading will assert-fail. */
60 void load_plugin(const std::string &lib_name);
61 
62 namespace Internal {
63 
64 /** Some numeric conversions are UB if the value won't fit in the result;
65  * safe_numeric_cast<>() is meant as a drop-in replacement for a C/C++ cast
66  * that adds well-defined behavior for the UB cases, attempting to mimic
67  * common implementation behavior as much as possible.
68  */
69 template<typename DST, typename SRC,
70  typename std::enable_if<std::is_floating_point<SRC>::value>::type * = nullptr>
71 DST safe_numeric_cast(SRC s) {
72  if (std::is_integral<DST>::value) {
73  // Treat float -> int as a saturating cast; this is handled
74  // in different ways by different compilers, so an arbitrary but safe
75  // choice like this is reasonable.
76  if (s < (SRC)std::numeric_limits<DST>::min()) {
78  }
79  if (s > (SRC)std::numeric_limits<DST>::max()) {
81  }
82  }
83  return (DST)s;
84 }
85 
86 template<typename DST, typename SRC,
87  typename std::enable_if<std::is_integral<SRC>::value>::type * = nullptr>
88 DST safe_numeric_cast(SRC s) {
89  if (std::is_integral<DST>::value) {
90  // any-int -> signed-int is technically UB if value won't fit;
91  // in practice, common compilers implement such conversions as done below
92  // (as verified by exhaustive testing on Clang for x86-64). We could
93  // probably continue to rely on that behavior, but making it explicit
94  // avoids possible wrather of UBSan and similar debug helpers.
95  // (Yes, using sizeof for this comparison is a little odd for the uint->int
96  // case, but the intent is to match existing common behavior, which this does.)
97  if (std::is_integral<SRC>::value && std::is_signed<DST>::value && sizeof(DST) < sizeof(SRC)) {
98  using UnsignedSrc = typename std::make_unsigned<SRC>::type;
99  return (DST)(s & (UnsignedSrc)(-1));
100  }
101  }
102  return (DST)s;
103 }
104 
105 /** An aggressive form of reinterpret cast used for correct type-punning. */
106 template<typename DstType, typename SrcType>
107 DstType reinterpret_bits(const SrcType &src) {
108  static_assert(sizeof(SrcType) == sizeof(DstType), "Types must be same size");
109  DstType dst;
110  memcpy(&dst, &src, sizeof(SrcType));
111  return dst;
112 }
113 
114 /** Make a unique name for an object based on the name of the stack
115  * variable passed in. If introspection isn't working or there are no
116  * debug symbols, just uses unique_name with the given prefix. */
117 std::string make_entity_name(void *stack_ptr, const std::string &type, char prefix);
118 
119 /** Get value of an environment variable. Returns its value
120  * is defined in the environment. If the var is not defined, an empty string
121  * is returned.
122  */
123 std::string get_env_variable(char const *env_var_name);
124 
125 /** Get the name of the currently running executable. Platform-specific.
126  * If program name cannot be retrieved, function returns an empty string. */
127 std::string running_program_name();
128 
129 /** Generate a unique name starting with the given prefix. It's unique
130  * relative to all other strings returned by unique_name in this
131  * process.
132  *
133  * The single-character version always appends a numeric suffix to the
134  * character.
135  *
136  * The string version will either return the input as-is (with high
137  * probability on the first time it is called with that input), or
138  * replace any existing '$' characters with underscores, then add a
139  * '$' sign and a numeric suffix to it.
140  *
141  * Note that unique_name('f') therefore differs from
142  * unique_name("f"). The former returns something like f123, and the
143  * latter returns either f or f$123.
144  */
145 // @{
146 std::string unique_name(char prefix);
147 std::string unique_name(const std::string &prefix);
148 // @}
149 
150 /** Test if the first string starts with the second string */
151 bool starts_with(const std::string &str, const std::string &prefix);
152 
153 /** Test if the first string ends with the second string */
154 bool ends_with(const std::string &str, const std::string &suffix);
155 
156 /** Replace all matches of the second string in the first string with the last string */
157 std::string replace_all(const std::string &str, const std::string &find, const std::string &replace);
158 
159 /** Split the source string using 'delim' as the divider. */
160 std::vector<std::string> split_string(const std::string &source, const std::string &delim);
161 
162 /** Perform a left fold of a vector. Returns a default-constructed
163  * vector element if the vector is empty. Similar to std::accumulate
164  * but with a less clunky syntax. */
165 template<typename T, typename Fn>
166 T fold_left(const std::vector<T> &vec, Fn f) {
167  T result;
168  if (vec.empty()) {
169  return result;
170  }
171  result = vec[0];
172  for (size_t i = 1; i < vec.size(); i++) {
173  result = f(result, vec[i]);
174  }
175  return result;
176 }
177 
178 /** Returns a right fold of a vector. Returns a default-constructed
179  * vector element if the vector is empty. */
180 template<typename T, typename Fn>
181 T fold_right(const std::vector<T> &vec, Fn f) {
182  T result;
183  if (vec.empty()) {
184  return result;
185  }
186  result = vec.back();
187  for (size_t i = vec.size() - 1; i > 0; i--) {
188  result = f(vec[i - 1], result);
189  }
190  return result;
191 }
192 
193 template<typename... T>
194 struct meta_and : std::true_type {};
195 
196 template<typename T1, typename... Args>
197 struct meta_and<T1, Args...> : std::integral_constant<bool, T1::value && meta_and<Args...>::value> {};
198 
199 template<typename... T>
200 struct meta_or : std::false_type {};
201 
202 template<typename T1, typename... Args>
203 struct meta_or<T1, Args...> : std::integral_constant<bool, T1::value || meta_or<Args...>::value> {};
204 
205 template<typename To, typename... Args>
206 struct all_are_convertible : meta_and<std::is_convertible<Args, To>...> {};
207 
208 /** Returns base name and fills in namespaces, outermost one first in vector. */
209 std::string extract_namespaces(const std::string &name, std::vector<std::string> &namespaces);
210 
211 /** Overload that returns base name only */
212 std::string extract_namespaces(const std::string &name);
213 
214 struct FileStat {
216  uint32_t mod_time; // Unix epoch time
220 };
221 
222 /** Create a unique file with a name of the form prefixXXXXXsuffix in an arbitrary
223  * (but writable) directory; this is typically /tmp, but the specific
224  * location is not guaranteed. (Note that the exact form of the file name
225  * may vary; in particular, the suffix may be ignored on Windows.)
226  * The file is created (but not opened), thus this can be called from
227  * different threads (or processes, e.g. when building with parallel make)
228  * without risking collision. Note that if this file is used as a temporary
229  * file, the caller is responsibly for deleting it. Neither the prefix nor suffix
230  * may contain a directory separator.
231  */
232 std::string file_make_temp(const std::string &prefix, const std::string &suffix);
233 
234 /** Create a unique directory in an arbitrary (but writable) directory; this is
235  * typically somewhere inside /tmp, but the specific location is not guaranteed.
236  * The directory will be empty (i.e., this will never return /tmp itself,
237  * but rather a new directory inside /tmp). The caller is responsible for removing the
238  * directory after use.
239  */
240 std::string dir_make_temp();
241 
242 /** Wrapper for access(). Quietly ignores errors. */
243 bool file_exists(const std::string &name);
244 
245 /** assert-fail if the file doesn't exist. useful primarily for testing purposes. */
246 void assert_file_exists(const std::string &name);
247 
248 /** assert-fail if the file DOES exist. useful primarily for testing purposes. */
249 void assert_no_file_exists(const std::string &name);
250 
251 /** Wrapper for unlink(). Asserts upon error. */
252 void file_unlink(const std::string &name);
253 
254 /** Wrapper for unlink(). Quietly ignores errors. */
255 void file_unlink(const std::string &name);
256 
257 /** Ensure that no file with this path exists. If such a file
258  * exists and cannot be removed, assert-fail. */
259 void ensure_no_file_exists(const std::string &name);
260 
261 /** Wrapper for rmdir(). Asserts upon error. */
262 void dir_rmdir(const std::string &name);
263 
264 /** Wrapper for stat(). Asserts upon error. */
265 FileStat file_stat(const std::string &name);
266 
267 /** Read the entire contents of a file into a vector<char>. The file
268  * is read in binary mode. Errors trigger an assertion failure. */
269 std::vector<char> read_entire_file(const std::string &pathname);
270 
271 /** Create or replace the contents of a file with a given pointer-and-length
272  * of memory. If the file doesn't exist, it is created; if it does exist, it
273  * is completely overwritten. Any error triggers an assertion failure. */
274 void write_entire_file(const std::string &pathname, const void *source, size_t source_len);
275 
276 inline void write_entire_file(const std::string &pathname, const std::vector<char> &source) {
277  write_entire_file(pathname, source.data(), source.size());
278 }
279 
280 /** A simple utility class that creates a temporary file in its ctor and
281  * deletes that file in its dtor; this is useful for temporary files that you
282  * want to ensure are deleted when exiting a certain scope. Since this is essentially
283  * just an RAII wrapper around file_make_temp() and file_unlink(), it has the same
284  * failure modes (i.e.: assertion upon error).
285  */
286 class TemporaryFile final {
287 public:
288  TemporaryFile(const std::string &prefix, const std::string &suffix)
289  : temp_path(file_make_temp(prefix, suffix)) {
290  }
291  const std::string &pathname() const {
292  return temp_path;
293  }
295  if (do_unlink) {
296  file_unlink(temp_path);
297  }
298  }
299  // You can call this if you want to defeat the automatic deletion;
300  // this is rarely what you want to do (since it defeats the purpose
301  // of this class), but can be quite handy for debugging purposes.
302  void detach() {
303  do_unlink = false;
304  }
305 
306 private:
307  const std::string temp_path;
308  bool do_unlink = true;
309 
310 public:
311  TemporaryFile(const TemporaryFile &) = delete;
315 };
316 
317 /** Routines to test if math would overflow for signed integers with
318  * the given number of bits. */
319 // @{
320 bool add_would_overflow(int bits, int64_t a, int64_t b);
321 bool sub_would_overflow(int bits, int64_t a, int64_t b);
322 bool mul_would_overflow(int bits, int64_t a, int64_t b);
323 // @}
324 
325 /** Helper class for saving/restoring variable values on the stack, to allow
326  * for early-exit that preserves correctness */
327 template<typename T>
328 struct ScopedValue {
329  T &var;
331  /** Preserve the old value, restored at dtor time */
333  : var(var), old_value(var) {
334  }
335  /** Preserve the old value, then set the var to a new value. */
336  ScopedValue(T &var, T new_value)
337  : var(var), old_value(var) {
338  var = new_value;
339  }
341  var = old_value;
342  }
343  operator T() const {
344  return old_value;
345  }
346  // allow move but not copy
347  ScopedValue(const ScopedValue &that) = delete;
348  ScopedValue(ScopedValue &&that) noexcept = default;
349 };
350 
351 // Wrappers for some C++14-isms that are useful and trivially implementable
352 // in C++11; these are defined in the Halide::Internal namespace. If we
353 // are compiling under C++14 or later, we just use the standard implementations
354 // rather than our own.
355 #if __cplusplus >= 201402L
356 
357 // C++14: Use the standard implementations
358 using std::index_sequence;
359 using std::integer_sequence;
362 
363 #else
364 
365 // C++11: std::integer_sequence (etc) is standard in C++14 but not C++11, but
366 // is easily written in C++11. This is a simple version that could
367 // probably be improved.
368 
369 template<typename T, T... Ints>
371  static constexpr size_t size() {
372  return sizeof...(Ints);
373  }
374 };
375 
376 template<typename T>
378 
379 template<typename T, T... Ints>
381  using type = integer_sequence<T, Ints..., sizeof...(Ints)>;
382 };
383 
384 template<typename T, T I, T N>
386  using type = typename next_integer_sequence<
388 };
389 
390 template<typename T, T N>
393 };
394 
395 template<typename T, T N>
397 
398 template<size_t... Ints>
400 
401 template<size_t N>
403 
404 #endif
405 
406 // Helpers for timing blocks of code. Put 'TIC;' at the start and
407 // 'TOC;' at the end. Timing is reported at the toc via
408 // debug(0). The calls can be nested and will pretty-print
409 // appropriately. Took this idea from matlab via Jon Barron.
410 //
411 // Note that this uses global state internally, and is not thread-safe
412 // at all. Only use it for single-threaded debugging sessions.
413 
414 void halide_tic_impl(const char *file, int line);
415 void halide_toc_impl(const char *file, int line);
416 #define HALIDE_TIC Halide::Internal::halide_tic_impl(__FILE__, __LINE__)
417 #define HALIDE_TOC Halide::Internal::halide_toc_impl(__FILE__, __LINE__)
418 #ifdef COMPILING_HALIDE
419 #define TIC HALIDE_TIC
420 #define TOC HALIDE_TOC
421 #endif
422 
423 // statically cast a value from one type to another: this is really just
424 // some syntactic sugar around static_cast<>() to avoid compiler warnings
425 // regarding 'bool' in some compliation configurations.
426 template<typename TO>
427 struct StaticCast {
428  template<typename FROM, typename TO2 = TO, typename std::enable_if<!std::is_same<TO2, bool>::value>::type * = nullptr>
429  inline constexpr static TO2 value(const FROM &from) {
430  return static_cast<TO2>(from);
431  }
432 
433  template<typename FROM, typename TO2 = TO, typename std::enable_if<std::is_same<TO2, bool>::value>::type * = nullptr>
434  inline constexpr static TO2 value(const FROM &from) {
435  return from != 0;
436  }
437 };
438 
439 // Like std::is_convertible, but with additional tests for arithmetic types:
440 // ensure that the value will roundtrip losslessly (e.g., no integer truncation
441 // or dropping of fractional parts).
442 template<typename TO>
444  template<typename FROM, typename TO2 = TO, typename std::enable_if<!std::is_convertible<FROM, TO>::value>::type * = nullptr>
445  inline constexpr static bool value(const FROM &from) {
446  return false;
447  }
448 
449  template<typename FROM, typename TO2 = TO, typename std::enable_if<std::is_convertible<FROM, TO>::value && std::is_arithmetic<TO>::value && std::is_arithmetic<FROM>::value && !std::is_same<TO, FROM>::value>::type * = nullptr>
450  inline constexpr static bool value(const FROM &from) {
451  return StaticCast<FROM>::value(StaticCast<TO>::value(from)) == from;
452  }
453 
454  template<typename FROM, typename TO2 = TO, typename std::enable_if<std::is_convertible<FROM, TO>::value && !(std::is_arithmetic<TO>::value && std::is_arithmetic<FROM>::value && !std::is_same<TO, FROM>::value)>::type * = nullptr>
455  inline constexpr static bool value(const FROM &from) {
456  return true;
457  }
458 };
459 
460 /** Emit a version of a string that is a valid identifier in C (. is replaced with _) */
461 std::string c_print_name(const std::string &name);
462 
463 /** Return the LLVM_VERSION against which this libHalide is compiled. This is provided
464  * only for internal tests which need to verify behavior; please don't use this outside
465  * of Halide tests. */
467 
468 /** Call the given action in a platform-specific context that provides at least
469  * 8MB of stack space. Currently only has any effect on Windows where it uses
470  * a Fiber. */
471 void run_with_large_stack(const std::function<void()> &action);
472 
473 } // namespace Internal
474 } // namespace Halide
475 
476 #endif
This file declares the routines used by Halide internally in its runtime.
A simple utility class that creates a temporary file in its ctor and deletes that file in its dtor; t...
Definition: Util.h:286
TemporaryFile(TemporaryFile &&)=delete
TemporaryFile & operator=(TemporaryFile &&)=delete
TemporaryFile(const TemporaryFile &)=delete
const std::string & pathname() const
Definition: Util.h:291
TemporaryFile(const std::string &prefix, const std::string &suffix)
Definition: Util.h:288
TemporaryFile & operator=(const TemporaryFile &)=delete
void assert_file_exists(const std::string &name)
assert-fail if the file doesn't exist.
void file_unlink(const std::string &name)
Wrapper for unlink().
std::string make_entity_name(void *stack_ptr, const std::string &type, char prefix)
Make a unique name for an object based on the name of the stack variable passed in.
bool ends_with(const std::string &str, const std::string &suffix)
Test if the first string ends with the second string.
std::vector< std::string > split_string(const std::string &source, const std::string &delim)
Split the source string using 'delim' as the divider.
void run_with_large_stack(const std::function< void()> &action)
Call the given action in a platform-specific context that provides at least 8MB of stack space.
void write_entire_file(const std::string &pathname, const void *source, size_t source_len)
Create or replace the contents of a file with a given pointer-and-length of memory.
std::string file_make_temp(const std::string &prefix, const std::string &suffix)
Create a unique file with a name of the form prefixXXXXXsuffix in an arbitrary (but writable) directo...
int get_llvm_version()
Return the LLVM_VERSION against which this libHalide is compiled.
void dir_rmdir(const std::string &name)
Wrapper for rmdir().
make_integer_sequence< size_t, N > make_index_sequence
Definition: Util.h:402
void halide_toc_impl(const char *file, int line)
bool sub_would_overflow(int bits, int64_t a, int64_t b)
std::string get_env_variable(char const *env_var_name)
Get value of an environment variable.
bool add_would_overflow(int bits, int64_t a, int64_t b)
Routines to test if math would overflow for signed integers with the given number of bits.
std::string extract_namespaces(const std::string &name, std::vector< std::string > &namespaces)
Returns base name and fills in namespaces, outermost one first in vector.
void ensure_no_file_exists(const std::string &name)
Ensure that no file with this path exists.
DstType reinterpret_bits(const SrcType &src)
An aggressive form of reinterpret cast used for correct type-punning.
Definition: Util.h:107
bool mul_would_overflow(int bits, int64_t a, int64_t b)
std::string replace_all(const std::string &str, const std::string &find, const std::string &replace)
Replace all matches of the second string in the first string with the last string.
FileStat file_stat(const std::string &name)
Wrapper for stat().
T fold_left(const std::vector< T > &vec, Fn f)
Perform a left fold of a vector.
Definition: Util.h:166
std::string unique_name(char prefix)
Generate a unique name starting with the given prefix.
std::string running_program_name()
Get the name of the currently running executable.
DST safe_numeric_cast(SRC s)
Some numeric conversions are UB if the value won't fit in the result; safe_numeric_cast<>() is meant ...
Definition: Util.h:71
void assert_no_file_exists(const std::string &name)
assert-fail if the file DOES exist.
std::string dir_make_temp()
Create a unique directory in an arbitrary (but writable) directory; this is typically somewhere insid...
integer_sequence< size_t, Ints... > index_sequence
Definition: Util.h:399
std::string c_print_name(const std::string &name)
Emit a version of a string that is a valid identifier in C (.
std::vector< char > read_entire_file(const std::string &pathname)
Read the entire contents of a file into a vector<char>.
void halide_tic_impl(const char *file, int line)
bool starts_with(const std::string &str, const std::string &prefix)
Test if the first string starts with the second string.
typename make_integer_sequence_helper< T, 0, N >::type make_integer_sequence
Definition: Util.h:396
T fold_right(const std::vector< T > &vec, Fn f)
Returns a right fold of a vector.
Definition: Util.h:181
bool file_exists(const std::string &name)
Wrapper for access().
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
Expr min(const FuncRef &a, const FuncRef &b)
Explicit overloads of min and max for FuncRef.
Definition: Func.h:578
void load_plugin(const std::string &lib_name)
Load a plugin in the form of a dynamic library (e.g.
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:581
char * dst
Definition: printer.h:32
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
__SIZE_TYPE__ size_t
unsigned __INT32_TYPE__ uint32_t
void * memcpy(void *s1, const void *s2, size_t n)
constexpr static bool value(const FROM &from)
Definition: Util.h:445
Helper class for saving/restoring variable values on the stack, to allow for early-exit that preserve...
Definition: Util.h:328
ScopedValue(ScopedValue &&that) noexcept=default
ScopedValue(T &var, T new_value)
Preserve the old value, then set the var to a new value.
Definition: Util.h:336
ScopedValue(T &var)
Preserve the old value, restored at dtor time.
Definition: Util.h:332
ScopedValue(const ScopedValue &that)=delete
constexpr static TO2 value(const FROM &from)
Definition: Util.h:429
static constexpr size_t size()
Definition: Util.h:371
typename next_integer_sequence< typename make_integer_sequence_helper< T, I+1, N >::type >::type type
Definition: Util.h:387