Refactor opcode inn.trunc_fmm_sx and inn.trunc_fmm_sx_sat (#1215)

This commit is contained in:
liang.he 2022-06-09 20:33:37 +08:00 committed by GitHub
parent 50982dd145
commit 25b48bce35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 303 additions and 117 deletions

View File

@ -9,16 +9,148 @@
#include "../jit_codegen.h"
#include "../jit_frontend.h"
static double
uint64_to_double(uint64 u64)
#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)
#define RETURN_IF_NANF(fp) \
if (isnanf(fp)) { \
return 0; \
}
#define RETURN_IF_NAN(fp) \
if (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 (double)u64;
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;
}
static float
uint64_to_float(uint64 u64)
FP_TO_INT_SAT(float, uint32, f32, u32)
{
return (float)u64;
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
@ -30,6 +162,7 @@ jit_compile_op_i32_wrap_i64(JitCompContext *cc)
res = jit_cc_new_reg_I32(cc);
GEN_INSN(I64TOI32, res, num);
PUSH_I32(res);
return true;
@ -37,57 +170,71 @@ fail:
return false;
}
bool
jit_compile_op_i32_trunc_f32(JitCompContext *cc, bool sign, bool saturating)
static bool
jit_compile_check_value_range(JitCompContext *cc, JitReg value, JitReg min_fp,
JitReg max_fp)
{
JitReg value, nan_ret, max_valid_float, min_valid_float, res;
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, isnanf, nan_ret, &value, 1);
else
emit_ret = jit_emit_callnative(cc, 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, 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, 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, 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);
min_valid_float =
sign ? NEW_CONST(F32, -2147483904.0f) : NEW_CONST(F32, -1.0f);
max_valid_float =
sign ? NEW_CONST(F32, 2147483648.0f) : NEW_CONST(F32, 4294967296.0f);
if (!saturating) {
/* If value is NaN, throw exception */
nan_ret = jit_cc_new_reg_I32(cc);
if (!jit_emit_callnative(cc, isnanf, nan_ret, &value, 1)) {
goto fail;
}
GEN_INSN(CMP, cc->cmp_reg, nan_ret, NEW_CONST(I32, 1));
if (!jit_emit_exception(cc, 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_valid_float, value);
if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BGES,
cc->cmp_reg, NULL)) {
goto fail;
}
GEN_INSN(CMP, cc->cmp_reg, value, max_valid_float);
if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BGES,
cc->cmp_reg, NULL)) {
goto fail;
}
}
if (saturating) {
JitReg tmp = jit_cc_new_reg_F32(cc);
GEN_INSN(MAX, tmp, value, min_valid_float);
GEN_INSN(MIN, value, tmp, max_valid_float);
}
res = jit_cc_new_reg_I32(cc);
if (sign) {
GEN_INSN(F32TOI32, res, value);
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 {
GEN_INSN(F32TOU32, res, value);
if (!jit_emit_callnative(cc,
sign ? (void *)i32_trunc_f32_sat
: (void *)u32_trunc_f32_sat,
res, &value, 1))
goto fail;
}
PUSH_I32(res);
@ -98,56 +245,31 @@ fail:
}
bool
jit_compile_op_i32_trunc_f64(JitCompContext *cc, bool sign, bool saturating)
jit_compile_op_i32_trunc_f64(JitCompContext *cc, bool sign, bool sat)
{
JitReg value, nan_ret, max_valid_double, min_valid_double, res;
JitReg value, res;
POP_F64(value);
min_valid_double =
sign ? NEW_CONST(F64, -2147483649.0) : NEW_CONST(F64, -1.0);
max_valid_double =
sign ? NEW_CONST(F64, 2147483648.0) : NEW_CONST(F64, 4294967296.0);
if (!saturating) {
/* If value is NaN, throw exception */
nan_ret = jit_cc_new_reg_I32(cc);
if (!jit_emit_callnative(cc, isnan, nan_ret, &value, 1)) {
goto fail;
}
GEN_INSN(CMP, cc->cmp_reg, nan_ret, NEW_CONST(I32, 1));
if (!jit_emit_exception(cc, 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_valid_double, value);
if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BGES,
cc->cmp_reg, NULL)) {
goto fail;
}
GEN_INSN(CMP, cc->cmp_reg, value, max_valid_double);
if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BGES,
cc->cmp_reg, NULL)) {
goto fail;
}
}
if (saturating) {
JitReg tmp = jit_cc_new_reg_F64(cc);
GEN_INSN(MAX, tmp, value, min_valid_double);
GEN_INSN(MIN, value, tmp, max_valid_double);
}
res = jit_cc_new_reg_I32(cc);
if (sign) {
GEN_INSN(F64TOI32, res, value);
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 {
GEN_INSN(F64TOU32, res, value);
if (!jit_emit_callnative(cc,
sign ? (void *)i32_trunc_f64_sat
: (void *)u32_trunc_f64_sat,
res, &value, 1))
goto fail;
}
PUSH_I32(res);
@ -165,12 +287,11 @@ jit_compile_op_i64_extend_i32(JitCompContext *cc, bool sign)
POP_I32(num);
res = jit_cc_new_reg_I64(cc);
if (sign) {
if (sign)
GEN_INSN(I32TOI64, res, num);
}
else {
else
GEN_INSN(U32TOI64, res, num);
}
PUSH_I64(res);
return true;
@ -259,18 +380,78 @@ fail:
}
bool
jit_compile_op_i64_trunc_f32(JitCompContext *cc, bool sign, bool saturating)
jit_compile_op_i64_trunc_f32(JitCompContext *cc, bool sign, bool sat)
{
/* TODO: f32 -> u64 algorithm */
bh_assert(0);
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 saturating)
jit_compile_op_i64_trunc_f64(JitCompContext *cc, bool sign, bool sat)
{
/* TODO: f64 -> u64 algorithm */
bh_assert(0);
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;
}
@ -288,6 +469,7 @@ jit_compile_op_f32_convert_i32(JitCompContext *cc, bool sign)
else {
GEN_INSN(U32TOF32, res, value);
}
PUSH_F32(res);
return true;
@ -302,13 +484,12 @@ jit_compile_op_f32_convert_i64(JitCompContext *cc, bool sign)
POP_I64(value);
res = jit_cc_new_reg_F32(cc);
if (sign) {
res = jit_cc_new_reg_F32(cc);
GEN_INSN(I64TOF32, res, value);
}
else {
res = jit_cc_new_reg_F32(cc);
if (!jit_emit_callnative(cc, uint64_to_float, res, &value, 1)) {
if (!jit_emit_callnative(cc, f32_convert_u64, res, &value, 1)) {
goto fail;
}
}
@ -329,6 +510,7 @@ jit_compile_op_f32_demote_f64(JitCompContext *cc)
res = jit_cc_new_reg_F32(cc);
GEN_INSN(F64TOF32, res, value);
PUSH_F32(res);
return true;
@ -344,12 +526,11 @@ jit_compile_op_f64_convert_i32(JitCompContext *cc, bool sign)
POP_I32(value);
res = jit_cc_new_reg_F64(cc);
if (sign) {
if (sign)
GEN_INSN(I32TOF64, res, value);
}
else {
else
GEN_INSN(U32TOF64, res, value);
}
PUSH_F64(res);
return true;
@ -364,16 +545,16 @@ jit_compile_op_f64_convert_i64(JitCompContext *cc, bool sign)
POP_I64(value);
res = jit_cc_new_reg_F64(cc);
if (sign) {
res = jit_cc_new_reg_F64(cc);
GEN_INSN(I64TOF64, res, value);
}
else {
res = jit_cc_new_reg_F64(cc);
if (!jit_emit_callnative(cc, uint64_to_double, res, &value, 1)) {
if (!jit_emit_callnative(cc, f64_convert_u64, res, &value, 1)) {
goto fail;
}
}
PUSH_F64(res);
return true;
@ -390,6 +571,7 @@ jit_compile_op_f64_promote_f32(JitCompContext *cc)
res = jit_cc_new_reg_F64(cc);
GEN_INSN(F32TOF64, res, value);
PUSH_F64(res);
return true;
@ -406,6 +588,7 @@ jit_compile_op_i64_reinterpret_f64(JitCompContext *cc)
res = jit_cc_new_reg_I64(cc);
GEN_INSN(F64CASTI64, res, value);
PUSH_I64(res);
return true;
@ -422,6 +605,7 @@ jit_compile_op_i32_reinterpret_f32(JitCompContext *cc)
res = jit_cc_new_reg_I32(cc);
GEN_INSN(F32CASTI32, res, value);
PUSH_I32(res);
return true;
@ -438,6 +622,7 @@ jit_compile_op_f64_reinterpret_i64(JitCompContext *cc)
res = jit_cc_new_reg_F64(cc);
GEN_INSN(I64CASTF64, res, value);
PUSH_F64(res);
return true;
@ -454,6 +639,7 @@ jit_compile_op_f32_reinterpret_i32(JitCompContext *cc)
res = jit_cc_new_reg_F32(cc);
GEN_INSN(I32CASTF32, res, value);
PUSH_F32(res);
return true;

View File

@ -16,10 +16,10 @@ bool
jit_compile_op_i32_wrap_i64(JitCompContext *cc);
bool
jit_compile_op_i32_trunc_f32(JitCompContext *cc, bool sign, bool saturating);
jit_compile_op_i32_trunc_f32(JitCompContext *cc, bool sign, bool sat);
bool
jit_compile_op_i32_trunc_f64(JitCompContext *cc, bool sign, bool saturating);
jit_compile_op_i32_trunc_f64(JitCompContext *cc, bool sign, bool sat);
bool
jit_compile_op_i64_extend_i32(JitCompContext *comp_ctx, bool sign);
@ -31,10 +31,10 @@ bool
jit_compile_op_i32_extend_i32(JitCompContext *comp_ctx, int8 bitwidth);
bool
jit_compile_op_i64_trunc_f32(JitCompContext *cc, bool sign, bool saturating);
jit_compile_op_i64_trunc_f32(JitCompContext *cc, bool sign, bool sat);
bool
jit_compile_op_i64_trunc_f64(JitCompContext *cc, bool sign, bool saturating);
jit_compile_op_i64_trunc_f64(JitCompContext *cc, bool sign, bool sat);
bool
jit_compile_op_f32_convert_i32(JitCompContext *comp_ctx, bool sign);