target-arm: A64: Implement remaining 3-same instructions

Implement the remaining instructions in the SIMD 3-reg-same
and scalar-3-reg-same groups: FMULX, FRECPS, FRSQRTS, FACGE,
FACGT, FMLA and FMLS.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Peter Maydell 2014-02-20 10:35:50 +00:00
parent 67d43538ae
commit 057d5f62f8
5 changed files with 130 additions and 4 deletions

View File

@ -198,3 +198,63 @@ uint64_t HELPER(neon_cgt_f64)(float64 a, float64 b, void *fpstp)
float_status *fpst = fpstp; float_status *fpst = fpstp;
return -float64_lt(b, a, fpst); return -float64_lt(b, a, fpst);
} }
/* Reciprocal step and sqrt step. Note that unlike the A32/T32
* versions, these do a fully fused multiply-add or
* multiply-add-and-halve.
*/
#define float32_two make_float32(0x40000000)
#define float32_three make_float32(0x40400000)
#define float32_one_point_five make_float32(0x3fc00000)
#define float64_two make_float64(0x4000000000000000ULL)
#define float64_three make_float64(0x4008000000000000ULL)
#define float64_one_point_five make_float64(0x3FF8000000000000ULL)
float32 HELPER(recpsf_f32)(float32 a, float32 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float32_chs(a);
if ((float32_is_infinity(a) && float32_is_zero(b)) ||
(float32_is_infinity(b) && float32_is_zero(a))) {
return float32_two;
}
return float32_muladd(a, b, float32_two, 0, fpst);
}
float64 HELPER(recpsf_f64)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float64_chs(a);
if ((float64_is_infinity(a) && float64_is_zero(b)) ||
(float64_is_infinity(b) && float64_is_zero(a))) {
return float64_two;
}
return float64_muladd(a, b, float64_two, 0, fpst);
}
float32 HELPER(rsqrtsf_f32)(float32 a, float32 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float32_chs(a);
if ((float32_is_infinity(a) && float32_is_zero(b)) ||
(float32_is_infinity(b) && float32_is_zero(a))) {
return float32_one_point_five;
}
return float32_muladd(a, b, float32_three, float_muladd_halve_result, fpst);
}
float64 HELPER(rsqrtsf_f64)(float64 a, float64 b, void *fpstp)
{
float_status *fpst = fpstp;
a = float64_chs(a);
if ((float64_is_infinity(a) && float64_is_zero(b)) ||
(float64_is_infinity(b) && float64_is_zero(a))) {
return float64_one_point_five;
}
return float64_muladd(a, b, float64_three, float_muladd_halve_result, fpst);
}

View File

@ -32,3 +32,7 @@ DEF_HELPER_FLAGS_3(vfp_mulxd, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
DEF_HELPER_FLAGS_3(neon_ceq_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr) DEF_HELPER_FLAGS_3(neon_ceq_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
DEF_HELPER_FLAGS_3(neon_cge_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr) DEF_HELPER_FLAGS_3(neon_cge_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
DEF_HELPER_FLAGS_3(neon_cgt_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr) DEF_HELPER_FLAGS_3(neon_cgt_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
DEF_HELPER_FLAGS_3(recpsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
DEF_HELPER_FLAGS_3(recpsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
DEF_HELPER_FLAGS_3(rsqrtsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
DEF_HELPER_FLAGS_3(rsqrtsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)

View File

@ -382,6 +382,8 @@ DEF_HELPER_3(neon_cge_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr) DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_acge_f32, i32, i32, i32, ptr) DEF_HELPER_3(neon_acge_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, ptr) DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, ptr)
DEF_HELPER_3(neon_acge_f64, i64, i64, i64, ptr)
DEF_HELPER_3(neon_acgt_f64, i64, i64, i64, ptr)
/* iwmmxt_helper.c */ /* iwmmxt_helper.c */
DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64) DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)

View File

@ -1823,6 +1823,22 @@ uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b, void *fpstp)
return -float32_lt(f1, f0, fpst); return -float32_lt(f1, f0, fpst);
} }
uint64_t HELPER(neon_acge_f64)(uint64_t a, uint64_t b, void *fpstp)
{
float_status *fpst = fpstp;
float64 f0 = float64_abs(make_float64(a));
float64 f1 = float64_abs(make_float64(b));
return -float64_le(f1, f0, fpst);
}
uint64_t HELPER(neon_acgt_f64)(uint64_t a, uint64_t b, void *fpstp)
{
float_status *fpst = fpstp;
float64 f0 = float64_abs(make_float64(a));
float64 f1 = float64_abs(make_float64(b));
return -float64_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))
void HELPER(neon_qunzip8)(CPUARMState *env, uint32_t rd, uint32_t rm) void HELPER(neon_qunzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)

