blob: f22cd04a87db2c5593bebcf404ab7b3ba9b68714 [file] [log] [blame]
// Copyright 2022 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 <stdio.h>
// Low-level IREE VM APIs.
// The higher-level iree/runtime/api.h can be used for more complete ML-like
// programs using the hardware abstraction layer (HAL). This simple sample just
// uses base VM types.
#include "iree/base/api.h"
#include "iree/vm/api.h"
#include "iree/vm/bytecode/module.h"
// HACK: this pokes in to private APIs for IO helpers while we expect
// applications to bring their own IO.
#include "iree/base/internal/file_io.h"
// Custom native module used in the sample.
// Modules may be linked in from native code or other bytecode modules loaded at
// runtime: there's no difference.
#include "module.h"
// NOTE: CHECKs are dangerous but this is a sample; a real application would
// want to handle errors gracefully. We know in this constrained case that
// these won't fail unless something is catastrophically wrong (out of memory,
// solar flares, etc).
int main(int argc, char** argv) {
if (argc != 3) {
fprintf(
stderr,
"Usage:\n"
" custom-module-basic-run - <entry.point> # read from stdin\n"
" custom-module-basic-run </path/to/say_hello.vmfb> <entry.point>\n");
fprintf(stderr, " (See the README for this sample for details)\n ");
return -1;
}
// Internally IREE does not (in general) use malloc and instead uses the
// provided allocator to allocate and free memory. Applications can integrate
// their own allocator as-needed.
iree_allocator_t allocator = iree_allocator_system();
// Create the root isolated VM instance that we can create contexts within.
iree_vm_instance_t* instance = NULL;
IREE_CHECK_OK(iree_vm_instance_create(IREE_VM_TYPE_CAPACITY_DEFAULT,
allocator, &instance));
// Create the custom module that can be reused across contexts.
iree_vm_module_t* custom_module = NULL;
IREE_CHECK_OK(
iree_custom_module_basic_create(instance, allocator, &custom_module));
// Load the module from stdin or a file on disk.
// Applications can ship and load modules however they want (such as mapping
// them into memory instead of allocating like this). Modules can also be
// embedded in the binary but in those cases it makes more sense to use emitc
// to avoid the bytecode entirely and have a fully static build (see
// samples/emitc_modules/ for some examples).
const char* module_path = argv[1];
iree_file_contents_t* module_contents = NULL;
if (strcmp(module_path, "-") == 0) {
IREE_CHECK_OK(iree_stdin_read_contents(allocator, &module_contents));
} else {
IREE_CHECK_OK(iree_file_read_contents(
module_path, IREE_FILE_READ_FLAG_DEFAULT, allocator, &module_contents));
}
// Load the bytecode module from the vmfb.
// This module can be reused across multiple contexts.
// Note that we let the module retain the file contents for as long as needed.
iree_vm_module_t* bytecode_module = NULL;
IREE_CHECK_OK(iree_vm_bytecode_module_create(
instance, module_contents->const_buffer,
iree_file_contents_deallocator(module_contents), allocator,
&bytecode_module));
// Create the context for this invocation reusing the loaded modules.
// Contexts hold isolated state and can be reused for multiple calls.
// Note that the module order matters: the input user module is dependent on
// the custom module.
iree_vm_module_t* modules[] = {custom_module, bytecode_module};
iree_vm_context_t* context = NULL;
IREE_CHECK_OK(iree_vm_context_create_with_modules(
instance, IREE_VM_CONTEXT_FLAG_NONE, IREE_ARRAYSIZE(modules), modules,
allocator, &context));
// Lookup the function by fully-qualified name (module.func).
iree_vm_function_t function;
IREE_CHECK_OK(iree_vm_context_resolve_function(
context, iree_make_cstring_view(argv[2]), &function));
fprintf(stdout, "INVOKE BEGIN %s\n", argv[2]);
fflush(stdout);
// Synchronously invoke the requested function.
// We don't pass in/out anything in these simple examples so the I/O lists
// are not needed.
IREE_CHECK_OK(iree_vm_invoke(context, function, IREE_VM_INVOCATION_FLAG_NONE,
/*policy=*/NULL, /*inputs=*/NULL,
/*outputs=*/NULL, allocator));
fprintf(stdout, "INVOKE END\n");
fflush(stdout);
iree_vm_context_release(context);
iree_vm_module_release(bytecode_module);
iree_vm_module_release(custom_module);
iree_vm_instance_release(instance);
return 0;
}