qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] target/arm: Implement ARMv8.5-FRINT
@ 2019-02-23  1:22 Richard Henderson
  2019-02-23  1:22 ` [Qemu-devel] [PATCH 1/2] target/arm: Restructure handle_fp_1src_{single, double} Richard Henderson
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Richard Henderson @ 2019-02-23  1:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Based-on: the ARMv8.2-FHM patch set, although I don't know that
this is an actual dependency; it's just the tree I started with.

There is not yet support for this extension within FVP, so I've
self-tested it against my own understanding of what is supposed
to go on with the file below.


r~


Richard Henderson (2):
  target/arm: Restructure handle_fp_1src_{single,double}
  target/arm: Implement ARMv8.5-FRINT

 target/arm/cpu.h           |   5 ++
 target/arm/helper.h        |   5 ++
 target/arm/cpu64.c         |   1 +
 target/arm/translate-a64.c | 161 ++++++++++++++++++++++++++-----------
 target/arm/vfp_helper.c    |  96 ++++++++++++++++++++++
 5 files changed, 222 insertions(+), 46 deletions(-)

-- 

#include <stdio.h>
#include <limits.h>

asm(".arch armv8.5-a");

static const float f32_i32_z[][2] = {
    { 0, 0 },
    { -0.0, -0.0 },
    { 0.9, 0.0 },
    { 1.0, 1.0 },
    { 1.1, 1.0 },
    { 1.9, 1.0 },
    { 0x1.fffffep30, 0x1.fffffep30 },		/* 2^31 - epsilon */
    { -0x1p31, -0x1.0p31 },			/* -2^31 = INT32_MIN */
    { 0x1.0p31, -0x1.0p31 },			/* overflow */
    { 0x1.0p32, -0x1.0p31 },			/* overflow */
    { -0x1.0p32, -0x1.0p31 },			/* overflow */
    { __builtin_inf(), -0x1.0p31 },		/* overflow */
};

static const double f64_i32_z[][2] = {
    { 0, 0 },
    { -0.0, -0.0 },
    { 0.9, 0.0 },
    { 1.0, 1.0 },
    { 1.1, 1.0 },
    { 1.9, 1.0 },
    { 2147483647, 2147483647 },			/* 2^31 - 1 = INT32_MAX */
    { -0x1p31, -0x1.0p31 },			/* -2^31 = INT32_MIN */
    { 0x1.0p31, -0x1.0p31 },			/* overflow */
    { 0x1.0p32, -0x1.0p31 },			/* overflow */
    { -0x1.0p32, -0x1.0p31 },			/* overflow */
    { __builtin_inf(), -0x1.0p31 },		/* overflow */
};

static const float f32_i64_z[][2] = {
    { 0, 0 },
    { -0.0, -0.0 },
    { 0.9, 0.0 },
    { 1.0, 1.0 },
    { 1.1, 1.0 },
    { 1.9, 1.0 },
    { 0x1.fffffep30, 0x1.fffffep30 },		/* 2^31 - epsilon */
    { -0x1p31, -0x1.0p31 },			/* -2^31 = INT32_MIN */
    { 0x1.0p31, 0x1.0p31 },
    { 0x1.0p32, 0x1.0p32 },
    { -0x1.0p32, -0x1.0p32 },
    { 0x1.0p62, 0x1.0p62 },
    { 0x1.fffffep62, 0x1.fffffep62 },		/* 2^63 - epsilon */
    { -0x1.0p63, -0x1.0p63 },			/* -2^63 = INT64_MIN */
    { 0x1.0p63, -0x1.0p63 },			/* overflow */
    { 0x1.0p64, -0x1.0p63 },			/* overflow */
    { -0x1.0p64, -0x1.0p63 },			/* overflow */
    { __builtin_inf(), -0x1.0p63 },		/* overflow */
};

static const double f64_i64_z[][2] = {
    { 0, 0 },
    { -0.0, -0.0 },
    { 0.9, 0.0 },
    { 1.0, 1.0 },
    { 1.1, 1.0 },
    { 1.9, 1.0 },
    { 2147483647, 2147483647 },			/* 2^31 - 1 = INT32_MAX */
    { -0x1p31, -0x1.0p31 },			/* -2^31 = INT32_MIN */
    { 0x1.0p31, 0x1.0p31 },
    { 0x1.0p32, 0x1.0p32 },
    { -0x1.0p32, -0x1.0p32 },
    { 0x1.0p62, 0x1.0p62 },
    { 0x1.fffffffffffffp62, 0x1.fffffffffffffp62 }, /* 2^63 - epsilon */
    { -0x1.0p63, -0x1.0p63 },			/* -2^63 = INT64_MIN */
    { 0x1.0p63, -0x1.0p63 },			/* overflow */
    { 0x1.0p64, -0x1.0p63 },			/* overflow */
    { -0x1.0p64, -0x1.0p63 },			/* overflow */
    { __builtin_inf(), -0x1.0p63 },		/* overflow */
};

int main()
{
    int i;

    for (i = 0; i < sizeof(f32_i32_z)/sizeof(f32_i32_z[0]); i++) {
        float x;
        asm("frint32z %s0,%s1" : "=w"(x) : "w"(f32_i32_z[i][0]));
        if (x != f32_i32_z[i][1]) {
            printf("%-2d: frint(%a) -> %a != %a\n",
                   i, f32_i32_z[i][0], x, f32_i32_z[i][1]);
        }
    }

    for (i = 0; i < sizeof(f32_i64_z)/sizeof(f32_i64_z[0]); i++) {
        float x;
        asm("frint64z %s0,%s1" : "=w"(x) : "w"(f32_i64_z[i][0]));
        if (x != f32_i64_z[i][1]) {
            printf("%-2d: frint(%a) -> %a != %a\n",
                   i, f32_i64_z[i][0], x, f32_i64_z[i][1]);
        }
    }

    for (i = 0; i < sizeof(f64_i32_z)/sizeof(f64_i32_z[0]); i++) {
        double x;
        asm("frint32z %d0,%d1" : "=w"(x) : "w"(f64_i32_z[i][0]));
        if (x != f64_i32_z[i][1]) {
            printf("%-2d: frint(%a) -> %a != %a\n",
                   i, f64_i32_z[i][0], x, f64_i32_z[i][1]);
        }
    }

    for (i = 0; i < sizeof(f64_i64_z)/sizeof(f64_i64_z[0]); i++) {
        double x;
        asm("frint64z %d0,%d1" : "=w"(x) : "w"(f64_i64_z[i][0]));
        if (x != f64_i64_z[i][1]) {
            printf("%-2d: frint(%a) -> %a != %a\n",
                   i, f64_i64_z[i][0], x, f64_i64_z[i][1]);
        }
    }

    return 0;
}

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Qemu-devel] [PATCH 1/2] target/arm: Restructure handle_fp_1src_{single, double}
  2019-02-23  1:22 [Qemu-devel] [PATCH 0/2] target/arm: Implement ARMv8.5-FRINT Richard Henderson
@ 2019-02-23  1:22 ` Richard Henderson
  2019-02-23  1:22 ` [Qemu-devel] [PATCH 2/2] target/arm: Implement ARMv8.5-FRINT Richard Henderson
  2019-02-25 10:06 ` [Qemu-devel] [PATCH 0/2] " Laurent Desnogues
  2 siblings, 0 replies; 4+ messages in thread
