#ifndef HALIDE_HALIDERUNTIME_H #define HALIDE_HALIDERUNTIME_H #include <stddef.h> #include <stdint.h> #include <stdbool.h> #ifdef __cplusplus extern "C" { #endif // Note that you should not use "inline" along with HALIDE_ALWAYS_INLINE; // it is not necessary, and may produce warnings for some build configurations. #ifdef _MSC_VER #define HALIDE_ALWAYS_INLINE __forceinline #define HALIDE_NEVER_INLINE __declspec(noinline) #else #define HALIDE_ALWAYS_INLINE __attribute__((always_inline)) inline #define HALIDE_NEVER_INLINE __attribute__((noinline)) #endif /** \file * * This file declares the routines used by Halide internally in its * runtime. On platforms that support weak linking, these can be * replaced with user-defined versions by defining an extern "C" * function with the same name and signature. * * When doing Just In Time (JIT) compilation methods on the Func being * compiled must be called instead. The corresponding methods are * documented below. * * All of these functions take a "void *user_context" parameter as their * first argument; if the Halide kernel that calls back to any of these * functions has been compiled with the UserContext feature set on its Target, * then the value of that pointer passed from the code that calls the * Halide kernel is piped through to the function. * * Some of these are also useful to call when using the default * implementation. E.g. halide_shutdown_thread_pool. * * Note that even on platforms with weak linking, some linker setups * may not respect the override you provide. E.g. if the override is * in a shared library and the halide object files are linked directly * into the output, the builtin versions of the runtime functions will * be called. See your linker documentation for more details. On * Linux, LD_DYNAMIC_WEAK=1 may help. * */ // Forward-declare to suppress warnings if compiling as C. struct halide_buffer_t; /** Types in the halide type system. They can be ints, unsigned ints, * or floats (of various bit-widths), or a handle (which is always 64-bits). * Note that the int/uint/float values do not imply a specific bit width * (the bit width is expected to be encoded in a separate value). */ typedef enum halide_type_code_t { halide_type_int = 0, //!< signed integers halide_type_uint = 1, //!< unsigned integers halide_type_float = 2, //!< floating point numbers halide_type_handle = 3 //!< opaque pointer type (void *) } halide_type_code_t; // Note that while __attribute__ can go before or after the declaration, // __declspec apparently is only allowed before. #ifndef HALIDE_ATTRIBUTE_ALIGN #ifdef _MSC_VER #define HALIDE_ATTRIBUTE_ALIGN(x) __declspec(align(x)) #else #define HALIDE_ATTRIBUTE_ALIGN(x) __attribute__((aligned(x))) #endif #endif /** A runtime tag for a type in the halide type system. Can be ints, * unsigned ints, or floats of various bit-widths (the 'bits' * field). Can also be vectors of the same (by setting the 'lanes' * field to something larger than one). This struct should be * exactly 32-bits in size. */ struct halide_type_t { /** The basic type code: signed integer, unsigned integer, or floating point. */ #if __cplusplus >= 201103L HALIDE_ATTRIBUTE_ALIGN(1) halide_type_code_t code; // halide_type_code_t #else HALIDE_ATTRIBUTE_ALIGN(1) uint8_t code; // halide_type_code_t #endif /** The number of bits of precision of a single scalar value of this type. */ HALIDE_ATTRIBUTE_ALIGN(1) uint8_t bits; /** How many elements in a vector. This is 1 for scalar types. */ HALIDE_ATTRIBUTE_ALIGN(2) uint16_t lanes; #ifdef __cplusplus /** Construct a runtime representation of a Halide type from: * code: The fundamental type from an enum. * bits: The bit size of one element. * lanes: The number of vector elements in the type. */ HALIDE_ALWAYS_INLINE halide_type_t(halide_type_code_t code, uint8_t bits, uint16_t lanes = 1) : code(code), bits(bits), lanes(lanes) { } /** Default constructor is required e.g. to declare halide_trace_event * instances. */ HALIDE_ALWAYS_INLINE halide_type_t() : code((halide_type_code_t)0), bits(0), lanes(0) {} /** Compare two types for equality. */ HALIDE_ALWAYS_INLINE bool operator==(const halide_type_t &other) const { return (code == other.code && bits == other.bits && lanes == other.lanes); } HALIDE_ALWAYS_INLINE bool operator!=(const halide_type_t &other) const { return !(*this == other); } /** Size in bytes for a single element, even if width is not 1, of this type. */ HALIDE_ALWAYS_INLINE int bytes() const { return (bits + 7) / 8; } #endif }; /** An opaque struct containing per-GPU API implementations of the * device functions. */ struct halide_device_interface_impl_t; /** Each GPU API provides a halide_device_interface_t struct pointing * to the code that manages device allocations. You can access these * functions directly from the struct member function pointers, or by * calling the functions declared below. Note that the global * functions are not available when using Halide as a JIT compiler. * If you are using raw halide_buffer_t in that context you must use * the function pointers in the device_interface struct. * * The function pointers below are currently the same for every GPU * API; only the impl field varies. These top-level functions do the * bookkeeping that is common across all GPU APIs, and then dispatch * to more API-specific functions via another set of function pointers * hidden inside the impl field. */ struct halide_device_interface_t { int (*device_malloc)(void *user_context, struct halide_buffer_t *buf, const struct halide_device_interface_t *device_interface); int (*device_free)(void *user_context, struct halide_buffer_t *buf); int (*device_sync)(void *user_context, struct halide_buffer_t *buf); void (*device_release)(void *user_context, const struct halide_device_interface_t *device_interface); int (*copy_to_host)(void *user_context, struct halide_buffer_t *buf); int (*copy_to_device)(void *user_context, struct halide_buffer_t *buf, const struct halide_device_interface_t *device_interface); int (*device_and_host_malloc)(void *user_context, struct halide_buffer_t *buf, const struct halide_device_interface_t *device_interface); int (*device_and_host_free)(void *user_context, struct halide_buffer_t *buf); int (*buffer_copy)(void *user_context, struct halide_buffer_t *src, const struct halide_device_interface_t *dst_device_interface, struct halide_buffer_t *dst); int (*device_crop)(void *user_context, const struct halide_buffer_t *src, struct halide_buffer_t *dst); int (*device_release_crop)(void *user_context, struct halide_buffer_t *buf); int (*wrap_native)(void *user_context, struct halide_buffer_t *buf, uint64_t handle, const struct halide_device_interface_t *device_interface); int (*detach_native)(void *user_context, struct halide_buffer_t *buf); const struct halide_device_interface_impl_t *impl; }; typedef struct halide_dimension_t { int32_t min, extent, stride; // Per-dimension flags. None are defined yet (This is reserved for future use). uint32_t flags; #ifdef __cplusplus HALIDE_ALWAYS_INLINE halide_dimension_t() : min(0), extent(0), stride(0), flags(0) {} HALIDE_ALWAYS_INLINE halide_dimension_t(int32_t m, int32_t e, int32_t s, uint32_t f = 0) : min(m), extent(e), stride(s), flags(f) {} HALIDE_ALWAYS_INLINE bool operator==(const halide_dimension_t &other) const { return (min == other.min) && (extent == other.extent) && (stride == other.stride) && (flags == other.flags); } HALIDE_ALWAYS_INLINE bool operator!=(const halide_dimension_t &other) const { return !(*this == other); } #endif } halide_dimension_t; #ifdef __cplusplus } // extern "C" #endif typedef enum {halide_buffer_flag_host_dirty = 1, halide_buffer_flag_device_dirty = 2} halide_buffer_flags; /** * The raw representation of an image passed around by generated * Halide code. It includes some stuff to track whether the image is * not actually in main memory, but instead on a device (like a * GPU). For a more convenient C++ wrapper, use Halide::Buffer<T>. */ typedef struct halide_buffer_t { /** A device-handle for e.g. GPU memory used to back this buffer. */ uint64_t device; /** The interface used to interpret the above handle. */ const struct halide_device_interface_t *device_interface; /** A pointer to the start of the data in main memory. In terms of * the Halide coordinate system, this is the address of the min * coordinates (defined below). */ uint8_t* host; /** flags with various meanings. */ uint64_t flags; /** The type of each buffer element. */ struct halide_type_t type; /** The dimensionality of the buffer. */ int32_t dimensions; /** The shape of the buffer. Halide does not own this array - you * must manage the memory for it yourself. */ halide_dimension_t *dim; /** Pads the buffer up to a multiple of 8 bytes */ void *padding; } halide_buffer_t; #ifdef __cplusplus namespace { template<typename T> struct check_is_pointer; template<typename T> struct check_is_pointer<T *> {}; } /** Construct the halide equivalent of a C type */ template<typename T> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of() { // Create a compile-time error if T is not a pointer (without // using any includes - this code goes into the runtime). check_is_pointer<T> check; (void)check; return halide_type_t(halide_type_handle, 64); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<float>() { return halide_type_t(halide_type_float, 32); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<double>() { return halide_type_t(halide_type_float, 64); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<bool>() { return halide_type_t(halide_type_uint, 1); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint8_t>() { return halide_type_t(halide_type_uint, 8); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint16_t>() { return halide_type_t(halide_type_uint, 16); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint32_t>() { return halide_type_t(halide_type_uint, 32); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint64_t>() { return halide_type_t(halide_type_uint, 64); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int8_t>() { return halide_type_t(halide_type_int, 8); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int16_t>() { return halide_type_t(halide_type_int, 16); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int32_t>() { return halide_type_t(halide_type_int, 32); } template<> HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int64_t>() { return halide_type_t(halide_type_int, 64); } #endif #endif // HALIDE_HALIDERUNTIME_H