diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index a3dacd33d..5f8ed0ebd 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -2093,8 +2093,14 @@ aot_convert_wasm_module(WASMModule *wasm_module, } option.is_jit_mode = 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 comp_ctx = aot_create_comp_context(comp_data, &option); if (!comp_ctx) { diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index d813300ec..d4aa718dc 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -240,7 +240,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_CALL: read_leb_uint32(frame_ip, frame_ip_end, func_idx); - if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, &frame_ip)) + if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, false)) return false; break; @@ -251,6 +251,33 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) return false; break; +#if WASM_ENABLE_TAIL_CALL != 0 + case WASM_OP_RETURN_CALL: + if (!comp_ctx->enable_tail_call) { + aot_set_last_error("unsupported opcode"); + return false; + } + read_leb_uint32(frame_ip, frame_ip_end, func_idx); + if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, true)) + return false; + if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip)) + return false; + break; + + case WASM_OP_RETURN_CALL_INDIRECT: + if (!comp_ctx->enable_tail_call) { + aot_set_last_error("unsupported opcode"); + return false; + } + read_leb_uint32(frame_ip, frame_ip_end, type_idx); + frame_ip++; /* skip 0x00 */ + if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx)) + return false; + if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip)) + return false; + break; +#endif /* end of WASM_ENABLE_TAIL_CALL */ + case WASM_OP_DROP: if (!aot_compile_op_drop(comp_ctx, func_ctx, true)) return false; @@ -993,6 +1020,7 @@ build_atomic_rmw: #endif /* end of WASM_ENABLE_SHARED_MEMORY */ default: + aot_set_last_error("unsupported opcode"); break; } } diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 21b49ad0c..054275115 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -304,7 +304,7 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 func_idx, uint8 **p_frame_ip) + uint32 func_idx, bool tail_call) { uint32 import_func_count = comp_ctx->comp_data->import_func_count; AOTImportFunc *import_funcs = comp_ctx->comp_data->import_funcs; @@ -476,8 +476,12 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Set calling convention for the call with the func's calling convention */ LLVMSetInstructionCallConv(value_ret, LLVMGetFunctionCallConv(func)); + if (tail_call) + LLVMSetTailCall(value_ret, true); + /* Check whether there was exception thrown when executing the function */ - if (!check_exception_thrown(comp_ctx, func_ctx)) + if (!tail_call + && !check_exception_thrown(comp_ctx, func_ctx)) goto fail; } diff --git a/core/iwasm/compilation/aot_emit_function.h b/core/iwasm/compilation/aot_emit_function.h index 28d7bff98..70aa4c5d1 100644 --- a/core/iwasm/compilation/aot_emit_function.h +++ b/core/iwasm/compilation/aot_emit_function.h @@ -14,7 +14,7 @@ extern "C" { bool aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - uint32 func_idx, uint8 **p_frame_ip); + uint32 func_idx, bool tail_call); bool aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 6dea84524..e81e4602c 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1062,6 +1062,9 @@ aot_create_comp_context(AOTCompData *comp_data, if (option->enable_thread_mgr) comp_ctx->enable_thread_mgr = true; + if (option->enable_tail_call) + comp_ctx->enable_tail_call = true; + if (option->is_jit_mode) { /* Create LLVM execution engine */ LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options)); diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 3658b5fd0..c15db867c 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -204,6 +204,9 @@ typedef struct AOTCompContext { /* Thread Manager */ bool enable_thread_mgr; + /* Tail Call */ + bool enable_tail_call; + /* Whether optimize the JITed code */ bool optimize; @@ -244,6 +247,7 @@ typedef struct AOTCompOption{ char *cpu_features; bool enable_bulk_memory; bool enable_thread_mgr; + bool enable_tail_call; bool is_sgx_platform; uint32 opt_level; uint32 size_level; diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index 778400d2f..ca0ffb6a8 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -41,6 +41,7 @@ typedef struct AOTCompOption{ char *cpu_features; bool enable_bulk_memory; bool enable_thread_mgr; + bool enable_tail_call; bool is_sgx_platform; uint32_t opt_level; uint32_t size_level; diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 8de6f65d5..114e186d2 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -26,6 +26,7 @@ add_definitions(-DWASM_ENABLE_BULK_MEMORY=1) add_definitions(-DWASM_DISABLE_HW_BOUND_CHECK=1) add_definitions(-DWASM_ENABLE_SHARED_MEMORY=1) add_definitions(-DWASM_ENABLE_THREAD_MGR=1) +add_definitions(-DWASM_ENABLE_TAIL_CALL=1) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "ARM_32", "MIPS_32", "XTENSA_32" diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 3c72dc381..d3505ad01 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -41,6 +41,7 @@ print_help() printf(" llvmir-opt Optimized LLVM IR\n"); printf(" --enable-bulk-memory Enable the post-MVP bulk memory feature\n"); printf(" --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and\n"); + printf(" --enable-tail-call Enable the post-MVP tail call feature\n"); printf(" thread-mgr will be enabled automatically\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"); @@ -146,6 +147,9 @@ main(int argc, char *argv[]) option.enable_bulk_memory = true; option.enable_thread_mgr = true; } + else if (!strcmp(argv[0], "--enable-tail-call")) { + option.enable_tail_call = true; + } else return print_help(); }