aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Bennée <alex.bennee@linaro.org>2014-03-17 16:31:50 +0000
committerPeter Maydell <peter.maydell@linaro.org>2014-03-17 16:31:50 +0000
commit8f0c6758b0e1c3b9676e7c3ccea8a176537cf843 (patch)
treefb94230a002c91f6b77badbe084b7675f169a14f
parenta566da1b02704a79038043ddbe850f40b033cd63 (diff)
target-arm: A64: Add FRECPX (reciprocal exponent)
These are fairly simple exponent only estimation functions using helpers. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <rth@twiddle.net> Message-id: 1394822294-14837-14-git-send-email-peter.maydell@linaro.org
-rw-r--r--target-arm/helper-a64.c59
-rw-r--r--target-arm/helper-a64.h2
-rw-r--r--target-arm/translate-a64.c70
3 files changed, 130 insertions, 1 deletions
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index c31c45e729..cea2468b30 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -354,3 +354,62 @@ uint64_t HELPER(neon_addlp_u16)(uint64_t a)
tmp += (a >> 16) & 0x0000ffff0000ffffULL;
return tmp;
}
+
+/* Floating-point reciprocal exponent - see FPRecpX in ARM ARM */
+float32 HELPER(frecpx_f32)(float32 a, void *fpstp)
+{
+ float_status *fpst = fpstp;
+ uint32_t val32, sbit;
+ int32_t exp;
+
+ if (float32_is_any_nan(a)) {
+ float32 nan = a;
+ if (float32_is_signaling_nan(a)) {
+ float_raise(float_flag_invalid, fpst);
+ nan = float32_maybe_silence_nan(a);
+ }
+ if (fpst->default_nan_mode) {
+ nan = float32_default_nan;
+ }
+ return nan;
+ }
+
+ val32 = float32_val(a);
+ sbit = 0x80000000ULL & val32;
+ exp = extract32(val32, 23, 8);
+
+ if (exp == 0) {
+ return make_float32(sbit | (0xfe << 23));
+ } else {
+ return make_float32(sbit | (~exp & 0xff) << 23);
+ }
+}
+
+float64 HELPER(frecpx_f64)(float64 a, void *fpstp)
+{
+ float_status *fpst = fpstp;
+ uint64_t val64, sbit;
+ int64_t exp;
+
+ if (float64_is_any_nan(a)) {
+ float64 nan = a;
+ if (float64_is_signaling_nan(a)) {
+ float_raise(float_flag_invalid, fpst);
+ nan = float64_maybe_silence_nan(a);
+ }
+ if (fpst->default_nan_mode) {
+ nan = float64_default_nan;
+ }
+ return nan;
+ }
+
+ val64 = float64_val(a);
+ sbit = 0x8000000000000000ULL & val64;
+ exp = extract64(float64_val(a), 52, 11);
+
+ if (exp == 0) {
+ return make_float64(sbit | (0x7feULL << 52));
+ } else {
+ return make_float64(sbit | (~exp & 0x7ffULL) << 52);
+ }
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index 88fc9fe9e7..8cbc3492d4 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -43,3 +43,5 @@ DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_1(neon_addlp_u8, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_1(neon_addlp_u16, TCG_CALL_NO_RWG_SE, i64, i64)
+DEF_HELPER_FLAGS_2(frecpx_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
+DEF_HELPER_FLAGS_2(frecpx_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 2b1ca64b19..86e5d3e1db 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -6886,6 +6886,72 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
tcg_temp_free_ptr(fpst);
}
+static void handle_2misc_reciprocal(DisasContext *s, int opcode,
+ bool is_scalar, bool is_u, bool is_q,
+ int size, int rn, int rd)
+{
+ bool is_double = (size == 3);
+ TCGv_ptr fpst = get_fpstatus_ptr();
+
+ if (is_double) {
+ TCGv_i64 tcg_op = tcg_temp_new_i64();
+ TCGv_i64 tcg_res = tcg_temp_new_i64();
+ int pass;
+
+ for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
+ read_vec_element(s, tcg_op, rn, pass, MO_64);
+ switch (opcode) {
+ case 0x3f: /* FRECPX */
+ gen_helper_frecpx_f64(tcg_res, tcg_op, fpst);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ write_vec_element(s, tcg_res, rd, pass, MO_64);
+ }
+ if (is_scalar) {
+ clear_vec_high(s, rd);
+ }
+
+ tcg_temp_free_i64(tcg_res);
+ tcg_temp_free_i64(tcg_op);
+ } else {
+ TCGv_i32 tcg_op = tcg_temp_new_i32();
+ TCGv_i32 tcg_res = tcg_temp_new_i32();
+ int pass, maxpasses;
+
+ if (is_scalar) {
+ maxpasses = 1;
+ } else {
+ maxpasses = is_q ? 4 : 2;
+ }
+
+ for (pass = 0; pass < maxpasses; pass++) {
+ read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
+
+ switch (opcode) {
+ case 0x3f: /* FRECPX */
+ gen_helper_frecpx_f32(tcg_res, tcg_op, fpst);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (is_scalar) {
+ write_fp_sreg(s, rd, tcg_res);
+ } else {
+ write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
+ }
+ }
+ tcg_temp_free_i32(tcg_res);
+ tcg_temp_free_i32(tcg_op);
+ if (!is_q && !is_scalar) {
+ clear_vec_high(s, rd);
+ }
+ }
+ tcg_temp_free_ptr(fpst);
+}
+
/* C3.6.12 AdvSIMD scalar two reg misc
* 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
* +-----+---+-----------+------+-----------+--------+-----+------+------+
@@ -6942,6 +7008,9 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
handle_simd_intfp_conv(s, rd, rn, 1, is_signed, 0, size);
return;
}
+ case 0x3f: /* FRECPX */
+ handle_2misc_reciprocal(s, opcode, true, u, true, size, rn, rd);
+ return;
case 0x1a: /* FCVTNS */
case 0x1b: /* FCVTMS */
case 0x3a: /* FCVTPS */
@@ -6960,7 +7029,6 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
rmode = FPROUNDING_TIEAWAY;
break;
case 0x3d: /* FRECPE */
- case 0x3f: /* FRECPX */
case 0x56: /* FCVTXN, FCVTXN2 */
case 0x7d: /* FRSQRTE */
unsupported_encoding(s, insn);