Enable lazy Orc JIT feature (#732)

The feature is disabled by default, to enable it, please use
`cmake -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1`
to build iwasm.
This commit is contained in:
Wenyong Huang
2021-09-07 11:39:57 +08:00
committed by GitHub
parent 7e60b8608e
commit 4b0d6083a3
9 changed files with 535 additions and 6 deletions

View File

@ -75,10 +75,17 @@
#define WASM_ENABLE_JIT 0
#endif
#ifndef WASM_ENABLE_LAZY_JIT
#define WASM_ENABLE_LAZY_JIT 0
#endif
#if (WASM_ENABLE_AOT == 0) && (WASM_ENABLE_JIT != 0)
/* JIT can only be enabled when AOT is enabled */
/* LazyJIT or MCJIT can only be enabled when AOT is enabled */
#undef WASM_ENABLE_JIT
#define WASM_ENABLE_JIT 0
#undef WASM_ENABLE_LAZY_JIT
#define WASM_ENABLE_LAZY_JIT 0
#endif
#ifndef WASM_ENABLE_WAMR_COMPILER

View File

@ -2535,6 +2535,13 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
char func_name[32];
AOTModule *module;
#if WASM_ENABLE_LAZY_JIT != 0
LLVMOrcThreadSafeModuleRef ts_module;
LLVMOrcJITDylibRef main_dylib;
LLVMErrorRef error;
LLVMOrcJITTargetAddress func_addr = 0;
#endif
/* Allocate memory for module */
if (!(module =
loader_malloc(sizeof(AOTModule), error_buf, error_buf_size))) {
@ -2597,6 +2604,47 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
goto fail2;
}
#if WASM_ENABLE_LAZY_JIT != 0
bh_assert(comp_ctx->lazy_orcjit);
main_dylib = LLVMOrcLLLazyJITGetMainJITDylib(comp_ctx->lazy_orcjit);
if (!main_dylib) {
set_error_buf(error_buf, error_buf_size,
"failed to get dynmaic library reference");
goto fail3;
}
ts_module = LLVMOrcCreateNewThreadSafeModule(comp_ctx->module,
comp_ctx->ts_context);
if (!ts_module) {
set_error_buf(error_buf, error_buf_size,
"failed to create thread safe module");
goto fail3;
}
if ((error = LLVMOrcLLLazyJITAddLLVMIRModule(comp_ctx->lazy_orcjit,
main_dylib, ts_module))) {
/*
* If adding the ThreadSafeModule fails then we need to clean it up
* ourselves. If adding it succeeds the JIT will manage the memory.
*/
aot_handle_llvm_errmsg(error_buf, error_buf_size,
"failed to addIRModule: ", error);
goto fail4;
}
for (i = 0; i < comp_data->func_count; i++) {
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
if ((error = LLVMOrcLLLazyJITLookup(comp_ctx->lazy_orcjit,
&func_addr, func_name))) {
aot_handle_llvm_errmsg(error_buf, error_buf_size,
"cannot lookup: ", error);
goto fail3;
}
module->func_ptrs[i] = (void *)func_addr;
func_addr = 0;
}
#else
/* Resolve function addresses */
bh_assert(comp_ctx->exec_engine);
for (i = 0; i < comp_data->func_count; i++) {
@ -2609,6 +2657,7 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
goto fail3;
}
}
#endif /* WASM_ENABLE_LAZY_JIT != 0 */
/* Allocation memory for function type indexes */
size = (uint64)module->func_count * sizeof(uint32);
@ -2662,6 +2711,11 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
return module;
#if WASM_ENABLE_LAZY_JIT != 0
fail4:
LLVMOrcDisposeThreadSafeModule(ts_module);
#endif
fail3:
if (module->func_ptrs)
wasm_runtime_free(module->func_ptrs);

View File