From: Richard Henderson @ 2019-02-23  1:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

This will allow sharing code that adjusts rmode beyond
the existing users.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/translate-a64.c | 90 +++++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 41 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index d3c8eaf089..fcbf6b16cf 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -5505,55 +5505,59 @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn)
 /* Floating-point data-processing (1 source) - single precision */
 static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
 {
+    void (*gen_fpst)(TCGv_i32, TCGv_i32, TCGv_ptr);
+    TCGv_i32 tcg_op, tcg_res;
     TCGv_ptr fpst;
-    TCGv_i32 tcg_op;
-    TCGv_i32 tcg_res;
+    int rmode = -1;
 
-    fpst = get_fpstatus_ptr(false);
     tcg_op = read_fp_sreg(s, rn);
     tcg_res = tcg_temp_new_i32();
 
     switch (opcode) {
     case 0x0: /* FMOV */
         tcg_gen_mov_i32(tcg_res, tcg_op);
-        break;
+        goto done;
     case 0x1: /* FABS */
         gen_helper_vfp_abss(tcg_res, tcg_op);
-        break;
+        goto done;
     case 0x2: /* FNEG */
         gen_helper_vfp_negs(tcg_res, tcg_op);
-        break;
+        goto done;
     case 0x3: /* FSQRT */
         gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
-        break;
+        goto done;
     case 0x8: /* FRINTN */
     case 0x9: /* FRINTP */
     case 0xa: /* FRINTM */
     case 0xb: /* FRINTZ */
     case 0xc: /* FRINTA */
-    {
-        TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
-
-        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
-        gen_helper_rints(tcg_res, tcg_op, fpst);
-
-        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
-        tcg_temp_free_i32(tcg_rmode);
+        rmode = arm_rmode_to_sf(opcode & 7);
+        gen_fpst = gen_helper_rints;
         break;
-    }
     case 0xe: /* FRINTX */
-        gen_helper_rints_exact(tcg_res, tcg_op, fpst);
+        gen_fpst = gen_helper_rints_exact;
         break;
     case 0xf: /* FRINTI */
-        gen_helper_rints(tcg_res, tcg_op, fpst);
+        gen_fpst = gen_helper_rints;
         break;
     default:
-        abort();
+        g_assert_not_reached();
     }
 
-    write_fp_sreg(s, rd, tcg_res);
-
+    fpst = get_fpstatus_ptr(false);
+    if (rmode >= 0) {
+        TCGv_i32 tcg_rmode = tcg_const_i32(rmode);
+        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
+        gen_fpst(tcg_res, tcg_op, fpst);
+        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
+        tcg_temp_free_i32(tcg_rmode);
+    } else {
+        gen_fpst(tcg_res, tcg_op, fpst);
+    }
     tcg_temp_free_ptr(fpst);
+
+ done:
+    write_fp_sreg(s, rd, tcg_res);
     tcg_temp_free_i32(tcg_op);
     tcg_temp_free_i32(tcg_res);
 }
