Implement JIT IR translation for opcode call_indirect (#1138)

This commit is contained in:
liang.he 2022-05-06 15:31:21 +08:00 committed by GitHub
parent 87b259a40a
commit dd966977a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -7,43 +7,18 @@
#include "jit_emit_exception.h"
#include "../jit_frontend.h"
#include "../jit_codegen.h"
#include "../../interpreter/wasm_runtime.h"
extern bool
jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
WASMInterpFrame *prev_frame);
bool
jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
/* Prepare parameters for the function to call */
static bool
pre_call(JitCompContext *cc, const WASMType *func_type)
{
WASMModule *wasm_module = cc->cur_wasm_module;
WASMFunctionImport *func_import;
WASMFunction *func;
WASMType *func_type;
JitFrame *jit_frame = cc->jit_frame;
JitReg value, result = 0, native_ret;
JitReg func_ptrs, jitted_code = 0;
JitInsn *insn;
uint32 i, n, outs_off, jitted_func_idx;
if (func_idx >= wasm_module->import_function_count) {
func_ptrs = get_func_ptrs_reg(jit_frame);
jitted_code = jit_cc_new_reg_ptr(cc);
/* jitted_code = func_ptrs[func_idx - import_function_count] */
jitted_func_idx = func_idx - wasm_module->import_function_count;
GEN_INSN(LDPTR, jitted_code, func_ptrs,
NEW_CONST(I32, (uint32)sizeof(void *) * jitted_func_idx));
}
if (func_idx < wasm_module->import_function_count) {
func_import = &wasm_module->import_functions[func_idx].u.function;
func_type = func_import->func_type;
}
else {
func = wasm_module
->functions[func_idx - wasm_module->import_function_count];
func_type = func->func_type;
}
JitReg value;
uint32 i, outs_off;
/* Prepare parameters for the function to call */
outs_off =
cc->total_frame_size + offsetof(WASMInterpFrame, lp)
@ -77,13 +52,107 @@ jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
break;
default:
bh_assert(0);
break;
goto fail;
}
}
/* Commit sp as the callee may use it to store the results */
gen_commit_sp_ip(cc->jit_frame);
return true;
fail:
return false;
}
/* Push results */
static bool
post_return(JitCompContext *cc, const WASMType *func_type)
{
uint32 i, n;
JitReg value;
n = cc->jit_frame->sp - cc->jit_frame->lp;
for (i = 0; i < func_type->result_count; i++) {
switch (func_type->types[func_type->param_count + i]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_EXTERNREF:
case VALUE_TYPE_FUNCREF:
#endif
value = jit_cc_new_reg_I32(cc);
GEN_INSN(LDI32, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_I32(value);
n++;
break;
case VALUE_TYPE_I64:
value = jit_cc_new_reg_I64(cc);
GEN_INSN(LDI64, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_I64(value);
n += 2;
break;
case VALUE_TYPE_F32:
value = jit_cc_new_reg_F32(cc);
GEN_INSN(LDF32, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_F32(value);
n++;
break;
case VALUE_TYPE_F64:
value = jit_cc_new_reg_F64(cc);
GEN_INSN(LDF64, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_F64(value);
n += 2;
break;
default:
bh_assert(0);
goto fail;
}
}
return true;
fail:
return false;
}
bool
jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
{
WASMModule *wasm_module = cc->cur_wasm_module;
WASMFunctionImport *func_import;
WASMFunction *func;
WASMType *func_type;
JitFrame *jit_frame = cc->jit_frame;
JitReg result = 0, native_ret;
JitReg func_ptrs, jitted_code = 0;
JitInsn *insn;
uint32 jitted_func_idx;
if (func_idx >= wasm_module->import_function_count) {
func_ptrs = get_func_ptrs_reg(jit_frame);
jitted_code = jit_cc_new_reg_ptr(cc);
/* jitted_code = func_ptrs[func_idx - import_function_count] */
jitted_func_idx = func_idx - wasm_module->import_function_count;
GEN_INSN(LDPTR, jitted_code, func_ptrs,
NEW_CONST(I32, (uint32)sizeof(void *) * jitted_func_idx));
}
if (func_idx < wasm_module->import_function_count) {
func_import = &wasm_module->import_functions[func_idx].u.function;
func_type = func_import->func_type;
}
else {
func = wasm_module
->functions[func_idx - wasm_module->import_function_count];
func_type = func->func_type;
}
if (!pre_call(cc, func_type)) {
goto fail;
}
if (func_idx < wasm_module->import_function_count) {
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
/* Set native_ret to x86::eax */
@ -144,46 +213,8 @@ jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
GEN_INSN(CALLBC, result, 0, jitted_code);
}
/* Push results */
n = cc->jit_frame->sp - cc->jit_frame->lp;
for (i = 0; i < func_type->result_count; i++) {
switch (func_type->types[func_type->param_count + i]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_EXTERNREF:
case VALUE_TYPE_FUNCREF:
#endif
value = jit_cc_new_reg_I32(cc);
GEN_INSN(LDI32, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_I32(value);
n++;
break;
case VALUE_TYPE_I64:
value = jit_cc_new_reg_I64(cc);
GEN_INSN(LDI64, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_I64(value);
n += 2;
break;
case VALUE_TYPE_F32:
value = jit_cc_new_reg_F32(cc);
GEN_INSN(LDF32, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_F32(value);
n++;
break;
case VALUE_TYPE_F64:
value = jit_cc_new_reg_F64(cc);
GEN_INSN(LDF64, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(n)));
PUSH_F64(value);
n += 2;
break;
default:
bh_assert(0);
break;
}
if (!post_return(cc, func_type)) {
goto fail;
}
/* Clear part of memory regs and table regs as their values
@ -198,10 +229,145 @@ fail:
return false;
}
static JitReg
pack_argv(JitCompContext *cc)
{
/* reuse the stack of the next frame*/
uint32 stack_base;
JitReg argv;
stack_base = cc->total_frame_size + offsetof(WASMInterpFrame, lp);
argv = jit_cc_new_reg_ptr(cc);
GEN_INSN(ADD, argv, cc->fp_reg, NEW_CONST(PTR, stack_base));
return argv;
}
static bool
unpack_argv(JitCompContext *cc, const WASMType *func_type, JitReg argv)
{
/* argv to stack*/
uint32 i, top_by_cell, offset_by_cell;
JitReg value;
/* stack top */
top_by_cell = cc->jit_frame->sp - cc->jit_frame->lp;
offset_by_cell = 0;
for (i = 0; i < func_type->result_count; i++) {
switch (func_type->types[func_type->param_count + i]) {
case VALUE_TYPE_I32:
#if WASM_ENABLE_REF_TYPES != 0
case VALUE_TYPE_EXTERNREF:
case VALUE_TYPE_FUNCREF:
#endif
{
value = jit_cc_new_reg_I32(cc);
GEN_INSN(LDI32, value, argv, NEW_CONST(I32, offset_by_cell));
GEN_INSN(STI32, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(top_by_cell
+ offset_by_cell)));
offset_by_cell += 1;
break;
}
case VALUE_TYPE_I64:
{
value = jit_cc_new_reg_I64(cc);
GEN_INSN(LDI64, value, argv, NEW_CONST(I32, offset_by_cell));
GEN_INSN(STI64, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(top_by_cell
+ offset_by_cell)));
offset_by_cell += 2;
break;
}
case VALUE_TYPE_F32:
{
value = jit_cc_new_reg_F32(cc);
GEN_INSN(LDF32, value, argv, NEW_CONST(I32, offset_by_cell));
GEN_INSN(STF32, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(top_by_cell
+ offset_by_cell)));
offset_by_cell += 1;
break;
}
case VALUE_TYPE_F64:
{
value = jit_cc_new_reg_F64(cc);
GEN_INSN(LDF64, value, argv, NEW_CONST(I32, offset_by_cell));
GEN_INSN(STF64, value, cc->fp_reg,
NEW_CONST(I32, offset_of_local(top_by_cell
+ offset_by_cell)));
offset_by_cell += 2;
break;
}
default:
{
bh_assert(0);
goto fail;
}
}
}
return true;
fail:
return false;
}
bool
jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
uint32 tbl_idx)
{
JitReg element_indices, native_ret, argv;
WASMType *func_type;
JitInsn *insn;
POP_I32(element_indices);
func_type = cc->cur_wasm_module->types[type_idx];
if (!pre_call(cc, func_type)) {
goto fail;
}
argv = pack_argv(cc);
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
/* Set native_ret to x86::eax */
native_ret = jit_codegen_get_hreg_by_name("eax");
#else
native_ret = jit_cc_new_reg_I32(cc);
#endif
insn = GEN_INSN(CALLNATIVE, native_ret,
NEW_CONST(PTR, (uintptr_t)wasm_call_indirect), 5);
if (!insn) {
goto fail;
}
*(jit_insn_opndv(insn, 2)) = cc->exec_env_reg;
*(jit_insn_opndv(insn, 3)) = NEW_CONST(I32, tbl_idx);
*(jit_insn_opndv(insn, 4)) = element_indices;
*(jit_insn_opndv(insn, 5)) = NEW_CONST(I32, func_type->param_count);
*(jit_insn_opndv(insn, 6)) = argv;
/* Check whether there is exception thrown */
GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0));
if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, cc->cmp_reg,
NULL)) {
return false;
}
if (!unpack_argv(cc, func_type, argv)) {
goto fail;
}
if (!post_return(cc, func_type)) {
goto fail;
}
/* Clear part of memory regs and table regs as their values
may be changed in the function call */
clear_memory_regs(cc->jit_frame);
clear_table_regs(cc->jit_frame);
return true;
fail:
return false;
}