From 25b48bce35ea84ca7b594b34bfbb8e30864bdf15 Mon Sep 17 00:00:00 2001 From: "liang.he" Date: Thu, 9 Jun 2022 20:33:37 +0800 Subject: [PATCH] Refactor opcode inn.trunc_fmm_sx and inn.trunc_fmm_sx_sat (#1215) --- core/iwasm/fast-jit/fe/jit_emit_conversion.c | 412 ++++++++++++++----- core/iwasm/fast-jit/fe/jit_emit_conversion.h | 8 +- 2 files changed, 303 insertions(+), 117 deletions(-) diff --git a/core/iwasm/fast-jit/fe/jit_emit_conversion.c b/core/iwasm/fast-jit/fe/jit_emit_conversion.c index 674e6050f..52488ea37 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_conversion.c +++ b/core/iwasm/fast-jit/fe/jit_emit_conversion.c @@ -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; diff --git a/core/iwasm/fast-jit/fe/jit_emit_conversion.h b/core/iwasm/fast-jit/fe/jit_emit_conversion.h index b90aa7064..28952fc61 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_conversion.h +++ b/core/iwasm/fast-jit/fe/jit_emit_conversion.h @@ -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);