Halide  17.0.2
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 <sstream>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 #include "runtime/HalideRuntime.h"
26 
27 #ifdef Halide_STATIC_DEFINE
28 #define HALIDE_EXPORT
29 #else
30 #if defined(_MSC_VER)
31 // Halide_EXPORTS is quietly defined by CMake when building a shared library
32 #ifdef Halide_EXPORTS
33 #define HALIDE_EXPORT __declspec(dllexport)
34 #else
35 #define HALIDE_EXPORT __declspec(dllimport)
36 #endif
37 #else
38 #define HALIDE_EXPORT __attribute__((visibility("default")))
39 #endif
40 #endif
41 
42 // If we're in user code, we don't want certain functions to be inlined.
43 #if defined(COMPILING_HALIDE) || defined(BUILDING_PYTHON)
44 #define HALIDE_NO_USER_CODE_INLINE
45 #else
46 #define HALIDE_NO_USER_CODE_INLINE HALIDE_NEVER_INLINE
47 #endif
48 
49 // Clang uses __has_feature() for sanitizers...
50 #if defined(__has_feature)
51 #if __has_feature(address_sanitizer)
52 #define HALIDE_INTERNAL_USING_ASAN
53 #endif
54 #if __has_feature(memory_sanitizer)
55 #define HALIDE_INTERNAL_USING_MSAN
56 #endif
57 #if __has_feature(thread_sanitizer)
58 #define HALIDE_INTERNAL_USING_TSAN
59 #endif
60 #if __has_feature(coverage_sanitizer)
61 #define HALIDE_INTERNAL_USING_COVSAN
62 #endif
63 #if __has_feature(undefined_behavior_sanitizer)
64 #define HALIDE_INTERNAL_USING_UBSAN
65 #endif
66 #endif
67 
68 // ...but GCC/MSVC don't like __has_feature, so handle them separately.
69 // (Only AddressSanitizer for now, not sure if any others are well-supported
70 // outside of Clang.
71 #if defined(__SANITIZE_ADDRESS__) && !defined(HALIDE_INTERNAL_USING_ASAN)
72 #define HALIDE_INTERNAL_USING_ASAN
73 #endif
74 
75 namespace Halide {
76 
77 /** Load a plugin in the form of a dynamic library (e.g. for custom autoschedulers).
78  * If the string doesn't contain any . characters, the proper prefix and/or suffix
79  * for the platform will be added:
80  *
81  * foo -> libfoo.so (Linux/OSX/etc -- note that .dylib is not supported)
82  * foo -> foo.dll (Windows)
83  *
84  * otherwise, it is assumed to be an appropriate pathname.
85  *
86  * Any error in loading will assert-fail. */
87 void load_plugin(const std::string &lib_name);
88 
89 namespace Internal {
90 
91 /** Some numeric conversions are UB if the value won't fit in the result;
92  * safe_numeric_cast<>() is meant as a drop-in replacement for a C/C++ cast
93  * that adds well-defined behavior for the UB cases, attempting to mimic
94  * common implementation behavior as much as possible.
95  */
96 template<typename DST, typename SRC,
97  typename std::enable_if<std::is_floating_point<SRC>::value>::type * = nullptr>
98 DST safe_numeric_cast(SRC s) {
99  if (std::is_integral<DST>::value) {
100  // Treat float -> int as a saturating cast; this is handled
101  // in different ways by different compilers, so an arbitrary but safe
102  // choice like this is reasonable.
103  if (s < (SRC)std::numeric_limits<DST>::min()) {
105  }
106  if (s > (SRC)std::numeric_limits<DST>::max()) {
108  }
109  }
110  return (DST)s;
111 }
112 
113 template<typename DST, typename SRC,
114  typename std::enable_if<std::is_integral<SRC>::value>::type * = nullptr>
115 DST safe_numeric_cast(SRC s) {
116  if (std::is_integral<DST>::value) {
117  // any-int -> signed-int is technically UB if value won't fit;
118  // in practice, common compilers implement such conversions as done below
119  // (as verified by exhaustive testing on Clang for x86-64). We could
120  // probably continue to rely on that behavior, but making it explicit
121  // avoids possible wrather of UBSan and similar debug helpers.
122  // (Yes, using sizeof for this comparison is a little odd for the uint->int
123  // case, but the intent is to match existing common behavior, which this does.)
124  if (std::is_integral<SRC>::value && std::is_signed<DST>::value && sizeof(DST) < sizeof(SRC)) {
125  using UnsignedSrc = typename std::make_unsigned<SRC>::type;
126  return (DST)(s & (UnsignedSrc)(-1));
127  }
128  }
129  return (DST)s;
130 }
131 
132 /** An aggressive form of reinterpret cast used for correct type-punning. */
133 template<typename DstType, typename SrcType>
134 DstType reinterpret_bits(const SrcType &src) {
135  static_assert(sizeof(SrcType) == sizeof(DstType), "Types must be same size");
136  DstType dst;
137  memcpy(&dst, &src, sizeof(SrcType));
138  return dst;
139 }
140 
141 /** Make a unique name for an object based on the name of the stack
142  * variable passed in. If introspection isn't working or there are no
143  * debug symbols, just uses unique_name with the given prefix. */
144 std::string make_entity_name(void *stack_ptr, const std::string &type, char prefix);
145 
146 /** Get value of an environment variable. Returns its value
147  * is defined in the environment. If the var is not defined, an empty string
148  * is returned.
149  */
150 std::string get_env_variable(char const *env_var_name);
151 
152 /** Get the name of the currently running executable. Platform-specific.
153  * If program name cannot be retrieved, function returns an empty string. */
154 std::string running_program_name();
155 
156 /** Generate a unique name starting with the given prefix. It's unique
157  * relative to all other strings returned by unique_name in this
158  * process.
159  *
160  * The single-character version always appends a numeric suffix to the
161  * character.
162  *
163  * The string version will either return the input as-is (with high
164  * probability on the first time it is called with that input), or
165  * replace any existing '$' characters with underscores, then add a
166  * '$' sign and a numeric suffix to it.
167  *
168  * Note that unique_name('f') therefore differs from
169  * unique_name("f"). The former returns something like f123, and the
170  * latter returns either f or f$123.
171  */
172 // @{
173 std::string unique_name(char prefix);
174 std::string unique_name(const std::string &prefix);
175 // @}
176 
177 /** Test if the first string starts with the second string */
178 bool starts_with(const std::string &str, const std::string &prefix);
179 
180 /** Test if the first string ends with the second string */
181 bool ends_with(const std::string &str, const std::string &suffix);
182 
183 /** Replace all matches of the second string in the first string with the last string */
184 std::string replace_all(const std::string &str, const std::string &find, const std::string &replace);
185 
186 /** Split the source string using 'delim' as the divider. */
187 std::vector<std::string> split_string(const std::string &source, const std::string &delim);
188 
189 /** Join the source vector using 'delim' as the divider. */
190 template<typename T>
191 std::string join_strings(const std::vector<T> &sources, const std::string &delim) {
192  size_t sz = 0;
193  if (!sources.empty()) {
194  sz += delim.size() * (sources.size() - 1);
195  }
196  for (const auto &s : sources) {
197  sz += s.size();
198  }
199  std::string result;
200  result.reserve(sz);
201  bool need_delim = false;
202  for (const auto &s : sources) {
203  if (need_delim) {
204  result += delim;
205  }
206  result += s;
207  need_delim = true;
208  }
209  return result;
210 }
211 
212 /** Perform a left fold of a vector. Returns a default-constructed
213  * vector element if the vector is empty. Similar to std::accumulate
214  * but with a less clunky syntax. */
215 template<typename T, typename Fn>
216 T fold_left(const std::vector<T> &vec, Fn f) {
217  T result;
218  if (vec.empty()) {
219  return result;
220  }
221  result = vec[0];
222  for (size_t i = 1; i < vec.size(); i++) {
223  result = f(result, vec[i]);
224  }
225  return result;
226 }
227 
228 /** Returns a right fold of a vector. Returns a default-constructed
229  * vector element if the vector is empty. */
230 template<typename T, typename Fn>
231 T fold_right(const std::vector<T> &vec, Fn f) {
232  T result;
233  if (vec.empty()) {
234  return result;
235  }
236  result = vec.back();
237  for (size_t i = vec.size() - 1; i > 0; i--) {
238  result = f(vec[i - 1], result);
239  }
240  return result;
241 }
242 
243 template<typename... T>
244 struct meta_and : std::true_type {};
245 
246 template<typename T1, typename... Args>
247 struct meta_and<T1, Args...> : std::integral_constant<bool, T1::value && meta_and<Args...>::value> {};
248 
249 template<typename... T>
250 struct meta_or : std::false_type {};
251 
252 template<typename T1, typename... Args>
253 struct meta_or<T1, Args...> : std::integral_constant<bool, T1::value || meta_or<Args...>::value> {};
254 
255 template<typename To, typename... Args>
256 struct all_are_convertible : meta_and<std::is_convertible<Args, To>...> {};
257 
258 /** Returns base name and fills in namespaces, outermost one first in vector. */
259 std::string extract_namespaces(const std::string &name, std::vector<std::string> &namespaces);
260 
261 /** Like extract_namespaces(), but strip and discard the namespaces, returning base name only */
262 std::string strip_namespaces(const std::string &name);
263 
264 struct FileStat {
266  uint32_t mod_time; // Unix epoch time
270 };
271 
272 /** Create a unique file with a name of the form prefixXXXXXsuffix in an arbitrary
273  * (but writable) directory; this is typically /tmp, but the specific
274  * location is not guaranteed. (Note that the exact form of the file name
275  * may vary; in particular, the suffix may be ignored on Windows.)
276  * The file is created (but not opened), thus this can be called from
277  * different threads (or processes, e.g. when building with parallel make)
278  * without risking collision. Note that if this file is used as a temporary
279  * file, the caller is responsibly for deleting it. Neither the prefix nor suffix
280  * may contain a directory separator.
281  */
282 std::string file_make_temp(const std::string &prefix, const std::string &suffix);
283 
284 /** Create a unique directory in an arbitrary (but writable) directory; this is
285  * typically somewhere inside /tmp, but the specific location is not guaranteed.
286  * The directory will be empty (i.e., this will never return /tmp itself,
287  * but rather a new directory inside /tmp). The caller is responsible for removing the
288  * directory after use.
289  */
290 std::string dir_make_temp();
291 
292 /** Wrapper for access(). Quietly ignores errors. */
293 bool file_exists(const std::string &name);
294 
295 /** assert-fail if the file doesn't exist. useful primarily for testing purposes. */
296 void assert_file_exists(const std::string &name);
297 
298 /** assert-fail if the file DOES exist. useful primarily for testing purposes. */
299 void assert_no_file_exists(const std::string &name);
300 
301 /** Wrapper for unlink(). Asserts upon error. */
302 void file_unlink(const std::string &name);
303 
304 /** Wrapper for unlink(). Quietly ignores errors. */
305 void file_unlink(const std::string &name);
306 
307 /** Ensure that no file with this path exists. If such a file
308  * exists and cannot be removed, assert-fail. */
309 void ensure_no_file_exists(const std::string &name);
310 
311 /** Wrapper for rmdir(). Asserts upon error. */
312 void dir_rmdir(const std::string &name);
313 
314 /** Wrapper for stat(). Asserts upon error. */
315 FileStat file_stat(const std::string &name);
316 
317 /** Read the entire contents of a file into a vector<char>. The file
318  * is read in binary mode. Errors trigger an assertion failure. */
319 std::vector<char> read_entire_file(const std::string &pathname);
320 
321 /** Create or replace the contents of a file with a given pointer-and-length
322  * of memory. If the file doesn't exist, it is created; if it does exist, it
323  * is completely overwritten. Any error triggers an assertion failure. */
324 void write_entire_file(const std::string &pathname, const void *source, size_t source_len);
325 
326 inline void write_entire_file(const std::string &pathname, const std::vector<char> &source) {
327  write_entire_file(pathname, source.data(), source.size());
328 }
329 
330 /** A simple utility class that creates a temporary file in its ctor and
331  * deletes that file in its dtor; this is useful for temporary files that you
332  * want to ensure are deleted when exiting a certain scope. Since this is essentially
333  * just an RAII wrapper around file_make_temp() and file_unlink(), it has the same
334  * failure modes (i.e.: assertion upon error).
335  */
336 class TemporaryFile final {
337 public:
338  TemporaryFile(const std::string &prefix, const std::string &suffix)
339  : temp_path(file_make_temp(prefix, suffix)) {
340  }
341  const std::string &pathname() const {
342  return temp_path;
343  }
345  if (do_unlink) {
346  file_unlink(temp_path);
347  }
348  }
349  // You can call this if you want to defeat the automatic deletion;
350  // this is rarely what you want to do (since it defeats the purpose
351  // of this class), but can be quite handy for debugging purposes.
352  void detach() {
353  do_unlink = false;
354  }
355 
356 private:
357  const std::string temp_path;
358  bool do_unlink = true;
359 
360 public:
361  TemporaryFile(const TemporaryFile &) = delete;
365 };
366 
367 /** Routines to test if math would overflow for signed integers with
368  * the given number of bits. */
369 // @{
370 bool add_would_overflow(int bits, int64_t a, int64_t b);
371 bool sub_would_overflow(int bits, int64_t a, int64_t b);
372 bool mul_would_overflow(int bits, int64_t a, int64_t b);
373 // @}
374 
375 /** Routines to perform arithmetic on signed types without triggering signed
376  * overflow. If overflow would occur, sets result to zero, and returns
377  * false. Otherwise set result to the correct value, and returns true. */
378 // @{
382 // @}
383 
384 /** Helper class for saving/restoring variable values on the stack, to allow
385  * for early-exit that preserves correctness */
386 template<typename T>
387 struct ScopedValue {
388  T &var;
390  /** Preserve the old value, restored at dtor time */
392  : var(var), old_value(var) {
393  }
394  /** Preserve the old value, then set the var to a new value. */
395  ScopedValue(T &var, T new_value)
396  : var(var), old_value(var) {
397  var = new_value;
398  }
400  var = old_value;
401  }
402  operator T() const {
403  return old_value;
404  }
405  // allow move but not copy
406  ScopedValue(const ScopedValue &that) = delete;
407  ScopedValue(ScopedValue &&that) noexcept = default;
408 };
409 
410 // Helpers for timing blocks of code. Put 'TIC;' at the start and
411 // 'TOC;' at the end. Timing is reported at the toc via
412 // debug(0). The calls can be nested and will pretty-print
413 // appropriately. Took this idea from matlab via Jon Barron.
414 //
415 // Note that this uses global state internally, and is not thread-safe
416 // at all. Only use it for single-threaded debugging sessions.
417 
418 void halide_tic_impl(const char *file, int line);
419 void halide_toc_impl(const char *file, int line);
420 #define HALIDE_TIC Halide::Internal::halide_tic_impl(__FILE__, __LINE__)
421 #define HALIDE_TOC Halide::Internal::halide_toc_impl(__FILE__, __LINE__)
422 #ifdef COMPILING_HALIDE
423 #define TIC HALIDE_TIC
424 #define TOC HALIDE_TOC
425 #endif
426 
427 // statically cast a value from one type to another: this is really just
428 // some syntactic sugar around static_cast<>() to avoid compiler warnings
429 // regarding 'bool' in some compliation configurations.
430 template<typename TO>
431 struct StaticCast {
432  template<typename FROM>
433  inline constexpr static TO value(const FROM &from) {
434  if constexpr (std::is_same<TO, bool>::value) {
435  return from != 0;
436  } else {
437  return static_cast<TO>(from);
438  }
439  }
440 };
441 
442 // Like std::is_convertible, but with additional tests for arithmetic types:
443 // ensure that the value will roundtrip losslessly (e.g., no integer truncation
444 // or dropping of fractional parts).
445 template<typename TO>
447  template<typename FROM>
448  inline constexpr static bool value(const FROM &from) {
449  if constexpr (std::is_convertible<FROM, TO>::value) {
450  if constexpr (std::is_arithmetic<TO>::value &&
451  std::is_arithmetic<FROM>::value &&
452  !std::is_same<TO, FROM>::value) {
453  const TO to = static_cast<TO>(from);
454  const FROM roundtripped = static_cast<FROM>(to);
455  return roundtripped == from;
456  } else {
457  return true;
458  }
459  } else {
460  return false;
461  }
462  }
463 };
464 
465 /** Emit a version of a string that is a valid identifier in C (. is replaced with _)
466  * If prefix_underscore is true (the default), an underscore will be prepended if the
467  * input starts with an alphabetic character to avoid reserved word clashes.
468  */
469 std::string c_print_name(const std::string &name, bool prefix_underscore = true);
470 
471 /** Return the LLVM_VERSION against which this libHalide is compiled. This is provided
472  * only for internal tests which need to verify behavior; please don't use this outside
473  * of Halide tests. */
475 
476 } // namespace Internal
477 
478 /** Set how much stack the compiler should use for compilation in
479  * bytes. This can also be set through the environment variable
480  * HL_COMPILER_STACK_SIZE, though this function takes precedence. A
481  * value of zero causes the compiler to just use the calling stack for
482  * all compilation tasks.
483  *
484  * Calling this or setting the environment variable should not be
485  * necessary. It is provided for three kinds of testing:
486  *
487  * First, Halide uses it in our internal tests to make sure
488  * we're not using a silly amount of stack size on some
489  * canary programs to avoid stack usage regressions.
490  *
491  * Second, if you have a mysterious crash inside a generator, you can
492  * set a larger stack size as a way to test if it's a stack
493  * overflow. Perhaps our default stack size is not large enough for
494  * your program and schedule. Use this call or the environment var as
495  * a workaround, and then open a bug with a reproducer at
496  * github.com/halide/Halide/issues so that we can determine what's
497  * going wrong that is causing your code to use so much stack.
498  *
499  * Third, perhaps using a side-stack is causing problems with
500  * sanitizing, debugging, or profiling tools. If this is a problem,
501  * you can set HL_COMPILER_STACK_SIZE to zero to make Halide stay on
502  * the main thread's stack.
503  */
505 
506 /** The default amount of stack used for lowering and codegen. 32 MB
507  * ought to be enough for anyone. */
508 constexpr size_t default_compiler_stack_size = 32 * 1024 * 1024;
509 
510 /** Return how much stack size the compiler should use for calls that
511  * go through run_with_large_stack below. Currently that's lowering
512  * and codegen. If no call to set_compiler_stack_size has been made,
513  * this checks the value of the environment variable
514  * HL_COMPILER_STACK_SIZE. If that's unset, it returns
515  * default_compiler_stack_size, defined above. */
517 
518 namespace Internal {
519 
520 /** Call the given action in a platform-specific context that
521  * provides at least the stack space returned by
522  * get_compiler_stack_size. If that value is zero, just calls the
523  * function on the calling thread. Otherwise on Windows this
524  * uses a Fiber, and on other platforms it uses swapcontext. */
525 void run_with_large_stack(const std::function<void()> &action);
526 
527 /** Portable versions of popcount, count-leading-zeros, and
528  count-trailing-zeros. */
529 // @{
533 // @}
534 
535 } // namespace Internal
536 } // namespace Halide
537 
538 #endif
This file declares the routines used by Halide internally in its runtime.
#define HALIDE_MUST_USE_RESULT
Definition: HalideRuntime.h:65
A simple utility class that creates a temporary file in its ctor and deletes that file in its dtor; t...
Definition: Util.h:336
TemporaryFile(TemporaryFile &&)=delete
TemporaryFile & operator=(TemporaryFile &&)=delete
TemporaryFile(const TemporaryFile &)=delete
const std::string & pathname() const
Definition: Util.h:341
TemporaryFile(const std::string &prefix, const std::string &suffix)
Definition: Util.h:338
TemporaryFile & operator=(const TemporaryFile &)=delete
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.
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 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::string join_strings(const std::vector< T > &sources, const std::string &delim)
Join the source vector using 'delim' as the divider.
Definition: Util.h:191
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)
HALIDE_MUST_USE_RESULT bool add_with_overflow(int bits, int64_t a, int64_t b, int64_t *result)
Routines to perform arithmetic on signed types without triggering signed overflow.
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.
HALIDE_MUST_USE_RESULT bool mul_with_overflow(int bits, int64_t a, int64_t b, int64_t *result)
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:134
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:216
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:98
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.
std::vector< char > read_entire_file(const std::string &pathname)
Read the entire contents of a file into a vector<char>.
HALIDE_MUST_USE_RESULT bool sub_with_overflow(int bits, int64_t a, int64_t b, int64_t *result)
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.
std::string strip_namespaces(const std::string &name)
Like extract_namespaces(), but strip and discard the namespaces, returning base name only.
T fold_right(const std::vector< T > &vec, Fn f)
Returns a right fold of a vector.
Definition: Util.h:231
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:508
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:603
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:606
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_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:448
Helper class for saving/restoring variable values on the stack, to allow for early-exit that preserve...
Definition: Util.h:387
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:395
ScopedValue(T &var)
Preserve the old value, restored at dtor time.
Definition: Util.h:391
ScopedValue(const ScopedValue &that)=delete
constexpr static TO value(const FROM &from)
Definition: Util.h:433