View File

@ -6045,18 +6045,33 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
read_vec_element(s, tcg_op2, rm, pass, MO_64); read_vec_element(s, tcg_op2, rm, pass, MO_64);
switch (fpopcode) { switch (fpopcode) {
case 0x39: /* FMLS */
/* As usual for ARM, separate negation for fused multiply-add */
gen_helper_vfp_negd(tcg_op1, tcg_op1);
/* fall through */
case 0x19: /* FMLA */
read_vec_element(s, tcg_res, rd, pass, MO_64);
gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2,
tcg_res, fpst);
break;
case 0x18: /* FMAXNM */ case 0x18: /* FMAXNM */
gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x1a: /* FADD */ case 0x1a: /* FADD */
gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x1b: /* FMULX */
gen_helper_vfp_mulxd(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x1c: /* FCMEQ */ case 0x1c: /* FCMEQ */
gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x1e: /* FMAX */ case 0x1e: /* FMAX */
gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x1f: /* FRECPS */
gen_helper_recpsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x38: /* FMINNM */ case 0x38: /* FMINNM */
gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
@ -6066,12 +6081,18 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
case 0x3e: /* FMIN */ case 0x3e: /* FMIN */
gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x3f: /* FRSQRTS */
gen_helper_rsqrtsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x5b: /* FMUL */ case 0x5b: /* FMUL */
gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x5c: /* FCMGE */ case 0x5c: /* FCMGE */
gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x5d: /* FACGE */
gen_helper_neon_acge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x5f: /* FDIV */ case 0x5f: /* FDIV */
gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
@ -6082,6 +6103,9 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
case 0x7c: /* FCMGT */ case 0x7c: /* FCMGT */
gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x7d: /* FACGT */
gen_helper_neon_acgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -6101,15 +6125,30 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
read_vec_element_i32(s, tcg_op2, rm, pass, MO_32); read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
switch (fpopcode) { switch (fpopcode) {
case 0x39: /* FMLS */
/* As usual for ARM, separate negation for fused multiply-add */
gen_helper_vfp_negs(tcg_op1, tcg_op1);
/* fall through */
case 0x19: /* FMLA */
read_vec_element_i32(s, tcg_res, rd, pass, MO_32);
gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2,
tcg_res, fpst);
break;
case 0x1a: /* FADD */ case 0x1a: /* FADD */
gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x1b: /* FMULX */
gen_helper_vfp_mulxs(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x1c: /* FCMEQ */ case 0x1c: /* FCMEQ */
gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x1e: /* FMAX */ case 0x1e: /* FMAX */
gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x1f: /* FRECPS */
gen_helper_recpsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x18: /* FMAXNM */ case 0x18: /* FMAXNM */
gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
@ -6122,12 +6161,18 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
case 0x3e: /* FMIN */ case 0x3e: /* FMIN */
gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x3f: /* FRSQRTS */
gen_helper_rsqrtsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x5b: /* FMUL */ case 0x5b: /* FMUL */
gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x5c: /* FCMGE */ case 0x5c: /* FCMGE */
gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x5d: /* FACGE */
gen_helper_neon_acge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
break;
case 0x5f: /* FDIV */ case 0x5f: /* FDIV */
gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
@ -6138,6 +6183,9 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
case 0x7c: /* FCMGT */ case 0x7c: /* FCMGT */
gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst); gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
break; break;
case 0x7d: /* FACGT */
gen_helper_neon_acgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -6192,8 +6240,6 @@ static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn)
case 0x3f: /* FRSQRTS */ case 0x3f: /* FRSQRTS */
case 0x5d: /* FACGE */ case 0x5d: /* FACGE */
case 0x7d: /* FACGT */ case 0x7d: /* FACGT */
unsupported_encoding(s, insn);
return;
case 0x1c: /* FCMEQ */ case 0x1c: /* FCMEQ */
case 0x5c: /* FCMGE */ case 0x5c: /* FCMGE */
case 0x7c: /* FCMGT */ case 0x7c: /* FCMGT */
@ -7303,8 +7349,6 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn)
case 0x7d: /* FACGT */ case 0x7d: /* FACGT */
case 0x19: /* FMLA */ case 0x19: /* FMLA */
case 0x39: /* FMLS */ case 0x39: /* FMLS */
unsupported_encoding(s, insn);
return;
case 0x18: /* FMAXNM */ case 0x18: /* FMAXNM */
case 0x1a: /* FADD */ case 0x1a: /* FADD */
case 0x1c: /* FCMEQ */ case 0x1c: /* FCMEQ */