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