* [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).