blob: 5228d4f28c52742b953db9f60724a7f5bf7eef09 [file]
// 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
#include "iree/vm/module.h"
#include <string.h>
#include "iree/base/internal/atomics.h"
#include "iree/base/tracing.h"
#include "iree/vm/ref.h"
IREE_API_EXPORT iree_status_t iree_vm_function_call_get_cconv_fragments(
const iree_vm_function_signature_t* signature,
iree_string_view_t* out_arguments, iree_string_view_t* out_results) {
memset(out_arguments, 0, sizeof(*out_arguments));
memset(out_results, 0, sizeof(*out_results));
iree_string_view_t cconv = signature->calling_convention;
if (!cconv.size) {
// No cconv string, so function is `()->()`.
return iree_ok_status();
} else if (cconv.data[0] != '0') {
return iree_make_status(IREE_STATUS_UNIMPLEMENTED,
"unsupported cconv version %c", cconv.data[0]);
}
iree_string_view_t cconv_body = iree_string_view_substr(cconv, 1, INTPTR_MAX);
if (iree_string_view_split(cconv_body, '_', out_arguments, out_results) ==
-1) {
*out_arguments = cconv_body;
}
return iree_ok_status();
}
static iree_status_t iree_vm_function_call_count_fragment_values(
iree_string_view_t cconv_fragment, iree_host_size_t* out_count) {
IREE_ASSERT_ARGUMENT(out_count);
*out_count = 0;
iree_host_size_t count = 0;
for (iree_host_size_t i = 0; i < cconv_fragment.size; ++i) {
switch (cconv_fragment.data[i]) {
case IREE_VM_CCONV_TYPE_VOID:
break;
case IREE_VM_CCONV_TYPE_I32:
case IREE_VM_CCONV_TYPE_F32:
case IREE_VM_CCONV_TYPE_I64:
case IREE_VM_CCONV_TYPE_F64:
case IREE_VM_CCONV_TYPE_REF:
++count;
break;
case IREE_VM_CCONV_TYPE_SPAN_START: {
for (i = i + 1; i < cconv_fragment.size &&
cconv_fragment.data[i] != IREE_VM_CCONV_TYPE_SPAN_END;
++i) {
switch (cconv_fragment.data[i]) {
case IREE_VM_CCONV_TYPE_VOID:
break;
case IREE_VM_CCONV_TYPE_I32:
case IREE_VM_CCONV_TYPE_F32:
case IREE_VM_CCONV_TYPE_I64:
case IREE_VM_CCONV_TYPE_F64:
case IREE_VM_CCONV_TYPE_REF:
++count;
break;
default:
return iree_make_status(IREE_STATUS_UNIMPLEMENTED,
"unsupported cconv span type %c",
cconv_fragment.data[i]);
}
}
} break;
default:
return iree_make_status(IREE_STATUS_UNIMPLEMENTED,
"unsupported cconv type %c",
cconv_fragment.data[i]);
}
}
*out_count = count;
return iree_ok_status();
}
IREE_API_EXPORT iree_status_t iree_vm_function_call_count_arguments_and_results(
const iree_vm_function_signature_t* signature,
iree_host_size_t* out_argument_count, iree_host_size_t* out_result_count) {
IREE_ASSERT_ARGUMENT(signature);
IREE_ASSERT_ARGUMENT(out_argument_count);
IREE_ASSERT_ARGUMENT(out_result_count);
*out_argument_count = 0;
*out_result_count = 0;
iree_string_view_t arguments, results;
IREE_RETURN_IF_ERROR(iree_vm_function_call_get_cconv_fragments(
signature, &arguments, &results));
IREE_RETURN_IF_ERROR(iree_vm_function_call_count_fragment_values(
arguments, out_argument_count));
IREE_RETURN_IF_ERROR(
iree_vm_function_call_count_fragment_values(results, out_result_count));
return iree_ok_status();
}
IREE_API_EXPORT bool iree_vm_function_call_is_variadic_cconv(
iree_string_view_t cconv) {
return iree_string_view_find_char(cconv, IREE_VM_CCONV_TYPE_SPAN_START, 0) !=
IREE_STRING_VIEW_NPOS;
}
IREE_API_EXPORT iree_status_t iree_vm_function_call_compute_cconv_fragment_size(
iree_string_view_t cconv_fragment,
const iree_vm_register_list_t* segment_size_list,
iree_host_size_t* out_required_size) {
iree_host_size_t required_size = 0;
for (iree_host_size_t i = 0, seg_i = 0; i < cconv_fragment.size;
++i, ++seg_i) {
switch (cconv_fragment.data[i]) {
case IREE_VM_CCONV_TYPE_VOID:
break;
case IREE_VM_CCONV_TYPE_I32:
case IREE_VM_CCONV_TYPE_F32:
required_size += sizeof(int32_t);
break;
case IREE_VM_CCONV_TYPE_I64:
case IREE_VM_CCONV_TYPE_F64:
required_size += sizeof(int64_t);
break;
case IREE_VM_CCONV_TYPE_REF:
required_size += sizeof(iree_vm_ref_t);
break;
case IREE_VM_CCONV_TYPE_SPAN_START: {
if (IREE_UNLIKELY(!segment_size_list) ||
IREE_UNLIKELY(seg_i >= segment_size_list->size)) {
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"variadic argument found but segment size "
"list is missing/underflowed");
}
iree_host_size_t span_count = segment_size_list->registers[seg_i];
required_size += sizeof(int32_t); // count
iree_host_size_t span_size = 0;
for (i = i + 1; i < cconv_fragment.size &&
cconv_fragment.data[i] != IREE_VM_CCONV_TYPE_SPAN_END;
++i) {
switch (cconv_fragment.data[i]) {
case IREE_VM_CCONV_TYPE_VOID:
break;
case IREE_VM_CCONV_TYPE_I32:
case IREE_VM_CCONV_TYPE_F32:
span_size += sizeof(int32_t);
break;
case IREE_VM_CCONV_TYPE_I64:
case IREE_VM_CCONV_TYPE_F64:
span_size += sizeof(int64_t);
break;
case IREE_VM_CCONV_TYPE_REF:
span_size += sizeof(iree_vm_ref_t);
break;
default:
return iree_make_status(IREE_STATUS_UNIMPLEMENTED,
"unsupported cconv span type %c",
cconv_fragment.data[i]);
}
}
required_size += span_size * span_count;
} break;
default:
return iree_make_status(IREE_STATUS_UNIMPLEMENTED,
"unsupported cconv type %c",
cconv_fragment.data[i]);
}
}
*out_required_size = required_size;
return iree_ok_status();
}
IREE_API_EXPORT void iree_vm_function_call_release(
iree_vm_function_call_t* call,
const iree_vm_function_signature_t* signature) {
if (!call->arguments.data_length || !call->results.data_length) {
return;
}
iree_string_view_t cconv = signature->calling_convention;
if (cconv.size == 0 || cconv.data[0] != '0') return;
uint8_t* p = call->arguments.data;
for (iree_host_size_t i = 1; i < cconv.size; ++i) {
char c = cconv.data[i];
if (c == '_') {
// Switch to results.
p = call->results.data;
}
switch (c) {
case IREE_VM_CCONV_TYPE_VOID:
break;
case IREE_VM_CCONV_TYPE_I32:
case IREE_VM_CCONV_TYPE_F32:
p += sizeof(int32_t);
break;
case IREE_VM_CCONV_TYPE_I64:
case IREE_VM_CCONV_TYPE_F64:
p += sizeof(int64_t);
break;
case IREE_VM_CCONV_TYPE_REF:
iree_vm_ref_release((iree_vm_ref_t*)p);
p += sizeof(iree_vm_ref_t);
break;
}
}
}
IREE_API_EXPORT iree_status_t
iree_vm_module_initialize(iree_vm_module_t* module, void* self) {
IREE_TRACE_ZONE_BEGIN(z0);
memset(module, 0, sizeof(iree_vm_module_t));
module->self = self;
iree_atomic_ref_count_init(&module->ref_count);
IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
IREE_API_EXPORT void iree_vm_module_retain(iree_vm_module_t* module) {
if (module) {
iree_atomic_ref_count_inc(&module->ref_count);
}
}
IREE_API_EXPORT void iree_vm_module_release(iree_vm_module_t* module) {
if (module && iree_atomic_ref_count_dec(&module->ref_count) == 1) {
module->destroy(module->self);
}
}
IREE_API_EXPORT iree_string_view_t
iree_vm_module_name(const iree_vm_module_t* module) {
if (!module) {
return iree_make_cstring_view("null");
}
return module->name(module->self);
}
IREE_API_EXPORT iree_vm_module_signature_t
iree_vm_module_signature(const iree_vm_module_t* module) {
if (!module) {
iree_vm_module_signature_t empty;
memset(&empty, 0, sizeof(empty));
return empty;
}
return module->signature(module->self);
}
IREE_API_EXPORT iree_status_t iree_vm_module_lookup_function_by_name(
const iree_vm_module_t* module, iree_vm_function_linkage_t linkage,
iree_string_view_t name, iree_vm_function_t* out_function) {
return module->lookup_function(module->self, linkage, name, out_function);
}
IREE_API_EXPORT iree_status_t iree_vm_module_lookup_function_by_ordinal(
const iree_vm_module_t* module, iree_vm_function_linkage_t linkage,
iree_host_size_t ordinal, iree_vm_function_t* out_function,
iree_string_view_t* linkage_name) {
return module->get_function(module->self, linkage, ordinal, out_function,
/*out_name=*/linkage_name,
/*out_signature=*/NULL);
}
IREE_API_EXPORT iree_string_view_t
iree_vm_function_name(const iree_vm_function_t* function) {
iree_string_view_t name;
iree_status_t status = function->module->get_function(
function->module->self, function->linkage, function->ordinal,
/*out_function=*/NULL,
/*out_name=*/&name,
/*out_signature=*/NULL);
if (!iree_status_is_ok(status)) {
iree_status_ignore(status);
return iree_make_cstring_view("<error>");
}
return name;
}
IREE_API_EXPORT iree_vm_function_signature_t
iree_vm_function_signature(const iree_vm_function_t* function) {
iree_vm_function_signature_t signature;
memset(&signature, 0, sizeof(signature));
IREE_IGNORE_ERROR(function->module->get_function(
function->module->self, function->linkage, function->ordinal,
/*out_function=*/NULL,
/*out_name=*/NULL,
/*out_signature=*/&signature));
return signature;
}
IREE_API_EXPORT iree_string_view_t iree_vm_function_reflection_attr(
const iree_vm_function_t* function, iree_string_view_t key) {
iree_vm_module_t* module = function->module;
if (!module->get_function_reflection_attr) {
return iree_string_view_empty();
}
for (int index = 0;; ++index) {
iree_string_view_t index_key, index_value;
iree_status_t status = module->get_function_reflection_attr(
module->self, function->linkage, function->ordinal, index, &index_key,
&index_value);
if (!iree_status_is_ok(status)) {
iree_status_ignore(status);
break;
}
if (iree_string_view_equal(key, index_key)) {
return index_value;
}
}
return iree_string_view_empty();
}
IREE_API_EXPORT iree_status_t iree_vm_get_function_reflection_attr(
iree_vm_function_t function, iree_host_size_t index,
iree_string_view_t* key, iree_string_view_t* value) {
if (!function.module->get_function_reflection_attr) {
return iree_make_status(IREE_STATUS_NOT_FOUND,
"reflection not available for the given module");
}
return function.module->get_function_reflection_attr(
function.module->self, function.linkage, function.ordinal, index, key,
value);
}