Halide 14.0.0
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
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
48namespace 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. */
60void load_plugin(const std::string &lib_name);
61
62namespace 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 */
69template<typename DST, typename SRC,
70 typename std::enable_if<std::is_floating_point<SRC>::value>::type * = nullptr>
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
86template<typename DST, typename SRC,
87 typename std::enable_if<std::is_integral<SRC>::value>::type * = nullptr>
88DST 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. */
106template<typename DstType, typename SrcType>
107DstType 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. */
117std::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 */
123std::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. */
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// @{
146std::string unique_name(char prefix);
147std::string unique_name(const std::string &prefix);
148// @}
149
150/** Test if the first string starts with the second string */
151bool starts_with(const std::string &str, const std::string &prefix);
152
153/** Test if the first string ends with the second string */
154bool 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 */
157std::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. */
160std::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. */
165template<typename T, typename Fn>
166T 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. */
180template<typename T, typename Fn>
181T 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
193template<typename... T>
194struct meta_and : std::true_type {};
195
196template<typename T1, typename... Args>
197struct meta_and<T1, Args...> : std::integral_constant<bool, T1::value && meta_and<Args...>::value> {};
198
199template<typename... T>
200struct meta_or : std::false_type {};
201
202template<typename T1, typename... Args>
203struct meta_or<T1, Args...> : std::integral_constant<bool, T1::value || meta_or<Args...>::value> {};
204
205template<typename To, typename... Args>
206struct all_are_convertible : meta_and<std::is_convertible<Args, To>...> {};
207
208/** Returns base name and fills in namespaces, outermost one first in vector. */
209std::string extract_namespaces(const std::string &name, std::vector<std::string> &namespaces);
210
211/** Overload that returns base name only */
212std::string extract_namespaces(const std::string &name);
213
214struct 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 */
232std::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 */
240std::string dir_make_temp();
241
242/** Wrapper for access(). Quietly ignores errors. */
243bool file_exists(const std::string &name);
244
245/** assert-fail if the file doesn't exist. useful primarily for testing purposes. */
246void assert_file_exists(const std::string &name);
247
248/** assert-fail if the file DOES exist. useful primarily for testing purposes. */
249void assert_no_file_exists(const std::string &name);
250
251/** Wrapper for unlink(). Asserts upon error. */
252void file_unlink(const std::string &name);
253
254/** Wrapper for unlink(). Quietly ignores errors. */
255void 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. */
259void ensure_no_file_exists(const std::string &name);
260
261/** Wrapper for rmdir(). Asserts upon error. */
262void dir_rmdir(const std::string &name);
263
264/** Wrapper for stat(). Asserts upon error. */
265FileStat 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. */
269std::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. */
274void write_entire_file(const std::string &pathname, const void *source, size_t source_len);
275
276inline 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 */
286class TemporaryFile final {
287public:
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
306private:
307 const std::string temp_path;
308 bool do_unlink = true;
309
310public:
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// @{
320bool add_would_overflow(int bits, int64_t a, int64_t b);
321bool sub_would_overflow(int bits, int64_t a, int64_t b);
322bool 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 */
327template<typename T>
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// Helpers for timing blocks of code. Put 'TIC;' at the start and
352// 'TOC;' at the end. Timing is reported at the toc via
353// debug(0). The calls can be nested and will pretty-print
354// appropriately. Took this idea from matlab via Jon Barron.
355//
356// Note that this uses global state internally, and is not thread-safe
357// at all. Only use it for single-threaded debugging sessions.
358
359void halide_tic_impl(const char *file, int line);
360void halide_toc_impl(const char *file, int line);
361#define HALIDE_TIC Halide::Internal::halide_tic_impl(__FILE__, __LINE__)
362#define HALIDE_TOC Halide::Internal::halide_toc_impl(__FILE__, __LINE__)
363#ifdef COMPILING_HALIDE
364#define TIC HALIDE_TIC
365#define TOC HALIDE_TOC
366#endif
367
368// statically cast a value from one type to another: this is really just
369// some syntactic sugar around static_cast<>() to avoid compiler warnings
370// regarding 'bool' in some compliation configurations.
371template<typename TO>
373 template<typename FROM, typename TO2 = TO, typename std::enable_if<!std::is_same<TO2, bool>::value>::type * = nullptr>
374 inline constexpr static TO2 value(const FROM &from) {
375 return static_cast<TO2>(from);
376 }
377
378 template<typename FROM, typename TO2 = TO, typename std::enable_if<std::is_same<TO2, bool>::value>::type * = nullptr>
379 inline constexpr static TO2 value(const FROM &from) {
380 return from != 0;
381 }
382};
383
384// Like std::is_convertible, but with additional tests for arithmetic types:
385// ensure that the value will roundtrip losslessly (e.g., no integer truncation
386// or dropping of fractional parts).
387template<typename TO>
389 template<typename FROM, typename TO2 = TO, typename std::enable_if<!std::is_convertible<FROM, TO>::value>::type * = nullptr>
390 inline constexpr static bool value(const FROM &from) {
391 return false;
392 }
393
394 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>
395 inline constexpr static bool value(const FROM &from) {
397 }
398
399 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>
400 inline constexpr static bool value(const FROM &from) {
401 return true;
402 }
403};
404
405/** Emit a version of a string that is a valid identifier in C (. is replaced with _)
406 * If prefix_underscore is true (the default), an underscore will be prepended if the
407 * input starts with an alphabetic character to avoid reserved word clashes.
408 */
409std::string c_print_name(const std::string &name, bool prefix_underscore = true);
410
411/** Return the LLVM_VERSION against which this libHalide is compiled. This is provided
412 * only for internal tests which need to verify behavior; please don't use this outside
413 * of Halide tests. */
415
416} // namespace Internal
417
418/** Set how much stack the compiler should use for compilation in
419 * bytes. This can also be set through the environment variable
420 * HL_COMPILER_STACK_SIZE, though this function takes precedence. A
421 * value of zero causes the compiler to just use the calling stack for
422 * all compilation tasks.
423 *
424 * Calling this or setting the environment variable should not be
425 * necessary. It is provided for three kinds of testing:
426 *
427 * First, Halide uses it in our internal tests to make sure
428 * we're not using a silly amount of stack size on some
429 * canary programs to avoid stack usage regressions.
430 *
431 * Second, if you have a mysterious crash inside a generator, you can
432 * set a larger stack size as a way to test if it's a stack
433 * overflow. Perhaps our default stack size is not large enough for
434 * your program and schedule. Use this call or the environment var as
435 * a workaround, and then open a bug with a reproducer at
436 * github.com/halide/Halide/issues so that we can determine what's
437 * going wrong that is causing your code to use so much stack.
438 *
439 * Third, perhaps using a side-stack is causing problems with
440 * sanitizing, debugging, or profiling tools. If this is a problem,
441 * you can set HL_COMPILER_STACK_SIZE to zero to make Halide stay on
442 * the main thread's stack.
443 */
445
446/** The default amount of stack used for lowering and codegen. 32 MB
447 * ought to be enough for anyone. */
448constexpr size_t default_compiler_stack_size = 32 * 1024 * 1024;
449
450/** Return how much stack size the compiler should use for calls that
451 * go through run_with_large_stack below. Currently that's lowering
452 * and codegen. If no call to set_compiler_stack_size has been made,
453 * this checks the value of the environment variable
454 * HL_COMPILER_STACK_SIZE. If that's unset, it returns
455 * default_compiler_stack_size, defined above. */
457
458namespace Internal {
459
460/** Call the given action in a platform-specific context that
461 * provides at least the stack space returned by
462 * get_compiler_stack_size. If that value is zero, just calls the
463 * function on the calling thread. Otherwise on Windows this
464 * uses a Fiber, and on other platforms it uses swapcontext. */
465void run_with_large_stack(const std::function<void()> &action);
466
467/** Portable versions of popcount, count-leading-zeros, and
468 count-trailing-zeros. */
469// @{
473// @}
474
475} // namespace Internal
476} // namespace Halide
477
478#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 & operator=(TemporaryFile &&)=delete
TemporaryFile(TemporaryFile &&)=delete
TemporaryFile & operator=(const TemporaryFile &)=delete
const std::string & pathname() const
Definition: Util.h:291
TemporaryFile(const TemporaryFile &)=delete
TemporaryFile(const std::string &prefix, const std::string &suffix)
Definition: Util.h:288
void assert_file_exists(const std::string &name)
assert-fail if the file doesn't exist.
int ctz64(uint64_t x)
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.
void run_with_large_stack(const std::function< void()> &action)
Call the given action in a platform-specific context that provides at least the stack space returned ...
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::vector< char > read_entire_file(const std::string &pathname)
Read the entire contents of a file into a vector<char>.
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().
std::string c_print_name(const std::string &name, bool prefix_underscore=true)
Emit a version of a string that is a valid identifier in C (.
int clz64(uint64_t x)
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().
std::vector< std::string > split_string(const std::string &source, const std::string &delim)
Split the source string using 'delim' as the divider.
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...
int popcount64(uint64_t x)
Portable versions of popcount, count-leading-zeros, and count-trailing-zeros.
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.
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.
constexpr size_t default_compiler_stack_size
The default amount of stack used for lowering and codegen.
Definition: Util.h:448
size_t get_compiler_stack_size()
Return how much stack size the compiler should use for calls that go through run_with_large_stack bel...
Expr min(const FuncRef &a, const FuncRef &b)
Explicit overloads of min and max for FuncRef.
Definition: Func.h:600
void load_plugin(const std::string &lib_name)
Load a plugin in the form of a dynamic library (e.g.
void set_compiler_stack_size(size_t)
Set how much stack the compiler should use for compilation in bytes.
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:603
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
void * memcpy(void *s1, const void *s2, size_t n)
unsigned __INT32_TYPE__ uint32_t
static constexpr bool value(const FROM &from)
Definition: Util.h:390
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
static constexpr TO2 value(const FROM &from)
Definition: Util.h:374