@@ -5561,9 +5565,10 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
 /* Floating-point data-processing (1 source) - double precision */
 static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
 {
+    void (*gen_fpst)(TCGv_i64, TCGv_i64, TCGv_ptr);
+    TCGv_i64 tcg_op, tcg_res;
     TCGv_ptr fpst;
-    TCGv_i64 tcg_op;
-    TCGv_i64 tcg_res;
+    int rmode = -1;
 
     switch (opcode) {
     case 0x0: /* FMOV */
@@ -5571,48 +5576,51 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
         return;
     }
 
-    fpst = get_fpstatus_ptr(false);
     tcg_op = read_fp_dreg(s, rn);
     tcg_res = tcg_temp_new_i64();
 
     switch (opcode) {
     case 0x1: /* FABS */
         gen_helper_vfp_absd(tcg_res, tcg_op);
-        break;
+        goto done;
     case 0x2: /* FNEG */
         gen_helper_vfp_negd(tcg_res, tcg_op);
-        break;
+        goto done;
     case 0x3: /* FSQRT */
         gen_helper_vfp_sqrtd(tcg_res, tcg_op, cpu_env);
-        break;
+        goto done;
     case 0x8: /* FRINTN */
     case 0x9: /* FRINTP */
     case 0xa: /* FRINTM */
     case 0xb: /* FRINTZ */
     case 0xc: /* FRINTA */
-    {
-        TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
-
-        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
-        gen_helper_rintd(tcg_res, tcg_op, fpst);
-
-        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
-        tcg_temp_free_i32(tcg_rmode);
+        rmode = arm_rmode_to_sf(opcode & 7);
+        gen_fpst = gen_helper_rintd;
         break;
-    }
     case 0xe: /* FRINTX */
-        gen_helper_rintd_exact(tcg_res, tcg_op, fpst);
+        gen_fpst = gen_helper_rintd_exact;
         break;
     case 0xf: /* FRINTI */
-        gen_helper_rintd(tcg_res, tcg_op, fpst);
+        gen_fpst = gen_helper_rintd;
         break;
     default:
-        abort();
+        g_assert_not_reached();
     }
 
-    write_fp_dreg(s, rd, tcg_res);
-
+    fpst = get_fpstatus_ptr(false);
+    if (rmode >= 0) {
+        TCGv_i32 tcg_rmode = tcg_const_i32(rmode);
+        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
+        gen_fpst(tcg_res, tcg_op, fpst);
+        gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
+        tcg_temp_free_i32(tcg_rmode);
+    } else {
+        gen_fpst(tcg_res, tcg_op, fpst);
+    }
     tcg_temp_free_ptr(fpst);
+
+ done:
+    write_fp_dreg(s, rd, tcg_res);
     tcg_temp_free_i64(tcg_op);
     tcg_temp_free_i64(tcg_res);
 }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [Qemu-devel] [PATCH 2/2] target/arm: Implement ARMv8.5-FRINT
  2019-02-23  1:22 [Qemu-devel] [PATCH 0/2] target/arm: Implement ARMv8.5-FRINT Richard Henderson
  2019-02-23  1:22 ` [Qemu-devel] [PATCH 1/2] target/arm: Restructure handle_fp_1src_{single, double} Richard Henderson
@ 2019-02-23  1:22 ` Richard Henderson
  2019-02-25 10:06 ` [Qemu-devel] [PATCH 0/2] " Laurent Desnogues
  2 siblings, 0 replies; 4+ messages in thread
From: Richard Henderson @ 2019-02-23  1:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h           |  5 ++
 target/arm/helper.h        |  5 ++
 target/arm/cpu64.c         |  1 +
 target/arm/translate-a64.c | 71 ++++++++++++++++++++++++++--
 target/arm/vfp_helper.c    | 96 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 173 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 9cf439fb8d..f60a2361fe 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3391,6 +3391,11 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id)
              FIELD_DP64(0, ID_AA64ISAR1, GPI, 0xf))) != 0;
 }
 
+static inline bool isar_feature_aa64_frint(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0;
+}
+
 static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
 {
     /* We always set the AdvSIMD and FP fields identically wrt FP16.  */
diff --git a/target/arm/helper.h b/target/arm/helper.h
index d363904278..c978a1d812 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -686,6 +686,11 @@ DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a32, TCG_CALL_NO_RWG,
 DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a64, TCG_CALL_NO_RWG,
                    void, ptr, ptr, ptr, ptr, i32)
 
+DEF_HELPER_FLAGS_2(frint32_s, TCG_CALL_NO_RWG, f32, f32, ptr)
+DEF_HELPER_FLAGS_2(frint64_s, TCG_CALL_NO_RWG, f32, f32, ptr)
+DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, ptr)
+DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, ptr)
+
 #ifdef TARGET_AARCH64
 #include "helper-a64.h"
 #include "helper-sve.h"
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 1b0c427277..645cc20eb6 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -318,6 +318,7 @@ static void aarch64_max_initfn(Object *obj)
         t = FIELD_DP64(t, ID_AA64ISAR1, API, 0);
         t = FIELD_DP64(t, ID_AA64ISAR1, GPA, 1);
         t = FIELD_DP64(t, ID_AA64ISAR1, GPI, 0);
+        t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1);
         cpu->isar.id_aa64isar1 = t;
 
         t = cpu->isar.id_aa64pfr0;
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index fcbf6b16cf..139e500df8 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -5540,6 +5540,20 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
     case 0xf: /* FRINTI */
         gen_fpst = gen_helper_rints;
         break;
+    case 0x10: /* FRINT32Z */
+        rmode = float_round_to_zero;
+        gen_fpst = gen_helper_frint32_s;
+        break;
+    case 0x11: /* FRINT32X */
+        gen_fpst = gen_helper_frint32_s;
+        break;
+    case 0x12: /* FRINT64Z */
+        rmode = float_round_to_zero;
+        gen_fpst = gen_helper_frint64_s;
+        break;
+    case 0x13: /* FRINT64X */
+        gen_fpst = gen_helper_frint64_s;
+        break;
     default:
         g_assert_not_reached();
     }
@@ -5603,6 +5617,20 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
     case 0xf: /* FRINTI */
         gen_fpst = gen_helper_rintd;
         break;
+    case 0x10: /* FRINT32Z */
+        rmode = float_round_to_zero;
+        gen_fpst = gen_helper_frint32_d;
+        break;
+    case 0x11: /* FRINT32X */
+        gen_fpst = gen_helper_frint32_d;
+        break;
+    case 0x12: /* FRINT64Z */
+        rmode = float_round_to_zero;
+        gen_fpst = gen_helper_frint64_d;
+        break;
+    case 0x13: /* FRINT64X */
+        gen_fpst = gen_helper_frint64_d;
+        break;
     default:
         g_assert_not_reached();
     }
@@ -5739,6 +5767,13 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
         handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
         break;
     }
+
+    case 0x10 ... 0x13: /* FRINT{32,64}{X,Z} */
+        if (type > 1 || !dc_isar_feature(aa64_frint, s)) {
+            unallocated_encoding(s);
+            return;
+        }
+        /* fall through */
     case 0x0 ... 0x3:
     case 0x8 ... 0xc:
     case 0xe ... 0xf:
@@ -5748,14 +5783,12 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
             if (!fp_access_check(s)) {
                 return;
             }
-
             handle_fp_1src_single(s, opcode, rd, rn);
             break;
         case 1:
             if (!fp_access_check(s)) {
                 return;
             }
-
             handle_fp_1src_double(s, opcode, rd, rn);
             break;
         case 3:
@@ -5767,13 +5800,13 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
             if (!fp_access_check(s)) {
                 return;
             }
-
             handle_fp_1src_half(s, opcode, rd, rn);
             break;
         default:
             unallocated_encoding(s);
         }
         break;
+
     default:
         unallocated_encoding(s);
         break;
@@ -9301,6 +9334,14 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u,
     case 0x59: /* FRINTX */
         gen_helper_rintd_exact(tcg_rd, tcg_rn, tcg_fpstatus);
         break;
+    case 0x1e: /* FRINT32Z */
+    case 0x5e: /* FRINT32X */
+        gen_helper_frint32_d(tcg_rd, tcg_rn, tcg_fpstatus);
+        break;
+    case 0x1f: /* FRINT64Z */
+    case 0x5f: /* FRINT64X */
+        gen_helper_frint64_d(tcg_rd, tcg_rn, tcg_fpstatus);
+        break;
     default:
         g_assert_not_reached();
     }
@@ -11951,8 +11992,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
         }
         break;
     case 0xc ... 0xf:
-    case 0x16 ... 0x1d:
-    case 0x1f:
+    case 0x16 ... 0x1f:
     {
         /* Floating point: U, size[1] and opcode indicate operation;
          * size[0] indicates single or double precision.
@@ -12095,6 +12135,19 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
             }
             need_fpstatus = true;
             break;
+        case 0x1e: /* FRINT32Z */
+        case 0x1f: /* FRINT64Z */
+            need_rmode = true;
+            rmode = FPROUNDING_ZERO;
+            /* fall through */
+        case 0x5e: /* FRINT32X */
+        case 0x5f: /* FRINT64X */
+            need_fpstatus = true;
+            if ((size == 3 && !is_q) || !dc_isar_feature(aa64_frint, s)) {
+                unallocated_encoding(s);
+                return;
+            }
+            break;
         default:
             unallocated_encoding(s);
             return;
@@ -12260,6 +12313,14 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
                 case 0x7c: /* URSQRTE */
                     gen_helper_rsqrte_u32(tcg_res, tcg_op, tcg_fpstatus);
                     break;
+                case 0x1e: /* FRINT32Z */
+                case 0x5e: /* FRINT32X */
+                    gen_helper_frint32_s(tcg_res, tcg_op, tcg_fpstatus);
+                    break;
+                case 0x1f: /* FRINT64Z */
+                case 0x5f: /* FRINT64X */
+                    gen_helper_frint64_s(tcg_res, tcg_op, tcg_fpstatus);
+                    break;
                 default:
                     g_assert_not_reached();
                 }
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
index f19c0606c2..c77000606e 100644
--- a/target/arm/vfp_helper.c
+++ b/target/arm/vfp_helper.c
@@ -1174,3 +1174,99 @@ uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env)
 
     return result;
 }
+
+/* Round a float32 to an integer that fits in int32_t or int64_t.  */
+static float32 frint_f32(float32 f, float_status *fpst, int intsize)
+{
+    int old_flags = get_float_exception_flags(fpst);
+    uint32_t exp = extract32(f, 23, 8);
+
+    if (unlikely(exp == 0xff)) {
+        /* NaN or Inf.  */
+        goto overflow;
+    }
+
+    /* Round and re-extract the exponent.  */
+    f = float32_round_to_int(f, fpst);
+    exp = extract32(f, 23, 8);
+
+    /* Validate the range of the result.  */
+    if (exp < 126 + intsize) {
+        /* abs(F) <= INT{N}_MAX */
+        return f;
+    }
+    if (exp == 126 + intsize) {
+        uint32_t sign = extract32(f, 31, 1);
+        uint32_t frac = extract32(f, 0, 23);
+        if (sign && frac == 0) {
+            /* F == INT{N}_MIN */
+            return f;
+        }
+    }
+
+ overflow:
+    /*
+     * Raise Invalid and return INT{N}_MIN as a float.  Revert any
+     * inexact exception float32_round_to_int may have raised.
+     */
+    set_float_exception_flags(old_flags | float_flag_invalid, fpst);
+    return (0x100u + 126u + intsize) << 23;
+}
+
+float32 HELPER(frint32_s)(float32 f, void *fpst)
+{
+    return frint_f32(f, fpst, 32);
+}
+
+float32 HELPER(frint64_s)(float32 f, void *fpst)
+{
+    return frint_f32(f, fpst, 64);
+}
+
+/* Round a float64 to an integer that fits in int32_t or int64_t.  */
+static float64 frint_f64(float64 f, float_status *fpst, int intsize)
+{
+    int old_flags = get_float_exception_flags(fpst);
+    uint32_t exp = extract64(f, 52, 11);
+
+    if (unlikely(exp == 0x7ff)) {
+        /* NaN or Inf.  */
+        goto overflow;
+    }
+
+    /* Round and re-extract the exponent.  */
+    f = float64_round_to_int(f, fpst);
+    exp = extract64(f, 52, 11);
+
+    /* Validate the range of the result.  */
+    if (exp < 1022 + intsize) {
+        /* abs(F) <= INT{N}_MAX */
+        return f;
+    }
+    if (exp == 1022 + intsize) {
+        uint64_t sign = extract64(f, 63, 1);
+        uint64_t frac = extract64(f, 0, 52);
+        if (sign && frac == 0) {
+            /* F == INT{N}_MIN */
+            return f;
+        }
+    }
+
+ overflow:
+    /*
+     * Raise Invalid and return INT{N}_MIN as a float.  Revert any
+     * inexact exception float32_round_to_int may have raised.
+     */
+    set_float_exception_flags(old_flags | float_flag_invalid, fpst);
+    return (uint64_t)(0x800 + 1022 + intsize) << 52;
+}
+
+float64 HELPER(frint32_d)(float64 f, void *fpst)
+{
+    return frint_f64(f, fpst, 32);
+}
+
+float64 HELPER(frint64_d)(float64 f, void *fpst)
+{
+    return frint_f64(f, fpst, 64);
+}
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [PATCH 0/2] target/arm: Implement ARMv8.5-FRINT
  2019-02-23  1:22 [Qemu-devel] [PATCH 0/2] target/arm: Implement ARMv8.5-FRINT Richard Henderson
  2019-02-23  1:22 ` [Qemu-devel] [PATCH 1/2] target/arm: Restructure handle_fp_1src_{single, double} Richard Henderson
  2019-02-23  1:22 ` [Qemu-devel] [PATCH 2/2] target/arm: Implement ARMv8.5-FRINT Richard Henderson
@ 2019-02-25 10:06 ` Laurent Desnogues
  2 siblings, 0 replies; 4+ messages in thread
