tcg: Add floating point support

* Accelerate x87 emulation using new TCG FP ops
* Implement FP support on x86-64 target using SSE2
This commit is contained in:
Matt Borgerson
2021-09-29 17:20:41 -07:00
committed by mborgerson
parent 631c818c1e
commit 55ea6adf5d
11 changed files with 1570 additions and 125 deletions

View File

@ -346,6 +346,221 @@ static inline void tcg_gen_discard_i32(TCGv_i32 arg)
tcg_gen_op1_i32(INDEX_op_discard, arg);
}
static inline void tcg_gen_flcr(TCGv_i32 arg)
{
tcg_gen_op1_i32(INDEX_op_flcr, arg);
}
static inline void tcg_gen_st80f_f32(TCGv_f32 arg, TCGv_ptr dst)
{
tcg_gen_op2(INDEX_op_st80f_f32, tcgv_f32_arg(arg), tcgv_ptr_arg(dst));
}
static inline void tcg_gen_st80f_f64(TCGv_f64 arg, TCGv_ptr dst)
{
tcg_gen_op2(INDEX_op_st80f_f64, tcgv_f64_arg(arg), tcgv_ptr_arg(dst));
}
static inline void tcg_gen_ld80f_f32(TCGv_f32 ret, TCGv_ptr src)
{
tcg_gen_op2(INDEX_op_ld80f_f32, tcgv_f32_arg(ret), tcgv_ptr_arg(src));
}
static inline void tcg_gen_ld80f_f64(TCGv_f64 ret, TCGv_ptr src)
{
tcg_gen_op2(INDEX_op_ld80f_f64, tcgv_f64_arg(ret), tcgv_ptr_arg(src));
}
static inline void tcg_gen_abs_f32(TCGv_f32 ret, TCGv_f32 src)
{
tcg_gen_op2(INDEX_op_abs_f32, tcgv_f32_arg(ret), tcgv_f32_arg(src));
}
static inline void tcg_gen_abs_f64(TCGv_f64 ret, TCGv_f64 src)
{
tcg_gen_op2(INDEX_op_abs_f64, tcgv_f64_arg(ret), tcgv_f64_arg(src));
}
static inline void tcg_gen_add_f32(TCGv_f32 ret, TCGv_f32 arg1, TCGv_f32 arg2)
{
tcg_gen_op3(INDEX_op_add_f32,
tcgv_f32_arg(ret), tcgv_f32_arg(arg1), tcgv_f32_arg(arg2));
}
static inline void tcg_gen_add_f64(TCGv_f64 ret, TCGv_f64 arg1, TCGv_f64 arg2)
{
tcg_gen_op3(INDEX_op_add_f64,
tcgv_f64_arg(ret), tcgv_f64_arg(arg1), tcgv_f64_arg(arg2));
}
static inline void tcg_gen_chs_f32(TCGv_f32 ret, TCGv_f32 src)
{
tcg_gen_op2(INDEX_op_chs_f32, tcgv_f32_arg(ret), tcgv_f32_arg(src));
}
static inline void tcg_gen_chs_f64(TCGv_f64 ret, TCGv_f64 src)
{
tcg_gen_op2(INDEX_op_chs_f64, tcgv_f64_arg(ret), tcgv_f64_arg(src));
}
static inline void tcg_gen_com_f32(TCGv_i64 ret, TCGv_f32 arg1, TCGv_f32 arg2)
{
tcg_gen_op3(INDEX_op_com_f32,
tcgv_i64_arg(ret), tcgv_f32_arg(arg1), tcgv_f32_arg(arg2));
}
static inline void tcg_gen_com_f64(TCGv_i64 ret, TCGv_f64 arg1, TCGv_f64 arg2)
{
tcg_gen_op3(INDEX_op_com_f64,
tcgv_i64_arg(ret), tcgv_f64_arg(arg1), tcgv_f64_arg(arg2));
}
static inline void tcg_gen_cos_f32(TCGv_f32 ret, TCGv_f32 arg)
{
tcg_gen_op2(INDEX_op_cos_f32, tcgv_f32_arg(ret), tcgv_f32_arg(arg));
}
static inline void tcg_gen_cos_f64(TCGv_f64 ret, TCGv_f64 arg)
{
tcg_gen_op2(INDEX_op_cos_f64, tcgv_f64_arg(ret), tcgv_f64_arg(arg));
}
static inline void tcg_gen_cvt32f_f64(TCGv_f64 ret, TCGv_f32 arg)
{
tcg_gen_op2(INDEX_op_cvt32f_f64, tcgv_f64_arg(ret), tcgv_f32_arg(arg));
}
static inline void tcg_gen_cvt32f_i32(TCGv_i32 ret, TCGv_f32 arg)
{
tcg_gen_op2(INDEX_op_cvt32f_i32, tcgv_i32_arg(ret), tcgv_f32_arg(arg));
}
static inline void tcg_gen_cvt32f_i64(TCGv_i64 ret, TCGv_f32 arg)
{
tcg_gen_op2(INDEX_op_cvt32f_i64, tcgv_i64_arg(ret), tcgv_f32_arg(arg));
}
static inline void tcg_gen_cvt32i_f32(TCGv_f32 ret, TCGv_i32 arg)
{
tcg_gen_op2(INDEX_op_cvt32i_f32, tcgv_f32_arg(ret), tcgv_i32_arg(arg));
}
static inline void tcg_gen_cvt32i_f64(TCGv_f64 ret, TCGv_i32 arg)
{
tcg_gen_op2(INDEX_op_cvt32i_f64, tcgv_f64_arg(ret), tcgv_i32_arg(arg));
}
static inline void tcg_gen_cvt64f_f32(TCGv_f32 ret, TCGv_f64 arg)
{
tcg_gen_op2(INDEX_op_cvt64f_f32, tcgv_f32_arg(ret), tcgv_f64_arg(arg));
}
static inline void tcg_gen_cvt64f_i32(TCGv_i32 ret, TCGv_f64 src)
{
tcg_gen_op2(INDEX_op_cvt64f_i32, tcgv_i32_arg(ret), tcgv_f64_arg(src));
}
static inline void tcg_gen_cvt64f_i64(TCGv_i64 ret, TCGv_f64 src)
{
tcg_gen_op2(INDEX_op_cvt64f_i64, tcgv_i64_arg(ret), tcgv_f64_arg(src));
}
static inline void tcg_gen_cvt64i_f32(TCGv_f32 ret, TCGv_i64 arg)
{
tcg_gen_op2(INDEX_op_cvt64i_f32, tcgv_f32_arg(ret), tcgv_i64_arg(arg));
}
static inline void tcg_gen_cvt64i_f64(TCGv_f64 ret, TCGv_i64 arg)
{
tcg_gen_op2(INDEX_op_cvt64i_f64, tcgv_f64_arg(ret), tcgv_i64_arg(arg));
}
static inline void tcg_gen_div_f32(TCGv_f32 ret, TCGv_f32 arg1, TCGv_f32 arg2)
{
tcg_gen_op3(INDEX_op_div_f32,
tcgv_f32_arg(ret), tcgv_f32_arg(arg1), tcgv_f32_arg(arg2));
}
static inline void tcg_gen_div_f64(TCGv_f64 ret, TCGv_f64 arg1, TCGv_f64 arg2)
{
tcg_gen_op3(INDEX_op_div_f64,
tcgv_f64_arg(ret), tcgv_f64_arg(arg1), tcgv_f64_arg(arg2));
}
static inline void tcg_gen_mov32f_i32(TCGv_i32 ret, TCGv_f32 src)
{
tcg_gen_op2(INDEX_op_mov32f_i32, tcgv_i32_arg(ret), tcgv_f32_arg(src));
}
static inline void tcg_gen_mov32i_f32(TCGv_f32 ret, TCGv_i32 arg)
{
tcg_gen_op2(INDEX_op_mov32i_f32, tcgv_f32_arg(ret), tcgv_i32_arg(arg));
}
static inline void tcg_gen_mov64f_i64(TCGv_i64 ret, TCGv_f64 src)
{
tcg_gen_op2(INDEX_op_mov64f_i64, tcgv_i64_arg(ret), tcgv_f64_arg(src));
}
static inline void tcg_gen_mov64i_f64(TCGv_f64 ret, TCGv_i64 arg)
{
tcg_gen_op2(INDEX_op_mov64i_f64, tcgv_f64_arg(ret), tcgv_i64_arg(arg));
}
static inline void tcg_gen_mov_f32(TCGv_f32 ret, TCGv_f32 src)
{
tcg_gen_op2(INDEX_op_mov_f32, tcgv_f32_arg(ret), tcgv_f32_arg(src));
}
static inline void tcg_gen_mov_f64(TCGv_f64 ret, TCGv_f64 src)
{
tcg_gen_op2(INDEX_op_mov_f64, tcgv_f64_arg(ret), tcgv_f64_arg(src));
}
static inline void tcg_gen_mul_f32(TCGv_f32 ret, TCGv_f32 arg1, TCGv_f32 arg2)
{
tcg_gen_op3(INDEX_op_mul_f32,
tcgv_f32_arg(ret), tcgv_f32_arg(arg1), tcgv_f32_arg(arg2));
}
static inline void tcg_gen_mul_f64(TCGv_f64 ret, TCGv_f64 arg1, TCGv_f64 arg2)
{
tcg_gen_op3(INDEX_op_mul_f64,
tcgv_f64_arg(ret), tcgv_f64_arg(arg1), tcgv_f64_arg(arg2));
}
static inline void tcg_gen_sin_f32(TCGv_f32 ret, TCGv_f32 arg)
{
tcg_gen_op2(INDEX_op_sin_f32, tcgv_f32_arg(ret), tcgv_f32_arg(arg));
}
static inline void tcg_gen_sin_f64(TCGv_f64 ret, TCGv_f64 arg)
{
tcg_gen_op2(INDEX_op_sin_f64, tcgv_f64_arg(ret), tcgv_f64_arg(arg));
}
static inline void tcg_gen_sqrt_f32(TCGv_f32 ret, TCGv_f32 arg)
{
tcg_gen_op2(INDEX_op_sqrt_f32, tcgv_f32_arg(ret), tcgv_f32_arg(arg));
}
static inline void tcg_gen_sqrt_f64(TCGv_f64 ret, TCGv_f64 arg)
{
tcg_gen_op2(INDEX_op_sqrt_f64, tcgv_f64_arg(ret), tcgv_f64_arg(arg));
}
static inline void tcg_gen_sub_f32(TCGv_f32 ret, TCGv_f32 arg1, TCGv_f32 arg2)
{
tcg_gen_op3(INDEX_op_sub_f32,
tcgv_f32_arg(ret), tcgv_f32_arg(arg1), tcgv_f32_arg(arg2));
}
static inline void tcg_gen_sub_f64(TCGv_f64 ret, TCGv_f64 arg1, TCGv_f64 arg2)
{
tcg_gen_op3(INDEX_op_sub_f64,
tcgv_f64_arg(ret), tcgv_f64_arg(arg1), tcgv_f64_arg(arg2));
}
static inline void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg)
{
if (ret != arg) {

View File

@ -213,6 +213,49 @@ DEF(qemu_st8_i32, 0, TLADDR_ARGS + 1, 1,
TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS |
IMPL(TCG_TARGET_HAS_qemu_st8_i32))
/* Host floating point support. */
DEF(flcr, 0, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(ld80f_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(ld80f_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(st80f_f32, 0, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(st80f_f64, 0, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(abs_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(abs_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(add_f32, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(add_f64, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(chs_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(chs_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(com_f32, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(com_f64, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cos_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cos_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt32f_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt32f_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt32f_i64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt32i_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt32i_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt64f_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt64f_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt64f_i64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt64i_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(cvt64i_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(div_f32, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(div_f64, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mov32f_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mov32i_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mov64f_i64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mov64i_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mov_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mov_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mul_f32, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(mul_f64, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(sin_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(sin_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(sqrt_f32, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(sqrt_f64, 1, 1, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(sub_f32, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
DEF(sub_f64, 1, 2, 0, IMPL(TCG_TARGET_HAS_fpu))
/* Host vector support. */
#define IMPLVEC TCG_OPF_VECTOR | IMPL(TCG_TARGET_MAYBE_vec)

View File

@ -207,6 +207,10 @@ typedef uint64_t TCGRegSet;
#define TCG_TARGET_HAS_v256 0
#endif
#ifndef TCG_TARGET_HAS_fpu
#define TCG_TARGET_HAS_fpu 0
#endif
#ifndef TARGET_INSN_START_EXTRA_WORDS
# define TARGET_INSN_START_WORDS 1
#else
@ -287,6 +291,9 @@ typedef enum TCGType {
TCG_TYPE_I32,
TCG_TYPE_I64,
TCG_TYPE_F32,
TCG_TYPE_F64,
TCG_TYPE_V64,
TCG_TYPE_V128,
TCG_TYPE_V256,
@ -355,6 +362,8 @@ typedef tcg_target_ulong TCGArg;
* TCGv_ptr : a host pointer type
* TCGv_vec : a host vector type; the exact size is not exposed
to the CPU front-end code.
* TCGv_f32 : 32 bit floating point type
* TCGv_f64 : 64 bit floating point type
* TCGv : an integer type the same size as target_ulong
(an alias for either TCGv_i32 or TCGv_i64)
The compiler's type checking will complain if you mix them
@ -378,6 +387,8 @@ typedef struct TCGv_i32_d *TCGv_i32;
typedef struct TCGv_i64_d *TCGv_i64;
typedef struct TCGv_ptr_d *TCGv_ptr;
typedef struct TCGv_vec_d *TCGv_vec;
typedef struct TCGv_f32_d *TCGv_f32;
typedef struct TCGv_f64_d *TCGv_f64;
typedef TCGv_ptr TCGv_env;
#if TARGET_LONG_BITS == 32
#define TCGv TCGv_i32
@ -625,6 +636,8 @@ struct TCGContext {
/* Exit to translator on overflow. */
sigjmp_buf jmp_trans;
void *disas_ctx;
};
static inline bool temp_readonly(TCGTemp *ts)
@ -697,6 +710,16 @@ static inline TCGTemp *tcgv_vec_temp(TCGv_vec v)
return tcgv_i32_temp((TCGv_i32)v);
}
static inline TCGTemp *tcgv_f32_temp(TCGv_f32 v)
{
return tcgv_i32_temp((TCGv_i32)v);
}
static inline TCGTemp *tcgv_f64_temp(TCGv_f64 v)
{
return tcgv_i32_temp((TCGv_i32)v);
}
static inline TCGArg tcgv_i32_arg(TCGv_i32 v)
{
return temp_arg(tcgv_i32_temp(v));
@ -717,6 +740,16 @@ static inline TCGArg tcgv_vec_arg(TCGv_vec v)
return temp_arg(tcgv_vec_temp(v));
}
static inline TCGArg tcgv_f32_arg(TCGv_f32 v)
{
return temp_arg(tcgv_f32_temp(v));
}
static inline TCGArg tcgv_f64_arg(TCGv_f64 v)
{
return temp_arg(tcgv_f64_temp(v));
}
static inline TCGv_i32 temp_tcgv_i32(TCGTemp *t)
{
(void)temp_idx(t); /* trigger embedded assert */
@ -738,6 +771,16 @@ static inline TCGv_vec temp_tcgv_vec(TCGTemp *t)
return (TCGv_vec)temp_tcgv_i32(t);
}
static inline TCGv_f32 temp_tcgv_f32(TCGTemp *t)
{
return (TCGv_f32)temp_tcgv_i32(t);
}
static inline TCGv_f64 temp_tcgv_f64(TCGTemp *t)
{
return (TCGv_f64)temp_tcgv_i32(t);
}
#if TCG_TARGET_REG_BITS == 32
static inline TCGv_i32 TCGV_LOW(TCGv_i64 t)
{
@ -876,6 +919,16 @@ static inline void tcg_temp_free_vec(TCGv_vec arg)
tcg_temp_free_internal(tcgv_vec_temp(arg));
}
static inline void tcg_temp_free_f32(TCGv_f32 arg)
{
tcg_temp_free_internal(tcgv_f32_temp(arg));
}
static inline void tcg_temp_free_f64(TCGv_f64 arg)
{
tcg_temp_free_internal(tcgv_f64_temp(arg));
}
static inline TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t offset,
const char *name)
{
@ -933,6 +986,44 @@ static inline TCGv_ptr tcg_temp_local_new_ptr(void)
return temp_tcgv_ptr(t);
}
static inline TCGv_f32 tcg_global_mem_new_f32(TCGv_ptr reg, intptr_t offset,
const char *name)
{
TCGTemp *t = tcg_global_mem_new_internal(TCG_TYPE_F32, reg, offset, name);
return temp_tcgv_f32(t);
}
static inline TCGv_f32 tcg_temp_new_f32(void)
{
TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_F32, false);
return temp_tcgv_f32(t);
}
static inline TCGv_f32 tcg_temp_local_new_f32(void)
{
TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_F32, true);
return temp_tcgv_f32(t);
}
static inline TCGv_f64 tcg_global_mem_new_f64(TCGv_ptr reg, intptr_t offset,
const char *name)
{
TCGTemp *t = tcg_global_mem_new_internal(TCG_TYPE_F64, reg, offset, name);
return temp_tcgv_f64(t);
}
static inline TCGv_f64 tcg_temp_new_f64(void)
{
TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_F64, false);
return temp_tcgv_f64(t);
}
static inline TCGv_f64 tcg_temp_local_new_f64(void)
{
TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_F64, true);
return temp_tcgv_f64(t);
}
#if defined(CONFIG_DEBUG_TCG)
/* If you call tcg_clear_temp_count() at the start of a section of
* code which is not supposed to leak any TCG temporaries, then
@ -1452,4 +1543,6 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
void gen_bb_epilogue(void); /* translate.c */
#endif /* TCG_H */