blob: 198818122760821aa8ca597c274aeca9009ddecd [file] [log] [blame]
// Copyright 2019 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_VM_BYTECODE_MODULE_IMPL_H_
#define IREE_VM_BYTECODE_MODULE_IMPL_H_
#include <stdint.h>
#include <string.h>
// VC++ does not have C11's stdalign.h.
#if !defined(_MSC_VER)
#include <stdalign.h>
#endif // _MSC_VER
#include "iree/base/api.h"
#include "iree/vm/api.h"
// NOTE: include order matters:
#include "iree/base/internal/flatcc/parsing.h"
#include "iree/schemas/bytecode_module_def_reader.h"
#include "iree/schemas/bytecode_module_def_verifier.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#define VMMAX(a, b) (((a) > (b)) ? (a) : (b))
#define VMMIN(a, b) (((a) < (b)) ? (a) : (b))
// Major bytecode version; mismatches on this will fail in either direction.
// This allows coarse versioning of completely incompatible versions.
// Matches BytecodeEncoder::kVersionMajor in the compiler.
#define IREE_VM_BYTECODE_VERSION_MAJOR 10
// Minor bytecode version; lower versions are allowed to enable newer runtimes
// to load older serialized files when there are backwards-compatible changes.
// Higher versions are disallowed as they occur when new ops are added that
// otherwise cannot be executed by older runtimes.
// Matches BytecodeEncoder::kVersionMinor in the compiler.
#define IREE_VM_BYTECODE_VERSION_MINOR 0
// Maximum register count per bank.
// This determines the bits required to reference registers in the VM bytecode.
#define IREE_I32_REGISTER_COUNT 0x7FFF
#define IREE_REF_REGISTER_COUNT 0x7FFF
#define IREE_I32_REGISTER_MASK 0x7FFF
#define IREE_REF_REGISTER_TYPE_BIT 0x8000
#define IREE_REF_REGISTER_MOVE_BIT 0x4000
#define IREE_REF_REGISTER_MASK 0x3FFF
// A loaded bytecode module.
typedef struct iree_vm_bytecode_module_t {
// Interface routing to the bytecode module functions.
// Must be first in the struct as we dereference the interface to find our
// members below.
iree_vm_module_t interface;
// Table of internal function bytecode descriptors.
// Mapped 1:1 with internal functions. Each defined bytecode span represents a
// range of bytes in |bytecode_data|.
iree_host_size_t function_descriptor_count;
const iree_vm_FunctionDescriptor_t* function_descriptor_table;
// A pointer to the bytecode data embedded within the module.
iree_const_byte_span_t bytecode_data;
// Allocator this module was allocated with and must be freed with.
iree_allocator_t allocator;
// Underlying archive data and allocator (which may be null).
iree_const_byte_span_t archive_contents;
iree_allocator_t archive_allocator;
// Offset into the archive data where external read-only data begins.
// This is added to any relative rodata reference in the FlatBuffer to get the
// aligned physical offset where content is located.
iree_host_size_t archive_rodata_offset;
// Loaded FlatBuffer module pointing into the archive contents.
iree_vm_BytecodeModuleDef_table_t def;
// Type table mapping module type IDs to registered VM types.
iree_host_size_t type_count;
iree_vm_type_def_t type_table[];
} iree_vm_bytecode_module_t;
// A resolved and split import in the module state table.
//
// NOTE: a table of these are stored per module per context so ideally we'd
// only store the absolute minimum information to reduce our fixed overhead.
// There's a big tradeoff though as a few extra bytes here can avoid non-trivial
// work per import function invocation.
typedef struct iree_vm_bytecode_import_t {
// Import function in the source module.
iree_vm_function_t function;
// Pre-parsed argument/result calling convention string fragments.
// For example, 0ii.r will be split to arguments=ii and results=r.
iree_string_view_t arguments;
iree_string_view_t results;
// Precomputed argument/result size requirements for marshaling values.
// Only usable for non-variadic signatures. Results are always usable as they
// don't support variadic values (yet).
uint16_t argument_buffer_size;
uint16_t result_buffer_size;
} iree_vm_bytecode_import_t;
// Per-instance module state.
// This is allocated with a provided allocator as a single flat allocation.
// This struct is a prefix to the allocation pointing into the dynamic offsets
// of the allocation storage.
typedef struct iree_vm_bytecode_module_state_t {
// Combined rwdata storage for the entire module, including globals.
// Aligned to 16 bytes (128-bits) for SIMD usage.
iree_byte_span_t rwdata_storage;
// Global ref values, indexed by global ordinal.
iree_host_size_t global_ref_count;
iree_vm_ref_t* global_ref_table;
// TODO(benvanik): move to iree_vm_bytecode_module_t if always static.
// Initialized references to rodata segments.
// Right now these don't do much, however we can perform lazy caching and
// on-the-fly decompression using this information.
iree_host_size_t rodata_ref_count;
iree_vm_buffer_t* rodata_ref_table;
// Resolved function imports.
iree_host_size_t import_count;
iree_vm_bytecode_import_t* import_table;
// Allocator used for the state itself and any runtime allocations needed.
iree_allocator_t allocator;
} iree_vm_bytecode_module_state_t;
// Begins execution of the current frame and continues until either a yield or
// return.
iree_status_t iree_vm_bytecode_dispatch_begin(
iree_vm_stack_t* stack, iree_vm_bytecode_module_t* module,
const iree_vm_function_call_t call, iree_string_view_t cconv_arguments,
iree_string_view_t cconv_results);
// Resumes execution of an in-progress frame and continues until either a yield
// or return.
iree_status_t iree_vm_bytecode_dispatch_resume(
iree_vm_stack_t* stack, iree_vm_bytecode_module_t* module,
iree_byte_span_t call_results);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // IREE_VM_BYTECODE_MODULE_IMPL_H_