aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2025-02-01 16:39:35 +0000
committerPeter Maydell <peter.maydell@linaro.org>2025-02-11 16:22:07 +0000
commitd091ce2d3f5bad6df30c686558807bcffb0c5a96 (patch)
treeda7731a41dc13491edcc5374c9db3b33b0b013f8
parente76df44d2dd06018016f35aff41258ce356d6e40 (diff)
downloadqemu-d091ce2d3f5bad6df30c686558807bcffb0c5a96.zip
qemu-d091ce2d3f5bad6df30c686558807bcffb0c5a96.tar.gz
qemu-d091ce2d3f5bad6df30c686558807bcffb0c5a96.tar.bz2
target/arm: Implement FPCR.AH handling for scalar FABS and FABD
FPCR.AH == 1 mandates that taking the absolute value of a NaN should not change its sign bit. This means we can no longer use gen_vfp_abs*() everywhere but must instead generate slightly more complex code when FPCR.AH is set. Implement these semantics for scalar FABS and FABD. This change also affects all other instructions whose psuedocode calls FPAbs(); we will extend the change to those instructions in following commits. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--target/arm/tcg/translate-a64.c69
1 files changed, 67 insertions, 2 deletions
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index abd0d91..83cfcdc 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -869,6 +869,43 @@ static void gen_vfp_ah_negd(TCGv_i64 d, TCGv_i64 s)
s, chs_s);
}
+/*
+ * These functions implement
+ * d = floatN_is_any_nan(s) ? s : floatN_abs(s)
+ * which for float32 is
+ * d = (s & ~(1 << 31)) > 0x7f800000UL) ? s : (s & ~(1 << 31))
+ * and similarly for the other float sizes.
+ */
+static void gen_vfp_ah_absh(TCGv_i32 d, TCGv_i32 s)
+{
+ TCGv_i32 abs_s = tcg_temp_new_i32();
+
+ gen_vfp_absh(abs_s, s);
+ tcg_gen_movcond_i32(TCG_COND_GTU, d,
+ abs_s, tcg_constant_i32(0x7c00),
+ s, abs_s);
+}
+
+static void gen_vfp_ah_abss(TCGv_i32 d, TCGv_i32 s)
+{
+ TCGv_i32 abs_s = tcg_temp_new_i32();
+
+ gen_vfp_abss(abs_s, s);
+ tcg_gen_movcond_i32(TCG_COND_GTU, d,
+ abs_s, tcg_constant_i32(0x7f800000UL),
+ s, abs_s);
+}
+
+static void gen_vfp_ah_absd(TCGv_i64 d, TCGv_i64 s)
+{
+ TCGv_i64 abs_s = tcg_temp_new_i64();
+
+ gen_vfp_absd(abs_s, s);
+ tcg_gen_movcond_i64(TCG_COND_GTU, d,
+ abs_s, tcg_constant_i64(0x7ff0000000000000ULL),
+ s, abs_s);
+}
+
static void gen_vfp_maybe_ah_negh(DisasContext *dc, TCGv_i32 d, TCGv_i32 s)
{
if (dc->fpcr_ah) {
@@ -5392,12 +5429,35 @@ static void gen_fabd_d(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_ptr s)
gen_vfp_absd(d, d);
}
+static void gen_fabd_ah_h(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m, TCGv_ptr s)
+{
+ gen_helper_vfp_subh(d, n, m, s);
+ gen_vfp_ah_absh(d, d);
+}
+
+static void gen_fabd_ah_s(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m, TCGv_ptr s)
+{
+ gen_helper_vfp_subs(d, n, m, s);
+ gen_vfp_ah_abss(d, d);
+}
+
+static void gen_fabd_ah_d(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_ptr s)
+{
+ gen_helper_vfp_subd(d, n, m, s);
+ gen_vfp_ah_absd(d, d);
+}
+
static const FPScalar f_scalar_fabd = {
gen_fabd_h,
gen_fabd_s,
gen_fabd_d,
};
-TRANS(FABD_s, do_fp3_scalar, a, &f_scalar_fabd, a->rn)
+static const FPScalar f_scalar_ah_fabd = {
+ gen_fabd_ah_h,
+ gen_fabd_ah_s,
+ gen_fabd_ah_d,
+};
+TRANS(FABD_s, do_fp3_scalar_2fn, a, &f_scalar_fabd, &f_scalar_ah_fabd, a->rn)
static const FPScalar f_scalar_frecps = {
gen_helper_recpsf_f16,
@@ -8643,7 +8703,12 @@ static const FPScalar1Int f_scalar_fabs = {
gen_vfp_abss,
gen_vfp_absd,
};
-TRANS(FABS_s, do_fp1_scalar_int, a, &f_scalar_fabs, true)
+static const FPScalar1Int f_scalar_ah_fabs = {
+ gen_vfp_ah_absh,
+ gen_vfp_ah_abss,
+ gen_vfp_ah_absd,
+};
+TRANS(FABS_s, do_fp1_scalar_int_2fn, a, &f_scalar_fabs, &f_scalar_ah_fabs)
static const FPScalar1Int f_scalar_fneg = {
gen_vfp_negh,