| // Copyright 2019 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // API Versioning |
| // ----------------------------------------------------------------------------- |
| // |
| // The C API is designed to be versioned such that breaking changes either in |
| // ABI (data types, struct sizes, etc) or signatures (function arguments change) |
| // will result in a bump of the IREE_API_VERSION_LATEST value. |
| // |
| // When linked in statically the runtime should never have a version conflict, |
| // however dynamic linking where the runtime is a shared object loaded at |
| // runtime (via dlopen/etc) must always verify the version is as expected. |
| // |
| // In the current experimental state of the runtime the API may break frequently |
| // and the version is pinned at 0. |
| // |
| // Example: |
| // void* library = dlopen("iree_rt.so", RTLD_LAZY | RTLD_LOCAL); |
| // iree_api_version_t actual_version; |
| // iree_status_t status = \ |
| // ((PFN_iree_api_version_check)dlsym(library, "iree_api_version_check"))( |
| // IREE_API_VERSION_LATEST, &actual_version); |
| // IREE_CHECK_OK(status); |
| // dlclose(library); |
| // |
| // Object Ownership and Lifetime |
| // ----------------------------------------------------------------------------- |
| // |
| // The API follows the CoreFoundation ownership policies: |
| // https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html |
| // |
| // These boil down to: |
| // * Objects returned from *_create or *_copy functions are owned by the caller |
| // and must be released when the caller no longer needs them. |
| // * Objects returned from accessors are not owned by the caller and must be |
| // retained by the caller if the object lifetime needs to be extended. |
| // * Objects passed to functions by argument may be retained by the callee if |
| // required. |
| // |
| // Example: |
| // iree_file_mapping_t* file_mapping; |
| // s = iree_file_mapping_open_read(..., &file_mapping); |
| // // file_mapping is now owned by this function. |
| // s = iree_file_mapping_some_call(file_mapping, ...); |
| // // Must release ownership when no longer required. |
| // s = iree_file_mapping_release(file_mapping); |
| // |
| // String Formatting |
| // ----------------------------------------------------------------------------- |
| // |
| // Functions that produce variable-length strings follow a standard usage |
| // pattern with the arguments: |
| // `iree_host_size_t buffer_capacity`: total bytes including \0 available. |
| // `char* buffer`: optional buffer to write into. |
| // `iree_host_size_t* out_buffer_length`: required/actual length excluding \0. |
| // |
| // To query the size required for the output and allocate storage: |
| // iree_host_size_t required_length = 0; |
| // iree_format_xyz(/*buffer_capacity=*/0, /*buffer=*/NULL, &required_length); |
| // iree_host_size_t buffer_capacity = required_length + 1; |
| // char* buffer = iree_allocator_malloc(buffer_capacity); |
| // iree_host_size_t actual_length = 0; |
| // iree_format_xyz(buffer_capacity, buffer, &actual_length); |
| // ASSERT(required_length == actual_length); |
| // |
| // To handle fixed-length maximum strings (common): |
| // // Fails if the string is longer than 127 characters (127 + \0 >= 128). |
| // char buffer[128]; |
| // IREE_RETURN_IF_ERROR(iree_format_xyz(sizeof(buffer), buffer, NULL)); |
| // |
| // Try fixed-length and fallback to a dynamic allocation: |
| // char inline_buffer[128]; |
| // iree_host_size_t required_length = 0; |
| // iree_status_t inline_status = iree_format_xyz(sizeof(inline_buffer), |
| // inline_buffer, |
| // &required_length); |
| // if (iree_status_is_out_of_range(inline_status)) { |
| // // Spilled inline_buffer, need to allocate required_length bytes and |
| // // try again. |
| // // ... see above for example ... |
| // } else if (iree_status_is_ok(inline_status)) { |
| // // Fit inside inline_buffer, required_length contains actual length. |
| // } else { |
| // return inline_status; |
| // } |
| |
| #ifndef IREE_BASE_API_H_ |
| #define IREE_BASE_API_H_ |
| |
| #include <assert.h> |
| #include <memory.h> |
| #include <stdarg.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "iree/base/alignment.h" |
| #include "iree/base/attributes.h" |
| #include "iree/base/config.h" |
| |
| #if defined(_WIN32) |
| // The safe malloca that may fall back to heap in the case of stack overflows: |
| // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/malloca?view=vs-2019 |
| // Because that gets really annoying to deal with during error handling we just |
| // go for _alloca which may generate SEH exceptions if we blow the stack. |
| #include <malloc.h> |
| #define iree_alloca(sz) _alloca(sz) |
| #else |
| #include <alloca.h> |
| #define iree_alloca(sz) alloca(sz) |
| #endif // _WIN32 |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif // __cplusplus |
| |
| //===----------------------------------------------------------------------===// |
| // Types and Enums |
| //===----------------------------------------------------------------------===// |
| |
| // Returns the number of elements in an array as a compile-time constant, which |
| // can be used in defining new arrays. Fails at compile-time if |arr| is not a |
| // static array (such as if used on a pointer type). |
| // |
| // Example: |
| // uint8_t kConstantArray[512]; |
| // assert(IREE_ARRAYSIZE(kConstantArray) == 512); |
| #define IREE_ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0])) |
| |
| #define iree_min(lhs, rhs) ((lhs) <= (rhs) ? (lhs) : (rhs)) |
| #define iree_max(lhs, rhs) ((lhs) <= (rhs) ? (rhs) : (lhs)) |
| |
| // Returns true if any bit from |rhs| is set in |lhs|. |
| #define iree_any_bit_set(lhs, rhs) (((lhs) & (rhs)) != 0) |
| // Returns true iff all bits from |rhs| are set in |lhs|. |
| #define iree_all_bits_set(lhs, rhs) (((lhs) & (rhs)) == (rhs)) |
| |
| //===----------------------------------------------------------------------===// |
| // Byte buffers and memory utilities |
| //===----------------------------------------------------------------------===// |
| |
| // A span of mutable bytes (ala std::span of uint8_t). |
| typedef struct { |
| uint8_t* data; |
| iree_host_size_t data_length; |
| } iree_byte_span_t; |
| |
| static inline iree_byte_span_t iree_make_byte_span( |
| void* data, iree_host_size_t data_length) { |
| iree_byte_span_t v = {(uint8_t*)data, data_length}; |
| return v; |
| } |
| |
| // A span of constant bytes (ala std::span of const uint8_t). |
| typedef struct { |
| const uint8_t* data; |
| iree_host_size_t data_length; |
| } iree_const_byte_span_t; |
| |
| static inline iree_const_byte_span_t iree_make_const_byte_span( |
| const void* data, iree_host_size_t data_length) { |
| iree_const_byte_span_t v = {(const uint8_t*)data, data_length}; |
| return v; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // iree_string_view_t (like std::string_view/absl::string_view) |
| //===----------------------------------------------------------------------===// |
| |
| #define IREE_STRING_VIEW_NPOS SIZE_MAX |
| |
| // A string view (ala std::string_view) into a non-NUL-terminated string. |
| typedef struct { |
| const char* data; |
| iree_host_size_t size; |
| } iree_string_view_t; |
| |
| // Returns an empty string view (""). |
| static inline iree_string_view_t iree_string_view_empty() { |
| iree_string_view_t v = {0, 0}; |
| return v; |
| } |
| |
| // Returns true if the given string view is the empty string. |
| #define iree_string_view_is_empty(sv) (((sv).data == NULL) || ((sv).size == 0)) |
| |
| static inline iree_string_view_t iree_make_string_view( |
| const char* str, iree_host_size_t str_length) { |
| iree_string_view_t v = {str, str_length}; |
| return v; |
| } |
| |
| // Returns a string view initialized with a reference to the given |
| // NUL-terminated string literal. |
| static inline iree_string_view_t iree_make_cstring_view(const char* str) { |
| iree_string_view_t v = {str, strlen(str)}; |
| return v; |
| } |
| |
| #define iree_string_view_literal(str) \ |
| { .data = (str), .size = IREE_ARRAYSIZE(str) - 1 } |
| |
| // Returns a string view initialized with the given cstring. |
| #define IREE_SV(cstr) iree_make_cstring_view(cstr) |
| |
| // Returns true if the two strings are equal (compare == 0). |
| IREE_API_EXPORT bool iree_string_view_equal(iree_string_view_t lhs, |
| iree_string_view_t rhs); |
| |
| // Like std::string::compare but with iree_string_view_t values. |
| IREE_API_EXPORT int iree_string_view_compare(iree_string_view_t lhs, |
| iree_string_view_t rhs); |
| |
| // Finds the first occurrence of |c| in |value| starting at |pos|. |
| // Returns the found character position or IREE_STRING_VIEW_NPOS if not found. |
| IREE_API_EXPORT iree_host_size_t iree_string_view_find_char( |
| iree_string_view_t value, char c, iree_host_size_t pos); |
| |
| // Returns the index of the first occurrence of one of the characters in |s| or |
| // -1 if none of the characters were found. |
| IREE_API_EXPORT iree_host_size_t iree_string_view_find_first_of( |
| iree_string_view_t value, iree_string_view_t s, iree_host_size_t pos); |
| |
| // Returns the index of the last occurrence of one of the characters in |s| or |
| // -1 if none of the characters were found. |
| IREE_API_EXPORT iree_host_size_t iree_string_view_find_last_of( |
| iree_string_view_t value, iree_string_view_t s, iree_host_size_t pos); |
| |
| // Returns true if the string starts with the given prefix. |
| IREE_API_EXPORT bool iree_string_view_starts_with(iree_string_view_t value, |
| iree_string_view_t prefix); |
| |
| // Returns true if the string starts with the given suffix. |
| IREE_API_EXPORT bool iree_string_view_ends_with(iree_string_view_t value, |
| iree_string_view_t suffix); |
| |
| // Removes the first |n| characters from the string view (not the data). |
| IREE_API_EXPORT iree_string_view_t |
| iree_string_view_remove_prefix(iree_string_view_t value, iree_host_size_t n); |
| |
| // Removes the last |n| characters from the string view (not the data). |
| IREE_API_EXPORT iree_string_view_t |
| iree_string_view_remove_suffix(iree_string_view_t value, iree_host_size_t n); |
| |
| // Removes the given substring prefix from the string view if present. |
| IREE_API_EXPORT iree_string_view_t iree_string_view_strip_prefix( |
| iree_string_view_t value, iree_string_view_t prefix); |
| |
| // Removes the given substring suffix from the string view if present. |
| IREE_API_EXPORT iree_string_view_t iree_string_view_strip_suffix( |
| iree_string_view_t value, iree_string_view_t suffix); |
| |
| // Removes the given substring prefix from the string view if present in-place. |
| // Returns true if the strip succeeded. |
| IREE_API_EXPORT bool iree_string_view_consume_prefix(iree_string_view_t* value, |
| iree_string_view_t prefix); |
| |
| // Removes the given substring suffix from the string view if present in-place. |
| // Returns true if the strip succeeded. |
| IREE_API_EXPORT bool iree_string_view_consume_suffix(iree_string_view_t* value, |
| iree_string_view_t suffix); |
| |
| // Removes leading and trailing whitespace. |
| IREE_API_EXPORT iree_string_view_t |
| iree_string_view_trim(iree_string_view_t value); |
| |
| // Returns a substring of the string view at offset |pos| and length |n|. |
| // Use |n| == INTPTR_MAX to take the remaineder of the string after |pos|. |
| // Returns empty string on failure. |
| IREE_API_EXPORT iree_string_view_t iree_string_view_substr( |
| iree_string_view_t value, iree_host_size_t pos, iree_host_size_t n); |
| |
| // Splits |value| into two parts based on the first occurrence of |split_char|. |
| // Returns the index of the |split_char| in the original |value| or -1 if not |
| // found. |
| IREE_API_EXPORT intptr_t iree_string_view_split(iree_string_view_t value, |
| char split_char, |
| iree_string_view_t* out_lhs, |
| iree_string_view_t* out_rhs); |
| |
| // Replaces all occurrences of |old_char| with |new_char|. |
| IREE_API_EXPORT void iree_string_view_replace_char(iree_string_view_t value, |
| char old_char, |
| char new_char); |
| |
| // Returns true if the given |value| matches |pattern| (normal * and ? rules). |
| // This accepts wildcards in the form of '*' and '?' for any delimited value. |
| // '*' will match zero or more of any character and '?' will match exactly one |
| // of any character. |
| // |
| // For example, |
| // 'foo-*-bar' matches: 'foo-123-bar', 'foo-456-789-bar' |
| // 'foo-10?' matches: 'foo-101', 'foo-102' |
| IREE_API_EXPORT bool iree_string_view_match_pattern(iree_string_view_t value, |
| iree_string_view_t pattern); |
| |
| // Copies the string bytes into the target buffer and returns the number of |
| // characters copied. Does not include a NUL terminator. |
| IREE_API_EXPORT iree_host_size_t iree_string_view_append_to_buffer( |
| iree_string_view_t source_value, iree_string_view_t* target_value, |
| char* buffer); |
| |
| //===----------------------------------------------------------------------===// |
| // IREE_STATUS_FEATURE flags and IREE_STATUS_MODE setting |
| //===----------------------------------------------------------------------===// |
| |
| // Captures origin source information on a call to iree_make_status. |
| // Status storage will be allocated and reference the __FILE__ and __LINE__ |
| // of where it is invoked. |
| #define IREE_STATUS_FEATURE_SOURCE_LOCATION (1 << 0) |
| |
| // Captures annotation messages provided via iree_make_status or |
| // iree_status_annotate. |
| // Status storage will be allocated. |
| #define IREE_STATUS_FEATURE_ANNOTATIONS (1 << 1) |
| |
| // Captures the current callstack on a call to iree_make_status. |
| // Status storage will be allocated. |
| #define IREE_STATUS_FEATURE_STACK_TRACE (1 << 2) |
| |
| // If no status mode override is provided we'll change the behavior based on |
| // build configuration. |
| #if !defined(IREE_STATUS_MODE) |
| #ifdef NDEBUG |
| // Release mode: just source location. |
| #define IREE_STATUS_MODE 2 |
| #else |
| // Debug mode: annotations and stack traces. |
| #define IREE_STATUS_MODE 3 |
| #endif // NDEBUG |
| #endif // !IREE_STATUS_MODE |
| |
| // Set IREE_STATUS_FEATURES based on IREE_STATUS_MODE if the user hasn't |
| // overridden it with more specific settings. |
| // |
| // IREE_STATUS_MODE = 0: statuses are just integers |
| // IREE_STATUS_MODE = 1: statuses have source location of error |
| // IREE_STATUS_MODE = 2: statuses also have custom annotations |
| // IREE_STATUS_MODE = 3: statuses also have stack traces of the error site |
| #if !defined(IREE_STATUS_FEATURES) |
| #if defined(IREE_STATUS_MODE) && IREE_STATUS_MODE == 1 |
| #define IREE_STATUS_FEATURES (IREE_STATUS_FEATURE_SOURCE_LOCATION) |
| #elif defined(IREE_STATUS_MODE) && IREE_STATUS_MODE == 2 |
| #define IREE_STATUS_FEATURES \ |
| (IREE_STATUS_FEATURE_SOURCE_LOCATION | IREE_STATUS_FEATURE_ANNOTATIONS) |
| #elif defined(IREE_STATUS_MODE) && IREE_STATUS_MODE == 3 |
| #define IREE_STATUS_FEATURES \ |
| (IREE_STATUS_FEATURE_SOURCE_LOCATION | IREE_STATUS_FEATURE_ANNOTATIONS | \ |
| IREE_STATUS_FEATURE_STACK_TRACE) |
| #else |
| #define IREE_STATUS_FEATURES 0 |
| #endif // IREE_STATUS_MODE |
| #endif // !IREE_STATUS_FEATURES |
| |
| //===----------------------------------------------------------------------===// |
| // iree_status_t and error reporting |
| //===----------------------------------------------------------------------===// |
| |
| // Well-known status codes matching iree::StatusCode. |
| // Note that any code within IREE_STATUS_CODE_MASK is valid even if not |
| // enumerated here. Always check for unhandled errors/have default conditions. |
| typedef enum { |
| IREE_STATUS_OK = 0, |
| IREE_STATUS_CANCELLED = 1, |
| IREE_STATUS_UNKNOWN = 2, |
| IREE_STATUS_INVALID_ARGUMENT = 3, |
| IREE_STATUS_DEADLINE_EXCEEDED = 4, |
| IREE_STATUS_NOT_FOUND = 5, |
| IREE_STATUS_ALREADY_EXISTS = 6, |
| IREE_STATUS_PERMISSION_DENIED = 7, |
| IREE_STATUS_RESOURCE_EXHAUSTED = 8, |
| IREE_STATUS_FAILED_PRECONDITION = 9, |
| IREE_STATUS_ABORTED = 10, |
| IREE_STATUS_OUT_OF_RANGE = 11, |
| IREE_STATUS_UNIMPLEMENTED = 12, |
| IREE_STATUS_INTERNAL = 13, |
| IREE_STATUS_UNAVAILABLE = 14, |
| IREE_STATUS_DATA_LOSS = 15, |
| IREE_STATUS_UNAUTHENTICATED = 16, |
| |
| IREE_STATUS_CODE_MASK = 0x1Fu, |
| } iree_status_code_t; |
| |
| // Opaque status structure containing an iree_status_code_t and optional status |
| // object with more detailed information and payloads. |
| // |
| // The status value uses the lower 5 bits to store the iree_status_code_t and |
| // the remaining uintptr_t bits to store an optional status payload pointer. |
| // An OK status will always be bit-equivalent to 0 to make success/failure |
| // checks as cheap as an integer non-zero comparison. As the payload is optional |
| // it's legal to construct an iree_status_t from an iree_status_code_t directly |
| // meaning `return iree_status_from_code(IREE_STATUS_INTERNAL);` (etc) is valid, |
| // though not as useful as constructing via iree_make_status (which captures |
| // additional info). |
| typedef struct iree_status_handle_t* iree_status_t; |
| |
| // Returns an iree_status_t from the an iree_status_code_t. |
| #define iree_status_from_code(code) \ |
| ((iree_status_t)((uintptr_t)((iree_status_code_t)(code)) & \ |
| IREE_STATUS_CODE_MASK)) |
| |
| // Returns the iree_status_code_t from an iree_status_t. |
| #define iree_status_code(value) \ |
| ((iree_status_code_t)(((uintptr_t)(value)) & IREE_STATUS_CODE_MASK)) |
| |
| // Macros to check the value of a status code. |
| #define iree_status_is_ok(value) \ |
| IREE_LIKELY((uintptr_t)(value) == IREE_STATUS_OK) |
| #define iree_status_is_cancelled(value) \ |
| (iree_status_code(value) == IREE_STATUS_CANCELLED) |
| #define iree_status_is_unknown(value) \ |
| (iree_status_code(value) == IREE_STATUS_UNKNOWN) |
| #define iree_status_is_invalid_argument(value) \ |
| (iree_status_code(value) == IREE_STATUS_INVALID_ARGUMENT) |
| #define iree_status_is_deadline_exceeded(value) \ |
| (iree_status_code(value) == IREE_STATUS_DEADLINE_EXCEEDED) |
| #define iree_status_is_not_found(value) \ |
| (iree_status_code(value) == IREE_STATUS_NOT_FOUND) |
| #define iree_status_is_already_exists(value) \ |
| (iree_status_code(value) == IREE_STATUS_ALREADY_EXISTS) |
| #define iree_status_is_permission_denied(value) \ |
| (iree_status_code(value) == IREE_STATUS_PERMISSION_DENIED) |
| #define iree_status_is_resource_exhausted(value) \ |
| (iree_status_code(value) == IREE_STATUS_RESOURCE_EXHAUSTED) |
| #define iree_status_is_failed_precondition(value) \ |
| (iree_status_code(value) == IREE_STATUS_FAILED_PRECONDITION) |
| #define iree_status_is_aborted(value) \ |
| (iree_status_code(value) == IREE_STATUS_ABORTED) |
| #define iree_status_is_out_of_range(value) \ |
| (iree_status_code(value) == IREE_STATUS_OUT_OF_RANGE) |
| #define iree_status_is_unimplemented(value) \ |
| (iree_status_code(value) == IREE_STATUS_UNIMPLEMENTED) |
| #define iree_status_is_internal(value) \ |
| (iree_status_code(value) == IREE_STATUS_INTERNAL) |
| #define iree_status_is_unavailable(value) \ |
| (iree_status_code(value) == IREE_STATUS_UNAVAILABLE) |
| #define iree_status_is_data_loss(value) \ |
| (iree_status_code(value) == IREE_STATUS_DATA_LOSS) |
| #define iree_status_is_unauthenticated(value) \ |
| (iree_status_code(value) == IREE_STATUS_UNAUTHENTICATED) |
| |
| #define IREE_STATUS_IMPL_CONCAT_INNER_(x, y) x##y |
| #define IREE_STATUS_IMPL_CONCAT_(x, y) IREE_STATUS_IMPL_CONCAT_INNER_(x, y) |
| |
| #define IREE_STATUS_IMPL_IDENTITY_(...) __VA_ARGS__ |
| #define IREE_STATUS_IMPL_GET_EXPR_(expr, ...) expr |
| #define IREE_STATUS_IMPL_GET_ARGS_(expr, ...) __VA_ARGS__ |
| #define IREE_STATUS_IMPL_GET_MACRO_(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ |
| _10, _11, _12, _13, _14, ...) \ |
| IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_GET_EXPR_)(__VA_ARGS__)) |
| |
| #define IREE_STATUS_IMPL_MAKE_EMPTY_(file, line, status_code, ...) \ |
| iree_status_allocate(status_code, file, line, iree_string_view_empty()) |
| #define IREE_STATUS_IMPL_MAKE_ANNOTATE_(file, line, status_code, message) \ |
| iree_status_allocate(status_code, file, line, iree_make_cstring_view(message)) |
| #define IREE_STATUS_IMPL_MAKE_ANNOTATE_F_(file, line, status_code, ...) \ |
| iree_status_allocate_f(status_code, file, line, __VA_ARGS__) |
| #define IREE_STATUS_IMPL_MAKE_SWITCH_(file, line, ...) \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_GET_MACRO_)( \ |
| __VA_ARGS__, IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, IREE_STATUS_IMPL_MAKE_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_MAKE_ANNOTATE_, IREE_STATUS_IMPL_MAKE_EMPTY_)) \ |
| (file, line, IREE_STATUS_IMPL_GET_EXPR_(__VA_ARGS__), \ |
| IREE_STATUS_IMPL_GET_ARGS_(__VA_ARGS__)) |
| |
| #define IREE_STATUS_IMPL_PASS_(var, ...) var |
| #define IREE_STATUS_IMPL_ANNOTATE_(var, ...) \ |
| IREE_STATUS_IMPL_IDENTITY_(iree_status_annotate( \ |
| var, iree_make_cstring_view(IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_GET_ARGS_)(__VA_ARGS__)))) |
| #define IREE_STATUS_IMPL_ANNOTATE_F_(var, ...) \ |
| IREE_STATUS_IMPL_IDENTITY_(iree_status_annotate_f( \ |
| var, \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_GET_ARGS_)(__VA_ARGS__))) |
| #define IREE_STATUS_IMPL_ANNOTATE_SWITCH_(...) \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_GET_MACRO_)( \ |
| __VA_ARGS__, IREE_STATUS_IMPL_ANNOTATE_F_, IREE_STATUS_IMPL_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_ANNOTATE_F_, IREE_STATUS_IMPL_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_ANNOTATE_F_, IREE_STATUS_IMPL_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_ANNOTATE_F_, IREE_STATUS_IMPL_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_ANNOTATE_F_, IREE_STATUS_IMPL_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_ANNOTATE_F_, IREE_STATUS_IMPL_ANNOTATE_F_, \ |
| IREE_STATUS_IMPL_ANNOTATE_, IREE_STATUS_IMPL_PASS_)) \ |
| (IREE_STATUS_IMPL_GET_EXPR_(__VA_ARGS__), \ |
| IREE_STATUS_IMPL_GET_ARGS_(__VA_ARGS__)) |
| #define IREE_STATUS_IMPL_RETURN_IF_API_ERROR_(var, ...) \ |
| iree_status_t var = (IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_GET_EXPR_)(__VA_ARGS__))); \ |
| if (IREE_UNLIKELY(var)) { \ |
| return IREE_STATUS_IMPL_ANNOTATE_SWITCH_(var, __VA_ARGS__); \ |
| } |
| #define IREE_STATUS_IMPL_RETURN_AND_EVAL_IF_API_ERROR_(tail_expr, var, ...) \ |
| iree_status_t var = (IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_GET_EXPR_)(__VA_ARGS__))); \ |
| if (IREE_UNLIKELY(var)) { \ |
| (tail_expr); \ |
| return IREE_STATUS_IMPL_ANNOTATE_SWITCH_(var, __VA_ARGS__); \ |
| } |
| #define IREE_STATUS_IMPL_IGNORE_ERROR_(var, expr) \ |
| iree_status_t var = (expr); \ |
| if (IREE_UNLIKELY(var)) iree_status_ignore(var); |
| |
| // We cut out all status storage code when not used. |
| #if IREE_STATUS_FEATURES == 0 |
| #define IREE_STATUS_IMPL_MAKE_(code, ...) \ |
| (iree_status_t)(uintptr_t)((code)&IREE_STATUS_CODE_MASK) |
| #undef IREE_STATUS_IMPL_RETURN_IF_API_ERROR_ |
| #define IREE_STATUS_IMPL_RETURN_IF_API_ERROR_(var, ...) \ |
| iree_status_t var = (IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_GET_EXPR_)(__VA_ARGS__))); \ |
| if (IREE_UNLIKELY(var)) return var; |
| #undef IREE_STATUS_IMPL_RETURN_AND_EVAL_IF_API_ERROR_ |
| #define IREE_STATUS_IMPL_RETURN_AND_EVAL_IF_API_ERROR_(tail_expr, var, ...) \ |
| iree_status_t var = (IREE_STATUS_IMPL_IDENTITY_( \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_GET_EXPR_)(__VA_ARGS__))); \ |
| if (IREE_UNLIKELY(var)) { \ |
| (tail_expr); \ |
| return var; \ |
| } |
| #undef IREE_STATUS_IMPL_IGNORE_ERROR_ |
| #define IREE_STATUS_IMPL_IGNORE_ERROR_(var, expr) \ |
| iree_status_t var = (expr); \ |
| (void)(var); |
| #else |
| #define IREE_STATUS_IMPL_MAKE_(...) \ |
| IREE_STATUS_IMPL_MAKE_SWITCH_(__FILE__, __LINE__, __VA_ARGS__) |
| #endif // !IREE_STATUS_FEATURES |
| |
| // Returns an IREE_STATUS_OK. |
| #define iree_ok_status() iree_status_from_code(IREE_STATUS_OK) |
| |
| // Makes an iree_status_t with the given iree_status_code_t code and records |
| // the current source location. |
| // |
| // Optionally either a message string literal or printf-style format string may |
| // be associated with the status. |
| // |
| // Examples: |
| // return iree_make_status(IREE_STATUS_CANCELLED); |
| // return iree_make_status(IREE_STATUS_CANCELLED, "because reasons"); |
| // return iree_make_status(IREE_STATUS_CANCELLED, "because %d > %d", a, b); |
| #define iree_make_status IREE_STATUS_IMPL_MAKE_ |
| |
| // Propagates the error returned by (expr) by returning from the current |
| // function on non-OK status. Optionally annotates the status with additional |
| // information (see iree_status_annotate for more information). |
| // |
| // Example: |
| // iree_status_t OtherFunc(...); |
| // iree_status_t MyFunc(...) { |
| // IREE_RETURN_IF_ERROR(OtherFunc(...)); |
| // IREE_RETURN_IF_ERROR(OtherFunc(...), "with a message"); |
| // IREE_RETURN_IF_ERROR(OtherFunc(...), "with a value: %d", 5); |
| // return iree_ok_status(); |
| // } |
| #define IREE_RETURN_IF_ERROR(...) \ |
| IREE_STATUS_IMPL_RETURN_IF_API_ERROR_( \ |
| IREE_STATUS_IMPL_CONCAT_(__status_, __COUNTER__), \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_IDENTITY_(__VA_ARGS__))) |
| |
| // IREE_RETURN_IF_ERROR with a custom expression to evaluate before returning. |
| #define IREE_RETURN_AND_EVAL_IF_ERROR(tail_expr, ...) \ |
| IREE_STATUS_IMPL_RETURN_AND_EVAL_IF_API_ERROR_( \ |
| tail_expr, IREE_STATUS_IMPL_CONCAT_(__status_, __COUNTER__), \ |
| IREE_STATUS_IMPL_IDENTITY_(IREE_STATUS_IMPL_IDENTITY_(__VA_ARGS__))) |
| |
| // Ignores the status result of (expr) regardless of its value. |
| // |
| // Example: |
| // IREE_IGNORE_ERROR(some_fn_that_may_fail()); |
| #define IREE_IGNORE_ERROR(expr) \ |
| IREE_STATUS_IMPL_IGNORE_ERROR_( \ |
| IREE_STATUS_IMPL_CONCAT_(__status_, __COUNTER__), (expr)) |
| |
| // TODO(#2843): better logging of status checks. |
| #define IREE_CHECK_OK(expr) \ |
| IREE_CHECK_EQ(IREE_STATUS_OK, iree_status_consume_code(expr)) |
| |
| //===----------------------------------------------------------------------===// |
| // IREE_ASSERT macros |
| //===----------------------------------------------------------------------===// |
| // These are no-oped in builds with NDEBUG defined (by default anything but |
| // `-c dbg`/`-DCMAKE_BUILD_TYPE=Debug`). They differ from assert in that |
| // they avoid unused variable warnings when NDEBUG is defined. As with normal |
| // assert() ensure that side-effecting behavior is avoided as the expression |
| // will not be evaluated when the asserts are removed! |
| |
| // TODO(benvanik): move to iree/base/assert.h. |
| #if defined(NDEBUG) // N(o) DEBUG |
| |
| // Assertions disabled: |
| |
| #define IREE_ASSERT(condition, ...) \ |
| while (false && (condition)) { \ |
| } |
| |
| // TODO(benvanik): replace the status_matchers version with a test macro. |
| // #define IREE_ASSERT_OK(status) IREE_ASSERT(iree_status_is_ok(status)) |
| |
| // However, we still want the compiler to parse x and y because |
| // we don't want to lose potentially useful errors and warnings |
| // (and want to hide unused variable warnings when asserts are disabled). |
| // _IREE_ASSERT_CMP is a helper and should not be used outside of this file. |
| #define _IREE_ASSERT_CMP(x, op, y, ...) \ |
| while (false && ((void)(x), (void)(y), 0)) { \ |
| } |
| |
| #else |
| |
| // Assertions enabled: |
| |
| #define IREE_ASSERT(condition, ...) assert(condition) |
| |
| // TODO(#2843): better logging of status assertions. |
| // #define IREE_ASSERT_OK(status) IREE_ASSERT(iree_status_is_ok(status)) |
| |
| #define _IREE_ASSERT_CMP(x, op, y, ...) IREE_ASSERT(((x)op(y)), __VA_ARGS__) |
| |
| #endif // NDEBUG |
| |
| #define IREE_ASSERT_ARGUMENT(name) IREE_ASSERT(name) |
| |
| #define IREE_ASSERT_TRUE(expr, ...) IREE_ASSERT(!!(expr), __VA_ARGS__) |
| #define IREE_ASSERT_FALSE(expr, ...) IREE_ASSERT(!(expr), __VA_ARGS__) |
| |
| #define IREE_ASSERT_EQ(x, y, ...) _IREE_ASSERT_CMP(x, ==, y, __VA_ARGS__) |
| #define IREE_ASSERT_NE(x, y, ...) _IREE_ASSERT_CMP(x, !=, y, __VA_ARGS__) |
| #define IREE_ASSERT_LE(x, y, ...) _IREE_ASSERT_CMP(x, <=, y, __VA_ARGS__) |
| #define IREE_ASSERT_LT(x, y, ...) _IREE_ASSERT_CMP(x, <, y, __VA_ARGS__) |
| #define IREE_ASSERT_GE(x, y, ...) _IREE_ASSERT_CMP(x, >=, y, __VA_ARGS__) |
| #define IREE_ASSERT_GT(x, y, ...) _IREE_ASSERT_CMP(x, >, y, __VA_ARGS__) |
| |
| // Returns the canonical status code for the given errno value. |
| // https://en.cppreference.com/w/cpp/error/errno_macros |
| IREE_API_EXPORT iree_status_code_t |
| iree_status_code_from_errno(int error_number); |
| |
| #if defined(_WIN32) || defined(_WIN64) |
| // Returns the canonical status code for the given Win32 GetLastError code. |
| // https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror |
| IREE_API_EXPORT iree_status_code_t |
| iree_status_code_from_win32_error(uint32_t error); |
| #endif // _WIN32 || _WIN64 |
| |
| // Returns a NUL-terminated string constant for the given status code, such as |
| // IREE_STATUS_UNAVAILABLE = "UNAVAILABLE". Do not rely on string-matching the |
| // result as the exact text may change. |
| IREE_API_EXPORT const char* iree_status_code_string(iree_status_code_t code); |
| |
| // Allocates a new status instance for a failing error |code|. |
| // |file| and |line| should be populated with __FILE__ and __LINE__ at the call |
| // site and an optional string |message| may be provided. |
| // |
| // The status will be allocated using the default system allocator and must be |
| // freed using either iree_status_free or iree_status_ignore. |
| IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t |
| iree_status_allocate(iree_status_code_t code, const char* file, uint32_t line, |
| iree_string_view_t message); |
| |
| // Allocates a new status instance for a failing error |code| and annotates it |
| // with a printf-style format string. Roughly equivalent (though more efficient) |
| // than iree_status_allocate + iree_status_annotate_f. |
| IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t IREE_PRINTF_ATTRIBUTE(4, 5) |
| iree_status_allocate_f(iree_status_code_t code, const char* file, |
| uint32_t line, const char* format, ...); |
| |
| IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t iree_status_allocate_vf( |
| iree_status_code_t code, const char* file, uint32_t line, |
| const char* format, va_list varargs_0, va_list varargs_1); |
| |
| // Clones |status| into a new status instance. |
| // No payloads, if present, will be cloned. |
| IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t |
| iree_status_clone(iree_status_t status); |
| |
| // Frees |status| if it has any associated storage. |
| IREE_API_EXPORT void iree_status_free(iree_status_t status); |
| |
| // Ignores |status| regardless of its value and frees any associated payloads. |
| // Returns an OK status that can be used when chaining. |
| IREE_API_EXPORT iree_status_t iree_status_ignore(iree_status_t status); |
| |
| // Consumes the |status| by freeing its storage and returning its code. |
| IREE_API_EXPORT iree_status_code_t |
| iree_status_consume_code(iree_status_t status); |
| |
| // Annotates a status message with the given constant string message. |
| // Ignored if |base_status| is OK. |
| IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t |
| iree_status_annotate(iree_status_t base_status, iree_string_view_t message); |
| |
| // Annotates a status message with the given printf-style message. |
| // Ignored if |base_status| is OK. |
| IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t IREE_PRINTF_ATTRIBUTE(2, 3) |
| iree_status_annotate_f(iree_status_t base_status, const char* format, ...); |
| |
| IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t |
| iree_status_annotate_vf(iree_status_t base_status, const char* format, |
| va_list varargs_0, va_list varargs_1); |
| |
| // Formats the status as a multi-line string containing all associated payloads. |
| // Note that this may contain PII such as file paths and must only be used for |
| // presenting errors to users and not sent to a logs aggregation service. |
| IREE_API_EXPORT bool iree_status_format(iree_status_t status, |
| iree_host_size_t buffer_capacity, |
| char* buffer, |
| iree_host_size_t* out_buffer_length); |
| |
| // Converts the status to an allocated string value. |
| // The caller must free the buffer with the system allocator. |
| IREE_API_EXPORT bool iree_status_to_string(iree_status_t status, |
| char** out_buffer, |
| iree_host_size_t* out_buffer_length); |
| |
| //===----------------------------------------------------------------------===// |
| // IREE Core API |
| //===----------------------------------------------------------------------===// |
| |
| // Sprinkle this wherever to make it easier to find structs/functions that are |
| // not yet stable. |
| #define IREE_API_UNSTABLE |
| |
| // Known versions of the API that can be referenced in code. |
| // Out-of-bounds values are possible in forward-versioned changes. |
| enum iree_api_version_e { |
| IREE_API_VERSION_0 = 0u, |
| // Always set to the latest version of the library from source. |
| IREE_API_VERSION_LATEST = IREE_API_VERSION_0, |
| }; |
| typedef uint32_t iree_api_version_t; |
| |
| // Checks whether the |expected_version| of the caller matches the implemented |
| // version of |out_actual_version|. Forward compatibility of the API is |
| // supported but backward compatibility is not: newer binaries using older |
| // shared libraries of the runtime will fail. |
| // |
| // Returns IREE_STATUS_OUT_OF_RANGE if the actual version is not compatible with |
| // the expected version. |
| IREE_API_EXPORT iree_status_t |
| iree_api_version_check(iree_api_version_t expected_version, |
| iree_api_version_t* out_actual_version); |
| |
| //===----------------------------------------------------------------------===// |
| // iree_time_t and iree_duration_t |
| //===----------------------------------------------------------------------===// |
| |
| // A point in time represented as nanoseconds since unix epoch. |
| // TODO(benvanik): pick something easy to get into/outof time_t/etc. |
| typedef int64_t iree_time_t; |
| // A time in the infinite past used to indicate "already happened". |
| // This forces APIs that wait for a point in time to act as a poll and always |
| // return IREE_STATUS_DEADLINE_EXCEEDED instead of blocking the caller. |
| #define IREE_TIME_INFINITE_PAST INT64_MIN |
| // A time in the infinite future used to indicate "never". |
| // This causes APIs that wait for a point in time to wait however long is needed |
| // to satisfy the wait condition. |
| #define IREE_TIME_INFINITE_FUTURE INT64_MAX |
| |
| // A duration represented as relative nanoseconds. |
| typedef int64_t iree_duration_t; |
| // A zero-length duration. |
| // Like IREE_TIME_INFINITE_FUTURE this forces APIs that would wait to instead |
| // return IREE_STATUS_DEADLINE_EXCEEDED immediately. |
| #define IREE_DURATION_ZERO 0 |
| // An infinite-length duration. |
| // Like IREE_TIME_INFINITE_FUTURE this causes APIs that wait to do so until |
| // their wait condition is satisfied without returning early. |
| #define IREE_DURATION_INFINITE INT64_MAX |
| |
| // Returns the current system time in unix nanoseconds. |
| // Depending on the system architecture and power mode this time may have a |
| // very coarse granularity (on the order of microseconds to milliseconds). |
| // |
| // The system timer may not be monotonic; users should ensure when comparing |
| // times they check for negative values in case the time moves backwards. |
| IREE_API_EXPORT iree_time_t iree_time_now(); |
| |
| // Converts a relative timeout duration to an absolute deadline time. |
| // This handles the special cases of IREE_DURATION_ZERO and |
| // IREE_DURATION_INFINITE to avoid extraneous time queries. |
| IREE_API_EXPORT iree_time_t |
| iree_relative_timeout_to_deadline_ns(iree_duration_t timeout_ns); |
| |
| // Converts an absolute deadline time to a relative timeout duration. |
| // This handles the special cases of IREE_TIME_INFINITE_PAST and |
| // IREE_TIME_INFINITE_FUTURE to avoid extraneous time queries. |
| IREE_API_EXPORT iree_duration_t |
| iree_absolute_deadline_to_timeout_ns(iree_time_t deadline_ns); |
| |
| typedef enum { |
| // Timeout is defined by an absolute value `deadline_ns`. |
| IREE_TIMEOUT_ABSOLUTE = 0, |
| // Timeout is defined by a relative value `timeout_ns`. |
| IREE_TIMEOUT_RELATIVE = 1, |
| } iree_timeout_type_t; |
| |
| // A timeout defined either by an absolute or relative value. |
| typedef struct { |
| iree_timeout_type_t type; |
| iree_time_t nanos; |
| } iree_timeout_t; |
| |
| // Returns a timeout that will be exceeded immediately. |
| // This can be used with APIs that would otherwise wait to cause them to poll. |
| // |
| // Example: |
| // status = iree_wait_for_signal_or_timeout(&obj, iree_immediate_timeout()); |
| // if (iree_status_is_deadline_exceeded(status)) { |
| // // Would have waited indicating the signal has not occurred. If the |
| // // timeout was not immediate the call would have blocked the caller. |
| // } |
| static inline iree_timeout_t iree_immediate_timeout() { |
| iree_timeout_t timeout = {IREE_TIMEOUT_ABSOLUTE, IREE_TIME_INFINITE_PAST}; |
| return timeout; |
| } |
| |
| // Returns true if the |timeout| indicates an immediate/polling/nonblocking |
| // timeout. |
| static inline bool iree_timeout_is_immediate(iree_timeout_t timeout) { |
| return timeout.type == IREE_TIMEOUT_ABSOLUTE |
| ? timeout.nanos == IREE_TIME_INFINITE_PAST |
| : timeout.nanos == IREE_DURATION_ZERO; |
| } |
| |
| // Returns a timeout that will never be reached. |
| // This can be used with APIs that can wait to disable the early |
| // deadline-exceeded returns when a condition is not met. It should be used with |
| // care as it can complicate program state and make termination more prone to |
| // hangs. On the other hand, it's really useful to not bother with actual |
| // deadlines. YMMV. |
| static inline iree_timeout_t iree_infinite_timeout() { |
| iree_timeout_t timeout = {IREE_TIMEOUT_ABSOLUTE, IREE_TIME_INFINITE_FUTURE}; |
| return timeout; |
| } |
| |
| // Returns true if the |timeout| indicates an infinite/forever blocking timeout. |
| static inline bool iree_timeout_is_infinite(iree_timeout_t timeout) { |
| return timeout.type == IREE_TIMEOUT_ABSOLUTE |
| ? timeout.nanos == IREE_TIME_INFINITE_FUTURE |
| : timeout.nanos == IREE_DURATION_INFINITE; |
| } |
| |
| // Defines an absolute timeout with the given time in nanoseconds. |
| static inline iree_timeout_t iree_make_deadline(iree_time_t deadline_ns) { |
| iree_timeout_t timeout = {IREE_TIMEOUT_ABSOLUTE, deadline_ns}; |
| return timeout; |
| } |
| |
| // Defines a relative timeout with the given time in nanoseconds. |
| static inline iree_timeout_t iree_make_timeout(iree_duration_t timeout_ns) { |
| iree_timeout_t timeout = {IREE_TIMEOUT_RELATIVE, timeout_ns}; |
| return timeout; |
| } |
| |
| // Converts a timeout from relative to absolute (if it is). |
| // |
| // Absolute timeouts (deadlines) are better for long-running tasks or when |
| // making calls that may complete in stages as relative ones will tend to skew; |
| // if a wait is performed with a relative timeout of 10ms but it takes 5ms to |
| // get from the origin of the call to the actual wait using the timeout then |
| // the total latency of the call may be 15ms (5ms to prepare + 10ms on the |
| // wait). Instead if an absolute deadline is used the caller can ensure that |
| // the total time spent in the operation happens regardless of the intervening |
| // work that happens. |
| // |
| // For this reason IREE internal APIs try to convert to absolute times and users |
| // may be able to reduce overhead by populating the times as absolute to start |
| // with via iree_make_deadline. |
| static inline void iree_convert_timeout_to_absolute(iree_timeout_t* timeout) { |
| if (timeout->type == IREE_TIMEOUT_RELATIVE) { |
| timeout->type = IREE_TIMEOUT_ABSOLUTE; |
| timeout->nanos = iree_relative_timeout_to_deadline_ns(timeout->nanos); |
| } |
| } |
| |
| // Returns an absolute deadline in nanoseconds from the given timeout. |
| static inline iree_time_t iree_timeout_as_deadline_ns(iree_timeout_t timeout) { |
| return timeout.type == IREE_TIMEOUT_ABSOLUTE |
| ? timeout.nanos |
| : iree_relative_timeout_to_deadline_ns(timeout.nanos); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // iree_allocator_t (std::allocator-like interface) |
| //===----------------------------------------------------------------------===// |
| |
| // Defines how an allocation from an iree_allocator_t should be made. |
| typedef enum { |
| // The contents of the allocation *must* be zeroed by the allocator prior to |
| // returning. Allocators may be able to elide the zeroing if they allocate |
| // fresh pages from the system. It is always safe to zero contents if the |
| // behavior of the allocator is not under our control. |
| IREE_ALLOCATION_MODE_ZERO_CONTENTS = 1 << 0, |
| // Tries to reuse an existing allocation provided via |out_ptr| if possible. |
| // If the existing allocation is not reused then it is freed as if a call to |
| // iree_allocator_free had been called on it. If the allocation fails then |
| // the provided existing allocation is unmodified. |
| // |
| // This models the C realloc behavior. |
| IREE_ALLOCATION_MODE_TRY_REUSE_EXISTING = 1 << 1, |
| } iree_allocation_mode_t; |
| |
| // TODO(benvanik): replace with a single method with the mode setting. This will |
| // reduce the overhead to just two pointers per allocator (from 3) and allow us |
| // to add more distinct behavior in the future. If we really wanted to stretch |
| // we could turn it into a pointer and require the allocator live somewhere |
| // (possibly in .text as a const static), but two pointers seems fine. |
| typedef iree_status_t(IREE_API_PTR* iree_allocator_alloc_fn_t)( |
| void* self, iree_allocation_mode_t mode, iree_host_size_t byte_length, |
| void** out_ptr); |
| typedef void(IREE_API_PTR* iree_allocator_free_fn_t)(void* self, void* ptr); |
| |
| // An allocator for host-memory allocations. |
| // IREE will attempt to use this in place of the system malloc and free. |
| // Pass the iree_allocator_system() macro to use the system allocator. |
| typedef struct { |
| // User-defined pointer passed to all functions. |
| void* self; |
| // Allocates |byte_length| of memory and stores the pointer in |out_ptr|. |
| // Systems should align to 16 byte boundaries (or otherwise their natural |
| // SIMD alignment). The runtime pools internally and small allocations |
| // (usually) won't be made through this interface. |
| iree_allocator_alloc_fn_t alloc; |
| // Frees |ptr| from a previous alloc call. |
| iree_allocator_free_fn_t free; |
| } iree_allocator_t; |
| |
| // Allocates a block of |byte_length| bytes from the given allocator. |
| // The contents of the returned memory is guaranteed to be zeroed. |
| IREE_API_EXPORT iree_status_t iree_allocator_malloc( |
| iree_allocator_t allocator, iree_host_size_t byte_length, void** out_ptr); |
| |
| // Reallocates |out_ptr| to |byte_length| bytes with the given allocator. |
| // If the reallocation fails then the original |out_ptr| is unmodified. |
| IREE_API_EXPORT iree_status_t iree_allocator_realloc( |
| iree_allocator_t allocator, iree_host_size_t byte_length, void** out_ptr); |
| |
| // Duplicates the given byte block by allocating memory and copying it in. |
| IREE_API_EXPORT iree_status_t |
| iree_allocator_clone(iree_allocator_t allocator, |
| iree_const_byte_span_t source_bytes, void** out_ptr); |
| |
| // Frees a previously-allocated block of memory to the given allocator. |
| IREE_API_EXPORT void iree_allocator_free(iree_allocator_t allocator, void* ptr); |
| |
| // Allocates a block of |byte_length| bytes from the default system allocator. |
| IREE_API_EXPORT iree_status_t |
| iree_allocator_system_allocate(void* self, iree_allocation_mode_t mode, |
| iree_host_size_t byte_length, void** out_ptr); |
| |
| // Frees a previously-allocated block of memory to the default system allocator. |
| IREE_API_EXPORT void iree_allocator_system_free(void* self, void* ptr); |
| |
| // Allocates using the iree_allocator_malloc and iree_allocator_free methods. |
| // These will usually be backed by malloc and free. |
| static inline iree_allocator_t iree_allocator_system() { |
| iree_allocator_t v = {NULL, iree_allocator_system_allocate, |
| iree_allocator_system_free}; |
| return v; |
| } |
| |
| // Does not perform any allocation or deallocation; used to wrap objects that |
| // are owned by external code/live in read-only memory/etc. |
| static inline iree_allocator_t iree_allocator_null() { |
| iree_allocator_t v = {NULL, NULL, NULL}; |
| return v; |
| } |
| |
| #ifdef __cplusplus |
| } // extern "C" |
| #endif // __cplusplus |
| |
| #endif // IREE_BASE_API_H_ |