From 5631a2aa18c38a48e4108bcc5f2a216f077fd4f0 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 24 Jan 2022 11:10:37 +0800 Subject: [PATCH] Use LLVM new pass manager for wamrc (#978) Use LLVM new pass manager for wamrc to replace the legacy pass manger, so as to gain better performance and reduce the compilation time. Reference links: - https://llvm.org/docs/NewPassManager.html - https://blog.llvm.org/posts/2021-03-26-the-new-pass-manager And add an option to use the legacy pm mode when building wamrc: cmake .. -DWAMR_BUILD_LLVM_LEGACY_PM=1 For JIT mode, keep it unchanged as it only runs several function passes and using new pass manager will increase the compilation time. And refactor the codes of applying LLVM passes. --- build-scripts/config_common.cmake | 4 +- core/config.h | 8 + core/iwasm/common/wasm_c_api.c | 61 +-- core/iwasm/compilation/aot_compiler.c | 539 +++++++++------------ core/iwasm/compilation/aot_emit_aot_file.c | 3 +- core/iwasm/compilation/aot_llvm.c | 49 -- core/iwasm/compilation/aot_llvm.h | 6 +- core/iwasm/compilation/aot_llvm_extra.cpp | 152 +++++- core/iwasm/include/aot_export.h | 11 - wamr-compiler/CMakeLists.txt | 4 + 10 files changed, 390 insertions(+), 447 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index ba44ceee6..19d12b6a4 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -131,9 +131,9 @@ else () endif () if (WAMR_BUILD_JIT EQUAL 1) if (WAMR_BUILD_LAZY_JIT EQUAL 1) - message (" WAMR Lazy JIT enabled") + message (" WAMR LLVM Orc Lazy JIT enabled") else () - message (" WAMR MC JIT enabled") + message (" WAMR LLVM MC JIT enabled") endif () else () message (" WAMR JIT disabled") diff --git a/core/config.h b/core/config.h index 065af251b..cd3a0eef2 100644 --- a/core/config.h +++ b/core/config.h @@ -98,6 +98,14 @@ #define WASM_ENABLE_WAMR_COMPILER 0 #endif +#if WASM_ENABLE_WAMR_COMPILER != 0 +#ifndef WASM_ENABLE_LLVM_LEGACY_PM +/* Whether to use LLVM legacy pass manager when building wamrc, + by default it is disabled and LLVM new pass manager is used */ +#define WASM_ENABLE_LLVM_LEGACY_PM 0 +#endif +#endif + #ifndef WASM_ENABLE_LIBC_BUILTIN #define WASM_ENABLE_LIBC_BUILTIN 0 #endif diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index a77f43c8d..660cdaf05 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -231,20 +231,6 @@ WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) WASM_DEFINE_VEC_OWN(store, wasm_store_delete) WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) -/* conflicting declaration between aot_export.h and aot.h */ -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 -bool -aot_compile_wasm_file_init(); - -void -aot_compile_wasm_file_destroy(); - -uint8 * -aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, - uint32 opt_level, uint32 size_level, char *error_buf, - uint32 error_buf_size, uint32 *p_aot_file_size); -#endif - /* Runtime Environment */ own wasm_config_t * wasm_config_new(void) @@ -266,10 +252,6 @@ wasm_engine_delete_internal(wasm_engine_t *engine) wasm_runtime_free(engine); } -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - aot_compile_wasm_file_destroy(); -#endif - wasm_runtime_destroy(); } @@ -317,12 +299,6 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) bh_log_set_verbose_level(3); #endif -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - if (!aot_compile_wasm_file_init()) { - goto failed; - } -#endif - /* create wasm_engine_t */ if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) { goto failed; @@ -1820,10 +1796,6 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) char error_buf[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; PackageType pkg_type; -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - uint8 *aot_file_buf = NULL; - uint32 aot_file_size; -#endif bh_assert(singleton_engine); @@ -1858,33 +1830,12 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 - if (Wasm_Module_Bytecode == pkg_type) { - if (!(aot_file_buf = aot_compile_wasm_file( - (uint8 *)module_ex->binary->data, - (uint32)module_ex->binary->size, 3, 3, error_buf, - (uint32)sizeof(error_buf), &aot_file_size))) { - LOG_ERROR(error_buf); - goto failed; - } - - if (!(module_ex->module_comm_rt = - wasm_runtime_load(aot_file_buf, aot_file_size, error_buf, - (uint32)sizeof(error_buf)))) { - LOG_ERROR(error_buf); - goto failed; - } - } - else -#endif - { - module_ex->module_comm_rt = wasm_runtime_load( - (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, - error_buf, (uint32)sizeof(error_buf)); - if (!(module_ex->module_comm_rt)) { - LOG_ERROR(error_buf); - goto failed; - } + module_ex->module_comm_rt = wasm_runtime_load( + (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, + error_buf, (uint32)sizeof(error_buf)); + if (!(module_ex->module_comm_rt)) { + LOG_ERROR(error_buf); + goto failed; } /* add it to a watching list in store */ diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 2807fef2f..c4dac553a 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2537,6 +2537,145 @@ fail: return false; } +static bool +veriy_module(AOTCompContext *comp_ctx) +{ + char *msg = NULL; + bool ret; + +#if WASM_ENABLE_LAZY_JIT == 0 + ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); + if (!ret && msg) { + if (msg[0] != '\0') { + aot_set_last_error(msg); + LLVMDisposeMessage(msg); + return false; + } + LLVMDisposeMessage(msg); + } +#else + uint32 i; + + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + ret = LLVMVerifyModule(comp_ctx->modules[i], LLVMPrintMessageAction, + &msg); + if (!ret && msg) { + if (msg[0] != '\0') { + aot_set_last_error(msg); + LLVMDisposeMessage(msg); + return false; + } + LLVMDisposeMessage(msg); + } + } +#endif + + return true; +} + +static bool +apply_func_passes(AOTCompContext *comp_ctx) +{ + LLVMPassManagerRef pass_mgr; + uint32 i; + +#if WASM_ENABLE_LAZY_JIT == 0 + pass_mgr = LLVMCreateFunctionPassManagerForModule(comp_ctx->module); +#else + pass_mgr = LLVMCreatePassManager(); +#endif + + if (!pass_mgr) { + aot_set_last_error("create LLVM pass manager failed."); + return false; + } + + LLVMAddPromoteMemoryToRegisterPass(pass_mgr); + LLVMAddInstructionCombiningPass(pass_mgr); + LLVMAddCFGSimplificationPass(pass_mgr); + LLVMAddJumpThreadingPass(pass_mgr); +#if LLVM_VERSION_MAJOR < 12 + LLVMAddConstantPropagationPass(pass_mgr); +#endif + LLVMAddIndVarSimplifyPass(pass_mgr); + + if (!comp_ctx->is_jit_mode) { + /* Put Vectorize passes before GVN/LICM passes as the former + might gain more performance improvement and the latter might + break the optimizations for the former */ + LLVMAddLoopVectorizePass(pass_mgr); + LLVMAddSLPVectorizePass(pass_mgr); + LLVMAddLoopRotatePass(pass_mgr); + LLVMAddLoopUnswitchPass(pass_mgr); + LLVMAddInstructionCombiningPass(pass_mgr); + LLVMAddCFGSimplificationPass(pass_mgr); + if (!comp_ctx->enable_thread_mgr) { + /* These two passes may destroy the volatile semantics, + disable them when building as multi-thread mode */ + LLVMAddGVNPass(pass_mgr); + LLVMAddLICMPass(pass_mgr); + LLVMAddInstructionCombiningPass(pass_mgr); + LLVMAddCFGSimplificationPass(pass_mgr); + } + } + +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMInitializeFunctionPassManager(pass_mgr); + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunFunctionPassManager(pass_mgr, comp_ctx->func_ctxes[i]->func); + } + LLVMFinalizeFunctionPassManager(pass_mgr); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunPassManager(pass_mgr, comp_ctx->modules[i]); + } +#endif + + LLVMDisposePassManager(pass_mgr); + return true; +} + +#if WASM_ENABLE_LLVM_LEGACY_PM != 0 +static bool +apply_lto_passes(AOTCompContext *comp_ctx) +{ + LLVMPassManagerRef common_pass_mgr; + LLVMPassManagerBuilderRef pass_mgr_builder; +#if WASM_ENABLE_LAZY_JIT != 0 + uint32 i; +#endif + + if (!(common_pass_mgr = LLVMCreatePassManager())) { + aot_set_last_error("create LLVM pass manager failed"); + return false; + } + + if (!(pass_mgr_builder = LLVMPassManagerBuilderCreate())) { + aot_set_last_error("create LLVM pass manager builder failed"); + LLVMDisposePassManager(common_pass_mgr); + return false; + } + + LLVMPassManagerBuilderSetOptLevel(pass_mgr_builder, comp_ctx->opt_level); + LLVMPassManagerBuilderPopulateModulePassManager(pass_mgr_builder, + common_pass_mgr); + LLVMPassManagerBuilderPopulateLTOPassManager(pass_mgr_builder, + common_pass_mgr, true, true); + +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMRunPassManager(common_pass_mgr, comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); + } +#endif + + LLVMDisposePassManager(common_pass_mgr); + LLVMPassManagerBuilderDispose(pass_mgr_builder); + return true; +} +#endif + /* Check whether the target supports hardware atomic instructions */ static bool aot_require_lower_atomic_pass(AOTCompContext *comp_ctx) @@ -2570,11 +2709,42 @@ aot_require_lower_switch_pass(AOTCompContext *comp_ctx) return ret; } +static bool +apply_passes_for_indirect_mode(AOTCompContext *comp_ctx) +{ + LLVMPassManagerRef common_pass_mgr; +#if WASM_ENABLE_LAZY_JIT != 0 + uint32 i; +#endif + + if (!(common_pass_mgr = LLVMCreatePassManager())) { + aot_set_last_error("create pass manager failed"); + return false; + } + + aot_add_expand_memory_op_pass(common_pass_mgr); + + if (aot_require_lower_atomic_pass(comp_ctx)) + LLVMAddLowerAtomicPass(common_pass_mgr); + + if (aot_require_lower_switch_pass(comp_ctx)) + LLVMAddLowerSwitchPass(common_pass_mgr); + +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMRunPassManager(common_pass_mgr, comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); + } +#endif + + LLVMDisposePassManager(common_pass_mgr); + return true; +} + bool aot_compile_wasm(AOTCompContext *comp_ctx) { - char *msg = NULL; - bool ret; uint32 i; #if WASM_ENABLE_LAZY_JIT != 0 LLVMErrorRef err; @@ -2587,142 +2757,60 @@ aot_compile_wasm(AOTCompContext *comp_ctx) } bh_print_time("Begin to compile WASM bytecode to LLVM IR"); - - for (i = 0; i < comp_ctx->func_ctx_count; i++) + for (i = 0; i < comp_ctx->func_ctx_count; i++) { if (!aot_compile_func(comp_ctx, i)) { -#if 0 - LLVMDumpModule(comp_ctx->module); - char *err; - LLVMTargetMachineEmitToFile(comp_ctx->target_machine, - comp_ctx->module, "./test.o", - LLVMObjectFile, &err); -#endif return false; } - -#if 0 - LLVMDumpModule(comp_ctx->module); - /* Clear error no, LLVMDumpModule may set errno */ - errno = 0; -#endif + } #if WASM_ENABLE_DEBUG_AOT != 0 LLVMDIBuilderFinalize(comp_ctx->debug_builder); #endif bh_print_time("Begin to verify LLVM module"); - -#if WASM_ENABLE_LAZY_JIT == 0 - ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); - if (!ret && msg) { - if (msg[0] != '\0') { - aot_set_last_error(msg); - LLVMDisposeMessage(msg); - return false; - } - LLVMDisposeMessage(msg); + if (!veriy_module(comp_ctx)) { + return false; } -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - ret = LLVMVerifyModule(comp_ctx->modules[i], LLVMPrintMessageAction, - &msg); - if (!ret && msg) { - if (msg[0] != '\0') { - aot_set_last_error(msg); - LLVMDisposeMessage(msg); + + if (comp_ctx->optimize) { + if (comp_ctx->is_jit_mode) { + /* Only run func passes for JIT mode */ + bh_print_time("Begin to run func optimization passes"); + if (!apply_func_passes(comp_ctx)) { return false; } - LLVMDisposeMessage(msg); - } - } -#endif - - bh_print_time("Begin to run function optimization passes"); - - /* Run function pass manager */ - if (comp_ctx->optimize) { -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMInitializeFunctionPassManager(comp_ctx->pass_mgr); - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunFunctionPassManager(comp_ctx->pass_mgr, - comp_ctx->func_ctxes[i]->func); } + else { +#if WASM_ENABLE_LLVM_LEGACY_PM == 0 + /* Run llvm new pass manager for AOT compiler if llvm + legacy pass manager isn't used */ + bh_print_time("Begin to run llvm optimization passes"); + aot_apply_llvm_new_pass_manager(comp_ctx); #else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunPassManager(comp_ctx->pass_mgr, comp_ctx->modules[i]); - } -#endif /* end of WASM_ENABLE_LAZY_JIT */ - } - -#if WASM_ENABLE_LAZY_JIT == 0 - /* Run common pass manager */ - if (comp_ctx->optimize && !comp_ctx->is_jit_mode - && !comp_ctx->disable_llvm_lto) { - LLVMPassManagerRef common_pass_mgr = NULL; - LLVMPassManagerBuilderRef pass_mgr_builder = NULL; - - if (!(common_pass_mgr = LLVMCreatePassManager())) { - aot_set_last_error("create pass manager failed"); - return false; - } - - if (!(pass_mgr_builder = LLVMPassManagerBuilderCreate())) { - aot_set_last_error("create pass manager builder failed"); - LLVMDisposePassManager(common_pass_mgr); - return false; - } - - LLVMPassManagerBuilderSetOptLevel(pass_mgr_builder, - comp_ctx->opt_level); - LLVMPassManagerBuilderPopulateModulePassManager(pass_mgr_builder, - common_pass_mgr); - LLVMPassManagerBuilderPopulateLTOPassManager( - pass_mgr_builder, common_pass_mgr, true, true); - - LLVMRunPassManager(common_pass_mgr, comp_ctx->module); - - LLVMDisposePassManager(common_pass_mgr); - LLVMPassManagerBuilderDispose(pass_mgr_builder); - } + /* Run func passes and lto passes for AOT compiler if llvm + legacy pass manager is used */ + bh_print_time("Begin to run func optimization passes"); + if (!apply_func_passes(comp_ctx)) { + return false; + } + if (!comp_ctx->disable_llvm_lto) { + bh_print_time("Begin to run lto optimization passes"); + if (!apply_lto_passes(comp_ctx)) { + return false; + } + } #endif - - if (comp_ctx->optimize && comp_ctx->is_indirect_mode) { - LLVMPassManagerRef common_pass_mgr = NULL; - - if (!(common_pass_mgr = LLVMCreatePassManager())) { - aot_set_last_error("create pass manager failed"); - return false; + /* Run passes for AOT indirect mode */ + if (comp_ctx->is_indirect_mode) { + bh_print_time("Begin to run optimization passes " + "for indirect mode"); + if (!apply_passes_for_indirect_mode(comp_ctx)) { + return false; + } + } } - - aot_add_expand_memory_op_pass(common_pass_mgr); - - if (aot_require_lower_atomic_pass(comp_ctx)) - LLVMAddLowerAtomicPass(common_pass_mgr); - - if (aot_require_lower_switch_pass(comp_ctx)) - LLVMAddLowerSwitchPass(common_pass_mgr); - -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMRunPassManager(common_pass_mgr, comp_ctx->module); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) - LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); -#endif - - LLVMDisposePassManager(common_pass_mgr); } -#if 0 -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMDumpModule(comp_ctx->module); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMDumpModule(comp_ctx->modules[i]); - os_printf("\n"); - } -#endif -#endif - #if WASM_ENABLE_LAZY_JIT != 0 orc_main_dylib = LLVMOrcLLJITGetMainJITDylib(comp_ctx->orc_lazyjit); if (!orc_main_dylib) { @@ -2750,6 +2838,16 @@ aot_compile_wasm(AOTCompContext *comp_ctx) } #endif +#if 0 +#if WASM_ENABLE_LAZY_JIT == 0 + LLVMDumpModule(comp_ctx->module); +#else + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + LLVMDumpModule(comp_ctx->modules[i]); + os_printf("\n"); + } +#endif +#endif return true; } @@ -2800,205 +2898,4 @@ aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name) return true; } - -typedef struct AOTFileMap { - uint8 *wasm_file_buf; - uint32 wasm_file_size; - uint8 *aot_file_buf; - uint32 aot_file_size; - struct AOTFileMap *next; -} AOTFileMap; - -static bool aot_compile_wasm_file_inited = false; -static AOTFileMap *aot_file_maps = NULL; -static korp_mutex aot_file_map_lock; - -bool -aot_compile_wasm_file_init() -{ - if (aot_compile_wasm_file_inited) { - return true; - } - - if (BHT_OK != os_mutex_init(&aot_file_map_lock)) { - return false; - } - - aot_file_maps = NULL; - aot_compile_wasm_file_inited = true; - return true; -} - -void -aot_compile_wasm_file_destroy() -{ - AOTFileMap *file_map = aot_file_maps, *file_map_next; - - if (!aot_compile_wasm_file_inited) { - return; - } - - while (file_map) { - file_map_next = file_map->next; - - wasm_runtime_free(file_map->wasm_file_buf); - wasm_runtime_free(file_map->aot_file_buf); - wasm_runtime_free(file_map); - - file_map = file_map_next; - } - - aot_file_maps = NULL; - os_mutex_destroy(&aot_file_map_lock); - aot_compile_wasm_file_inited = false; -} - -static void -set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) -{ - if (error_buf != NULL) { - snprintf(error_buf, error_buf_size, "WASM module load failed: %s", - string); - } -} - -uint8 * -aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, - uint32 opt_level, uint32 size_level, char *error_buf, - uint32 error_buf_size, uint32 *p_aot_file_size) -{ - WASMModule *wasm_module = NULL; - AOTCompData *comp_data = NULL; - AOTCompContext *comp_ctx = NULL; - RuntimeInitArgs init_args; - AOTCompOption option = { 0 }; - AOTFileMap *file_map = NULL, *file_map_next; - uint8 *wasm_file_buf_cloned = NULL; - uint8 *aot_file_buf = NULL; - uint32 aot_file_size; - - option.is_jit_mode = false; - option.opt_level = opt_level; - option.size_level = size_level; - option.output_format = AOT_FORMAT_FILE; - /* default value, enable or disable depends on the platform */ - option.bounds_checks = 2; - option.enable_aux_stack_check = true; -#if WASM_ENABLE_BULK_MEMORY != 0 - option.enable_bulk_memory = true; -#endif -#if WASM_ENABLE_THREAD_MGR != 0 - option.enable_thread_mgr = true; -#endif -#if WASM_ENABLE_TAIL_CALL != 0 - option.enable_tail_call = true; -#endif -#if WASM_ENABLE_SIMD != 0 - option.enable_simd = true; -#endif -#if WASM_ENABLE_REF_TYPES != 0 - option.enable_ref_types = true; -#endif -#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) - option.enable_aux_stack_frame = true; -#endif - - memset(&init_args, 0, sizeof(RuntimeInitArgs)); - - init_args.mem_alloc_type = Alloc_With_Allocator; - init_args.mem_alloc_option.allocator.malloc_func = malloc; - init_args.mem_alloc_option.allocator.realloc_func = realloc; - init_args.mem_alloc_option.allocator.free_func = free; - - os_mutex_lock(&aot_file_map_lock); - - /* lookup the file maps */ - file_map = aot_file_maps; - while (file_map) { - file_map_next = file_map->next; - - if (wasm_file_size == file_map->wasm_file_size - && memcmp(wasm_file_buf, file_map->wasm_file_buf, wasm_file_size) - == 0) { - os_mutex_unlock(&aot_file_map_lock); - /* found */ - *p_aot_file_size = file_map->aot_file_size; - return file_map->aot_file_buf; - } - - file_map = file_map_next; - } - - /* not found, initialize file map and clone wasm file */ - if (!(file_map = wasm_runtime_malloc(sizeof(AOTFileMap))) - || !(wasm_file_buf_cloned = wasm_runtime_malloc(wasm_file_size))) { - set_error_buf(error_buf, error_buf_size, "allocate memory failed"); - goto fail1; - } - - bh_memcpy_s(wasm_file_buf_cloned, wasm_file_size, wasm_file_buf, - wasm_file_size); - memset(file_map, 0, sizeof(AOTFileMap)); - file_map->wasm_file_buf = wasm_file_buf_cloned; - file_map->wasm_file_size = wasm_file_size; - - /* load WASM module */ - if (!(wasm_module = wasm_load(wasm_file_buf, wasm_file_size, error_buf, - sizeof(error_buf)))) { - goto fail1; - } - - if (!(comp_data = aot_create_comp_data(wasm_module))) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail2; - } - - if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail3; - } - - if (!aot_compile_wasm(comp_ctx)) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail4; - } - - if (!(aot_file_buf = - aot_emit_aot_file_buf(comp_ctx, comp_data, &aot_file_size))) { - set_error_buf(error_buf, error_buf_size, aot_get_last_error()); - goto fail4; - } - - file_map->aot_file_buf = aot_file_buf; - file_map->aot_file_size = aot_file_size; - - if (!aot_file_maps) - aot_file_maps = file_map; - else { - file_map->next = aot_file_maps; - aot_file_maps = file_map; - } - - *p_aot_file_size = aot_file_size; - -fail4: - /* Destroy compiler context */ - aot_destroy_comp_context(comp_ctx); -fail3: - /* Destroy compile data */ - aot_destroy_comp_data(comp_data); -fail2: - wasm_unload(wasm_module); -fail1: - if (!aot_file_buf) { - if (wasm_file_buf_cloned) - wasm_runtime_free(wasm_file_buf_cloned); - if (file_map) - wasm_runtime_free(file_map); - } - - os_mutex_unlock(&aot_file_map_lock); - - return aot_file_buf; -} #endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index d0b1d74a0..7b98482ec 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -2806,5 +2806,4 @@ fail1: return ret; } - -#endif /* end of WASM_ENABLE_JIT */ +#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index c126dcdd4..f9e03f9c5 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -2024,48 +2024,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) if (option->output_format == AOT_LLVMIR_UNOPT_FILE) comp_ctx->optimize = false; -#if WASM_ENABLE_LAZY_JIT == 0 - if (!(comp_ctx->pass_mgr = - LLVMCreateFunctionPassManagerForModule(comp_ctx->module))) { - aot_set_last_error("create LLVM pass manager failed."); - goto fail; - } -#else - if (!(comp_ctx->pass_mgr = LLVMCreatePassManager())) { - aot_set_last_error("create LLVM pass manager failed."); - goto fail; - } -#endif - - LLVMAddPromoteMemoryToRegisterPass(comp_ctx->pass_mgr); - LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); - LLVMAddJumpThreadingPass(comp_ctx->pass_mgr); -#if LLVM_VERSION_MAJOR < 12 - LLVMAddConstantPropagationPass(comp_ctx->pass_mgr); -#endif - LLVMAddIndVarSimplifyPass(comp_ctx->pass_mgr); - - if (!option->is_jit_mode) { - /* Put Vectorize passes before GVN/LICM passes as the former - might gain more performance improvement and the latter might - break the optimizations for the former */ - LLVMAddLoopVectorizePass(comp_ctx->pass_mgr); - LLVMAddSLPVectorizePass(comp_ctx->pass_mgr); - LLVMAddLoopRotatePass(comp_ctx->pass_mgr); - LLVMAddLoopUnswitchPass(comp_ctx->pass_mgr); - LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); - if (!option->enable_thread_mgr) { - /* These two passes may destroy the volatile semantics, - disable them when building as multi-thread mode */ - LLVMAddGVNPass(comp_ctx->pass_mgr); - LLVMAddLICMPass(comp_ctx->pass_mgr); - LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr); - LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr); - } - } - /* Create metadata for llvm float experimental constrained intrinsics */ if (!(comp_ctx->fp_rounding_mode = LLVMMDStringInContext( comp_ctx->context, fp_round, (uint32)strlen(fp_round))) @@ -2132,13 +2090,6 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx) if (!comp_ctx) return; - if (comp_ctx->pass_mgr) { -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMFinalizeFunctionPassManager(comp_ctx->pass_mgr); -#endif - LLVMDisposePassManager(comp_ctx->pass_mgr); - } - #if WASM_ENABLE_LAZY_JIT != 0 if (comp_ctx->orc_symbol_map_pairs) wasm_runtime_free(comp_ctx->orc_symbol_map_pairs); diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 82f4b0dcb..1cb8d3b75 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -331,9 +331,6 @@ typedef struct AOTCompContext { uint32 opt_level; uint32 size_level; - /* LLVM pass manager to optimize the JITed code */ - LLVMPassManagerRef pass_mgr; - /* LLVM floating-point rounding mode metadata */ LLVMValueRef fp_rounding_mode; @@ -469,6 +466,9 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); void aot_add_expand_memory_op_pass(LLVMPassManagerRef pass); +void +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx); + #if WASM_ENABLE_LAZY_JIT != 0 LLVMOrcJITTargetMachineBuilderRef LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM); diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index f3aaf4ec8..45aeb9cdd 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -30,29 +30,55 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LLVM_VERSION_MAJOR >= 12 +#include +#endif #include #if WASM_ENABLE_LAZY_JIT != 0 #include "../aot/aot_runtime.h" #endif +#include "aot_llvm.h" + using namespace llvm; using namespace llvm::orc; -extern "C" LLVMBool +extern "C" { + +LLVMBool WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions, char **OutError); -extern "C" bool +bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); -extern "C" void +void aot_add_expand_memory_op_pass(LLVMPassManagerRef pass); -extern "C" void +void aot_func_disable_tce(LLVMValueRef func); +void +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx); +} + +static TargetMachine * +unwrap(LLVMTargetMachineRef P) +{ + return reinterpret_cast(P); +} + LLVMBool WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, @@ -334,3 +360,121 @@ aot_func_disable_tce(LLVMValueRef func) "disable-tail-calls", "true"); F->setAttributes(Attrs); } + +void +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx) +{ + Module *M; + TargetMachine *TM = unwrap(comp_ctx->target_machine); + bool disable_llvm_lto = false; + + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + PipelineTuningOptions PTO; + PTO.LoopVectorization = true; + PTO.SLPVectorization = true; + PTO.LoopUnrolling = true; + +#if LLVM_VERSION_MAJOR == 12 + PassBuilder PB(false, TM, PTO); +#else + PassBuilder PB(TM, PTO); +#endif + + // Register the target library analysis directly and give it a + // customized preset TLI. + std::unique_ptr TLII( + new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()))); + FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); + + // Register the AA manager first so that our version is the one used. + AAManager AA = PB.buildDefaultAAPipeline(); + FAM.registerPass([&] { return std::move(AA); }); + + // Register all the basic analyses with the managers. + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; + + PassBuilder::OptimizationLevel OL; + + switch (comp_ctx->opt_level) { + case 0: + OL = PassBuilder::OptimizationLevel::O0; + break; + case 1: + OL = PassBuilder::OptimizationLevel::O1; + break; + case 2: + OL = PassBuilder::OptimizationLevel::O2; + break; + case 3: + default: + OL = PassBuilder::OptimizationLevel::O3; + break; + } + + if (comp_ctx->disable_llvm_lto) { + disable_llvm_lto = true; + } +#if WASM_ENABLE_SPEC_TEST != 0 + disable_llvm_lto = true; +#endif + + if (disable_llvm_lto) { + uint32 i; + + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + aot_func_disable_tce(comp_ctx->func_ctxes[i]->func); + } + } + + if (comp_ctx->is_jit_mode) { + /* Apply normal pipeline for JIT mode, without + Vectorize related passes, without LTO */ + MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); + } + else { + FunctionPassManager FPM; + + /* Apply Vectorize related passes for AOT mode */ + FPM.addPass(LoopVectorizePass()); + FPM.addPass(SLPVectorizerPass()); + FPM.addPass(LoadStoreVectorizerPass()); + + /* + FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass())); + FPM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass())); + FPM.addPass(createFunctionToLoopPassAdaptor(SimpleLoopUnswitchPass())); + */ + + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + + if (!disable_llvm_lto) { + /* Apply LTO for AOT mode */ + MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL)); + } + else { + MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); + } + } + +#if WASM_ENABLE_LAZY_JIT == 0 + M = unwrap(comp_ctx->module); + MPM.run(*M, MAM); +#else + uint32 i; + + for (i = 0; i < comp_ctx->func_ctx_count; i++) { + M = unwrap(comp_ctx->modules[i]); + MPM.run(*M, MAM); + } +#endif +} diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index d71f945f5..e0ee89668 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -83,17 +83,6 @@ aot_emit_aot_file(aot_comp_context_t comp_ctx, aot_comp_data_t comp_data, void aot_destroy_aot_file(uint8_t *aot_file); -bool -aot_compile_wasm_file_init(); - -uint8_t * -aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size, - uint32_t opt_level, uint32_t size_level, char *error_buf, - uint32_t error_buf_size, uint32_t *p_aot_file_size); - -void -aot_compile_wasm_file_destroy(); - char * aot_get_last_error(); diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 8d943d97e..edec4c7a5 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -36,6 +36,10 @@ add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1) add_definitions(-DWASM_ENABLE_PERF_PROFILING=1) +if (WAMR_BUILD_LLVM_LEGACY_PM EQUAL 1) + add_definitions(-DWASM_ENABLE_LLVM_LEGACY_PM=1) +endif() + # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" if (NOT WAMR_BUILD_TARGET)