blob: 4c14b6be84e8eb62639a498714f56431661317df [file] [log] [blame]
// 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_