blob: 5a2071ece091a06fad7c5b492b108b57edfc3346 [file] [log] [blame]
// Copyright 2020 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_HAL_BUFFER_VIEW_H_
#define IREE_HAL_BUFFER_VIEW_H_
#include <stdint.h>
#include "iree/base/api.h"
#include "iree/hal/buffer.h"
#include "iree/hal/resource.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
//===----------------------------------------------------------------------===//
// Types and Enums
//===----------------------------------------------------------------------===//
// NOTE: these values must be in sync with
// iree/compiler/Dialect/HAL/IR/HALTypes.cpp
enum iree_hal_numerical_type_bits_t {
// Opaque or unknown - bytes cannot be interpreted. Indexing is still allowed
// so long as the bit width of the elements is known.
IREE_HAL_NUMERICAL_TYPE_UNKNOWN = 0x00u,
// Signless integer-like.
IREE_HAL_NUMERICAL_TYPE_INTEGER = 0x10u,
// Signed integer.
IREE_HAL_NUMERICAL_TYPE_INTEGER_SIGNED =
IREE_HAL_NUMERICAL_TYPE_INTEGER | 0x01u,
// Unsigned integer.
IREE_HAL_NUMERICAL_TYPE_INTEGER_UNSIGNED =
IREE_HAL_NUMERICAL_TYPE_INTEGER | 0x02u,
// Boolean; stored as an integer but only 1 bit is valid.
IREE_HAL_NUMERICAL_TYPE_BOOLEAN = IREE_HAL_NUMERICAL_TYPE_INTEGER | 0x03u,
// Float-like.
IREE_HAL_NUMERICAL_TYPE_FLOAT = 0x20,
// IEEE754-compatible floating point semantics.
IREE_HAL_NUMERICAL_TYPE_FLOAT_IEEE = IREE_HAL_NUMERICAL_TYPE_FLOAT | 0x01u,
// 'Brain' floating point semantics (currently only bf16).
IREE_HAL_NUMERICAL_TYPE_FLOAT_BRAIN = IREE_HAL_NUMERICAL_TYPE_FLOAT | 0x02u,
// Paired (real, imag) complex number in floating-point format.
IREE_HAL_NUMERICAL_TYPE_FLOAT_COMPLEX = IREE_HAL_NUMERICAL_TYPE_FLOAT | 0x03u,
};
typedef uint8_t iree_hal_numerical_type_t;
#define IREE_HAL_ELEMENT_TYPE_VALUE(numerical_type, bit_count) \
(((uint32_t)(numerical_type) << 24) | (uint32_t)(bit_count))
// Composes an iree_hal_element_type_t value with the given attributes.
#define iree_hal_make_element_type(numerical_type, bit_count) \
(iree_hal_element_type_t)( \
IREE_HAL_ELEMENT_TYPE_VALUE(numerical_type, bit_count))
// Returns the numerical type of the element, if known and not opaque.
#define iree_hal_element_numerical_type(element_type) \
(iree_hal_numerical_type_t)((uint32_t)(element_type) >> 24)
// Returns true if |element_type| is opaque and cannot be interpreted.
#define iree_hal_element_numerical_type_is_opaque(element_type) \
(iree_hal_element_numerical_type(element_type) == \
IREE_HAL_NUMERICAL_TYPE_UNKNOWN)
// Returns true if |element_type| is a boolean of some width and semantics.
#define iree_hal_element_numerical_type_is_boolean(element_type) \
iree_all_bits_set(iree_hal_element_numerical_type(element_type), \
IREE_HAL_NUMERICAL_TYPE_BOOLEAN)
// Returns true if |element_type| is an integer of some width and semantics.
#define iree_hal_element_numerical_type_is_integer(element_type) \
iree_all_bits_set(iree_hal_element_numerical_type(element_type), \
IREE_HAL_NUMERICAL_TYPE_INTEGER)
// Returns true if |element_type| is a float of some width and semantics.
#define iree_hal_element_numerical_type_is_float(element_type) \
iree_all_bits_set(iree_hal_element_numerical_type(element_type), \
IREE_HAL_NUMERICAL_TYPE_FLOAT)
// Returns true if |element_type| is a (real, imag) complex number in float.
#define iree_hal_element_numerical_type_is_complex_float(element_type) \
iree_all_bits_set(iree_hal_element_numerical_type(element_type), \
IREE_HAL_NUMERICAL_TYPE_FLOAT_COMPLEX)
// TODO(#8193): split out logical and physical bit widths.
// Returns the bit width of each element.
#define iree_hal_element_bit_count(element_type) \
(iree_host_size_t)((element_type)&0xFF)
// Returns true if the element is byte-aligned.
// Sub-byte aligned types such as i4 require user handling of the packing.
#define iree_hal_element_is_byte_aligned(element_type) \
(iree_hal_element_bit_count(element_type) % 8 == 0)
// Returns the number of bytes each |element_type| consumes in memory.
// This is only valid when the encoding type is dense as sub-byte bit widths
// may be packed in various forms (for example, i4 may be stored as nibbles
// where each byte in memory contains two elements).
#define iree_hal_element_dense_byte_count(element_type) \
((iree_hal_element_bit_count(element_type) + 8 - 1) / 8)
// Returns true if the given |element_type| represents an integer of exactly
// |bit_width|. This ignores the signedness of the integer type.
#define iree_hal_element_type_is_integer(element_type, bit_width) \
(iree_hal_element_numerical_type_is_integer(element_type) && \
iree_hal_element_bit_count(element_type) == (bit_width))
// Defines the element type of a buffer in a standard format.
//
// Composed as a 32-bit bitfield to allow for opaque data types. Use
// iree_hal_make_element_type to make a bitfield with the appropriate ordering.
//
// MSB ----------------------------------------------- LSB
// [numerical type] [reserved] [reserved] [number of bits]
//
// clang-format off
enum iree_hal_element_types_t {
IREE_HAL_ELEMENT_TYPE_NONE = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_UNKNOWN, 0), // NOLINT
IREE_HAL_ELEMENT_TYPE_OPAQUE_8 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_UNKNOWN, 8), // NOLINT
IREE_HAL_ELEMENT_TYPE_OPAQUE_16 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_UNKNOWN, 16), // NOLINT
IREE_HAL_ELEMENT_TYPE_OPAQUE_32 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_UNKNOWN, 32), // NOLINT
IREE_HAL_ELEMENT_TYPE_OPAQUE_64 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_UNKNOWN, 64), // NOLINT
IREE_HAL_ELEMENT_TYPE_BOOL_8 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_BOOLEAN, 8), // NOLINT
IREE_HAL_ELEMENT_TYPE_INT_4 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER, 4), // NOLINT
IREE_HAL_ELEMENT_TYPE_SINT_4 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_SIGNED, 4), // NOLINT
IREE_HAL_ELEMENT_TYPE_UINT_4 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_UNSIGNED, 4), // NOLINT
IREE_HAL_ELEMENT_TYPE_INT_8 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER, 8), // NOLINT
IREE_HAL_ELEMENT_TYPE_SINT_8 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_SIGNED, 8), // NOLINT
IREE_HAL_ELEMENT_TYPE_UINT_8 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_UNSIGNED, 8), // NOLINT
IREE_HAL_ELEMENT_TYPE_INT_16 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER, 16), // NOLINT
IREE_HAL_ELEMENT_TYPE_SINT_16 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_SIGNED, 16), // NOLINT
IREE_HAL_ELEMENT_TYPE_UINT_16 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_UNSIGNED, 16), // NOLINT
IREE_HAL_ELEMENT_TYPE_INT_32 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER, 32), // NOLINT
IREE_HAL_ELEMENT_TYPE_SINT_32 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_SIGNED, 32), // NOLINT
IREE_HAL_ELEMENT_TYPE_UINT_32 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_UNSIGNED, 32), // NOLINT
IREE_HAL_ELEMENT_TYPE_INT_64 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER, 64), // NOLINT
IREE_HAL_ELEMENT_TYPE_SINT_64 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_SIGNED, 64), // NOLINT
IREE_HAL_ELEMENT_TYPE_UINT_64 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_INTEGER_UNSIGNED, 64), // NOLINT
IREE_HAL_ELEMENT_TYPE_FLOAT_16 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_FLOAT_IEEE, 16), // NOLINT
IREE_HAL_ELEMENT_TYPE_FLOAT_32 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_FLOAT_IEEE, 32), // NOLINT
IREE_HAL_ELEMENT_TYPE_FLOAT_64 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_FLOAT_IEEE, 64), // NOLINT
IREE_HAL_ELEMENT_TYPE_BFLOAT_16 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_FLOAT_BRAIN, 16), // NOLINT
IREE_HAL_ELEMENT_TYPE_COMPLEX_FLOAT_64 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_FLOAT_COMPLEX, 64), // NOLINT
IREE_HAL_ELEMENT_TYPE_COMPLEX_FLOAT_128 = IREE_HAL_ELEMENT_TYPE_VALUE(IREE_HAL_NUMERICAL_TYPE_FLOAT_COMPLEX, 128), // NOLINT
};
typedef uint32_t iree_hal_element_type_t;
// clang-format on
// Defines the encoding type of a buffer when known.
enum iree_hal_encoding_types_t {
// Encoding is unknown or unspecified. Generic interpretation of the buffer
// contents is not possible.
IREE_HAL_ENCODING_TYPE_OPAQUE = 0,
// Encoding is a densely-packed numpy/C-style row-major format.
// All elements are contiguous in memory.
IREE_HAL_ENCODING_TYPE_DENSE_ROW_MAJOR = 1,
// TODO(#6762): sparse encodings we care about (_SPARSE_CSR)
// We will likely want to make this a bitfield like the element type is that
// we can more easily distinguish between encoding types that we can use for
// certain operations; for example, size calculations on a DENSE_ROW_MAJOR
// and DENSE_COLUMN_MAJOR would be easier to perform if we had a bit to test
// for whether it's dense.
};
typedef uint32_t iree_hal_encoding_type_t;
// A dimension within a shape.
typedef iree_device_size_t iree_hal_dim_t;
#define PRIdim PRIdsz
//===----------------------------------------------------------------------===//
// iree_hal_buffer_view_t
//===----------------------------------------------------------------------===//
// A shaped and typed view into a storage buffer.
// This is the closest thing to a "tensor" we have, and it's purely used to ease
// application code and not treated special internally by IREE. They are
// effectively just `tuple(shape, type, buffer)`, and if the application is
// already tracking this information in its own structures this entire type can
// be ignored.
typedef struct iree_hal_buffer_view_t iree_hal_buffer_view_t;
// Creates a buffer view with the given |buffer|.
// |out_buffer_view| must be released by the caller.
IREE_API_EXPORT iree_status_t iree_hal_buffer_view_create(
iree_hal_buffer_t* buffer, iree_host_size_t shape_rank,
const iree_hal_dim_t* shape, iree_hal_element_type_t element_type,
iree_hal_encoding_type_t encoding_type, iree_allocator_t host_allocator,
iree_hal_buffer_view_t** out_buffer_view);
// Creates a buffer view with the given |buffer| and metadata from |like_view|.
// |out_buffer_view| must be released by the caller.
IREE_API_EXPORT iree_status_t iree_hal_buffer_view_create_like(
iree_hal_buffer_t* buffer, iree_hal_buffer_view_t* like_view,
iree_allocator_t host_allocator, iree_hal_buffer_view_t** out_buffer_view);
// Retains the given |buffer_view| for the caller.
IREE_API_EXPORT void iree_hal_buffer_view_retain(
iree_hal_buffer_view_t* buffer_view);
// Releases the given |buffer_view| from the caller.
IREE_API_EXPORT void iree_hal_buffer_view_release(
iree_hal_buffer_view_t* buffer_view);
// Returns the buffer underlying the buffer view.
// The caller must retain the returned buffer if they want to continue using it.
//
// NOTE: the returned buffer length will almost always be larger than the valid
// bytes representing this buffer view due to padding. Always query the actual
// valid length with iree_hal_buffer_view_byte_length instead of assuming the
// buffer is already clamped.
IREE_API_EXPORT iree_hal_buffer_t* iree_hal_buffer_view_buffer(
const iree_hal_buffer_view_t* buffer_view);
// Returns the rank of the shape associated with the buffer view.
IREE_API_EXPORT iree_host_size_t
iree_hal_buffer_view_shape_rank(const iree_hal_buffer_view_t* buffer_view);
// Returns a pointer to the shape dimensions; the array limit is defined by
// iree_hal_buffer_view_shape_rank.
IREE_API_EXPORT const iree_hal_dim_t* iree_hal_buffer_view_shape_dims(
const iree_hal_buffer_view_t* buffer_view);
// Returns the value of the given dimension.
IREE_API_EXPORT iree_hal_dim_t iree_hal_buffer_view_shape_dim(
const iree_hal_buffer_view_t* buffer_view, iree_host_size_t index);
// Returns the dimensions of the shape in |out_shape| and its rank in
// |out_shape_rank|. |rank_capacity| indicates the number of dimensions
// available in the |out_shape| buffer. If there is not enough capacity to store
// all of the dimensions IREE_STATUS_OUT_OF_RANGE is returned.
// |out_shape_rank| can be omitted if the rank is already known.
IREE_API_EXPORT iree_status_t iree_hal_buffer_view_shape(
const iree_hal_buffer_view_t* buffer_view, iree_host_size_t rank_capacity,
iree_hal_dim_t* out_shape, iree_host_size_t* out_shape_rank);
// Performs a **metadata update-only** reshape.
// The new rank and element count must match the existing values. The buffer
// contents are left untouched; if the buffer is not dense this may make the
// contents undefined.
IREE_API_EXPORT iree_status_t iree_hal_buffer_view_reshape(
iree_hal_buffer_view_t* buffer_view, const iree_hal_dim_t* shape,
iree_host_size_t shape_rank);
// Returns the total number of elements stored in the view.
IREE_API_EXPORT iree_host_size_t
iree_hal_buffer_view_element_count(const iree_hal_buffer_view_t* buffer_view);
// Returns the element type of the buffer.
IREE_API_EXPORT iree_hal_element_type_t
iree_hal_buffer_view_element_type(const iree_hal_buffer_view_t* buffer_view);
// Returns the size of each element in the buffer view in bytes.
// Note that not all buffers are contiguous or densely packed.
IREE_API_EXPORT iree_host_size_t
iree_hal_buffer_view_element_size(const iree_hal_buffer_view_t* buffer_view);
// Returns the encoding type of the buffer.
IREE_API_EXPORT iree_hal_encoding_type_t
iree_hal_buffer_view_encoding_type(const iree_hal_buffer_view_t* buffer_view);
// Returns the total size of the specified view in bytes.
// Note that not all buffers are contiguous or densely packed.
IREE_API_EXPORT iree_device_size_t
iree_hal_buffer_view_byte_length(const iree_hal_buffer_view_t* buffer_view);
// Calculates a byte offset into the |buffer_view| at the given indices.
// Requires that the encoding and element type support indexing.
IREE_API_EXPORT iree_status_t iree_hal_buffer_view_compute_offset(
const iree_hal_buffer_view_t* buffer_view, iree_host_size_t indices_count,
const iree_hal_dim_t* indices, iree_device_size_t* out_offset);
// Calculates a byte range into the |buffer_view| of the given contiguous range.
// Requires that the encoding and element type support indexing.
IREE_API_EXPORT iree_status_t iree_hal_buffer_view_compute_range(
const iree_hal_buffer_view_t* buffer_view, iree_host_size_t indices_count,
const iree_hal_dim_t* start_indices, iree_host_size_t lengths_count,
const iree_hal_dim_t* lengths, iree_device_size_t* out_start_offset,
iree_device_size_t* out_length);
//===----------------------------------------------------------------------===//
// iree_hal_buffer_view_t implementation details
//===----------------------------------------------------------------------===//
IREE_API_EXPORT void iree_hal_buffer_view_destroy(
iree_hal_buffer_view_t* buffer_view);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // IREE_HAL_BUFFER_VIEW_H_