@ -1207,13 +1207,174 @@ WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
void LLVMAddPromoteMemoryToRegisterPass(LLVMPassManagerRef PM);
#if WASM_ENABLE_LAZY_JIT != 0
void
aot_handle_llvm_errmsg(char *error_buf,
uint32 error_buf_size,
const char *string,
LLVMErrorRef error)
{
char *err_msg = LLVMGetErrorMessage(error);
if (error_buf != NULL) {
snprintf(error_buf, error_buf_size,
"%s: %s", string, err_msg);
}
LLVMDisposeErrorMessage(err_msg);
}
static bool
llvm_orcjit_create(AOTCompContext *comp_ctx)
{
char *err_msg = NULL;
char *cpu = NULL;
char *features = NULL;
char *llvm_triple = NULL;
char buf[128] = {0};
LLVMErrorRef error;
LLVMTargetRef llvm_targetref = NULL;
LLVMTargetMachineRef tm_opt = NULL;
LLVMTargetMachineRef tm_opt2 = NULL;
LLVMOrcLLLazyJITRef lazy_orcjit = NULL;
LLVMOrcJITTargetMachineBuilderRef tm_builder = NULL;
LLVMOrcLLLazyJITBuilderRef lazy_orcjit_builder = NULL;
#if LLVM_VERSION_MAJOR < 12
LLVMOrcJITDylibDefinitionGeneratorRef main_gen = NULL;
#else
LLVMOrcDefinitionGeneratorRef main_gen = NULL;
#endif
llvm_triple = LLVMGetDefaultTargetTriple();
if (llvm_triple == NULL) {
snprintf(buf, sizeof(buf), "failed to get default target triple.");
goto fail;
}
if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &err_msg) != 0) {
snprintf(buf, sizeof(buf),
"failed to get target reference from triple %s.", err_msg);
LLVMDisposeMessage(err_msg);
goto fail;
}
if (!LLVMTargetHasJIT(llvm_targetref)) {
snprintf(buf, sizeof(buf), "unspported JIT on this platform.");
goto fail;
}
cpu = LLVMGetHostCPUName();
if (cpu == NULL) {
snprintf(buf, sizeof(buf), "failed to get host cpu information.");
goto fail;
}
features = LLVMGetHostCPUFeatures();
if (features == NULL) {
snprintf(buf, sizeof(buf), "failed to get host cpu features.");
goto fail;
}
LOG_VERBOSE("LLVM ORCJIT detected CPU \"%s\", with features \"%s\"\n",
cpu, features);
tm_opt = LLVMCreateTargetMachine(llvm_targetref, llvm_triple,
cpu, features,
LLVMCodeGenLevelAggressive,
LLVMRelocDefault,
LLVMCodeModelJITDefault);
if (!tm_opt) {
snprintf(buf, sizeof(buf), "failed to create target machine.");
goto fail;
}
tm_opt2 = LLVMCreateTargetMachine(llvm_targetref, llvm_triple,
cpu, features,
LLVMCodeGenLevelAggressive,
LLVMRelocDefault,
LLVMCodeModelJITDefault);
if (!tm_opt2) {
snprintf(buf, sizeof(buf), "failed to create target machine2.");
goto fail;
}
/* if success, it will dispose tm_opt2 memory. */
tm_builder = LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm_opt2);
if (!tm_builder) {
snprintf(buf, sizeof(buf), "failed to create target machine builder.");
goto fail;
}
tm_opt2 = NULL;
lazy_orcjit_builder = LLVMOrcCreateLLLazyJITBuilder();
if (!lazy_orcjit_builder) {
snprintf(buf, sizeof(buf), "failed to create lazy jit builder.");
goto fail;
}
LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(lazy_orcjit_builder,
tm_builder);
/* if success, it will dispose lazy_orcjit_builder memory */
error = LLVMOrcCreateLLLazyJIT(&lazy_orcjit, lazy_orcjit_builder);
if (error) {
aot_handle_llvm_errmsg(buf, sizeof(buf),
"failed to create llvm lazy orcjit instance",
error);
goto fail;
}
lazy_orcjit_builder = NULL;
error = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(
&main_gen, LLVMOrcLLLazyJITGetGlobalPrefix(lazy_orcjit),
0, NULL);
if (error) {
aot_handle_llvm_errmsg(buf, sizeof(buf),
"failed to create dynmaic library search generator", error);
goto fail;
}
LLVMOrcJITDylibAddGenerator(LLVMOrcLLLazyJITGetMainJITDylib(lazy_orcjit),
main_gen);
comp_ctx->lazy_orcjit = lazy_orcjit;
comp_ctx->target_machine = tm_opt;
comp_ctx->tm_builder = tm_builder;
LLVMDisposeMessage(llvm_triple);
LLVMDisposeMessage(cpu);
LLVMDisposeMessage(features);
return true;
fail:
if (lazy_orcjit)
LLVMOrcDisposeLLLazyJIT(lazy_orcjit);
if (tm_builder)
LLVMOrcDisposeJITTargetMachineBuilder(tm_builder);
if (lazy_orcjit_builder)
LLVMOrcDisposeLLLazyJITBuilder(lazy_orcjit_builder);
if (tm_opt2)
LLVMDisposeTargetMachine(tm_opt2);
if (tm_opt)
LLVMDisposeTargetMachine(tm_opt);
if (features)
LLVMDisposeMessage(features);
if (cpu)
LLVMDisposeMessage(cpu);
if (llvm_triple)
LLVMDisposeMessage(llvm_triple);
aot_set_last_error(buf);
return false;
}
#endif /* WASM_ENABLE_LAZY_JIT != 0 */
AOTCompContext *
aot_create_comp_context(AOTCompData *comp_data,
aot_comp_option_t option)
{
AOTCompContext *comp_ctx, *ret = NULL;
/*LLVMTypeRef elem_types[8];*/
#if WASM_ENABLE_LAZY_JIT == 0
struct LLVMMCJITCompilerOptions jit_options;
#endif
LLVMTargetRef target;
char *triple = NULL, *triple_norm, *arch, *abi;
char *cpu = NULL, *features, buf[128];
@ -1225,11 +1386,18 @@ aot_create_comp_context(AOTCompData *comp_data,
LLVMTargetDataRef target_data_ref;
/* Initialize LLVM environment */
#if WASM_ENABLE_LAZY_JIT != 0
LLVMInitializeCore(LLVMGetGlobalPassRegistry());
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
#else
LLVMInitializeAllTargetInfos();
LLVMInitializeAllTargets();
LLVMInitializeAllTargetMCs();
LLVMInitializeAllAsmPrinters();
LLVMLinkInMCJIT();
#endif
/* Allocate memory */
if (!(comp_ctx = wasm_runtime_malloc(sizeof(AOTCompContext)))) {
@ -1241,10 +1409,24 @@ aot_create_comp_context(AOTCompData *comp_data,
comp_ctx->comp_data = comp_data;
/* Create LLVM context, module and builder */
#if WASM_ENABLE_LAZY_JIT != 0
comp_ctx->ts_context = LLVMOrcCreateNewThreadSafeContext();
if (!comp_ctx->ts_context) {
aot_set_last_error("create LLVM ThreadSafeContext failed.");
return NULL;
}
/* Get a reference to the underlying LLVMContext */
if (!(comp_ctx->context =
LLVMOrcThreadSafeContextGetContext(comp_ctx->ts_context))) {
aot_set_last_error("get context from LLVM ThreadSafeContext failed.");
goto fail;
}
#else
if (!(comp_ctx->context = LLVMContextCreate())) {
aot_set_last_error("create LLVM context failed.");
goto fail;
}
#endif
if (!(comp_ctx->builder = LLVMCreateBuilderInContext(comp_ctx->context))) {
aot_set_last_error("create LLVM builder failed.");
@ -1288,6 +1470,14 @@ aot_create_comp_context(AOTCompData *comp_data,
if (option->is_jit_mode) {
char *triple_jit = NULL;
#if WASM_ENABLE_LAZY_JIT != 0
/* Create LLLazyJIT Instance */
if (!llvm_orcjit_create(comp_ctx)) {
aot_set_last_error("create LLVM Lazy JIT Compiler failed.");
goto fail;
}
#else
/* Create LLVM execution engine */
LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options));
jit_options.OptLevel = LLVMCodeGenLevelAggressive;
@ -1303,15 +1493,28 @@ aot_create_comp_context(AOTCompData *comp_data,
aot_set_last_error("create LLVM JIT compiler failed.");
goto fail;
}
comp_ctx->is_jit_mode = true;
comp_ctx->target_machine =
LLVMGetExecutionEngineTargetMachine(comp_ctx->exec_engine);
#endif
comp_ctx->is_jit_mode = true;
#ifndef OS_ENABLE_HW_BOUND_CHECK
comp_ctx->enable_bound_check = true;
#else
comp_ctx->enable_bound_check = false;
#endif
#if WASM_ENABLE_LAZY_JIT != 0
if (!(triple_jit =
(char *)LLVMOrcLLLazyJITGetTripleString(comp_ctx->lazy_orcjit))) {
aot_set_last_error("can not get triple from the target machine");
goto fail;
}
/* Save target arch */
get_target_arch_from_triple(triple_jit, comp_ctx->target_arch,
sizeof(comp_ctx->target_arch));
#else
if (!(triple_jit =
LLVMGetTargetMachineTriple(comp_ctx->target_machine))) {
aot_set_last_error("can not get triple from the target machine");
@ -1322,6 +1525,7 @@ aot_create_comp_context(AOTCompData *comp_data,
get_target_arch_from_triple(triple_jit, comp_ctx->target_arch,
sizeof(comp_ctx->target_arch));
LLVMDisposeMessage(triple_jit);
#endif
}
else {
/* Create LLVM target machine */
@ -1706,9 +1910,29 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
if (!comp_ctx)
return;
if (comp_ctx->pass_mgr)
if (comp_ctx->pass_mgr) {
LLVMFinalizeFunctionPassManager(comp_ctx->pass_mgr);
LLVMDisposePassManager(comp_ctx->pass_mgr);
}
#if WASM_ENABLE_LAZY_JIT != 0
if (comp_ctx->target_machine && comp_ctx->is_jit_mode)
LLVMDisposeTargetMachine(comp_ctx->target_machine);
if (comp_ctx->builder)
LLVMDisposeBuilder(comp_ctx->builder);
if (comp_ctx->lazy_orcjit)
LLVMOrcDisposeLLLazyJIT(comp_ctx->lazy_orcjit);
if (comp_ctx->ts_context)
LLVMOrcDisposeThreadSafeContext(comp_ctx->ts_context);
if (comp_ctx->tm_builder)
LLVMOrcDisposeJITTargetMachineBuilder(comp_ctx->tm_builder);
LLVMShutdown();
#else
if (comp_ctx->target_machine && !comp_ctx->is_jit_mode)
LLVMDisposeTargetMachine(comp_ctx->target_machine);
@ -1725,6 +1949,7 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
if (comp_ctx->context)
LLVMContextDispose(comp_ctx->context);
#endif
if (comp_ctx->func_ctxes)
aot_destroy_func_contexts(comp_ctx->func_ctxes,

View File

@ -18,6 +18,14 @@
#include "llvm-c/Transforms/Scalar.h"
#include "llvm-c/Transforms/Vectorize.h"
#if WASM_ENABLE_LAZY_JIT != 0
#include "aot_llvm_lazyjit.h"
#include "llvm-c/Orc.h"
#include "llvm-c/Error.h"
#include "llvm-c/Initialization.h"
#include "llvm-c/Support.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -227,7 +235,13 @@ typedef struct AOTCompContext {
uint64 flags[8];
/* LLVM execution engine required by JIT */
#if WASM_ENABLE_LAZY_JIT != 0
LLVMOrcLLLazyJITRef lazy_orcjit;
LLVMOrcThreadSafeContextRef ts_context;
LLVMOrcJITTargetMachineBuilderRef tm_builder;
#else
LLVMExecutionEngineRef exec_engine;
#endif
bool is_jit_mode;
/* AOT indirect mode flag & symbol list */
@ -403,6 +417,14 @@ aot_get_func_from_table(const AOTCompContext *comp_ctx,
bool
aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
#if WASM_ENABLE_LAZY_JIT != 0
void
aot_handle_llvm_errmsg(char *error_buf,
uint32 error_buf_size,
const char *string,
LLVMErrorRef error);
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -0,0 +1,128 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_llvm_lazyjit.h"
LLVMOrcJITTargetMachineBuilderRef
LLVMOrcJITTargetMachineBuilderFromTargetMachine(LLVMTargetMachineRef TM);
LLVMOrcLLJITBuilderRef
LLVMOrcCreateLLJITBuilder(void);
void
LLVMOrcDisposeLLJITBuilder(LLVMOrcLLJITBuilderRef Builder);
LLVMErrorRef
LLVMOrcCreateLLJIT(LLVMOrcLLJITRef *Result,
LLVMOrcLLJITBuilderRef Builder);
LLVMErrorRef
LLVMOrcDisposeLLJIT(LLVMOrcLLJITRef J);
LLVMOrcJITDylibRef
LLVMOrcLLJITGetMainJITDylib(LLVMOrcLLJITRef J);
const char *
LLVMOrcLLJITGetTripleString(LLVMOrcLLJITRef J);
char
LLVMOrcLLJITGetGlobalPrefix(LLVMOrcLLJITRef J);
LLVMErrorRef
LLVMOrcLLJITAddLLVMIRModule(LLVMOrcLLJITRef J,
LLVMOrcJITDylibRef JD,
LLVMOrcThreadSafeModuleRef TSM);
LLVMErrorRef
LLVMOrcLLJITLookup(LLVMOrcLLJITRef J,
LLVMOrcJITTargetAddress *Result,
const char *Name);
const char *
LLVMOrcLLJITGetTripleString(LLVMOrcLLJITRef J);
void
LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(
LLVMOrcLLJITBuilderRef Builder,
LLVMOrcJITTargetMachineBuilderRef JTMB);
char
LLVMOrcLLJITGetGlobalPrefix(LLVMOrcLLJITRef J);
#if LLVM_VERSION_MAJOR < 12
LLVMOrcJITTargetMachineBuilderRef
LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM)
{
return LLVMOrcJITTargetMachineBuilderFromTargetMachine(TM);
}
#endif
LLVMOrcJITDylibRef
LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J)
{
return LLVMOrcLLJITGetMainJITDylib(J);
}
LLVMOrcLLLazyJITBuilderRef
LLVMOrcCreateLLLazyJITBuilder(void)
{
return LLVMOrcCreateLLJITBuilder();
}
void
LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder)
{
return LLVMOrcDisposeLLJITBuilder(Builder);
}
LLVMErrorRef
LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result,
LLVMOrcLLLazyJITBuilderRef Builder)
{
return LLVMOrcCreateLLJIT(Result, Builder);
}
LLVMErrorRef
LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J)
{
return LLVMOrcDisposeLLJIT(J);
}
LLVMErrorRef
LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J,
LLVMOrcJITDylibRef JD,
LLVMOrcThreadSafeModuleRef TSM)
{
return LLVMOrcLLJITAddLLVMIRModule(J, JD, TSM);
}
LLVMErrorRef
LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J,
LLVMOrcJITTargetAddress *Result,
const char *Name)
{
return LLVMOrcLLJITLookup(J, Result, Name);
}
const char *
LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J)
{
return LLVMOrcLLJITGetTripleString(J);
}
void
LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(
LLVMOrcLLLazyJITBuilderRef Builder,
LLVMOrcJITTargetMachineBuilderRef JTMB)
{
return LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);
}
char
LLVMOrcLLLazyJITGetGlobalPrefix(LLVMOrcLLLazyJITRef J)
{
return LLVMOrcLLJITGetGlobalPrefix(J);
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef AOT_LLVM_LAZYJIT_H
#define AOT_LLVM_LAZYJIT_H
#include "llvm-c/Error.h"
#include "llvm-c/Orc.h"
#include "llvm-c/TargetMachine.h"
#include "llvm-c/Types.h"
#if LLVM_VERSION_MAJOR >= 12
#include "llvm-c/LLJIT.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef LLVMOrcLLJITBuilderRef LLVMOrcLLLazyJITBuilderRef;
typedef LLVMOrcLLJITRef LLVMOrcLLLazyJITRef;
LLVMOrcJITTargetMachineBuilderRef
LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM);
LLVMOrcLLLazyJITBuilderRef
LLVMOrcCreateLLLazyJITBuilder(void);
void
LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder);
LLVMErrorRef
LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result,
LLVMOrcLLLazyJITBuilderRef Builder);
LLVMErrorRef
LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J);
LLVMOrcJITDylibRef
LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J);
const char *
LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J);
char
LLVMOrcLLLazyJITGetGlobalPrefix(LLVMOrcLLLazyJITRef J);
LLVMErrorRef
LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J,
LLVMOrcJITDylibRef JD,
LLVMOrcThreadSafeModuleRef TSM);
LLVMErrorRef
LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J,
LLVMOrcJITTargetAddress *Result,
const char *Name);
const char *
LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J);
void
LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(
LLVMOrcLLLazyJITBuilderRef Builder,
LLVMOrcJITTargetMachineBuilderRef JTMB);
char
LLVMOrcLLLazyJITGetGlobalPrefix(LLVMOrcLLLazyJITRef J);
#ifdef __cplusplus
}
#endif
#endif /* end of AOT_LLVM_LAZYJIT_H */