/* * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include "jit_emit_variable.h" #include "jit_emit_exception.h" #include "../jit_frontend.h" #define CHECK_LOCAL(idx) \ do { \ if (idx \ >= wasm_func->func_type->param_count + wasm_func->local_count) { \ jit_set_last_error(cc, "local index out of range"); \ goto fail; \ } \ } while (0) static uint8 get_local_type(const WASMFunction *wasm_func, uint32 local_idx) { uint32 param_count = wasm_func->func_type->param_count; return local_idx < param_count ? wasm_func->func_type->types[local_idx] : wasm_func->local_types[local_idx - param_count]; } bool jit_compile_op_get_local(JitCompContext *cc, uint32 local_idx) { WASMFunction *wasm_func = cc->cur_wasm_func; uint16 *local_offsets = wasm_func->local_offsets; uint16 local_offset; uint8 local_type; JitReg value = 0; CHECK_LOCAL(local_idx); local_offset = local_offsets[local_idx]; local_type = get_local_type(wasm_func, local_idx); switch (local_type) { case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_EXTERNREF: case VALUE_TYPE_FUNCREF: #endif value = local_i32(cc->jit_frame, local_offset); break; case VALUE_TYPE_I64: value = local_i64(cc->jit_frame, local_offset); break; case VALUE_TYPE_F32: value = local_f32(cc->jit_frame, local_offset); break; case VALUE_TYPE_F64: value = local_f64(cc->jit_frame, local_offset); break; default: bh_assert(0); break; } PUSH(value, local_type); return true; fail: return false; } bool jit_compile_op_set_local(JitCompContext *cc, uint32 local_idx) { WASMFunction *wasm_func = cc->cur_wasm_func; uint16 *local_offsets = wasm_func->local_offsets; uint16 local_offset; uint8 local_type; JitReg value; CHECK_LOCAL(local_idx); local_offset = local_offsets[local_idx]; local_type = get_local_type(wasm_func, local_idx); switch (local_type) { case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_EXTERNREF: case VALUE_TYPE_FUNCREF: #endif POP_I32(value); set_local_i32(cc->jit_frame, local_offset, value); break; case VALUE_TYPE_I64: POP_I64(value); set_local_i64(cc->jit_frame, local_offset, value); break; case VALUE_TYPE_F32: POP_F32(value); set_local_f32(cc->jit_frame, local_offset, value); break; case VALUE_TYPE_F64: POP_F64(value); set_local_f64(cc->jit_frame, local_offset, value); break; default: bh_assert(0); break; } return true; fail: return false; } bool jit_compile_op_tee_local(JitCompContext *cc, uint32 local_idx) { WASMFunction *wasm_func = cc->cur_wasm_func; uint16 *local_offsets = wasm_func->local_offsets; uint16 local_offset; uint8 local_type; JitReg value = 0; CHECK_LOCAL(local_idx); local_offset = local_offsets[local_idx]; local_type = get_local_type(wasm_func, local_idx); switch (local_type) { case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_EXTERNREF: case VALUE_TYPE_FUNCREF: #endif POP_I32(value); set_local_i32(cc->jit_frame, local_offset, value); PUSH_I32(value); break; case VALUE_TYPE_I64: POP_I64(value); set_local_i64(cc->jit_frame, local_offset, value); PUSH_I64(value); break; case VALUE_TYPE_F32: POP_F32(value); set_local_f32(cc->jit_frame, local_offset, value); PUSH_F32(value); break; case VALUE_TYPE_F64: POP_F64(value); set_local_f64(cc->jit_frame, local_offset, value); PUSH_F64(value); break; default: bh_assert(0); goto fail; } return true; fail: return false; } static uint8 get_global_type(const WASMModule *module, uint32 global_idx) { if (global_idx < module->import_global_count) { const WASMGlobalImport *import_global = &((module->import_globals + global_idx)->u.global); return import_global->type.val_type; } else { const WASMGlobal *global = module->globals + (global_idx - module->import_global_count); return global->type.val_type; } } bool jit_compile_op_get_global(JitCompContext *cc, uint32 global_idx) { uint32 data_offset; uint8 global_type = 0; JitReg value = 0; bh_assert(global_idx < cc->cur_wasm_module->import_global_count + cc->cur_wasm_module->global_count); data_offset = jit_frontend_get_global_data_offset(cc->cur_wasm_module, global_idx); global_type = get_global_type(cc->cur_wasm_module, global_idx); switch (global_type) { 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, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_I64: { value = jit_cc_new_reg_I64(cc); GEN_INSN(LDI64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F32: { value = jit_cc_new_reg_F32(cc); GEN_INSN(LDF32, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F64: { value = jit_cc_new_reg_F64(cc); GEN_INSN(LDF64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } default: { jit_set_last_error(cc, "unexpected global type"); goto fail; } } PUSH(value, global_type); return true; fail: return false; } bool jit_compile_op_set_global(JitCompContext *cc, uint32 global_idx, bool is_aux_stack) { uint32 data_offset; uint8 global_type = 0; JitReg value = 0; bh_assert(global_idx < cc->cur_wasm_module->import_global_count + cc->cur_wasm_module->global_count); data_offset = jit_frontend_get_global_data_offset(cc->cur_wasm_module, global_idx); global_type = get_global_type(cc->cur_wasm_module, global_idx); switch (global_type) { case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 case VALUE_TYPE_EXTERNREF: case VALUE_TYPE_FUNCREF: #endif { POP_I32(value); if (is_aux_stack) { JitReg aux_stack_bound = get_aux_stack_bound_reg(cc->jit_frame); JitReg aux_stack_bottom = get_aux_stack_bottom_reg(cc->jit_frame); GEN_INSN(CMP, cc->cmp_reg, value, aux_stack_bound); if (!(jit_emit_exception(cc, EXCE_AUX_STACK_OVERFLOW, JIT_OP_BLEU, cc->cmp_reg, NULL))) goto fail; GEN_INSN(CMP, cc->cmp_reg, value, aux_stack_bottom); if (!(jit_emit_exception(cc, EXCE_AUX_STACK_UNDERFLOW, JIT_OP_BGTU, cc->cmp_reg, NULL))) goto fail; } GEN_INSN(STI32, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_I64: { POP_I64(value); GEN_INSN(STI64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F32: { POP_F32(value); GEN_INSN(STF32, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F64: { POP_F64(value); GEN_INSN(STF64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } default: { jit_set_last_error(cc, "unexpected global type"); goto fail; } } return true; fail: return false; }