Import WAMR Fast JIT (#1343)
Import WAMR Fast JIT which is a lightweight JIT with quick startup, small footprint, relatively good performance (~40% to ~50% of LLVM JIT) and good portability. Platforms supported: Linux, MacOS and Linux SGX. Arch supported: x86-64.
This commit is contained in:
345
core/iwasm/fast-jit/fe/jit_emit_compare.c
Normal file
345
core/iwasm/fast-jit/fe/jit_emit_compare.c
Normal file
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_compare.h"
|
||||
#include "jit_emit_function.h"
|
||||
#include "../jit_frontend.h"
|
||||
#include "../jit_codegen.h"
|
||||
|
||||
static bool
|
||||
jit_compile_op_compare_integer(JitCompContext *cc, IntCond cond, bool is64Bit)
|
||||
{
|
||||
JitReg lhs, rhs, res, const_zero, const_one;
|
||||
|
||||
if (cond < INT_EQZ || cond > INT_GE_U) {
|
||||
jit_set_last_error(cc, "unsupported comparation operation");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
const_zero = NEW_CONST(I32, 0);
|
||||
const_one = NEW_CONST(I32, 1);
|
||||
|
||||
if (is64Bit) {
|
||||
if (INT_EQZ == cond) {
|
||||
rhs = NEW_CONST(I64, 0);
|
||||
}
|
||||
else {
|
||||
POP_I64(rhs);
|
||||
}
|
||||
POP_I64(lhs);
|
||||
}
|
||||
else {
|
||||
if (INT_EQZ == cond) {
|
||||
rhs = NEW_CONST(I32, 0);
|
||||
}
|
||||
else {
|
||||
POP_I32(rhs);
|
||||
}
|
||||
POP_I32(lhs);
|
||||
}
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, lhs, rhs);
|
||||
switch (cond) {
|
||||
case INT_EQ:
|
||||
case INT_EQZ:
|
||||
{
|
||||
GEN_INSN(SELECTEQ, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_NE:
|
||||
{
|
||||
GEN_INSN(SELECTNE, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_LT_S:
|
||||
{
|
||||
GEN_INSN(SELECTLTS, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_LT_U:
|
||||
{
|
||||
GEN_INSN(SELECTLTU, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_GT_S:
|
||||
{
|
||||
GEN_INSN(SELECTGTS, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_GT_U:
|
||||
{
|
||||
GEN_INSN(SELECTGTU, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_LE_S:
|
||||
{
|
||||
GEN_INSN(SELECTLES, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_LE_U:
|
||||
{
|
||||
GEN_INSN(SELECTLEU, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case INT_GE_S:
|
||||
{
|
||||
GEN_INSN(SELECTGES, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
default: /* INT_GE_U */
|
||||
{
|
||||
GEN_INSN(SELECTGEU, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_compare(JitCompContext *cc, IntCond cond)
|
||||
{
|
||||
return jit_compile_op_compare_integer(cc, cond, false);
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_compare(JitCompContext *cc, IntCond cond)
|
||||
{
|
||||
return jit_compile_op_compare_integer(cc, cond, true);
|
||||
}
|
||||
|
||||
static int32
|
||||
float_cmp_eq(float f1, float f2)
|
||||
{
|
||||
if (isnan(f1) || isnan(f2))
|
||||
return 0;
|
||||
|
||||
return f1 == f2;
|
||||
}
|
||||
|
||||
static int32
|
||||
float_cmp_ne(float f1, float f2)
|
||||
{
|
||||
if (isnan(f1) || isnan(f2))
|
||||
return 1;
|
||||
|
||||
return f1 != f2;
|
||||
}
|
||||
|
||||
static int32
|
||||
double_cmp_eq(double d1, double d2)
|
||||
{
|
||||
if (isnan(d1) || isnan(d2))
|
||||
return 0;
|
||||
|
||||
return d1 == d2;
|
||||
}
|
||||
|
||||
static int32
|
||||
double_cmp_ne(double d1, double d2)
|
||||
{
|
||||
if (isnan(d1) || isnan(d2))
|
||||
return 1;
|
||||
|
||||
return d1 != d2;
|
||||
}
|
||||
|
||||
static bool
|
||||
jit_compile_op_compare_float_point(JitCompContext *cc, FloatCond cond,
|
||||
JitReg lhs, JitReg rhs)
|
||||
{
|
||||
JitReg res, args[2], const_zero, const_one;
|
||||
JitRegKind kind;
|
||||
void *func;
|
||||
|
||||
if (cond == FLOAT_EQ || cond == FLOAT_NE) {
|
||||
kind = jit_reg_kind(lhs);
|
||||
if (cond == FLOAT_EQ)
|
||||
func = (kind == JIT_REG_KIND_F32) ? (void *)float_cmp_eq
|
||||
: (void *)double_cmp_eq;
|
||||
else
|
||||
func = (kind == JIT_REG_KIND_F32) ? (void *)float_cmp_ne
|
||||
: (void *)double_cmp_ne;
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = lhs;
|
||||
args[1] = rhs;
|
||||
|
||||
if (!jit_emit_callnative(cc, func, res, args, 2)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
const_zero = NEW_CONST(I32, 0);
|
||||
const_one = NEW_CONST(I32, 1);
|
||||
switch (cond) {
|
||||
case FLOAT_LT:
|
||||
{
|
||||
GEN_INSN(CMP, cc->cmp_reg, rhs, lhs);
|
||||
GEN_INSN(SELECTGTS, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case FLOAT_GT:
|
||||
{
|
||||
GEN_INSN(CMP, cc->cmp_reg, lhs, rhs);
|
||||
GEN_INSN(SELECTGTS, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case FLOAT_LE:
|
||||
{
|
||||
GEN_INSN(CMP, cc->cmp_reg, rhs, lhs);
|
||||
GEN_INSN(SELECTGES, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
case FLOAT_GE:
|
||||
{
|
||||
GEN_INSN(CMP, cc->cmp_reg, lhs, rhs);
|
||||
GEN_INSN(SELECTGES, res, cc->cmp_reg, const_one, const_zero);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(!"unknown FloatCond");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_compare(JitCompContext *cc, FloatCond cond)
|
||||
{
|
||||
JitReg res, const_zero, const_one;
|
||||
JitReg lhs, rhs;
|
||||
|
||||
POP_F32(rhs);
|
||||
POP_F32(lhs);
|
||||
|
||||
if (jit_reg_is_const_val(lhs) && jit_reg_is_const_val(rhs)) {
|
||||
float32 lvalue = jit_cc_get_const_F32(cc, lhs);
|
||||
float32 rvalue = jit_cc_get_const_F32(cc, rhs);
|
||||
|
||||
const_zero = NEW_CONST(I32, 0);
|
||||
const_one = NEW_CONST(I32, 1);
|
||||
|
||||
switch (cond) {
|
||||
case FLOAT_EQ:
|
||||
{
|
||||
res = (lvalue == rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_NE:
|
||||
{
|
||||
res = (lvalue != rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_LT:
|
||||
{
|
||||
res = (lvalue < rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_GT:
|
||||
{
|
||||
res = (lvalue > rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_LE:
|
||||
{
|
||||
res = (lvalue <= rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_GE:
|
||||
{
|
||||
res = (lvalue >= rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(!"unknown FloatCond");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
return jit_compile_op_compare_float_point(cc, cond, lhs, rhs);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_compare(JitCompContext *cc, FloatCond cond)
|
||||
{
|
||||
JitReg res, const_zero, const_one;
|
||||
JitReg lhs, rhs;
|
||||
|
||||
POP_F64(rhs);
|
||||
POP_F64(lhs);
|
||||
|
||||
if (jit_reg_is_const_val(lhs) && jit_reg_is_const_val(rhs)) {
|
||||
float64 lvalue = jit_cc_get_const_F64(cc, lhs);
|
||||
float64 rvalue = jit_cc_get_const_F64(cc, rhs);
|
||||
|
||||
const_zero = NEW_CONST(I32, 0);
|
||||
const_one = NEW_CONST(I32, 1);
|
||||
|
||||
switch (cond) {
|
||||
case FLOAT_EQ:
|
||||
{
|
||||
res = (lvalue == rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_NE:
|
||||
{
|
||||
res = (lvalue != rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_LT:
|
||||
{
|
||||
res = (lvalue < rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_GT:
|
||||
{
|
||||
res = (lvalue > rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_LE:
|
||||
{
|
||||
res = (lvalue <= rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
case FLOAT_GE:
|
||||
{
|
||||
res = (lvalue >= rvalue) ? const_one : const_zero;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(!"unknown FloatCond");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
return jit_compile_op_compare_float_point(cc, cond, lhs, rhs);
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
32
core/iwasm/fast-jit/fe/jit_emit_compare.h
Normal file
32
core/iwasm/fast-jit/fe/jit_emit_compare.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_COMPARE_H_
|
||||
#define _JIT_EMIT_COMPARE_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
#include "../jit_frontend.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_compare(JitCompContext *cc, IntCond cond);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_compare(JitCompContext *cc, IntCond cond);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_compare(JitCompContext *cc, FloatCond cond);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_compare(JitCompContext *cc, FloatCond cond);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_COMPARE_H_ */
|
||||
47
core/iwasm/fast-jit/fe/jit_emit_const.c
Normal file
47
core/iwasm/fast-jit/fe/jit_emit_const.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_const.h"
|
||||
#include "../jit_frontend.h"
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_const(JitCompContext *cc, int32 i32_const)
|
||||
{
|
||||
JitReg value = NEW_CONST(I32, i32_const);
|
||||
PUSH_I32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_const(JitCompContext *cc, int64 i64_const)
|
||||
{
|
||||
JitReg value = NEW_CONST(I64, i64_const);
|
||||
PUSH_I64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_const(JitCompContext *cc, float32 f32_const)
|
||||
{
|
||||
JitReg value = NEW_CONST(F32, f32_const);
|
||||
PUSH_F32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_const(JitCompContext *cc, float64 f64_const)
|
||||
{
|
||||
JitReg value = NEW_CONST(F64, f64_const);
|
||||
PUSH_F64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
31
core/iwasm/fast-jit/fe/jit_emit_const.h
Normal file
31
core/iwasm/fast-jit/fe/jit_emit_const.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_CONST_H_
|
||||
#define _JIT_EMIT_CONST_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_const(JitCompContext *cc, int32 i32_const);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_const(JitCompContext *cc, int64 i64_const);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_const(JitCompContext *cc, float32 f32_const);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_const(JitCompContext *cc, float64 f64_const);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_CONST_H_ */
|
||||
1209
core/iwasm/fast-jit/fe/jit_emit_control.c
Normal file
1209
core/iwasm/fast-jit/fe/jit_emit_control.c
Normal file
File diff suppressed because it is too large
Load Diff
56
core/iwasm/fast-jit/fe/jit_emit_control.h
Normal file
56
core/iwasm/fast-jit/fe/jit_emit_control.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_CONTROL_H_
|
||||
#define _JIT_EMIT_CONTROL_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_block(JitCompContext *cc, uint8 **p_frame_ip,
|
||||
uint8 *frame_ip_end, uint32 label_type, uint32 param_count,
|
||||
uint8 *param_types, uint32 result_count,
|
||||
uint8 *result_types, bool merge_cmp_and_if);
|
||||
|
||||
bool
|
||||
jit_compile_op_else(JitCompContext *cc, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_end(JitCompContext *cc, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_br(JitCompContext *cc, uint32 br_depth, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_br_if(JitCompContext *cc, uint32 br_depth,
|
||||
bool merge_cmp_and_br_if, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_br_table(JitCompContext *cc, uint32 *br_depths, uint32 br_count,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_return(JitCompContext *cc, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_unreachable(JitCompContext *cc, uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_handle_next_reachable_block(JitCompContext *cc, uint8 **p_frame_ip);
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
bool
|
||||
jit_check_suspend_flags(JitCompContext *cc);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_CONTROL_H_ */
|
||||
660
core/iwasm/fast-jit/fe/jit_emit_conversion.c
Normal file
660
core/iwasm/fast-jit/fe/jit_emit_conversion.c
Normal file
@ -0,0 +1,660 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_conversion.h"
|
||||
#include "jit_emit_exception.h"
|
||||
#include "jit_emit_function.h"
|
||||
#include "../jit_codegen.h"
|
||||
#include "../jit_frontend.h"
|
||||
|
||||
#define F32_I32_S_MIN (-2147483904.0f)
|
||||
#define F32_I32_S_MAX (2147483648.0f)
|
||||
#define F32_I32_U_MIN (-1.0f)
|
||||
#define F32_I32_U_MAX (4294967296.0f)
|
||||
#define F32_I64_S_MIN (-9223373136366403584.0f)
|
||||
#define F32_I64_S_MAX (9223372036854775808.0f)
|
||||
#define F32_I64_U_MIN (-1.0f)
|
||||
#define F32_I64_U_MAX (18446744073709551616.0f)
|
||||
|
||||
#define F64_I32_S_MIN (-2147483649.0)
|
||||
#define F64_I32_S_MAX (2147483648.0)
|
||||
#define F64_I32_U_MIN (-1.0)
|
||||
#define F64_I32_U_MAX (4294967296.0)
|
||||
#define F64_I64_S_MIN (-9223372036854777856.0)
|
||||
#define F64_I64_S_MAX (9223372036854775808.0)
|
||||
#define F64_I64_U_MIN (-1.0)
|
||||
#define F64_I64_U_MAX (18446744073709551616.0)
|
||||
|
||||
#define FP_TO_INT(f_ty, i_ty, f_nm, i_nm) \
|
||||
static i_ty i_nm##_trunc_##f_nm(f_ty fp)
|
||||
|
||||
#define INT_TO_FP(i_ty, f_ty, i_nm, f_nm) \
|
||||
static f_ty f_nm##_convert_##i_nm(i_ty i)
|
||||
|
||||
#define FP_TO_INT_SAT(f_ty, i_ty, f_nm, i_nm) \
|
||||
static i_ty i_nm##_trunc_##f_nm##_sat(f_ty fp)
|
||||
|
||||
static int
|
||||
local_isnan(double x)
|
||||
{
|
||||
return isnan(x);
|
||||
}
|
||||
|
||||
static int
|
||||
local_isnanf(float x)
|
||||
{
|
||||
return isnan(x);
|
||||
}
|
||||
|
||||
#define RETURN_IF_NANF(fp) \
|
||||
if (local_isnanf(fp)) { \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define RETURN_IF_NAN(fp) \
|
||||
if (local_isnan(fp)) { \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define RETURN_IF_INF(fp, i_min, i_max) \
|
||||
if (isinf(fp)) { \
|
||||
return fp < 0 ? i_min : i_max; \
|
||||
}
|
||||
|
||||
#define RETURN_IF_MIN(fp, f_min, i_min) \
|
||||
if (fp <= f_min) { \
|
||||
return i_min; \
|
||||
}
|
||||
|
||||
#define RETURN_IF_MAX(fp, f_max, i_max) \
|
||||
if (fp >= f_max) { \
|
||||
return i_max; \
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(float, int32, f32, i32)
|
||||
{
|
||||
RETURN_IF_NANF(fp)
|
||||
RETURN_IF_INF(fp, INT32_MIN, INT32_MAX)
|
||||
RETURN_IF_MIN(fp, F32_I32_S_MIN, INT32_MIN)
|
||||
RETURN_IF_MAX(fp, F32_I32_S_MAX, INT32_MAX)
|
||||
return (int32)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(float, uint32, f32, u32)
|
||||
{
|
||||
RETURN_IF_NANF(fp)
|
||||
RETURN_IF_INF(fp, 0, UINT32_MAX)
|
||||
RETURN_IF_MIN(fp, F32_I32_U_MIN, 0)
|
||||
RETURN_IF_MAX(fp, F32_I32_U_MAX, UINT32_MAX)
|
||||
return (uint32)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(double, int32, f64, i32)
|
||||
{
|
||||
RETURN_IF_NAN(fp)
|
||||
RETURN_IF_INF(fp, INT32_MIN, INT32_MAX)
|
||||
RETURN_IF_MIN(fp, F64_I32_S_MIN, INT32_MIN)
|
||||
RETURN_IF_MAX(fp, F64_I32_S_MAX, INT32_MAX)
|
||||
return (int32)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(double, uint32, f64, u32)
|
||||
{
|
||||
RETURN_IF_NAN(fp)
|
||||
RETURN_IF_INF(fp, 0, UINT32_MAX)
|
||||
RETURN_IF_MIN(fp, F64_I32_U_MIN, 0)
|
||||
RETURN_IF_MAX(fp, F64_I32_U_MAX, UINT32_MAX)
|
||||
return (uint32)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(float, int64, f32, i64)
|
||||
{
|
||||
RETURN_IF_NANF(fp)
|
||||
RETURN_IF_INF(fp, INT64_MIN, INT64_MAX)
|
||||
RETURN_IF_MIN(fp, F32_I64_S_MIN, INT64_MIN)
|
||||
RETURN_IF_MAX(fp, F32_I64_S_MAX, INT64_MAX)
|
||||
return (int64)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT(float, uint64, f32, u64)
|
||||
{
|
||||
return (uint64)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(float, uint64, f32, u64)
|
||||
{
|
||||
RETURN_IF_NANF(fp)
|
||||
RETURN_IF_INF(fp, 0, UINT64_MAX)
|
||||
RETURN_IF_MIN(fp, F32_I64_U_MIN, 0)
|
||||
RETURN_IF_MAX(fp, F32_I64_U_MAX, UINT64_MAX)
|
||||
return (uint64)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(double, int64, f64, i64)
|
||||
{
|
||||
RETURN_IF_NANF(fp)
|
||||
RETURN_IF_INF(fp, INT64_MIN, INT64_MAX)
|
||||
RETURN_IF_MIN(fp, F64_I64_S_MIN, INT64_MIN)
|
||||
RETURN_IF_MAX(fp, F64_I64_S_MAX, INT64_MAX)
|
||||
return (int64)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT(double, uint64, f64, u64)
|
||||
{
|
||||
return (uint64)fp;
|
||||
}
|
||||
|
||||
FP_TO_INT_SAT(double, uint64, f64, u64)
|
||||
{
|
||||
RETURN_IF_NANF(fp)
|
||||
RETURN_IF_INF(fp, 0, UINT64_MAX)
|
||||
RETURN_IF_MIN(fp, F64_I64_U_MIN, 0)
|
||||
RETURN_IF_MAX(fp, F64_I64_U_MAX, UINT64_MAX)
|
||||
return (uint64)fp;
|
||||
}
|
||||
|
||||
INT_TO_FP(uint64, float, u64, f32)
|
||||
{
|
||||
return (float)i;
|
||||
}
|
||||
|
||||
INT_TO_FP(uint64, double, u64, f64)
|
||||
{
|
||||
return (double)i;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_wrap_i64(JitCompContext *cc)
|
||||
{
|
||||
JitReg num, res;
|
||||
|
||||
POP_I64(num);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(I64TOI32, res, num);
|
||||
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
jit_compile_check_value_range(JitCompContext *cc, JitReg value, JitReg min_fp,
|
||||
JitReg max_fp)
|
||||
{
|
||||
JitReg nan_ret = jit_cc_new_reg_I32(cc);
|
||||
JitRegKind kind = jit_reg_kind(value);
|
||||
bool emit_ret = false;
|
||||
|
||||
bh_assert(JIT_REG_KIND_F32 == kind || JIT_REG_KIND_F64 == kind);
|
||||
|
||||
/* If value is NaN, throw exception */
|
||||
if (JIT_REG_KIND_F32 == kind)
|
||||
emit_ret = jit_emit_callnative(cc, local_isnanf, nan_ret, &value, 1);
|
||||
else
|
||||
emit_ret = jit_emit_callnative(cc, local_isnan, nan_ret, &value, 1);
|
||||
if (!emit_ret)
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, nan_ret, NEW_CONST(I32, 1));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_INVALID_CONVERSION_TO_INTEGER,
|
||||
JIT_OP_BEQ, cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
/* If value is out of integer range, throw exception */
|
||||
GEN_INSN(CMP, cc->cmp_reg, min_fp, value);
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_INTEGER_OVERFLOW, JIT_OP_BGES,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, value, max_fp);
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_INTEGER_OVERFLOW, JIT_OP_BGES,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_trunc_f32(JitCompContext *cc, bool sign, bool sat)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
if (!sat) {
|
||||
JitReg min_fp = NEW_CONST(F32, sign ? F32_I32_S_MIN : F32_I32_U_MIN);
|
||||
JitReg max_fp = NEW_CONST(F32, sign ? F32_I32_S_MAX : F32_I32_U_MAX);
|
||||
|
||||
if (!jit_compile_check_value_range(cc, value, min_fp, max_fp))
|
||||
goto fail;
|
||||
|
||||
if (sign)
|
||||
GEN_INSN(F32TOI32, res, value);
|
||||
else
|
||||
GEN_INSN(F32TOU32, res, value);
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc,
|
||||
sign ? (void *)i32_trunc_f32_sat
|
||||
: (void *)u32_trunc_f32_sat,
|
||||
res, &value, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_trunc_f64(JitCompContext *cc, bool sign, bool sat)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
if (!sat) {
|
||||
JitReg min_fp = NEW_CONST(F64, sign ? F64_I32_S_MIN : F64_I32_U_MIN);
|
||||
JitReg max_fp = NEW_CONST(F64, sign ? F64_I32_S_MAX : F64_I32_U_MAX);
|
||||
|
||||
if (!jit_compile_check_value_range(cc, value, min_fp, max_fp))
|
||||
goto fail;
|
||||
|
||||
if (sign)
|
||||
GEN_INSN(F64TOI32, res, value);
|
||||
else
|
||||
GEN_INSN(F64TOU32, res, value);
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc,
|
||||
sign ? (void *)i32_trunc_f64_sat
|
||||
: (void *)u32_trunc_f64_sat,
|
||||
res, &value, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_extend_i32(JitCompContext *cc, bool sign)
|
||||
{
|
||||
JitReg num, res;
|
||||
|
||||
POP_I32(num);
|
||||
|
||||
res = jit_cc_new_reg_I64(cc);
|
||||
if (sign)
|
||||
GEN_INSN(I32TOI64, res, num);
|
||||
else
|
||||
GEN_INSN(U32TOI64, res, num);
|
||||
|
||||
PUSH_I64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_extend_i64(JitCompContext *cc, int8 bitwidth)
|
||||
{
|
||||
JitReg value, tmp, res;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
tmp = jit_cc_new_reg_I32(cc);
|
||||
res = jit_cc_new_reg_I64(cc);
|
||||
|
||||
switch (bitwidth) {
|
||||
case 8:
|
||||
{
|
||||
GEN_INSN(I64TOI8, tmp, value);
|
||||
GEN_INSN(I8TOI64, res, tmp);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
GEN_INSN(I64TOI16, tmp, value);
|
||||
GEN_INSN(I16TOI64, res, tmp);
|
||||
break;
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
GEN_INSN(I64TOI32, tmp, value);
|
||||
GEN_INSN(I32TOI64, res, tmp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_I64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_extend_i32(JitCompContext *cc, int8 bitwidth)
|
||||
{
|
||||
JitReg value, tmp, res;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
tmp = jit_cc_new_reg_I32(cc);
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
|
||||
switch (bitwidth) {
|
||||
case 8:
|
||||
{
|
||||
GEN_INSN(I32TOI8, tmp, value);
|
||||
GEN_INSN(I8TOI32, res, tmp);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
GEN_INSN(I32TOI16, tmp, value);
|
||||
GEN_INSN(I16TOI32, res, tmp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_trunc_f32(JitCompContext *cc, bool sign, bool sat)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
res = jit_cc_new_reg_I64(cc);
|
||||
if (!sat) {
|
||||
JitReg min_fp = NEW_CONST(F32, sign ? F32_I64_S_MIN : F32_I64_U_MIN);
|
||||
JitReg max_fp = NEW_CONST(F32, sign ? F32_I64_S_MAX : F32_I64_U_MAX);
|
||||
|
||||
if (!jit_compile_check_value_range(cc, value, min_fp, max_fp))
|
||||
goto fail;
|
||||
|
||||
if (sign) {
|
||||
GEN_INSN(F32TOI64, res, value);
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc, u64_trunc_f32, res, &value, 1))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc,
|
||||
sign ? (void *)i64_trunc_f32_sat
|
||||
: (void *)u64_trunc_f32_sat,
|
||||
res, &value, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_trunc_f64(JitCompContext *cc, bool sign, bool sat)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
res = jit_cc_new_reg_I64(cc);
|
||||
if (!sat) {
|
||||
JitReg min_fp = NEW_CONST(F64, sign ? F64_I64_S_MIN : F64_I64_U_MIN);
|
||||
JitReg max_fp = NEW_CONST(F64, sign ? F64_I64_S_MAX : F64_I64_U_MAX);
|
||||
|
||||
if (!jit_compile_check_value_range(cc, value, min_fp, max_fp))
|
||||
goto fail;
|
||||
|
||||
if (sign) {
|
||||
GEN_INSN(F64TOI64, res, value);
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc, u64_trunc_f64, res, &value, 1))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc,
|
||||
sign ? (void *)i64_trunc_f64_sat
|
||||
: (void *)u64_trunc_f64_sat,
|
||||
res, &value, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PUSH_I64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_convert_i32(JitCompContext *cc, bool sign)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
res = jit_cc_new_reg_F32(cc);
|
||||
if (sign) {
|
||||
GEN_INSN(I32TOF32, res, value);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(U32TOF32, res, value);
|
||||
}
|
||||
|
||||
PUSH_F32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_convert_i64(JitCompContext *cc, bool sign)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
res = jit_cc_new_reg_F32(cc);
|
||||
if (sign) {
|
||||
GEN_INSN(I64TOF32, res, value);
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc, f32_convert_u64, res, &value, 1)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_F32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_demote_f64(JitCompContext *cc)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
res = jit_cc_new_reg_F32(cc);
|
||||
GEN_INSN(F64TOF32, res, value);
|
||||
|
||||
PUSH_F32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_convert_i32(JitCompContext *cc, bool sign)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
res = jit_cc_new_reg_F64(cc);
|
||||
if (sign)
|
||||
GEN_INSN(I32TOF64, res, value);
|
||||
else
|
||||
GEN_INSN(U32TOF64, res, value);
|
||||
|
||||
PUSH_F64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_convert_i64(JitCompContext *cc, bool sign)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
res = jit_cc_new_reg_F64(cc);
|
||||
if (sign) {
|
||||
GEN_INSN(I64TOF64, res, value);
|
||||
}
|
||||
else {
|
||||
if (!jit_emit_callnative(cc, f64_convert_u64, res, &value, 1)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_F64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_promote_f32(JitCompContext *cc)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
res = jit_cc_new_reg_F64(cc);
|
||||
GEN_INSN(F32TOF64, res, value);
|
||||
|
||||
PUSH_F64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_reinterpret_f64(JitCompContext *cc)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F64(value);
|
||||
|
||||
res = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(F64CASTI64, res, value);
|
||||
|
||||
PUSH_I64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_reinterpret_f32(JitCompContext *cc)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_F32(value);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(F32CASTI32, res, value);
|
||||
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_reinterpret_i64(JitCompContext *cc)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_I64(value);
|
||||
|
||||
res = jit_cc_new_reg_F64(cc);
|
||||
GEN_INSN(I64CASTF64, res, value);
|
||||
|
||||
PUSH_F64(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_reinterpret_i32(JitCompContext *cc)
|
||||
{
|
||||
JitReg value, res;
|
||||
|
||||
POP_I32(value);
|
||||
|
||||
res = jit_cc_new_reg_F32(cc);
|
||||
GEN_INSN(I32CASTF32, res, value);
|
||||
|
||||
PUSH_F32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
73
core/iwasm/fast-jit/fe/jit_emit_conversion.h
Normal file
73
core/iwasm/fast-jit/fe/jit_emit_conversion.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_CONVERSION_H_
|
||||
#define _JIT_EMIT_CONVERSION_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_wrap_i64(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_trunc_f32(JitCompContext *cc, bool sign, bool sat);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_trunc_f64(JitCompContext *cc, bool sign, bool sat);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_extend_i32(JitCompContext *comp_ctx, bool sign);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_extend_i64(JitCompContext *comp_ctx, int8 bitwidth);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_extend_i32(JitCompContext *comp_ctx, int8 bitwidth);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_trunc_f32(JitCompContext *cc, bool sign, bool sat);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_trunc_f64(JitCompContext *cc, bool sign, bool sat);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_convert_i32(JitCompContext *comp_ctx, bool sign);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_convert_i64(JitCompContext *comp_ctx, bool sign);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_demote_f64(JitCompContext *comp_ctx);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_convert_i32(JitCompContext *comp_ctx, bool sign);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_convert_i64(JitCompContext *comp_ctx, bool sign);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_promote_f32(JitCompContext *comp_ctx);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_reinterpret_f64(JitCompContext *comp_ctx);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_reinterpret_f32(JitCompContext *comp_ctx);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_reinterpret_i64(JitCompContext *comp_ctx);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_reinterpret_i32(JitCompContext *comp_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_CONVERSION_H_ */
|
||||
78
core/iwasm/fast-jit/fe/jit_emit_exception.c
Normal file
78
core/iwasm/fast-jit/fe/jit_emit_exception.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_exception.h"
|
||||
#include "../jit_frontend.h"
|
||||
|
||||
bool
|
||||
jit_emit_exception(JitCompContext *cc, int32 exception_id, uint8 jit_opcode,
|
||||
JitReg cond_br_if, JitBasicBlock *cond_br_else_block)
|
||||
{
|
||||
JitInsn *insn = NULL;
|
||||
JitIncomingInsn *incoming_insn;
|
||||
JitReg else_label;
|
||||
|
||||
bh_assert(exception_id < JIT_EXCE_NUM);
|
||||
|
||||
if (jit_opcode >= JIT_OP_BEQ && jit_opcode <= JIT_OP_BLEU) {
|
||||
bh_assert(cond_br_if == cc->cmp_reg);
|
||||
else_label =
|
||||
cond_br_else_block ? jit_basic_block_label(cond_br_else_block) : 0;
|
||||
switch (jit_opcode) {
|
||||
case JIT_OP_BEQ:
|
||||
insn = GEN_INSN(BEQ, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BNE:
|
||||
insn = GEN_INSN(BNE, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BGTS:
|
||||
insn = GEN_INSN(BGTS, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BGES:
|
||||
insn = GEN_INSN(BGES, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BLTS:
|
||||
insn = GEN_INSN(BLTS, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BLES:
|
||||
insn = GEN_INSN(BLES, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BGTU:
|
||||
insn = GEN_INSN(BGTU, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BGEU:
|
||||
insn = GEN_INSN(BGEU, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BLTU:
|
||||
insn = GEN_INSN(BLTU, cond_br_if, 0, else_label);
|
||||
break;
|
||||
case JIT_OP_BLEU:
|
||||
insn = GEN_INSN(BLEU, cond_br_if, 0, else_label);
|
||||
break;
|
||||
}
|
||||
if (!insn) {
|
||||
jit_set_last_error(cc, "generate cond br insn failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (jit_opcode == JIT_OP_JMP) {
|
||||
insn = GEN_INSN(JMP, 0);
|
||||
if (!insn) {
|
||||
jit_set_last_error(cc, "generate jmp insn failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
incoming_insn = jit_calloc(sizeof(JitIncomingInsn));
|
||||
if (!incoming_insn) {
|
||||
jit_set_last_error(cc, "allocate memory failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
incoming_insn->insn = insn;
|
||||
incoming_insn->next = cc->incoming_insns_for_exec_bbs[exception_id];
|
||||
cc->incoming_insns_for_exec_bbs[exception_id] = incoming_insn;
|
||||
return true;
|
||||
}
|
||||
23
core/iwasm/fast-jit/fe/jit_emit_exception.h
Normal file
23
core/iwasm/fast-jit/fe/jit_emit_exception.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_EXCEPTION_H_
|
||||
#define _JIT_EMIT_EXCEPTION_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_emit_exception(JitCompContext *cc, int32 exception_id, uint8 jit_opcode,
|
||||
JitReg cond_br_if, JitBasicBlock *cond_br_else_block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_EXCEPTION_H_ */
|
||||
535
core/iwasm/fast-jit/fe/jit_emit_function.c
Normal file
535
core/iwasm/fast-jit/fe/jit_emit_function.c
Normal file
@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_function.h"
|
||||
#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);
|
||||
|
||||
/* Prepare parameters for the function to call */
|
||||
static bool
|
||||
pre_call(JitCompContext *cc, const WASMType *func_type)
|
||||
{
|
||||
JitReg value;
|
||||
uint32 i, outs_off;
|
||||
/* Prepare parameters for the function to call */
|
||||
outs_off =
|
||||
cc->total_frame_size + offsetof(WASMInterpFrame, lp)
|
||||
+ wasm_get_cell_num(func_type->types, func_type->param_count) * 4;
|
||||
|
||||
for (i = 0; i < func_type->param_count; i++) {
|
||||
switch (func_type->types[func_type->param_count - 1 - i]) {
|
||||
case VALUE_TYPE_I32:
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
#endif
|
||||
POP_I32(value);
|
||||
outs_off -= 4;
|
||||
GEN_INSN(STI32, value, cc->fp_reg, NEW_CONST(I32, outs_off));
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
POP_I64(value);
|
||||
outs_off -= 8;
|
||||
GEN_INSN(STI64, value, cc->fp_reg, NEW_CONST(I32, outs_off));
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
POP_F32(value);
|
||||
outs_off -= 4;
|
||||
GEN_INSN(STF32, value, cc->fp_reg, NEW_CONST(I32, outs_off));
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
POP_F64(value);
|
||||
outs_off -= 8;
|
||||
GEN_INSN(STF64, value, cc->fp_reg, NEW_CONST(I32, outs_off));
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
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, JitReg first_res)
|
||||
{
|
||||
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
|
||||
if (i == 0 && first_res) {
|
||||
bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I32);
|
||||
value = first_res;
|
||||
}
|
||||
else {
|
||||
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:
|
||||
if (i == 0 && first_res) {
|
||||
bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I64);
|
||||
value = first_res;
|
||||
}
|
||||
else {
|
||||
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:
|
||||
if (i == 0 && first_res) {
|
||||
bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F32);
|
||||
value = first_res;
|
||||
}
|
||||
else {
|
||||
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:
|
||||
if (i == 0 && first_res) {
|
||||
bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F64);
|
||||
value = first_res;
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the committed_sp as the callee has updated the frame sp */
|
||||
cc->jit_frame->committed_sp = cc->jit_frame->sp;
|
||||
|
||||
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 native_ret;
|
||||
JitReg fast_jit_func_ptrs, jitted_code = 0;
|
||||
uint32 jitted_func_idx;
|
||||
|
||||
if (func_idx >= wasm_module->import_function_count) {
|
||||
fast_jit_func_ptrs = get_fast_jit_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, fast_jit_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) {
|
||||
JitReg arg_regs[3];
|
||||
|
||||
native_ret = jit_cc_new_reg_I32(cc);
|
||||
arg_regs[0] = cc->exec_env_reg;
|
||||
arg_regs[1] = NEW_CONST(I32, func_idx);
|
||||
arg_regs[2] = cc->fp_reg;
|
||||
|
||||
if (!jit_emit_callnative(cc, jit_invoke_native, native_ret, arg_regs,
|
||||
3)) {
|
||||
return false;
|
||||
}
|
||||
/* Convert bool to uint32 */
|
||||
GEN_INSN(AND, native_ret, native_ret, NEW_CONST(I32, 0xFF));
|
||||
|
||||
/* Check whether there is exception thrown */
|
||||
GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BEQ,
|
||||
cc->cmp_reg, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!post_return(cc, func_type, 0)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
JitReg res = 0;
|
||||
|
||||
if (func_type->result_count > 0) {
|
||||
switch (func_type->types[func_type->param_count]) {
|
||||
case VALUE_TYPE_I32:
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
#endif
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
res = jit_cc_new_reg_I64(cc);
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
res = jit_cc_new_reg_F32(cc);
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
res = jit_cc_new_reg_F64(cc);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
GEN_INSN(CALLBC, res, 0, jitted_code);
|
||||
|
||||
if (!post_return(cc, func_type, res)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear part of memory regs and table regs as their values
|
||||
may be changed in the function call */
|
||||
if (cc->cur_wasm_module->possible_memory_grow)
|
||||
clear_memory_regs(jit_frame);
|
||||
clear_table_regs(jit_frame);
|
||||
|
||||
/* Ignore tail call currently */
|
||||
(void)tail_call;
|
||||
return true;
|
||||
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)
|
||||
{
|
||||
uint32 i, offset_by_cell = 0;
|
||||
JitReg value;
|
||||
|
||||
/* push results in argv to stack */
|
||||
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));
|
||||
PUSH_I32(value);
|
||||
offset_by_cell += 4;
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_I64:
|
||||
{
|
||||
value = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(LDI64, value, argv, NEW_CONST(I32, offset_by_cell));
|
||||
PUSH_I64(value);
|
||||
offset_by_cell += 8;
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_F32:
|
||||
{
|
||||
value = jit_cc_new_reg_F32(cc);
|
||||
GEN_INSN(LDF32, value, argv, NEW_CONST(I32, offset_by_cell));
|
||||
PUSH_F32(value);
|
||||
offset_by_cell += 4;
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_F64:
|
||||
{
|
||||
value = jit_cc_new_reg_F64(cc);
|
||||
GEN_INSN(LDF64, value, argv, NEW_CONST(I32, offset_by_cell));
|
||||
PUSH_F64(value);
|
||||
offset_by_cell += 8;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the committed_sp as the callee has updated the frame sp */
|
||||
cc->jit_frame->committed_sp = cc->jit_frame->sp;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
JitReg elem_idx, native_ret, argv, arg_regs[6];
|
||||
WASMType *func_type;
|
||||
|
||||
POP_I32(elem_idx);
|
||||
|
||||
func_type = cc->cur_wasm_module->types[type_idx];
|
||||
if (!pre_call(cc, func_type)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
argv = pack_argv(cc);
|
||||
|
||||
native_ret = jit_cc_new_reg_I32(cc);
|
||||
arg_regs[0] = cc->exec_env_reg;
|
||||
arg_regs[1] = NEW_CONST(I32, tbl_idx);
|
||||
arg_regs[2] = elem_idx;
|
||||
arg_regs[3] = NEW_CONST(I32, type_idx);
|
||||
arg_regs[4] = NEW_CONST(I32, func_type->param_cell_num);
|
||||
arg_regs[5] = argv;
|
||||
|
||||
if (!jit_emit_callnative(cc, jit_call_indirect, native_ret, arg_regs, 6)) {
|
||||
return false;
|
||||
}
|
||||
/* Convert bool to uint32 */
|
||||
GEN_INSN(AND, native_ret, native_ret, NEW_CONST(I32, 0xFF));
|
||||
|
||||
/* Check whether there is exception thrown */
|
||||
GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BEQ,
|
||||
cc->cmp_reg, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unpack_argv(cc, func_type, argv)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Clear part of memory regs and table regs as their values
|
||||
may be changed in the function call */
|
||||
if (cc->cur_wasm_module->possible_memory_grow)
|
||||
clear_memory_regs(cc->jit_frame);
|
||||
clear_table_regs(cc->jit_frame);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
bool
|
||||
jit_compile_op_ref_null(JitCompContext *cc, uint32 ref_type)
|
||||
{
|
||||
PUSH_I32(NEW_CONST(I32, NULL_REF));
|
||||
(void)ref_type;
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_ref_is_null(JitCompContext *cc)
|
||||
{
|
||||
JitReg ref, res;
|
||||
|
||||
POP_I32(ref);
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, ref, NEW_CONST(I32, NULL_REF));
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(SELECTEQ, res, cc->cmp_reg, NEW_CONST(I32, 1), NEW_CONST(I32, 0));
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_ref_func(JitCompContext *cc, uint32 func_idx)
|
||||
{
|
||||
PUSH_I32(NEW_CONST(I32, func_idx));
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
|
||||
bool
|
||||
jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res,
|
||||
JitReg *params, uint32 param_count)
|
||||
{
|
||||
JitInsn *insn;
|
||||
char *i64_arg_names[] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" };
|
||||
char *f32_arg_names[] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" };
|
||||
char *f64_arg_names[] = { "xmm0_f64", "xmm1_f64", "xmm2_f64",
|
||||
"xmm3_f64", "xmm4_f64", "xmm5_f64" };
|
||||
JitReg i64_arg_regs[6], f32_arg_regs[6], f64_arg_regs[6], res_hreg = 0;
|
||||
JitReg eax_hreg = jit_codegen_get_hreg_by_name("eax");
|
||||
JitReg rax_hreg = jit_codegen_get_hreg_by_name("rax");
|
||||
JitReg xmm0_hreg = jit_codegen_get_hreg_by_name("xmm0");
|
||||
JitReg xmm0_f64_hreg = jit_codegen_get_hreg_by_name("xmm0_f64");
|
||||
uint32 i, i64_reg_idx, float_reg_idx;
|
||||
|
||||
bh_assert(param_count <= 6);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
i64_arg_regs[i] = jit_codegen_get_hreg_by_name(i64_arg_names[i]);
|
||||
f32_arg_regs[i] = jit_codegen_get_hreg_by_name(f32_arg_names[i]);
|
||||
f64_arg_regs[i] = jit_codegen_get_hreg_by_name(f64_arg_names[i]);
|
||||
}
|
||||
|
||||
i64_reg_idx = float_reg_idx = 0;
|
||||
for (i = 0; i < param_count; i++) {
|
||||
switch (jit_reg_kind(params[i])) {
|
||||
case JIT_REG_KIND_I32:
|
||||
GEN_INSN(I32TOI64, i64_arg_regs[i64_reg_idx++], params[i]);
|
||||
break;
|
||||
case JIT_REG_KIND_I64:
|
||||
GEN_INSN(MOV, i64_arg_regs[i64_reg_idx++], params[i]);
|
||||
break;
|
||||
case JIT_REG_KIND_F32:
|
||||
GEN_INSN(MOV, f32_arg_regs[float_reg_idx++], params[i]);
|
||||
break;
|
||||
case JIT_REG_KIND_F64:
|
||||
GEN_INSN(MOV, f64_arg_regs[float_reg_idx++], params[i]);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
switch (jit_reg_kind(res)) {
|
||||
case JIT_REG_KIND_I32:
|
||||
res_hreg = eax_hreg;
|
||||
break;
|
||||
case JIT_REG_KIND_I64:
|
||||
res_hreg = rax_hreg;
|
||||
break;
|
||||
case JIT_REG_KIND_F32:
|
||||
res_hreg = xmm0_hreg;
|
||||
break;
|
||||
case JIT_REG_KIND_F64:
|
||||
res_hreg = xmm0_f64_hreg;
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
insn = GEN_INSN(CALLNATIVE, res_hreg,
|
||||
NEW_CONST(PTR, (uintptr_t)native_func), param_count);
|
||||
if (!insn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i64_reg_idx = float_reg_idx = 0;
|
||||
for (i = 0; i < param_count; i++) {
|
||||
switch (jit_reg_kind(params[i])) {
|
||||
case JIT_REG_KIND_I32:
|
||||
case JIT_REG_KIND_I64:
|
||||
*(jit_insn_opndv(insn, i + 2)) = i64_arg_regs[i64_reg_idx++];
|
||||
break;
|
||||
case JIT_REG_KIND_F32:
|
||||
*(jit_insn_opndv(insn, i + 2)) = f32_arg_regs[float_reg_idx++];
|
||||
break;
|
||||
case JIT_REG_KIND_F64:
|
||||
*(jit_insn_opndv(insn, i + 2)) = f64_arg_regs[float_reg_idx++];
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
GEN_INSN(MOV, res, res_hreg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
bool
|
||||
jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res,
|
||||
JitReg *params, uint32 param_count)
|
||||
{
|
||||
JitInsn *insn;
|
||||
uint32 i;
|
||||
|
||||
bh_assert(param_count <= 6);
|
||||
|
||||
insn = GEN_INSN(CALLNATIVE, res, NEW_CONST(PTR, (uintptr_t)native_func),
|
||||
param_count);
|
||||
if (!insn)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < param_count; i++) {
|
||||
*(jit_insn_opndv(insn, i + 2)) = params[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
39
core/iwasm/fast-jit/fe/jit_emit_function.h
Normal file
39
core/iwasm/fast-jit/fe/jit_emit_function.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_FUNCTION_H_
|
||||
#define _JIT_EMIT_FUNCTION_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call);
|
||||
|
||||
bool
|
||||
jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
|
||||
uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_ref_null(JitCompContext *cc, uint32 ref_type);
|
||||
|
||||
bool
|
||||
jit_compile_op_ref_is_null(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_ref_func(JitCompContext *cc, uint32 func_idx);
|
||||
|
||||
bool
|
||||
jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res,
|
||||
JitReg *params, uint32 param_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_FUNCTION_H_ */
|
||||
782
core/iwasm/fast-jit/fe/jit_emit_memory.c
Normal file
782
core/iwasm/fast-jit/fe/jit_emit_memory.c
Normal file
@ -0,0 +1,782 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_memory.h"
|
||||
#include "jit_emit_exception.h"
|
||||
#include "jit_emit_function.h"
|
||||
#include "../jit_frontend.h"
|
||||
#include "../jit_codegen.h"
|
||||
#include "../../interpreter/wasm_runtime.h"
|
||||
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
static JitReg
|
||||
get_memory_boundary(JitCompContext *cc, uint32 mem_idx, uint32 bytes)
|
||||
{
|
||||
JitReg memory_boundary;
|
||||
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
{
|
||||
memory_boundary =
|
||||
get_mem_bound_check_1byte_reg(cc->jit_frame, mem_idx);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
memory_boundary =
|
||||
get_mem_bound_check_2bytes_reg(cc->jit_frame, mem_idx);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
memory_boundary =
|
||||
get_mem_bound_check_4bytes_reg(cc->jit_frame, mem_idx);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
memory_boundary =
|
||||
get_mem_bound_check_8bytes_reg(cc->jit_frame, mem_idx);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
memory_boundary =
|
||||
get_mem_bound_check_16bytes_reg(cc->jit_frame, mem_idx);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return memory_boundary;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
static JitReg
|
||||
check_and_seek_on_64bit_platform(JitCompContext *cc, JitReg addr, JitReg offset,
|
||||
JitReg memory_boundary)
|
||||
{
|
||||
JitReg long_addr, offset1;
|
||||
|
||||
/* long_addr = (int64_t)addr */
|
||||
long_addr = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(U32TOI64, long_addr, addr);
|
||||
|
||||
/* offset1 = offset + long_addr */
|
||||
offset1 = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(ADD, offset1, offset, long_addr);
|
||||
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
/* if (offset1 > memory_boundary) goto EXCEPTION */
|
||||
GEN_INSN(CMP, cc->cmp_reg, offset1, memory_boundary);
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
JIT_OP_BGTU, cc->cmp_reg, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
return offset1;
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
fail:
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static JitReg
|
||||
check_and_seek_on_32bit_platform(JitCompContext *cc, JitReg addr, JitReg offset,
|
||||
JitReg memory_boundary)
|
||||
{
|
||||
JitReg offset1;
|
||||
|
||||
/* offset1 = offset + addr */
|
||||
offset1 = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(ADD, offset1, offset, addr);
|
||||
|
||||
/* if (offset1 < addr) goto EXCEPTION */
|
||||
GEN_INSN(CMP, cc->cmp_reg, offset1, addr);
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
JIT_OP_BLTU, cc->cmp_reg, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
/* if (offset1 > memory_boundary) goto EXCEPTION */
|
||||
GEN_INSN(CMP, cc->cmp_reg, offset1, memory_boundary);
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
JIT_OP_BGTU, cc->cmp_reg, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
return offset1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static JitReg
|
||||
check_and_seek(JitCompContext *cc, JitReg addr, uint32 offset, uint32 bytes)
|
||||
{
|
||||
JitReg memory_boundary = 0, offset1;
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
/* the default memory */
|
||||
uint32 mem_idx = 0;
|
||||
#endif
|
||||
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
/* ---------- check ---------- */
|
||||
/* 1. shortcut if the memory size is 0 */
|
||||
if (0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) {
|
||||
JitReg memory_inst, cur_mem_page_count;
|
||||
|
||||
/* if (cur_mem_page_count == 0) goto EXCEPTION */
|
||||
memory_inst = get_memory_inst_reg(cc->jit_frame, mem_idx);
|
||||
cur_mem_page_count = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(LDI32, cur_mem_page_count, memory_inst,
|
||||
NEW_CONST(I32, offsetof(WASMMemoryInstance, cur_page_count)));
|
||||
GEN_INSN(CMP, cc->cmp_reg, cur_mem_page_count, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS,
|
||||
JIT_OP_BEQ, cc->cmp_reg, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. a complete boundary check */
|
||||
memory_boundary = get_memory_boundary(cc, mem_idx, bytes);
|
||||
if (!memory_boundary)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
offset1 = check_and_seek_on_64bit_platform(cc, addr, NEW_CONST(I64, offset),
|
||||
memory_boundary);
|
||||
if (!offset1)
|
||||
goto fail;
|
||||
#else
|
||||
offset1 = check_and_seek_on_32bit_platform(cc, addr, NEW_CONST(I32, offset),
|
||||
memory_boundary);
|
||||
if (!offset1)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
return offset1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool sign, bool atomic)
|
||||
{
|
||||
JitReg addr, offset1, value, memory_data;
|
||||
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, bytes);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
value = jit_cc_new_reg_I32(cc);
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
{
|
||||
if (sign) {
|
||||
GEN_INSN(LDI8, value, memory_data, offset1);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(LDU8, value, memory_data, offset1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (sign) {
|
||||
GEN_INSN(LDI16, value, memory_data, offset1);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(LDU16, value, memory_data, offset1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if (sign) {
|
||||
GEN_INSN(LDI32, value, memory_data, offset1);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(LDU32, value, memory_data, offset1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_I32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_load(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool sign, bool atomic)
|
||||
{
|
||||
JitReg addr, offset1, value, memory_data;
|
||||
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, bytes);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
value = jit_cc_new_reg_I64(cc);
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
{
|
||||
if (sign) {
|
||||
GEN_INSN(LDI8, value, memory_data, offset1);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(LDU8, value, memory_data, offset1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (sign) {
|
||||
GEN_INSN(LDI16, value, memory_data, offset1);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(LDU16, value, memory_data, offset1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if (sign) {
|
||||
GEN_INSN(LDI32, value, memory_data, offset1);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(LDU32, value, memory_data, offset1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
if (sign) {
|
||||
GEN_INSN(LDI64, value, memory_data, offset1);
|
||||
}
|
||||
else {
|
||||
GEN_INSN(LDU64, value, memory_data, offset1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_I64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_load(JitCompContext *cc, uint32 align, uint32 offset)
|
||||
{
|
||||
JitReg addr, offset1, value, memory_data;
|
||||
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, 4);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
value = jit_cc_new_reg_F32(cc);
|
||||
GEN_INSN(LDF32, value, memory_data, offset1);
|
||||
|
||||
PUSH_F32(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_load(JitCompContext *cc, uint32 align, uint32 offset)
|
||||
{
|
||||
JitReg addr, offset1, value, memory_data;
|
||||
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, 8);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
value = jit_cc_new_reg_F64(cc);
|
||||
GEN_INSN(LDF64, value, memory_data, offset1);
|
||||
|
||||
PUSH_F64(value);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_store(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool atomic)
|
||||
{
|
||||
JitReg value, addr, offset1, memory_data;
|
||||
|
||||
POP_I32(value);
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, bytes);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
{
|
||||
GEN_INSN(STI8, value, memory_data, offset1);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
GEN_INSN(STI16, value, memory_data, offset1);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
GEN_INSN(STI32, value, memory_data, offset1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_store(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool atomic)
|
||||
{
|
||||
JitReg value, addr, offset1, memory_data;
|
||||
|
||||
POP_I64(value);
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, bytes);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (jit_reg_is_const(value) && bytes < 8) {
|
||||
value = NEW_CONST(I32, (int32)jit_cc_get_const_I64(cc, value));
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
{
|
||||
GEN_INSN(STI8, value, memory_data, offset1);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
GEN_INSN(STI16, value, memory_data, offset1);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
GEN_INSN(STI32, value, memory_data, offset1);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
GEN_INSN(STI64, value, memory_data, offset1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_store(JitCompContext *cc, uint32 align, uint32 offset)
|
||||
{
|
||||
JitReg value, addr, offset1, memory_data;
|
||||
|
||||
POP_F32(value);
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, 4);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
GEN_INSN(STF32, value, memory_data, offset1);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_store(JitCompContext *cc, uint32 align, uint32 offset)
|
||||
{
|
||||
JitReg value, addr, offset1, memory_data;
|
||||
|
||||
POP_F64(value);
|
||||
POP_I32(addr);
|
||||
|
||||
offset1 = check_and_seek(cc, addr, offset, 8);
|
||||
if (!offset1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memory_data = get_memory_data_reg(cc->jit_frame, 0);
|
||||
|
||||
GEN_INSN(STF64, value, memory_data, offset1);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_size(JitCompContext *cc, uint32 mem_idx)
|
||||
{
|
||||
JitReg mem_inst, res;
|
||||
|
||||
mem_inst = get_memory_inst_reg(cc->jit_frame, mem_idx);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(LDI32, res, mem_inst,
|
||||
NEW_CONST(I32, offsetof(WASMMemoryInstance, cur_page_count)));
|
||||
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_grow(JitCompContext *cc, uint32 mem_idx)
|
||||
{
|
||||
JitReg memory_inst, grow_res, res;
|
||||
JitReg prev_page_count, inc_page_count, args[2];
|
||||
|
||||
/* Get current page count */
|
||||
memory_inst = get_memory_inst_reg(cc->jit_frame, mem_idx);
|
||||
prev_page_count = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(LDI32, prev_page_count, memory_inst,
|
||||
NEW_CONST(I32, offsetof(WASMMemoryInstance, cur_page_count)));
|
||||
|
||||
/* Call wasm_enlarge_memory */
|
||||
POP_I32(inc_page_count);
|
||||
|
||||
grow_res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = inc_page_count;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_enlarge_memory, grow_res, args, 2)) {
|
||||
goto fail;
|
||||
}
|
||||
/* Convert bool to uint32 */
|
||||
GEN_INSN(AND, grow_res, grow_res, NEW_CONST(I32, 0xFF));
|
||||
|
||||
/* return different values according to memory.grow result */
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(CMP, cc->cmp_reg, grow_res, NEW_CONST(I32, 0));
|
||||
GEN_INSN(SELECTNE, res, cc->cmp_reg, prev_page_count,
|
||||
NEW_CONST(I32, (int32)-1));
|
||||
PUSH_I32(res);
|
||||
|
||||
/* Ensure a refresh in next get memory related registers */
|
||||
clear_memory_regs(cc->jit_frame);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
static int
|
||||
wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx,
|
||||
uint32 len, uint32 mem_offset, uint32 data_offset)
|
||||
{
|
||||
WASMMemoryInstance *mem_inst;
|
||||
WASMDataSeg *data_segment;
|
||||
uint32 mem_size;
|
||||
uint8 *mem_addr, *data_addr;
|
||||
|
||||
/* if d + n > the length of mem.data */
|
||||
mem_inst = inst->memories[mem_idx];
|
||||
mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page;
|
||||
if (mem_size < mem_offset || mem_size - mem_offset < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
/* if s + n > the length of data.data */
|
||||
bh_assert(seg_idx < inst->module->data_seg_count);
|
||||
data_segment = inst->module->data_segments[seg_idx];
|
||||
if (data_segment->data_length < data_offset
|
||||
|| data_segment->data_length - data_offset < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
mem_addr = mem_inst->memory_data + mem_offset;
|
||||
data_addr = data_segment->data + data_offset;
|
||||
bh_memcpy_s(mem_addr, mem_size - mem_offset, data_addr, len);
|
||||
|
||||
return 0;
|
||||
out_of_bounds:
|
||||
wasm_set_exception(inst, "out of bounds memory access");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_init(JitCompContext *cc, uint32 mem_idx, uint32 seg_idx)
|
||||
{
|
||||
JitReg len, mem_offset, data_offset, res;
|
||||
JitReg args[6] = { 0 };
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(data_offset);
|
||||
POP_I32(mem_offset);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = NEW_CONST(I32, mem_idx);
|
||||
args[2] = NEW_CONST(I32, seg_idx);
|
||||
args[3] = len;
|
||||
args[4] = mem_offset;
|
||||
args[5] = data_offset;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_init_memory, res, args,
|
||||
sizeof(args) / sizeof(args[0])))
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx)
|
||||
{
|
||||
JitReg module = get_module_reg(cc->jit_frame);
|
||||
JitReg data_segments = jit_cc_new_reg_ptr(cc);
|
||||
JitReg data_segment = jit_cc_new_reg_ptr(cc);
|
||||
|
||||
GEN_INSN(LDPTR, data_segments, module,
|
||||
NEW_CONST(I32, offsetof(WASMModule, data_segments)));
|
||||
GEN_INSN(LDPTR, data_segment, data_segments,
|
||||
NEW_CONST(I32, seg_idx * sizeof(WASMDataSeg *)));
|
||||
GEN_INSN(STI32, NEW_CONST(I32, 0), data_segment,
|
||||
NEW_CONST(I32, offsetof(WASMDataSeg, data_length)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
wasm_copy_memory(WASMModuleInstance *inst, uint32 src_mem_idx,
|
||||
uint32 dst_mem_idx, uint32 len, uint32 src_offset,
|
||||
uint32 dst_offset)
|
||||
{
|
||||
WASMMemoryInstance *src_mem, *dst_mem;
|
||||
uint32 src_mem_size, dst_mem_size;
|
||||
uint8 *src_addr, *dst_addr;
|
||||
|
||||
src_mem = inst->memories[src_mem_idx];
|
||||
dst_mem = inst->memories[dst_mem_idx];
|
||||
src_mem_size = src_mem->cur_page_count * src_mem->num_bytes_per_page;
|
||||
dst_mem_size = dst_mem->cur_page_count * dst_mem->num_bytes_per_page;
|
||||
|
||||
/* if s + n > the length of mem.data */
|
||||
if (src_mem_size < src_offset || src_mem_size - src_offset < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
/* if d + n > the length of mem.data */
|
||||
if (dst_mem_size < dst_offset || dst_mem_size - dst_offset < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
src_addr = src_mem->memory_data + src_offset;
|
||||
dst_addr = dst_mem->memory_data + dst_offset;
|
||||
/* allowing the destination and source to overlap */
|
||||
bh_memmove_s(dst_addr, dst_mem_size - dst_offset, src_addr, len);
|
||||
|
||||
return 0;
|
||||
out_of_bounds:
|
||||
wasm_set_exception(inst, "out of bounds memory access");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_copy(JitCompContext *cc, uint32 src_mem_idx,
|
||||
uint32 dst_mem_idx)
|
||||
{
|
||||
JitReg len, src, dst, res;
|
||||
JitReg args[6] = { 0 };
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(src);
|
||||
POP_I32(dst);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = NEW_CONST(I32, src_mem_idx);
|
||||
args[2] = NEW_CONST(I32, dst_mem_idx);
|
||||
args[3] = len;
|
||||
args[4] = src;
|
||||
args[5] = dst;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_copy_memory, res, args,
|
||||
sizeof(args) / sizeof(args[0])))
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
wasm_fill_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 len,
|
||||
uint32 val, uint32 dst)
|
||||
{
|
||||
WASMMemoryInstance *mem_inst;
|
||||
uint32 mem_size;
|
||||
uint8 *dst_addr;
|
||||
|
||||
mem_inst = inst->memories[mem_idx];
|
||||
mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page;
|
||||
|
||||
if (mem_size < dst || mem_size - dst < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
dst_addr = mem_inst->memory_data + dst;
|
||||
memset(dst_addr, val, len);
|
||||
|
||||
return 0;
|
||||
out_of_bounds:
|
||||
wasm_set_exception(inst, "out of bounds memory access");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_fill(JitCompContext *cc, uint32 mem_idx)
|
||||
{
|
||||
JitReg res, len, val, dst;
|
||||
JitReg args[5] = { 0 };
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(val);
|
||||
POP_I32(dst);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = NEW_CONST(I32, mem_idx);
|
||||
args[2] = len;
|
||||
args[3] = val;
|
||||
args[4] = dst;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_fill_memory, res, args,
|
||||
sizeof(args) / sizeof(args[0])))
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
bool
|
||||
jit_compile_op_atomic_rmw(JitCompContext *cc, uint8 atomic_op, uint8 op_type,
|
||||
uint32 align, uint32 offset, uint32 bytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_atomic_cmpxchg(JitCompContext *cc, uint8 op_type, uint32 align,
|
||||
uint32 offset, uint32 bytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align,
|
||||
uint32 offset, uint32 bytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
89
core/iwasm/fast-jit/fe/jit_emit_memory.h
Normal file
89
core/iwasm/fast-jit/fe/jit_emit_memory.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_MEMORY_H_
|
||||
#define _JIT_EMIT_MEMORY_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
#include "../../common/wasm_shared_memory.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool sign, bool atomic);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_load(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool sign, bool atomic);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_load(JitCompContext *cc, uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_load(JitCompContext *cc, uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_store(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool atomic);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_store(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes, bool atomic);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_store(JitCompContext *cc, uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_store(JitCompContext *cc, uint32 align, uint32 offset);
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_size(JitCompContext *cc, uint32 mem_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_grow(JitCompContext *cc, uint32 mem_idx);
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bool
|
||||
jit_compile_op_memory_init(JitCompContext *cc, uint32 mem_idx, uint32 seg_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_copy(JitCompContext *cc, uint32 src_mem_idx,
|
||||
uint32 dst_mem_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_memory_fill(JitCompContext *cc, uint32 mem_idx);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
bool
|
||||
jit_compile_op_atomic_rmw(JitCompContext *cc, uint8 atomic_op, uint8 op_type,
|
||||
uint32 align, uint32 offset, uint32 bytes);
|
||||
|
||||
bool
|
||||
jit_compile_op_atomic_cmpxchg(JitCompContext *cc, uint8 op_type, uint32 align,
|
||||
uint32 offset, uint32 bytes);
|
||||
|
||||
bool
|
||||
jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align,
|
||||
uint32 offset, uint32 bytes);
|
||||
|
||||
bool
|
||||
jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset,
|
||||
uint32 bytes);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_MEMORY_H_ */
|
||||
1651
core/iwasm/fast-jit/fe/jit_emit_numberic.c
Normal file
1651
core/iwasm/fast-jit/fe/jit_emit_numberic.c
Normal file
File diff suppressed because it is too large
Load Diff
76
core/iwasm/fast-jit/fe/jit_emit_numberic.h
Normal file
76
core/iwasm/fast-jit/fe/jit_emit_numberic.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_NUMBERIC_H_
|
||||
#define _JIT_EMIT_NUMBERIC_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
#include "../jit_frontend.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_clz(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_ctz(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_popcnt(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_clz(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_ctz(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_popcnt(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_arithmetic(JitCompContext *cc, IntArithmetic arith_op,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_arithmetic(JitCompContext *cc, IntArithmetic arith_op,
|
||||
uint8 **p_frame_ip);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_bitwise(JitCompContext *cc, IntBitwise bitwise_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_bitwise(JitCompContext *cc, IntBitwise bitwise_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_i32_shift(JitCompContext *cc, IntShift shift_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_i64_shift(JitCompContext *cc, IntShift shift_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_math(JitCompContext *cc, FloatMath math_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_math(JitCompContext *cc, FloatMath math_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_arithmetic(JitCompContext *cc, FloatArithmetic arith_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_arithmetic(JitCompContext *cc, FloatArithmetic arith_op);
|
||||
|
||||
bool
|
||||
jit_compile_op_f32_copysign(JitCompContext *cc);
|
||||
|
||||
bool
|
||||
jit_compile_op_f64_copysign(JitCompContext *cc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_NUMBERIC_H_ */
|
||||
130
core/iwasm/fast-jit/fe/jit_emit_parametric.c
Normal file
130
core/iwasm/fast-jit/fe/jit_emit_parametric.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_parametric.h"
|
||||
#include "../jit_frontend.h"
|
||||
|
||||
static bool
|
||||
pop_value_from_wasm_stack(JitCompContext *cc, bool is_32bit, JitReg *p_value,
|
||||
uint8 *p_type)
|
||||
{
|
||||
JitValue *jit_value;
|
||||
JitReg value;
|
||||
uint8 type;
|
||||
|
||||
if (!jit_block_stack_top(&cc->block_stack)) {
|
||||
jit_set_last_error(cc, "WASM block stack underflow.");
|
||||
return false;
|
||||
}
|
||||
if (!jit_block_stack_top(&cc->block_stack)->value_stack.value_list_end) {
|
||||
jit_set_last_error(cc, "WASM data stack underflow.");
|
||||
return false;
|
||||
}
|
||||
|
||||
jit_value = jit_value_stack_pop(
|
||||
&jit_block_stack_top(&cc->block_stack)->value_stack);
|
||||
type = jit_value->type;
|
||||
|
||||
if (p_type != NULL) {
|
||||
*p_type = jit_value->type;
|
||||
}
|
||||
|
||||
wasm_runtime_free(jit_value);
|
||||
|
||||
/* is_32: i32, f32, ref.func, ref.extern, v128 */
|
||||
if (is_32bit
|
||||
&& !(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
|| type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
|
||||
#endif
|
||||
|| type == VALUE_TYPE_V128)) {
|
||||
jit_set_last_error(cc, "invalid WASM stack data type.");
|
||||
return false;
|
||||
}
|
||||
/* !is_32: i64, f64 */
|
||||
if (!is_32bit && !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)) {
|
||||
jit_set_last_error(cc, "invalid WASM stack data type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case VALUE_TYPE_I32:
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
#endif
|
||||
value = pop_i32(cc->jit_frame);
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
value = pop_i64(cc->jit_frame);
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
value = pop_f32(cc->jit_frame);
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
value = pop_f64(cc->jit_frame);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_value != NULL) {
|
||||
*p_value = value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_drop(JitCompContext *cc, bool is_drop_32)
|
||||
{
|
||||
if (!pop_value_from_wasm_stack(cc, is_drop_32, NULL, NULL))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_select(JitCompContext *cc, bool is_select_32)
|
||||
{
|
||||
JitReg val1, val2, cond, selected;
|
||||
uint8 val1_type, val2_type;
|
||||
|
||||
POP_I32(cond);
|
||||
|
||||
if (!pop_value_from_wasm_stack(cc, is_select_32, &val2, &val2_type)
|
||||
|| !pop_value_from_wasm_stack(cc, is_select_32, &val1, &val1_type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (val1_type != val2_type) {
|
||||
jit_set_last_error(cc, "invalid stack values with different type");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (val1_type) {
|
||||
case VALUE_TYPE_I32:
|
||||
selected = jit_cc_new_reg_I32(cc);
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
selected = jit_cc_new_reg_I64(cc);
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
selected = jit_cc_new_reg_F32(cc);
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
selected = jit_cc_new_reg_F64(cc);
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, cond, NEW_CONST(I32, 0));
|
||||
GEN_INSN(SELECTNE, selected, cc->cmp_reg, val1, val2);
|
||||
PUSH(selected, val1_type);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
25
core/iwasm/fast-jit/fe/jit_emit_parametric.h
Normal file
25
core/iwasm/fast-jit/fe/jit_emit_parametric.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_PARAMETRIC_H_
|
||||
#define _JIT_EMIT_PARAMETRIC_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_drop(JitCompContext *cc, bool is_drop_32);
|
||||
|
||||
bool
|
||||
jit_compile_op_select(JitCompContext *cc, bool is_select_32);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_PARAMETRIC_H_ */
|
||||
318
core/iwasm/fast-jit/fe/jit_emit_table.c
Normal file
318
core/iwasm/fast-jit/fe/jit_emit_table.c
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "jit_emit_table.h"
|
||||
#include "jit_emit_exception.h"
|
||||
#include "jit_emit_function.h"
|
||||
#include "../../interpreter/wasm_runtime.h"
|
||||
#include "../jit_frontend.h"
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
bool
|
||||
jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx)
|
||||
{
|
||||
JitReg module, tbl_segs;
|
||||
|
||||
module = get_module_reg(cc->jit_frame);
|
||||
|
||||
tbl_segs = jit_cc_new_reg_ptr(cc);
|
||||
GEN_INSN(LDPTR, tbl_segs, module,
|
||||
NEW_CONST(I32, offsetof(WASMModule, table_segments)));
|
||||
|
||||
GEN_INSN(STI32, NEW_CONST(I32, true), tbl_segs,
|
||||
NEW_CONST(I32, tbl_seg_idx * sizeof(WASMTableSeg)
|
||||
+ offsetof(WASMTableSeg, is_dropped)));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_table_get(JitCompContext *cc, uint32 tbl_idx)
|
||||
{
|
||||
JitReg elem_idx, tbl_sz, tbl_data, elem_idx_long, offset, res;
|
||||
|
||||
POP_I32(elem_idx);
|
||||
|
||||
/* if (elem_idx >= tbl_sz) goto exception; */
|
||||
tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx);
|
||||
GEN_INSN(CMP, cc->cmp_reg, elem_idx, tbl_sz);
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
|
||||
JIT_OP_BGEU, cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
elem_idx_long = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(I32TOI64, elem_idx_long, elem_idx);
|
||||
|
||||
offset = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(uint32)));
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
tbl_data = get_table_data_reg(cc->jit_frame, tbl_idx);
|
||||
GEN_INSN(LDI32, res, tbl_data, offset);
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_table_set(JitCompContext *cc, uint32 tbl_idx)
|
||||
{
|
||||
JitReg elem_idx, elem_val, tbl_sz, tbl_data, elem_idx_long, offset;
|
||||
|
||||
POP_I32(elem_val);
|
||||
POP_I32(elem_idx);
|
||||
|
||||
/* if (elem_idx >= tbl_sz) goto exception; */
|
||||
tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx);
|
||||
GEN_INSN(CMP, cc->cmp_reg, elem_idx, tbl_sz);
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
|
||||
JIT_OP_BGEU, cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
elem_idx_long = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(I32TOI64, elem_idx_long, elem_idx);
|
||||
|
||||
offset = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(uint32)));
|
||||
|
||||
tbl_data = get_table_data_reg(cc->jit_frame, tbl_idx);
|
||||
GEN_INSN(STI32, elem_val, tbl_data, offset);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx,
|
||||
uint32 dst, uint32 len, uint32 src)
|
||||
{
|
||||
WASMTableInstance *tbl;
|
||||
uint32 tbl_sz;
|
||||
WASMTableSeg *elem;
|
||||
uint32 elem_len;
|
||||
|
||||
tbl = inst->tables[tbl_idx];
|
||||
tbl_sz = tbl->cur_size;
|
||||
if (dst > tbl_sz || tbl_sz - dst < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
elem = inst->module->table_segments + elem_idx;
|
||||
elem_len = elem->function_count;
|
||||
if (src > elem_len || elem_len - src < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
bh_memcpy_s((uint8 *)(tbl) + offsetof(WASMTableInstance, base_addr)
|
||||
+ dst * sizeof(uint32),
|
||||
(uint32)((tbl_sz - dst) * sizeof(uint32)),
|
||||
elem->func_indexes + src, (uint32)(len * sizeof(uint32)));
|
||||
|
||||
return 0;
|
||||
out_of_bounds:
|
||||
wasm_set_exception(inst, "out of bounds table access");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_table_init(JitCompContext *cc, uint32 tbl_idx,
|
||||
uint32 tbl_seg_idx)
|
||||
{
|
||||
JitReg len, src, dst, res;
|
||||
JitReg args[6] = { 0 };
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(src);
|
||||
POP_I32(dst);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = NEW_CONST(I32, tbl_idx);
|
||||
args[2] = NEW_CONST(I32, tbl_seg_idx);
|
||||
args[3] = dst;
|
||||
args[4] = len;
|
||||
args[5] = src;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_init_table, res, args,
|
||||
sizeof(args) / sizeof(args[0])))
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
wasm_copy_table(WASMModuleInstance *inst, uint32 src_tbl_idx,
|
||||
uint32 dst_tbl_idx, uint32 dst_offset, uint32 len,
|
||||
uint32 src_offset)
|
||||
{
|
||||
WASMTableInstance *src_tbl, *dst_tbl;
|
||||
uint32 src_tbl_sz, dst_tbl_sz;
|
||||
|
||||
src_tbl = inst->tables[src_tbl_idx];
|
||||
src_tbl_sz = src_tbl->cur_size;
|
||||
if (src_offset > src_tbl_sz || src_tbl_sz - src_offset < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
dst_tbl = inst->tables[dst_tbl_idx];
|
||||
dst_tbl_sz = dst_tbl->cur_size;
|
||||
if (dst_offset > dst_tbl_sz || dst_tbl_sz - dst_offset < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
bh_memmove_s((uint8 *)(dst_tbl) + offsetof(WASMTableInstance, base_addr)
|
||||
+ dst_offset * sizeof(uint32),
|
||||
(uint32)((dst_tbl_sz - dst_offset) * sizeof(uint32)),
|
||||
(uint8 *)(src_tbl) + offsetof(WASMTableInstance, base_addr)
|
||||
+ src_offset * sizeof(uint32),
|
||||
(uint32)(len * sizeof(uint32)));
|
||||
|
||||
return 0;
|
||||
out_of_bounds:
|
||||
wasm_set_exception(inst, "out of bounds table access");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_table_copy(JitCompContext *cc, uint32 src_tbl_idx,
|
||||
uint32 dst_tbl_idx)
|
||||
{
|
||||
JitReg len, src, dst, res;
|
||||
JitReg args[6] = { 0 };
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(src);
|
||||
POP_I32(dst);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = NEW_CONST(I32, src_tbl_idx);
|
||||
args[2] = NEW_CONST(I32, dst_tbl_idx);
|
||||
args[3] = dst;
|
||||
args[4] = len;
|
||||
args[5] = src;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_copy_table, res, args,
|
||||
sizeof(args) / sizeof(args[0])))
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_table_size(JitCompContext *cc, uint32 tbl_idx)
|
||||
{
|
||||
JitReg res;
|
||||
|
||||
res = get_table_cur_size_reg(cc->jit_frame, tbl_idx);
|
||||
PUSH_I32(res);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_table_grow(JitCompContext *cc, uint32 tbl_idx)
|
||||
{
|
||||
JitReg tbl_sz, n, val, enlarge_ret, res;
|
||||
JitReg args[4] = { 0 };
|
||||
|
||||
POP_I32(n);
|
||||
POP_I32(val);
|
||||
|
||||
tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx);
|
||||
|
||||
enlarge_ret = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = NEW_CONST(I32, tbl_idx);
|
||||
args[2] = n;
|
||||
args[3] = val;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_enlarge_table, enlarge_ret, args,
|
||||
sizeof(args) / sizeof(args[0])))
|
||||
goto fail;
|
||||
|
||||
/* Convert bool to uint32 */
|
||||
GEN_INSN(AND, enlarge_ret, enlarge_ret, NEW_CONST(I32, 0xFF));
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(CMP, cc->cmp_reg, enlarge_ret, NEW_CONST(I32, 1));
|
||||
GEN_INSN(SELECTEQ, res, cc->cmp_reg, tbl_sz, NEW_CONST(I32, -1));
|
||||
PUSH_I32(res);
|
||||
|
||||
/* Ensure a refresh in next get memory related registers */
|
||||
clear_table_regs(cc->jit_frame);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst,
|
||||
uint32 val, uint32 len)
|
||||
{
|
||||
WASMTableInstance *tbl;
|
||||
uint32 tbl_sz;
|
||||
|
||||
tbl = inst->tables[tbl_idx];
|
||||
tbl_sz = tbl->cur_size;
|
||||
|
||||
if (dst > tbl_sz || tbl_sz - dst < len)
|
||||
goto out_of_bounds;
|
||||
|
||||
for (; len != 0; dst++, len--) {
|
||||
((uint32 *)(tbl->base_addr))[dst] = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_of_bounds:
|
||||
wasm_set_exception(inst, "out of bounds table access");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_table_fill(JitCompContext *cc, uint32 tbl_idx)
|
||||
{
|
||||
JitReg len, val, dst, res;
|
||||
JitReg args[5] = { 0 };
|
||||
|
||||
POP_I32(len);
|
||||
POP_I32(val);
|
||||
POP_I32(dst);
|
||||
|
||||
res = jit_cc_new_reg_I32(cc);
|
||||
args[0] = get_module_inst_reg(cc->jit_frame);
|
||||
args[1] = NEW_CONST(I32, tbl_idx);
|
||||
args[2] = dst;
|
||||
args[3] = val;
|
||||
args[4] = len;
|
||||
|
||||
if (!jit_emit_callnative(cc, wasm_fill_table, res, args,
|
||||
sizeof(args) / sizeof(args[0])))
|
||||
goto fail;
|
||||
|
||||
GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS,
|
||||
cc->cmp_reg, NULL))
|
||||
goto fail;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
47
core/iwasm/fast-jit/fe/jit_emit_table.h
Normal file
47
core/iwasm/fast-jit/fe/jit_emit_table.h
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_TABLE_H_
|
||||
#define _JIT_EMIT_TABLE_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
bool
|
||||
jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_table_get(JitCompContext *cc, uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_table_set(JitCompContext *cc, uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_table_init(JitCompContext *cc, uint32 tbl_idx,
|
||||
uint32 tbl_seg_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_table_copy(JitCompContext *cc, uint32 src_tbl_idx,
|
||||
uint32 dst_tbl_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_table_size(JitCompContext *cc, uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_table_grow(JitCompContext *cc, uint32 tbl_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_table_fill(JitCompContext *cc, uint32 tbl_idx);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
#endif
|
||||
323
core/iwasm/fast-jit/fe/jit_emit_variable.c
Normal file
323
core/iwasm/fast-jit/fe/jit_emit_variable.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
else {
|
||||
const WASMGlobal *global =
|
||||
module->globals + (global_idx - module->import_global_count);
|
||||
return global->type;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32
|
||||
get_global_data_offset(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->data_offset;
|
||||
}
|
||||
else {
|
||||
const WASMGlobal *global =
|
||||
module->globals + (global_idx - module->import_global_count);
|
||||
return global->data_offset;
|
||||
}
|
||||
}
|
||||
|
||||
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 = 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_global_data_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_global_data_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_global_data_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_global_data_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 = 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, JIT_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, JIT_EXCE_AUX_STACK_UNDERFLOW,
|
||||
JIT_OP_BGTU, cc->cmp_reg, NULL)))
|
||||
goto fail;
|
||||
}
|
||||
GEN_INSN(STI32, value, get_global_data_reg(cc->jit_frame),
|
||||
NEW_CONST(I32, data_offset));
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_I64:
|
||||
{
|
||||
POP_I64(value);
|
||||
GEN_INSN(STI64, value, get_global_data_reg(cc->jit_frame),
|
||||
NEW_CONST(I32, data_offset));
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_F32:
|
||||
{
|
||||
POP_F32(value);
|
||||
GEN_INSN(STF32, value, get_global_data_reg(cc->jit_frame),
|
||||
NEW_CONST(I32, data_offset));
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_F64:
|
||||
{
|
||||
POP_F64(value);
|
||||
GEN_INSN(STF64, value, get_global_data_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;
|
||||
}
|
||||
35
core/iwasm/fast-jit/fe/jit_emit_variable.h
Normal file
35
core/iwasm/fast-jit/fe/jit_emit_variable.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _JIT_EMIT_VARIABLE_H_
|
||||
#define _JIT_EMIT_VARIABLE_H_
|
||||
|
||||
#include "../jit_compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool
|
||||
jit_compile_op_get_local(JitCompContext *cc, uint32 local_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_set_local(JitCompContext *cc, uint32 local_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_tee_local(JitCompContext *cc, uint32 local_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_get_global(JitCompContext *cc, uint32 global_idx);
|
||||
|
||||
bool
|
||||
jit_compile_op_set_global(JitCompContext *cc, uint32 global_idx,
|
||||
bool is_aux_stack);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* end of _JIT_EMIT_VARIABLE_H_ */
|
||||
Reference in New Issue
Block a user