blob: b93619f10ab4d70a837f37114fb0d91221844976 [file] [log] [blame]
// 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/builtins/ukernel/api.h"
#include "iree/hal/local/executable_plugin.h"
// Implementation of iree_uk_assert_fail failure is deferred to users code, i.e.
// to us here, as core ukernel/ code can't use the standard library.
#if defined(IREE_UK_STANDALONE) // Building a standalone plugin.
void iree_uk_assert_fail(const char* file, int line, const char* function,
const char* condition) {
// Doing nothing at the moment.
}
#else // Building a system plugin.
#include <stdio.h>
#include <stdlib.h>
void iree_uk_assert_fail(const char* file, int line, const char* function,
const char* condition) {
fflush(stdout);
// Must be a single fprintf call (which must make a single write) - typically
// called from multiple worker threads concurrently.
fprintf(stderr, "%s:%d: %s: assertion failed: %s\n", file, line, function,
condition);
fflush(stderr);
abort();
}
#endif // defined(IREE_UK_STANDALONE)
// Plugin entry points wrapping the actual ukernels.
static int iree_uk_plugin_mmt4d(void* context, void* params_ptr,
void* reserved) {
iree_uk_mmt4d((const iree_uk_mmt4d_params_t*)params_ptr);
return 0;
}
static int iree_uk_plugin_pack(void* context, void* params_ptr,
void* reserved) {
iree_uk_pack((const iree_uk_pack_params_t*)params_ptr);
return 0;
}
static int iree_uk_plugin_unpack(void* context, void* params_ptr,
void* reserved) {
iree_uk_unpack((const iree_uk_unpack_params_t*)params_ptr);
return 0;
}
static iree_hal_executable_plugin_status_t iree_uk_plugin_load(
const iree_hal_executable_plugin_environment_v0_t* environment,
size_t param_count, const iree_hal_executable_plugin_string_pair_t* params,
void** out_self) {
*out_self = NULL; // no state in this plugin
return iree_hal_executable_plugin_ok_status();
}
// Called to free any plugin state allocated in load.
static void iree_uk_plugin_unload(void* self) {}
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
// Called to resolve one or more imports by symbol name.
// See the plugin API header for more information. Note that some of the
// functions may already be resolved and some may be optional.
static iree_hal_executable_plugin_status_t iree_uk_plugin_resolve(
void* self, const iree_hal_executable_plugin_resolve_params_v0_t* params,
iree_hal_executable_plugin_resolution_t* out_resolution) {
typedef struct {
const char* symbol_name;
const void* fn_ptr;
} plugin_entry_point_t;
static const plugin_entry_point_t entry_points[] = {
{"ukernel.mmt4d", iree_uk_plugin_mmt4d},
{"ukernel.pack", iree_uk_plugin_pack},
{"ukernel.unpack", iree_uk_plugin_unpack},
};
*out_resolution = 0;
bool any_required_not_found = false;
for (size_t i = 0; i < params->count; ++i) {
if (params->out_fn_ptrs[i]) continue;
const char* symbol_name = params->symbol_names[i];
bool is_optional =
iree_hal_executable_plugin_import_is_optional(symbol_name);
if (is_optional) ++symbol_name;
bool found = false;
for (int ep_idx = 0; ep_idx < ARRAYSIZE(entry_points); ++ep_idx) {
const plugin_entry_point_t* entry_point = &entry_points[ep_idx];
if (iree_hal_executable_plugin_strcmp(symbol_name,
entry_point->symbol_name) == 0) {
params->out_fn_ptrs[i] = (void*)(entry_point->fn_ptr);
params->out_fn_contexts[i] = NULL;
found = true;
break;
}
}
if (!found) {
if (is_optional) {
*out_resolution |=
IREE_HAL_EXECUTABLE_PLUGIN_RESOLUTION_MISSING_OPTIONAL;
} else {
any_required_not_found = true;
}
}
}
return any_required_not_found
? iree_hal_executable_plugin_status_from_code(
IREE_HAL_EXECUTABLE_PLUGIN_STATUS_NOT_FOUND)
: iree_hal_executable_plugin_ok_status();
}
// Exported on the shared library and used by the runtime to query the plugin
// interface. When statically linking the plugin this is just a function that
// can be called and can have any name to allow for multiple plugins. When
// dynamically linking the exported symbol must be exactly this with no C++
// name mangling.
IREE_HAL_EXECUTABLE_PLUGIN_EXPORT const iree_hal_executable_plugin_header_t**
iree_hal_executable_plugin_query(
iree_hal_executable_plugin_version_t max_version, void* reserved) {
static const iree_hal_executable_plugin_header_t header = {
// Declares what library version is present: newer runtimes may support
// loading older plugins but newer plugins cannot load on older runtimes.
.version = IREE_HAL_EXECUTABLE_PLUGIN_VERSION_LATEST,
#if defined(IREE_UK_STANDALONE) // Building a standalone plugin.
// Name and description are used for tracing/logging/diagnostics.
.name = "builtin_ukernel_standalone_plugin",
.description = "builtin ukernels as standalone plugin (" __FILE__ ")",
// Standalone plugins must declare that they are standalone so that the
// runtime can verify support.
.features = IREE_HAL_EXECUTABLE_PLUGIN_FEATURE_STANDALONE,
// Standalone plugins don't support sanitizers.
.sanitizer = IREE_HAL_EXECUTABLE_PLUGIN_SANITIZER_NONE,
#else // Building a system plugin.
// Name and description are used for tracing/logging/diagnostics.
.name = "builtin_ukernel_system_plugin",
.description = "builtin ukernels as system plugin (" __FILE__ ")",
.features = 0,
// Let the runtime know what sanitizer this plugin was compiled with.
.sanitizer = IREE_HAL_EXECUTABLE_PLUGIN_SANITIZER_KIND,
#endif // defined(IREE_UK_STANDALONE)
};
static const iree_hal_executable_plugin_v0_t plugin = {
.header = &header,
.load = iree_uk_plugin_load,
.unload = iree_uk_plugin_unload,
.resolve = iree_uk_plugin_resolve,
};
return max_version <= IREE_HAL_EXECUTABLE_PLUGIN_VERSION_LATEST
? (const iree_hal_executable_plugin_header_t**)&plugin
: NULL;
}