mirror of https://github.com/xemu-project/xemu.git
target-arm: Pass fp status pointer explicitly to neon fp helpers
Make the Neon helpers for various floating point operations take an explicit pointer to the float_status they use, so they don't rely on the global environment pointer any more. This also allows us to drop the mul/sub/add helpers completely and just use the vfp versions. Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
ae1857eca2
commit
aa47cfdd17
|
@ -350,17 +350,14 @@ DEF_HELPER_1(neon_qneg_s8, i32, i32)
|
||||||
DEF_HELPER_1(neon_qneg_s16, i32, i32)
|
DEF_HELPER_1(neon_qneg_s16, i32, i32)
|
||||||
DEF_HELPER_1(neon_qneg_s32, i32, i32)
|
DEF_HELPER_1(neon_qneg_s32, i32, i32)
|
||||||
|
|
||||||
DEF_HELPER_2(neon_min_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_min_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_max_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_max_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_abd_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_abd_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_add_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_ceq_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_sub_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_cge_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_mul_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_ceq_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_acge_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_cge_f32, i32, i32, i32)
|
DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, ptr)
|
||||||
DEF_HELPER_2(neon_cgt_f32, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_acge_f32, i32, i32, i32)
|
|
||||||
DEF_HELPER_2(neon_acgt_f32, i32, i32, i32)
|
|
||||||
|
|
||||||
/* iwmmxt_helper.c */
|
/* iwmmxt_helper.c */
|
||||||
DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
|
DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q
|
#define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q
|
||||||
|
|
||||||
#define NFS (&env->vfp.standard_fp_status)
|
|
||||||
|
|
||||||
#define NEON_TYPE1(name, type) \
|
#define NEON_TYPE1(name, type) \
|
||||||
typedef struct \
|
typedef struct \
|
||||||
{ \
|
{ \
|
||||||
|
@ -1770,69 +1768,62 @@ uint32_t HELPER(neon_qneg_s32)(uint32_t x)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NEON Float helpers. */
|
/* NEON Float helpers. */
|
||||||
uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
return float32_val(float32_min(make_float32(a), make_float32(b), NFS));
|
float_status *fpst = fpstp;
|
||||||
|
return float32_val(float32_min(make_float32(a), make_float32(b), fpst));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
return float32_val(float32_max(make_float32(a), make_float32(b), NFS));
|
float_status *fpst = fpstp;
|
||||||
|
return float32_val(float32_max(make_float32(a), make_float32(b), fpst));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
|
float_status *fpst = fpstp;
|
||||||
float32 f0 = make_float32(a);
|
float32 f0 = make_float32(a);
|
||||||
float32 f1 = make_float32(b);
|
float32 f1 = make_float32(b);
|
||||||
return float32_val(float32_abs(float32_sub(f0, f1, NFS)));
|
return float32_val(float32_abs(float32_sub(f0, f1, fpst)));
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b)
|
|
||||||
{
|
|
||||||
return float32_val(float32_add(make_float32(a), make_float32(b), NFS));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t HELPER(neon_sub_f32)(uint32_t a, uint32_t b)
|
|
||||||
{
|
|
||||||
return float32_val(float32_sub(make_float32(a), make_float32(b), NFS));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b)
|
|
||||||
{
|
|
||||||
return float32_val(float32_mul(make_float32(a), make_float32(b), NFS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Floating point comparisons produce an integer result.
|
/* Floating point comparisons produce an integer result.
|
||||||
* Note that EQ doesn't signal InvalidOp for QNaNs but GE and GT do.
|
* Note that EQ doesn't signal InvalidOp for QNaNs but GE and GT do.
|
||||||
* Softfloat routines return 0/1, which we convert to the 0/-1 Neon requires.
|
* Softfloat routines return 0/1, which we convert to the 0/-1 Neon requires.
|
||||||
*/
|
*/
|
||||||
uint32_t HELPER(neon_ceq_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_ceq_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
return -float32_eq_quiet(make_float32(a), make_float32(b), NFS);
|
float_status *fpst = fpstp;
|
||||||
|
return -float32_eq_quiet(make_float32(a), make_float32(b), fpst);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(neon_cge_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_cge_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
return -float32_le(make_float32(b), make_float32(a), NFS);
|
float_status *fpst = fpstp;
|
||||||
|
return -float32_le(make_float32(b), make_float32(a), fpst);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(neon_cgt_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_cgt_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
return -float32_lt(make_float32(b), make_float32(a), NFS);
|
float_status *fpst = fpstp;
|
||||||
|
return -float32_lt(make_float32(b), make_float32(a), fpst);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
|
float_status *fpst = fpstp;
|
||||||
float32 f0 = float32_abs(make_float32(a));
|
float32 f0 = float32_abs(make_float32(a));
|
||||||
float32 f1 = float32_abs(make_float32(b));
|
float32 f1 = float32_abs(make_float32(b));
|
||||||
return -float32_le(f1, f0, NFS);
|
return -float32_le(f1, f0, fpst);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b)
|
uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||||
{
|
{
|
||||||
|
float_status *fpst = fpstp;
|
||||||
float32 f0 = float32_abs(make_float32(a));
|
float32 f0 = float32_abs(make_float32(a));
|
||||||
float32 f1 = float32_abs(make_float32(b));
|
float32 f1 = float32_abs(make_float32(b));
|
||||||
return -float32_lt(f1, f0, NFS);
|
return -float32_lt(f1, f0, fpst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
|
#define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1))
|
||||||
|
|
|
@ -4857,57 +4857,78 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
|
case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
|
||||||
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
switch ((u << 2) | size) {
|
switch ((u << 2) | size) {
|
||||||
case 0: /* VADD */
|
case 0: /* VADD */
|
||||||
gen_helper_neon_add_f32(tmp, tmp, tmp2);
|
case 4: /* VPADD */
|
||||||
|
gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
|
||||||
break;
|
break;
|
||||||
case 2: /* VSUB */
|
case 2: /* VSUB */
|
||||||
gen_helper_neon_sub_f32(tmp, tmp, tmp2);
|
gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
|
||||||
break;
|
|
||||||
case 4: /* VPADD */
|
|
||||||
gen_helper_neon_add_f32(tmp, tmp, tmp2);
|
|
||||||
break;
|
break;
|
||||||
case 6: /* VABD */
|
case 6: /* VABD */
|
||||||
gen_helper_neon_abd_f32(tmp, tmp, tmp2);
|
gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_3R_FLOAT_MULTIPLY:
|
case NEON_3R_FLOAT_MULTIPLY:
|
||||||
gen_helper_neon_mul_f32(tmp, tmp, tmp2);
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
|
gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
|
||||||
if (!u) {
|
if (!u) {
|
||||||
tcg_temp_free_i32(tmp2);
|
tcg_temp_free_i32(tmp2);
|
||||||
tmp2 = neon_load_reg(rd, pass);
|
tmp2 = neon_load_reg(rd, pass);
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
gen_helper_neon_add_f32(tmp, tmp, tmp2);
|
gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
|
||||||
} else {
|
} else {
|
||||||
gen_helper_neon_sub_f32(tmp, tmp2, tmp);
|
gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_3R_FLOAT_CMP:
|
case NEON_3R_FLOAT_CMP:
|
||||||
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
if (!u) {
|
if (!u) {
|
||||||
gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
|
gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
} else {
|
} else {
|
||||||
if (size == 0)
|
if (size == 0) {
|
||||||
gen_helper_neon_cge_f32(tmp, tmp, tmp2);
|
gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
else
|
} else {
|
||||||
gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
|
gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_3R_FLOAT_ACMP:
|
case NEON_3R_FLOAT_ACMP:
|
||||||
if (size == 0)
|
{
|
||||||
gen_helper_neon_acge_f32(tmp, tmp, tmp2);
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
else
|
if (size == 0) {
|
||||||
gen_helper_neon_acgt_f32(tmp, tmp, tmp2);
|
gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
|
} else {
|
||||||
|
gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
|
}
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_3R_FLOAT_MINMAX:
|
case NEON_3R_FLOAT_MINMAX:
|
||||||
if (size == 0)
|
{
|
||||||
gen_helper_neon_max_f32(tmp, tmp, tmp2);
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
else
|
if (size == 0) {
|
||||||
gen_helper_neon_min_f32(tmp, tmp, tmp2);
|
gen_helper_neon_max_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
|
} else {
|
||||||
|
gen_helper_neon_min_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
|
}
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_3R_VRECPS_VRSQRTS:
|
case NEON_3R_VRECPS_VRSQRTS:
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
|
gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
|
||||||
|
@ -5606,7 +5627,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||||
gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2);
|
gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2);
|
||||||
}
|
}
|
||||||
} else if (op & 1) {
|
} else if (op & 1) {
|
||||||
gen_helper_neon_mul_f32(tmp, tmp, tmp2);
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
|
gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
} else {
|
} else {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
|
case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
|
||||||
|
@ -5624,14 +5647,22 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||||
gen_neon_add(size, tmp, tmp2);
|
gen_neon_add(size, tmp, tmp2);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
gen_helper_neon_add_f32(tmp, tmp, tmp2);
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
|
gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 4:
|
case 4:
|
||||||
gen_neon_rsb(size, tmp, tmp2);
|
gen_neon_rsb(size, tmp, tmp2);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
gen_helper_neon_sub_f32(tmp, tmp2, tmp);
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
|
gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -6029,30 +6060,50 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||||
tcg_temp_free(tmp2);
|
tcg_temp_free(tmp2);
|
||||||
break;
|
break;
|
||||||
case NEON_2RM_VCGT0_F:
|
case NEON_2RM_VCGT0_F:
|
||||||
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
tmp2 = tcg_const_i32(0);
|
tmp2 = tcg_const_i32(0);
|
||||||
gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
|
gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
tcg_temp_free(tmp2);
|
tcg_temp_free(tmp2);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_2RM_VCGE0_F:
|
case NEON_2RM_VCGE0_F:
|
||||||
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
tmp2 = tcg_const_i32(0);
|
tmp2 = tcg_const_i32(0);
|
||||||
gen_helper_neon_cge_f32(tmp, tmp, tmp2);
|
gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
tcg_temp_free(tmp2);
|
tcg_temp_free(tmp2);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_2RM_VCEQ0_F:
|
case NEON_2RM_VCEQ0_F:
|
||||||
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
tmp2 = tcg_const_i32(0);
|
tmp2 = tcg_const_i32(0);
|
||||||
gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
|
gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
|
||||||
tcg_temp_free(tmp2);
|
tcg_temp_free(tmp2);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_2RM_VCLE0_F:
|
case NEON_2RM_VCLE0_F:
|
||||||
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
tmp2 = tcg_const_i32(0);
|
tmp2 = tcg_const_i32(0);
|
||||||
gen_helper_neon_cge_f32(tmp, tmp2, tmp);
|
gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
|
||||||
tcg_temp_free(tmp2);
|
tcg_temp_free(tmp2);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_2RM_VCLT0_F:
|
case NEON_2RM_VCLT0_F:
|
||||||
|
{
|
||||||
|
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||||
tmp2 = tcg_const_i32(0);
|
tmp2 = tcg_const_i32(0);
|
||||||
gen_helper_neon_cgt_f32(tmp, tmp2, tmp);
|
gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
|
||||||
tcg_temp_free(tmp2);
|
tcg_temp_free(tmp2);
|
||||||
|
tcg_temp_free_ptr(fpstatus);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case NEON_2RM_VABS_F:
|
case NEON_2RM_VABS_F:
|
||||||
gen_vfp_abs(0);
|
gen_vfp_abs(0);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue