| // 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; |
| } |