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:
parent
67d43538ae
commit
057d5f62f8
@ -198,3 +198,63 @@ uint64_t HELPER(neon_cgt_f64)(float64 a, float64 b, void *fpstp)
|
||||
float_status *fpst = fpstp;
|
||||
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);
|
||||
}
|
||||
|
@ -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_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(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)
|
||||
|
@ -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_acge_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 */
|
||||
DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
|
||||
|
@ -1823,6 +1823,22 @@ uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||
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))
|
||||
|
||||
void HELPER(neon_qunzip8)(CPUARMState *env, uint32_t rd, uint32_t rm)
|
||||
|
@ -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);
|
||||
|
||||
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 */
|
||||
gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1a: /* FADD */
|
||||
gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1b: /* FMULX */
|
||||
gen_helper_vfp_mulxd(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1c: /* FCMEQ */
|
||||
gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1e: /* FMAX */
|
||||
gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1f: /* FRECPS */
|
||||
gen_helper_recpsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x38: /* FMINNM */
|
||||
gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
@ -6066,12 +6081,18 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
|
||||
case 0x3e: /* FMIN */
|
||||
gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x3f: /* FRSQRTS */
|
||||
gen_helper_rsqrtsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5b: /* FMUL */
|
||||
gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5c: /* FCMGE */
|
||||
gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5d: /* FACGE */
|
||||
gen_helper_neon_acge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5f: /* FDIV */
|
||||
gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
@ -6082,6 +6103,9 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
|
||||
case 0x7c: /* FCMGT */
|
||||
gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x7d: /* FACGT */
|
||||
gen_helper_neon_acgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
|
||||
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 */
|
||||
gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1b: /* FMULX */
|
||||
gen_helper_vfp_mulxs(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1c: /* FCMEQ */
|
||||
gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1e: /* FMAX */
|
||||
gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x1f: /* FRECPS */
|
||||
gen_helper_recpsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x18: /* FMAXNM */
|
||||
gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
@ -6122,12 +6161,18 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
|
||||
case 0x3e: /* FMIN */
|
||||
gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x3f: /* FRSQRTS */
|
||||
gen_helper_rsqrtsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5b: /* FMUL */
|
||||
gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5c: /* FCMGE */
|
||||
gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5d: /* FACGE */
|
||||
gen_helper_neon_acge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x5f: /* FDIV */
|
||||
gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
@ -6138,6 +6183,9 @@ static void handle_3same_float(DisasContext *s, int size, int elements,
|
||||
case 0x7c: /* FCMGT */
|
||||
gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
case 0x7d: /* FACGT */
|
||||
gen_helper_neon_acgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
|
||||
break;
|
||||
default:
|
||||
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 0x5d: /* FACGE */
|
||||
case 0x7d: /* FACGT */
|
||||
unsupported_encoding(s, insn);
|
||||
return;
|
||||
case 0x1c: /* FCMEQ */
|
||||
case 0x5c: /* FCMGE */
|
||||
case 0x7c: /* FCMGT */
|
||||
@ -7303,8 +7349,6 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn)
|
||||
case 0x7d: /* FACGT */
|
||||
case 0x19: /* FMLA */
|
||||
case 0x39: /* FMLS */
|
||||
unsupported_encoding(s, insn);
|
||||
return;
|
||||
case 0x18: /* FMAXNM */
|
||||
case 0x1a: /* FADD */
|
||||
case 0x1c: /* FCMEQ */
|
||||
|
Loading…
Reference in New Issue
Block a user