| // Copyright 2022 The IREE Authors |
| // |
| // Licensed under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| #ifndef IREE_BASE_LOOP_INLINE_H_ |
| #define IREE_BASE_LOOP_INLINE_H_ |
| |
| #include <inttypes.h> |
| |
| #include "iree/base/loop.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif // __cplusplus |
| |
| //===----------------------------------------------------------------------===// |
| // iree_loop_inline |
| //===----------------------------------------------------------------------===// |
| |
| IREE_API_EXPORT iree_status_t iree_loop_inline_ctl(void* self, |
| iree_loop_command_t command, |
| const void* params, |
| void** inout_ptr); |
| IREE_API_EXPORT iree_status_t |
| iree_loop_inline_using_storage_ctl(void* self, iree_loop_command_t command, |
| const void* params, void** inout_ptr); |
| |
| // Returns a loop that doesn't really loop. |
| // All operations are run as they are enqueued on the stack. This uses no |
| // additional memory and ensures that everything completes upon return to the |
| // user but does eliminate the ability for pipelining and overlapping work from |
| // multiple subprograms. This approach limits the amount of work that can be |
| // reentrantly scheduled and should only be used when in the tiniest of |
| // environments with programs tested to be compatible with it. |
| // |
| // Reentrant enqueuing is possible and can be used to create tail call chains |
| // (or recursion) that executes roughly in order. |
| // |
| // Caveats: |
| // - Reentrant enqueuing of operations is limited to some small number (~4). |
| // - Waits are performed as they are enqueued and the loop must be able to |
| // make forward progress on each. |
| // - Execution deadlines are ignored in order to fully drain on each operation. |
| // - Errors propagate immediately to the top-level caller and abort all pending |
| // operations. |
| // |
| // Thread-compatible: stateless and executes all work on the calling thread. |
| static inline iree_loop_t iree_loop_inline(iree_status_t* out_status) { |
| iree_loop_t loop = {out_status, iree_loop_inline_ctl}; |
| return loop; |
| } |
| |
| // Minimum size in bytes required for iree_loop_inline_storage_t. |
| // If we wanted to shrink this size to the absolute minimum we'd just expose the |
| // structures here; not the worst thing but messy (as this is a public API). |
| #define IREE_LOOP_INLINE_STORAGE_SIZE 512 |
| |
| // Storage for an inline loop. |
| // May be either allocated on the stack or on the heap and only needs to remain |
| // valid for the lifetime of the iree_loop_t referencing it. |
| typedef iree_alignas(iree_max_align_t) struct iree_loop_inline_storage_t { |
| uint8_t opaque[IREE_LOOP_INLINE_STORAGE_SIZE]; |
| iree_status_t status; |
| } iree_loop_inline_storage_t; |
| |
| // Returns an inline loop that uses an external |storage| instead of the stack. |
| // The storage will only be used while executing and can be reused if the caller |
| // knows it is safe (not reentrantly inside of a loop execution). Errors that |
| // arise will be set in the storage status field and must be checked (or |
| // ignored) by the caller to avoid leaks. |
| // |
| // See iree_loop_inline for details on the execution behavior. |
| static inline iree_loop_t iree_loop_inline_initialize( |
| iree_loop_inline_storage_t* storage) { |
| storage->status = iree_ok_status(); |
| iree_loop_t loop = { |
| storage, |
| iree_loop_inline_using_storage_ctl, |
| }; |
| return loop; |
| } |
| |
| static inline void iree_loop_inline_deinitialize( |
| iree_loop_inline_storage_t* storage) { |
| if (!storage) return; |
| iree_status_ignore(storage->status); |
| storage->status = iree_ok_status(); |
| } |
| |
| #ifdef __cplusplus |
| } // extern "C" |
| #endif // __cplusplus |
| |
| #endif // IREE_BASE_LOOP_INLINE_H_ |