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.
This commit is contained in:
Wenyong Huang 2022-01-24 11:10:37 +08:00 committed by GitHub
parent 7636d86a76
commit 5631a2aa18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 390 additions and 447 deletions

View File

@ -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")

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -2806,5 +2806,4 @@ fail1:
return ret;
}
#endif /* end of WASM_ENABLE_JIT */
#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */

View File

@ -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);

View File

@ -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);

View File

@ -30,29 +30,55 @@
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
#include <llvm/Transforms/Vectorize/LoopVectorize.h>
#include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
#include <llvm/Transforms/Vectorize/SLPVectorizer.h>
#include <llvm/Transforms/Scalar/LoopRotation.h>
#include <llvm/Transforms/Scalar/SimpleLoopUnswitch.h>
#include <llvm/Transforms/Scalar/LICM.h>
#include <llvm/Transforms/Scalar/GVN.h>
#include <llvm/Passes/PassBuilder.h>
#include <llvm/Analysis/TargetLibraryInfo.h>
#if LLVM_VERSION_MAJOR >= 12
#include <llvm/Analysis/AliasAnalysis.h>
#endif
#include <cstring>
#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<TargetMachine *>(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<TargetLibraryInfoImpl> 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
}

View File

@ -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();

View File

@ -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)