From: Laurent Desnogues @ 2019-02-25 10:06 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel@nongnu.org, Peter Maydell

Hi Richard,

On Sat, Feb 23, 2019 at 2:23 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Based-on: the ARMv8.2-FHM patch set, although I don't know that
> this is an actual dependency; it's just the tree I started with.
>
> There is not yet support for this extension within FVP, so I've
> self-tested it against my own understanding of what is supposed
> to go on with the file below.

I ran some tests and found no issue.  Your understanding looks correct :-)

Tested-by: Laurent Desnogues <laurent.desnogues@gmail.com>

Thanks,

Laurent


>
> r~
>
>
> Richard Henderson (2):
>   target/arm: Restructure handle_fp_1src_{single,double}
>   target/arm: Implement ARMv8.5-FRINT
>
>  target/arm/cpu.h           |   5 ++
>  target/arm/helper.h        |   5 ++
>  target/arm/cpu64.c         |   1 +
>  target/arm/translate-a64.c | 161 ++++++++++++++++++++++++++-----------
>  target/arm/vfp_helper.c    |  96 ++++++++++++++++++++++
>  5 files changed, 222 insertions(+), 46 deletions(-)
>
> --
>
> #include <stdio.h>
> #include <limits.h>
>
> asm(".arch armv8.5-a");
>
> static const float f32_i32_z[][2] = {
>     { 0, 0 },
>     { -0.0, -0.0 },
>     { 0.9, 0.0 },
>     { 1.0, 1.0 },
>     { 1.1, 1.0 },
>     { 1.9, 1.0 },
>     { 0x1.fffffep30, 0x1.fffffep30 },           /* 2^31 - epsilon */
>     { -0x1p31, -0x1.0p31 },                     /* -2^31 = INT32_MIN */
>     { 0x1.0p31, -0x1.0p31 },                    /* overflow */
>     { 0x1.0p32, -0x1.0p31 },                    /* overflow */
>     { -0x1.0p32, -0x1.0p31 },                   /* overflow */
>     { __builtin_inf(), -0x1.0p31 },             /* overflow */
> };
>
> static const double f64_i32_z[][2] = {
>     { 0, 0 },
>     { -0.0, -0.0 },
>     { 0.9, 0.0 },
>     { 1.0, 1.0 },
>     { 1.1, 1.0 },
>     { 1.9, 1.0 },
>     { 2147483647, 2147483647 },                 /* 2^31 - 1 = INT32_MAX */
>     { -0x1p31, -0x1.0p31 },                     /* -2^31 = INT32_MIN */
>     { 0x1.0p31, -0x1.0p31 },                    /* overflow */
>     { 0x1.0p32, -0x1.0p31 },                    /* overflow */
>     { -0x1.0p32, -0x1.0p31 },                   /* overflow */
>     { __builtin_inf(), -0x1.0p31 },             /* overflow */
> };
>
> static const float f32_i64_z[][2] = {
>     { 0, 0 },
>     { -0.0, -0.0 },
>     { 0.9, 0.0 },
>     { 1.0, 1.0 },
>     { 1.1, 1.0 },
>     { 1.9, 1.0 },
>     { 0x1.fffffep30, 0x1.fffffep30 },           /* 2^31 - epsilon */
>     { -0x1p31, -0x1.0p31 },                     /* -2^31 = INT32_MIN */
>     { 0x1.0p31, 0x1.0p31 },
>     { 0x1.0p32, 0x1.0p32 },
>     { -0x1.0p32, -0x1.0p32 },
>     { 0x1.0p62, 0x1.0p62 },
>     { 0x1.fffffep62, 0x1.fffffep62 },           /* 2^63 - epsilon */
>     { -0x1.0p63, -0x1.0p63 },                   /* -2^63 = INT64_MIN */
>     { 0x1.0p63, -0x1.0p63 },                    /* overflow */
>     { 0x1.0p64, -0x1.0p63 },                    /* overflow */
>     { -0x1.0p64, -0x1.0p63 },                   /* overflow */
>     { __builtin_inf(), -0x1.0p63 },             /* overflow */
> };
>
> static const double f64_i64_z[][2] = {
>     { 0, 0 },
>     { -0.0, -0.0 },
>     { 0.9, 0.0 },
>     { 1.0, 1.0 },
>     { 1.1, 1.0 },
>     { 1.9, 1.0 },
>     { 2147483647, 2147483647 },                 /* 2^31 - 1 = INT32_MAX */
>     { -0x1p31, -0x1.0p31 },                     /* -2^31 = INT32_MIN */
>     { 0x1.0p31, 0x1.0p31 },
>     { 0x1.0p32, 0x1.0p32 },
>     { -0x1.0p32, -0x1.0p32 },
>     { 0x1.0p62, 0x1.0p62 },
>     { 0x1.fffffffffffffp62, 0x1.fffffffffffffp62 }, /* 2^63 - epsilon */
>     { -0x1.0p63, -0x1.0p63 },                   /* -2^63 = INT64_MIN */
>     { 0x1.0p63, -0x1.0p63 },                    /* overflow */
>     { 0x1.0p64, -0x1.0p63 },                    /* overflow */
>     { -0x1.0p64, -0x1.0p63 },                   /* overflow */
>     { __builtin_inf(), -0x1.0p63 },             /* overflow */
> };
>
> int main()
> {
>     int i;
>
>     for (i = 0; i < sizeof(f32_i32_z)/sizeof(f32_i32_z[0]); i++) {
>         float x;
>         asm("frint32z %s0,%s1" : "=w"(x) : "w"(f32_i32_z[i][0]));
>         if (x != f32_i32_z[i][1]) {
>             printf("%-2d: frint(%a) -> %a != %a\n",
>                    i, f32_i32_z[i][0], x, f32_i32_z[i][1]);
>         }
>     }
>
>     for (i = 0; i < sizeof(f32_i64_z)/sizeof(f32_i64_z[0]); i++) {
>         float x;
>         asm("frint64z %s0,%s1" : "=w"(x) : "w"(f32_i64_z[i][0]));
>         if (x != f32_i64_z[i][1]) {
>             printf("%-2d: frint(%a) -> %a != %a\n",
>                    i, f32_i64_z[i][0], x, f32_i64_z[i][1]);
>         }
>     }
>
>     for (i = 0; i < sizeof(f64_i32_z)/sizeof(f64_i32_z[0]); i++) {
>         double x;
>         asm("frint32z %d0,%d1" : "=w"(x) : "w"(f64_i32_z[i][0]));
>         if (x != f64_i32_z[i][1]) {
>             printf("%-2d: frint(%a) -> %a != %a\n",
>                    i, f64_i32_z[i][0], x, f64_i32_z[i][1]);
>         }
>     }
>
>     for (i = 0; i < sizeof(f64_i64_z)/sizeof(f64_i64_z[0]); i++) {
>         double x;
>         asm("frint64z %d0,%d1" : "=w"(x) : "w"(f64_i64_z[i][0]));
>         if (x != f64_i64_z[i][1]) {
>             printf("%-2d: frint(%a) -> %a != %a\n",
>                    i, f64_i64_z[i][0], x, f64_i64_z[i][1]);
>         }
>     }
>
>     return 0;
> }
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-02-25 10:06 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-02-23  1:22 [Qemu-devel] [PATCH 0/2] target/arm: Implement ARMv8.5-FRINT Richard Henderson
2019-02-23  1:22 ` [Qemu-devel] [PATCH 1/2] target/arm: Restructure handle_fp_1src_{single, double} Richard Henderson
2019-02-23  1:22 ` [Qemu-devel] [PATCH 2/2] target/arm: Implement ARMv8.5-FRINT Richard Henderson
2019-02-25 10:06 ` [Qemu-devel] [PATCH 0/2] " Laurent Desnogues

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).