Refactor Orc JIT to enable lazy compilation (#974)
Refactor LLVM Orc JIT to actually enable the lazy compilation and speedup the launching process: https://llvm.org/docs/ORCv2.html#laziness Main modifications: - Create LLVM module for each wasm function, wrap it with thread safe module so that the modules can be compiled parallelly - Lookup function from aot module instance's func_ptrs but not directly call the function to decouple the module relationship - Compile the function when it is first called and hasn't been compiled - Create threads to pre-compile the WASM functions parallelly when loading - Set Lazy JIT as default, update document and build/test scripts
This commit is contained in:
@ -18,6 +18,7 @@
|
||||
#include <llvm/ExecutionEngine/GenericValue.h>
|
||||
#include <llvm/ExecutionEngine/JITEventListener.h>
|
||||
#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
|
||||
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
@ -30,8 +31,12 @@
|
||||
#include <llvm/Target/TargetOptions.h>
|
||||
#include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
|
||||
#include <cstring>
|
||||
#if WASM_ENABLE_LAZY_JIT != 0
|
||||
#include "../aot/aot_runtime.h"
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::orc;
|
||||
|
||||
extern "C" LLVMBool
|
||||
WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
|
||||
@ -262,6 +267,63 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
|
||||
#endif /* WASM_ENABLE_SIMD */
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 12
|
||||
LLVMOrcJITTargetMachineBuilderRef
|
||||
LLVMOrcJITTargetMachineBuilderFromTargetMachine(LLVMTargetMachineRef TM);
|
||||
|
||||
LLVMOrcJITTargetMachineBuilderRef
|
||||
LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM)
|
||||
{
|
||||
return LLVMOrcJITTargetMachineBuilderFromTargetMachine(TM);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LAZY_JIT != 0
|
||||
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef)
|
||||
|
||||
void
|
||||
LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef orcjit_builder,
|
||||
unsigned num_compile_threads)
|
||||
{
|
||||
unwrap(orcjit_builder)->setNumCompileThreads(num_compile_threads);
|
||||
}
|
||||
|
||||
void *
|
||||
aot_lookup_orcjit_func(LLVMOrcLLJITRef orc_lazyjit, void *module_inst,
|
||||
uint32 func_idx)
|
||||
{
|
||||
char func_name[32], buf[128], *err_msg = NULL;
|
||||
LLVMErrorRef error;
|
||||
LLVMOrcJITTargetAddress func_addr = 0;
|
||||
AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst;
|
||||
AOTModule *aot_module = (AOTModule *)aot_inst->aot_module.ptr;
|
||||
void **func_ptrs = (void **)aot_inst->func_ptrs.ptr;
|
||||
|
||||
/**
|
||||
* No need to lock the func_ptr[func_idx] here as it is basic
|
||||
* data type, the load/store for it can be finished by one cpu
|
||||
* instruction, and there can be only one cpu instruction
|
||||
* loading/storing at the same time.
|
||||
*/
|
||||
if (func_ptrs[func_idx])
|
||||
return func_ptrs[func_idx];
|
||||
|
||||
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX,
|
||||
func_idx - aot_module->import_func_count);
|
||||
if ((error = LLVMOrcLLJITLookup(orc_lazyjit, &func_addr, func_name))) {
|
||||
err_msg = LLVMGetErrorMessage(error);
|
||||
snprintf(buf, sizeof(buf), "failed to lookup orcjit function: %s",
|
||||
err_msg);
|
||||
aot_set_exception(aot_inst, buf);
|
||||
LLVMDisposeErrorMessage(err_msg);
|
||||
return NULL;
|
||||
}
|
||||
func_ptrs[func_idx] = (void *)func_addr;
|
||||
return (void *)func_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
aot_func_disable_tce(LLVMValueRef func)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user