blob: 789014584e11327f79870c4e8f6c909855913574 [file]
// Copyright 2023 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
#include "iree/hal/local/executable_library_util.h"
iree_status_t iree_hal_executable_library_verify(
const iree_hal_executable_params_t* executable_params,
const iree_hal_executable_library_v0_t* library) {
// Tooling and testing may disable verification to make it easier to define
// libraries. The compiler should never produce anything that fails
// verification, though, and should always have it enabled.
const bool disable_verification =
iree_all_bits_set(executable_params->caching_mode,
IREE_HAL_EXECUTABLE_CACHING_MODE_DISABLE_VERIFICATION);
if (disable_verification) return iree_ok_status();
// Check to make sure that the constant table has values for all constants.
if (library->constants.count != executable_params->constant_count) {
return iree_make_status(IREE_STATUS_FAILED_PRECONDITION,
"executable requires %u constants but caller "
"provided %" PRIhsz "; must match",
library->constants.count,
executable_params->constant_count);
}
// Validate that dispatch attributes are present.
if (!library->exports.attrs) {
return iree_make_status(
IREE_STATUS_FAILED_PRECONDITION,
"executable exports must provide dispatch attributes");
}
if (library->exports.count && !library->exports.names) {
return iree_make_status(IREE_STATUS_FAILED_PRECONDITION,
"executable exports must provide function names");
}
// Validate dispatch attributes are in range and names are usable.
for (uint32_t i = 0; i < library->exports.count; ++i) {
const iree_hal_executable_dispatch_attrs_v0_t dispatch_attrs =
library->exports.attrs[i];
if (dispatch_attrs.constant_count >
IREE_HAL_EXECUTABLE_MAX_CONSTANT_COUNT) {
return iree_make_status(
IREE_STATUS_OUT_OF_RANGE,
"dispatch requiring %u constants exceeds limit of %d",
dispatch_attrs.constant_count,
IREE_HAL_EXECUTABLE_MAX_CONSTANT_COUNT);
}
if (dispatch_attrs.binding_count > IREE_HAL_EXECUTABLE_MAX_BINDING_COUNT) {
return iree_make_status(
IREE_STATUS_OUT_OF_RANGE,
"dispatch requiring %u bindings exceeds limit of %d",
dispatch_attrs.binding_count, IREE_HAL_EXECUTABLE_MAX_BINDING_COUNT);
}
if (!library->exports.names[i] || !library->exports.names[i][0]) {
return iree_make_status(IREE_STATUS_FAILED_PRECONDITION,
"executable export %u missing function name", i);
}
}
return iree_ok_status();
}
iree_status_t iree_hal_executable_library_initialize_imports(
iree_hal_executable_environment_v0_t* environment,
const iree_hal_executable_import_provider_t import_provider,
const iree_hal_executable_import_table_v0_t* import_table,
iree_hal_executable_import_thunk_v0_t import_thunk,
iree_allocator_t host_allocator) {
IREE_ASSERT_ARGUMENT(environment);
IREE_ASSERT_ARGUMENT(import_thunk);
if (!import_table || !import_table->count) return iree_ok_status();
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, import_table->count);
// The thunk is used to give the loader a chance to intercept import calls
// in cases where it needs to JIT, perform FFI/ABI conversion, etc.
environment->import_thunk = import_thunk;
// Allocate storage for the imports with overflow checking.
iree_host_size_t total_size = 0;
iree_host_size_t import_contexts_offset = 0;
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, IREE_STRUCT_LAYOUT(
0, &total_size,
IREE_STRUCT_FIELD_ALIGNED(import_table->count,
iree_hal_executable_import_v0_t,
iree_max_align_t, NULL),
IREE_STRUCT_FIELD_ALIGNED(import_table->count, const void*,
iree_max_align_t,
&import_contexts_offset)));
uint8_t* base_ptr = NULL;
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_allocator_malloc(host_allocator, total_size, (void**)&base_ptr));
environment->import_funcs = (const iree_hal_executable_import_v0_t*)base_ptr;
environment->import_contexts =
(const void**)(base_ptr + import_contexts_offset);
// Try to resolve each import.
// Will fail if any required import is not found.
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_hal_executable_import_provider_try_resolve(
import_provider, import_table->count, import_table->symbols,
(void**)environment->import_funcs,
(void**)environment->import_contexts,
/*out_resolution=*/NULL));
IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
void iree_hal_executable_library_deinitialize_imports(
iree_hal_executable_environment_v0_t* environment,
iree_allocator_t host_allocator) {
// NOTE: import_funcs and import_contexts are allocated as one block.
if (environment->import_funcs != NULL) {
iree_allocator_free(host_allocator, (void*)environment->import_funcs);
}
environment->import_funcs = NULL;
environment->import_contexts = NULL;
environment->import_thunk = NULL;
}
iree_host_size_t iree_hal_executable_library_export_count(
const iree_hal_executable_library_v0_t* library) {
IREE_ASSERT_ARGUMENT(library);
return library->exports.count;
}
iree_status_t iree_hal_executable_library_export_info(
const iree_hal_executable_library_v0_t* library,
iree_hal_executable_function_t function,
iree_hal_executable_function_info_t* out_info) {
IREE_ASSERT_ARGUMENT(library);
IREE_ASSERT_ARGUMENT(out_info);
memset(out_info, 0, sizeof(*out_info));
if (!iree_hal_executable_function_is_index_in_range(function,
library->exports.count)) {
return iree_make_status(IREE_STATUS_OUT_OF_RANGE,
"function id %" PRIu64 " out of range (count: %u)",
function.value, library->exports.count);
}
const uint32_t export_ordinal = iree_hal_executable_function_index(function);
// Set the name if available.
if (library->exports.names && library->exports.names[export_ordinal]) {
out_info->name =
iree_make_cstring_view(library->exports.names[export_ordinal]);
} else {
out_info->name = iree_string_view_empty();
}
// Get dispatch attributes if available.
if (library->exports.attrs) {
const iree_hal_executable_dispatch_attrs_v0_t* attrs =
&library->exports.attrs[export_ordinal];
if (iree_any_bit_set(attrs->flags,
IREE_HAL_EXECUTABLE_DISPATCH_FLAG_V0_SEQUENTIAL)) {
out_info->flags |= IREE_HAL_EXECUTABLE_FUNCTION_FLAG_SEQUENTIAL;
}
if (iree_any_bit_set(
attrs->flags,
IREE_HAL_EXECUTABLE_DISPATCH_FLAG_V0_WORKGROUP_SIZE_DYNAMIC)) {
out_info->flags |=
IREE_HAL_EXECUTABLE_FUNCTION_FLAG_WORKGROUP_SIZE_DYNAMIC;
}
out_info->constant_count = attrs->constant_count;
out_info->binding_count = attrs->binding_count;
out_info->parameter_count = attrs->parameter_count;
out_info->workgroup_size[0] = attrs->workgroup_size_x;
out_info->workgroup_size[1] = attrs->workgroup_size_y;
out_info->workgroup_size[2] = attrs->workgroup_size_z;
}
// Occupancy info is not yet implemented.
memset(&out_info->occupancy_info, 0, sizeof(out_info->occupancy_info));
return iree_ok_status();
}
iree_status_t iree_hal_executable_library_export_parameters(
const iree_hal_executable_library_v0_t* library,
iree_hal_executable_function_t function, iree_host_size_t capacity,
iree_hal_executable_function_parameter_t* out_parameters) {
IREE_ASSERT_ARGUMENT(library);
IREE_ASSERT_ARGUMENT(out_parameters || capacity == 0);
if (!iree_hal_executable_function_is_index_in_range(function,
library->exports.count)) {
return iree_make_status(IREE_STATUS_OUT_OF_RANGE,
"function id %" PRIu64 " out of range (count: %u)",
function.value, library->exports.count);
}
const uint32_t export_ordinal = iree_hal_executable_function_index(function);
if (!library->exports.attrs || !library->exports.params ||
!library->exports.params[export_ordinal]) {
return iree_make_status(IREE_STATUS_UNAVAILABLE,
"reflection data not available");
}
const iree_hal_executable_dispatch_attrs_v0_t* attrs =
&library->exports.attrs[export_ordinal];
const iree_hal_executable_dispatch_parameter_v0_t** params =
library->exports.params;
const iree_hal_executable_dispatch_parameter_v0_t* export_params =
params[export_ordinal];
// Copy as many parameters as we can fit.
iree_host_size_t count =
iree_min(capacity, (iree_host_size_t)attrs->parameter_count);
for (iree_host_size_t i = 0; i < count; ++i) {
const iree_hal_executable_dispatch_parameter_v0_t* src = &export_params[i];
iree_hal_executable_function_parameter_t* dst = &out_parameters[i];
switch (src->type) {
case IREE_HAL_EXECUTABLE_DISPATCH_PARAM_TYPE_V0_CONSTANT:
dst->type = IREE_HAL_EXECUTABLE_FUNCTION_PARAMETER_TYPE_CONSTANT;
break;
case IREE_HAL_EXECUTABLE_DISPATCH_PARAM_TYPE_V0_BINDING:
dst->type = IREE_HAL_EXECUTABLE_FUNCTION_PARAMETER_TYPE_BINDING;
break;
case IREE_HAL_EXECUTABLE_DISPATCH_PARAM_TYPE_V0_BUFFER_PTR:
dst->type = IREE_HAL_EXECUTABLE_FUNCTION_PARAMETER_TYPE_BUFFER_PTR;
break;
default:
dst->type = IREE_HAL_EXECUTABLE_FUNCTION_PARAMETER_TYPE_CONSTANT;
break;
}
dst->size = src->size;
dst->flags = src->flags;
dst->offset = src->offset;
if (library->exports.parameter_names && src->name < UINT16_MAX &&
library->exports.parameter_names[src->name]) {
dst->name =
iree_make_cstring_view(library->exports.parameter_names[src->name]);
} else {
dst->name = iree_string_view_empty();
}
}
return iree_ok_status();
}
iree_status_t iree_hal_executable_library_lookup_export_by_name(
const iree_hal_executable_library_v0_t* library, iree_string_view_t name,
iree_hal_executable_function_t* out_export_ordinal) {
IREE_ASSERT_ARGUMENT(library);
IREE_ASSERT_ARGUMENT(out_export_ordinal);
if (!library->exports.names) {
return iree_make_status(IREE_STATUS_UNAVAILABLE,
"function names not available in library");
}
// Linear search through function names.
for (uint32_t i = 0; i < library->exports.count; ++i) {
if (library->exports.names[i]) {
iree_string_view_t export_name =
iree_make_cstring_view(library->exports.names[i]);
if (iree_string_view_equal(export_name, name)) {
*out_export_ordinal = iree_hal_executable_function_from_index(i);
return iree_ok_status();
}
}
}
return iree_make_status(IREE_STATUS_NOT_FOUND,
"export '%.*s' not found in library", (int)name.size,
name.data);
}
#if IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION
void iree_hal_executable_library_publish_source_files(
const iree_hal_executable_library_v0_t* library) {
for (uint32_t i = 0; i < library->sources.count; ++i) {
const iree_hal_executable_source_file_v0_t* source_file =
&library->sources.files[i];
IREE_TRACE_PUBLISH_SOURCE_FILE(source_file->path, source_file->path_length,
source_file->content,
source_file->content_length);
}
}
iree_zone_id_t iree_hal_executable_library_call_zone_begin(
iree_string_view_t executable_identifier,
const iree_hal_executable_library_v0_t* library, iree_host_size_t ordinal) {
iree_string_view_t entry_point_name = iree_string_view_empty();
if (library->exports.names != NULL && library->exports.names[ordinal]) {
entry_point_name = iree_make_cstring_view(library->exports.names[ordinal]);
}
if (iree_string_view_is_empty(entry_point_name)) {
entry_point_name = iree_make_cstring_view("unknown_dylib_call");
}
const char* source_file = NULL;
size_t source_file_length = 0;
uint32_t source_line = 0;
if (library->exports.stage_locations != NULL) {
for (uint32_t i = 0; i < library->exports.stage_locations->count; ++i) {
// TODO(benvanik): a way to select what location is chosen. For now we
// just pick the first one.
// const char* name = library->exports.stage_locations->names[i];
const iree_hal_executable_source_location_v0_t* location =
&library->exports.stage_locations->locations[i];
source_file = location->path;
source_file_length = location->path_length;
source_line = location->line;
break;
}
}
if (source_file == NULL) {
if (library->exports.source_locations != NULL) {
// We have source location data, so use it.
const iree_hal_executable_source_location_v0_t* location =
&library->exports.source_locations[ordinal];
source_file = location->path;
source_file_length = location->path_length;
source_line = location->line;
} else {
// No source location data, so make do with what we have.
source_file = executable_identifier.data;
source_file_length = executable_identifier.size;
source_line = ordinal;
}
}
IREE_TRACE_ZONE_BEGIN_EXTERNAL(z0, source_file, source_file_length,
source_line, entry_point_name.data,
entry_point_name.size, NULL, 0);
if (library->exports.tags != NULL) {
const char* tag = library->exports.tags[ordinal];
if (tag) {
IREE_TRACE_ZONE_APPEND_TEXT(z0, tag);
}
}
return z0;
}
#endif // IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION