qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 2/4] target/ppc: Implement instruction caching for fsqrt


From: Víctor Colombo
Subject: [RFC PATCH 2/4] target/ppc: Implement instruction caching for fsqrt
Date: Wed, 5 Oct 2022 11:37:17 -0300

This patch adds the code necessary to cache fsqrt for usage
with hardfpu in Power. It is also the first instruction to
use the new cache instruction system.

fsqrt is an instruction that receives two arguments, one f64 and
one status, and returns f64. This info will be cached inside a new
union in env, which will grow when other instructions with other
signatures are added.

Hardfpu in QEMU only works when the inexact is already set. So,
CACHE_FN_3 will check if FP_XX is set, and set float_flag_inexact
to enable the hardfpu behavior. When the instruction is later
reexecuted, it will be with float_flag_inexact cleared, forcing
softfloat and correctly updating the relevant flags, as is today.

Signed-off-by: Víctor Colombo <victor.colombo@eldorado.org.br>
---
 target/ppc/cpu.h        | 11 +++++++++++
 target/ppc/fpu_helper.c | 39 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 1132d60162..b423e33a0c 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1082,6 +1082,14 @@ struct ppc_radix_page_info {
 
 enum {
     CACHED_FN_TYPE_NONE,
+    CACHED_FN_TYPE_F64_F64_FSTATUS,
+
+};
+
+struct cached_fn_f64_f64_fstatus {
+    float64 (*fn)(float64, float_status*);
+    float64 arg1;
+    float_status arg2;
 };
 
 struct CPUArchState {
@@ -1162,6 +1170,9 @@ struct CPUArchState {
     target_ulong fpscr;     /* Floating point status and control register */
 
     int cached_fn_type;
+    union {
+        struct cached_fn_f64_f64_fstatus f64_f64_fstatus;
+    } cached_fn;
 
     /* Internal devices resources */
     ppc_tb_t *tb_env;      /* Time base and decrementer */
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 6aaee37619..b68f12a1a9 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -30,6 +30,21 @@
         env->cached_fn_type = CACHED_FN_TYPE_NONE;                            \
     } while (0)
 
+#define CACHE_FN_3(env, FN, ARG1, ARG2, FIELD, TYPE)                          \
+    do {                                                                      \
+        if (env->fpscr & FP_XX) {                                             \
+            env->cached_fn_type = TYPE;                                       \
+            env->cached_fn.FIELD.fn = FN;                                     \
+            env->cached_fn.FIELD.arg1 = ARG1;                                 \
+            env->cached_fn.FIELD.arg2 = ARG2;                                 \
+            env->fp_status.float_exception_flags |= float_flag_inexact;       \
+        } else {                                                              \
+            assert(!(env->fp_status.float_exception_flags &                   \
+                     float_flag_inexact));                                    \
+            env->cached_fn_type = CACHED_FN_TYPE_NONE;                        \
+        }                                                                     \
+    } while (0)
+
 static inline float128 float128_snan_to_qnan(float128 x)
 {
     float128 r;
@@ -530,6 +545,27 @@ void helper_execute_fp_cached(CPUPPCState *env)
          * so no need to execute it again
          */
         break;
+    case CACHED_FN_TYPE_F64_F64_FSTATUS:
+        /*
+         * execute the cached insn. At this point, float_exception_flags
+         * should have FI not set, otherwise the result will not be correct
+         */
+        assert((env->cached_fn.f64_f64_fstatus.arg2.float_exception_flags &
+               float_flag_inexact) == 0);
+        env->cached_fn.f64_f64_fstatus.fn(
+            env->cached_fn.f64_f64_fstatus.arg1,
+            &env->cached_fn.f64_f64_fstatus.arg2);
+
+        env->fpscr &= ~FP_FI;
+        /*
+         * if the cached instruction resulted in FI being set
+         * then we update fpscr with this value
+         */
+        if (env->cached_fn.f64_f64_fstatus.arg2.float_exception_flags &
+            float_flag_inexact) {
+            env->fpscr |= FP_FI | FP_XX;
+        }
+        break;
     default:
         g_assert_not_reached();
     }
@@ -872,7 +908,8 @@ static void float_invalid_op_sqrt(CPUPPCState *env, int 
flags,
 #define FPU_FSQRT(name, op)                                                   \
 float64 helper_##name(CPUPPCState *env, float64 arg)                          \
 {                                                                             \
-    CACHE_FN_NONE(env);                                                       \
+    CACHE_FN_3(env, op, arg, env->fp_status, f64_f64_fstatus,                 \
+        CACHED_FN_TYPE_F64_F64_FSTATUS);                                      \
     float64 ret = op(arg, &env->fp_status);                                   \
     int flags = get_float_exception_flags(&env->fp_status);                   \
                                                                               \
-- 
2.25.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]