Enable LLVM link time optimization (LTO) for AOT (#831)

Enable LLVM link time optimization for AOT and enable it by default,
and provide "wamrc --disable-llvm-lto" option to disable it.
And modify the spec test script, disable it by default when testing
spec cases.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang 2021-11-13 16:59:35 +08:00 committed by GitHub
parent 9281286181
commit a1ad950ae1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 72 additions and 2 deletions

View File

@ -110,8 +110,9 @@ typedef struct {
REG_SYM(aot_call_indirect), \ REG_SYM(aot_call_indirect), \
REG_SYM(aot_enlarge_memory), \ REG_SYM(aot_enlarge_memory), \
REG_SYM(aot_set_exception), \ REG_SYM(aot_set_exception), \
{"memset", (void*)aot_memset}, \ { "memset", (void*)aot_memset }, \
{"memmove", (void*)aot_memmove}, \ { "memmove", (void*)aot_memmove }, \
{ "memcpy", (void*)aot_memmove }, \
REG_SYM(fmin), \ REG_SYM(fmin), \
REG_SYM(fminf), \ REG_SYM(fminf), \
REG_SYM(fmax), \ REG_SYM(fmax), \

View File

@ -2548,6 +2548,7 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
bh_print_time("Begin to run function optimization passes"); bh_print_time("Begin to run function optimization passes");
/* Run function pass manager */
if (comp_ctx->optimize) { if (comp_ctx->optimize) {
LLVMInitializeFunctionPassManager(comp_ctx->pass_mgr); LLVMInitializeFunctionPassManager(comp_ctx->pass_mgr);
for (i = 0; i < comp_ctx->func_ctx_count; i++) for (i = 0; i < comp_ctx->func_ctx_count; i++)
@ -2555,6 +2556,36 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
comp_ctx->func_ctxes[i]->func); comp_ctx->func_ctxes[i]->func);
} }
/* 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);
}
return true; return true;
} }

View File

@ -1482,6 +1482,12 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
if (option->disable_llvm_intrinsics) if (option->disable_llvm_intrinsics)
comp_ctx->disable_llvm_intrinsics = true; comp_ctx->disable_llvm_intrinsics = true;
if (option->disable_llvm_lto)
comp_ctx->disable_llvm_lto = true;
comp_ctx->opt_level = option->opt_level;
comp_ctx->size_level = option->size_level;
if (option->is_jit_mode) { if (option->is_jit_mode) {
char *triple_jit = NULL; char *triple_jit = NULL;

View File

@ -17,6 +17,7 @@
#include "llvm-c/Transforms/Utils.h" #include "llvm-c/Transforms/Utils.h"
#include "llvm-c/Transforms/Scalar.h" #include "llvm-c/Transforms/Scalar.h"
#include "llvm-c/Transforms/Vectorize.h" #include "llvm-c/Transforms/Vectorize.h"
#include "llvm-c/Transforms/PassManagerBuilder.h"
#if WASM_ENABLE_LAZY_JIT != 0 #if WASM_ENABLE_LAZY_JIT != 0
#include "aot_llvm_lazyjit.h" #include "aot_llvm_lazyjit.h"
@ -304,9 +305,15 @@ typedef struct AOTCompContext {
/* Disable LLVM built-in intrinsics */ /* Disable LLVM built-in intrinsics */
bool disable_llvm_intrinsics; bool disable_llvm_intrinsics;
/* Disable LLVM link time optimization */
bool disable_llvm_lto;
/* Whether optimize the JITed code */ /* Whether optimize the JITed code */
bool optimize; bool optimize;
uint32 opt_level;
uint32 size_level;
/* LLVM pass manager to optimize the JITed code */ /* LLVM pass manager to optimize the JITed code */
LLVMPassManagerRef pass_mgr; LLVMPassManagerRef pass_mgr;
@ -352,6 +359,7 @@ typedef struct AOTCompOption {
bool enable_aux_stack_check; bool enable_aux_stack_check;
bool enable_aux_stack_frame; bool enable_aux_stack_frame;
bool disable_llvm_intrinsics; bool disable_llvm_intrinsics;
bool disable_llvm_lto;
uint32 opt_level; uint32 opt_level;
uint32 size_level; uint32 size_level;
uint32 output_format; uint32 output_format;

View File

@ -33,6 +33,9 @@ WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
extern "C" bool extern "C" bool
aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
extern "C" void
aot_func_disable_tce(LLVMValueRef func);
LLVMBool LLVMBool
WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
LLVMModuleRef M, LLVMModuleRef M,
@ -143,3 +146,14 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
return true; return true;
#endif /* WASM_ENABLE_SIMD */ #endif /* WASM_ENABLE_SIMD */
} }
void
aot_func_disable_tce(LLVMValueRef func)
{
Function *F = unwrap<Function>(func);
auto Attrs = F->getAttributes();
Attrs = Attrs.addAttribute(F->getContext(), AttributeList::FunctionIndex,
"disable-tail-calls", "true");
F->setAttributes(Attrs);
}

View File

@ -54,6 +54,7 @@ typedef struct AOTCompOption {
bool enable_aux_stack_check; bool enable_aux_stack_check;
bool enable_aux_stack_frame; bool enable_aux_stack_frame;
bool disable_llvm_intrinsics; bool disable_llvm_intrinsics;
bool disable_llvm_lto;
uint32_t opt_level; uint32_t opt_level;
uint32_t size_level; uint32_t size_level;
uint32_t output_format; uint32_t output_format;

View File

@ -946,6 +946,11 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r):
cmd.append("--enable-ref-types") cmd.append("--enable-ref-types")
cmd.append("--enable-bulk-memory") cmd.append("--enable-bulk-memory")
# disable llvm link time optimization as it might convert
# code of tail call into code of dead loop, and stack overflow
# exception isn't thrown in several cases
cmd.append("--disable-llvm-lto")
cmd += ["-o", aot_tempfile, wasm_tempfile] cmd += ["-o", aot_tempfile, wasm_tempfile]
log("Running: %s" % " ".join(cmd)) log("Running: %s" % " ".join(cmd))

View File

@ -62,6 +62,7 @@ print_help()
printf(" --enable-perf-profiling Enable function performance profiling\n"); printf(" --enable-perf-profiling Enable function performance profiling\n");
printf(" --enable-indirect-mode Enalbe call function through symbol table but not direct call\n"); printf(" --enable-indirect-mode Enalbe call function through symbol table but not direct call\n");
printf(" --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n"); printf(" --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n");
printf(" --disable-llvm-lto Disable the LLVM link time optimization\n");
printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n");
printf("Examples: wamrc -o test.aot test.wasm\n"); printf("Examples: wamrc -o test.aot test.wasm\n");
printf(" wamrc --target=i386 -o test.aot test.wasm\n"); printf(" wamrc --target=i386 -o test.aot test.wasm\n");
@ -198,6 +199,9 @@ main(int argc, char *argv[])
else if (!strcmp(argv[0], "--disable-llvm-intrinsics")) { else if (!strcmp(argv[0], "--disable-llvm-intrinsics")) {
option.disable_llvm_intrinsics = true; option.disable_llvm_intrinsics = true;
} }
else if (!strcmp(argv[0], "--disable-llvm-lto")) {
option.disable_llvm_lto = true;
}
else else
return print_help(); return print_help();
} }