diff mbox

[v2,21/24] target-sparc: Use explicit writes to cpu_fsr

Message ID 1456261920-29900-22-git-send-email-rth@twiddle.net (mailing list archive)
State New, archived
Headers show

Commit Message

Richard Henderson Feb. 23, 2016, 9:11 p.m. UTC
By arranging for explicit writes to cpu_fsr after floating point
operations, we are able to mark the helpers as not writing to
tcg globals, which means that we don't need to invalidate the
integer register set across said calls.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-sparc/fop_helper.c | 223 +++++++++++++++-------------------------------
 target-sparc/helper.h     | 112 +++++++++++------------
 target-sparc/translate.c  |  76 +++++++++-------
 3 files changed, 174 insertions(+), 237 deletions(-)
diff mbox

Patch

diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index 0830643..cdc58ea 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -24,43 +24,46 @@ 
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
 
-static void check_ieee_exceptions(CPUSPARCState *env)
+target_ulong helper_check_ieee_exceptions(CPUSPARCState *env)
 {
-    target_ulong status;
+    target_ulong status = get_float_exception_flags(&env->fp_status);
+    target_ulong fsr = env->fsr;
+
+    if (unlikely(status)) {
+        /* Keep exception flags clear for next time.  */
+        set_float_exception_flags(0, &env->fp_status);
 
-    status = get_float_exception_flags(&env->fp_status);
-    if (status) {
         /* Copy IEEE 754 flags into FSR */
         if (status & float_flag_invalid) {
-            env->fsr |= FSR_NVC;
+            fsr |= FSR_NVC;
         }
         if (status & float_flag_overflow) {
-            env->fsr |= FSR_OFC;
+            fsr |= FSR_OFC;
         }
         if (status & float_flag_underflow) {
-            env->fsr |= FSR_UFC;
+            fsr |= FSR_UFC;
         }
         if (status & float_flag_divbyzero) {
-            env->fsr |= FSR_DZC;
+            fsr |= FSR_DZC;
         }
         if (status & float_flag_inexact) {
-            env->fsr |= FSR_NXC;
+            fsr |= FSR_NXC;
         }
 
-        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
-            /* Unmasked exception, generate a trap */
-            env->fsr |= FSR_FTT_IEEE_EXCP;
+        if ((fsr & FSR_CEXC_MASK) & ((fsr & FSR_TEM_MASK) >> 23)) {
+            /* Unmasked exception, generate a trap.  Note that while
+               the helper is marked as NO_WG, we can get away with
+               writing to cpu state along the exception path, since
+               TCG generated code will never see the write.  */
+            env->fsr = fsr | FSR_FTT_IEEE_EXCP;
             helper_raise_exception(env, TT_FP_EXCP);
         } else {
             /* Accumulate exceptions */
-            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+            fsr |= (fsr & FSR_CEXC_MASK) << 5;
         }
     }
-}
 
-static inline void clear_float_exceptions(CPUSPARCState *env)
-{
-    set_float_exception_flags(0, &env->fp_status);
+    return fsr;
 }
 
 #define F_HELPER(name, p) void helper_f##name##p(CPUSPARCState *env)
@@ -69,26 +72,16 @@  static inline void clear_float_exceptions(CPUSPARCState *env)
     float32 helper_f ## name ## s (CPUSPARCState *env, float32 src1, \
                                    float32 src2)                \
     {                                                           \
-        float32 ret;                                            \
-        clear_float_exceptions(env);                            \
-        ret = float32_ ## name (src1, src2, &env->fp_status);   \
-        check_ieee_exceptions(env);                             \
-        return ret;                                             \
+        return float32_ ## name (src1, src2, &env->fp_status);  \
     }                                                           \
     float64 helper_f ## name ## d (CPUSPARCState * env, float64 src1,\
                                    float64 src2)                \
     {                                                           \
-        float64 ret;                                            \
-        clear_float_exceptions(env);                            \
-        ret = float64_ ## name (src1, src2, &env->fp_status);   \
-        check_ieee_exceptions(env);                             \
-        return ret;                                             \
+        return float64_ ## name (src1, src2, &env->fp_status);  \
     }                                                           \
     F_HELPER(name, q)                                           \
     {                                                           \
-        clear_float_exceptions(env);                            \
         QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
-        check_ieee_exceptions(env);                             \
     }
 
 F_BINOP(add);
@@ -99,22 +92,16 @@  F_BINOP(div);
 
 float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float64_mul(float32_to_float64(src1, &env->fp_status),
-                      float32_to_float64(src2, &env->fp_status),
-                      &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_mul(float32_to_float64(src1, &env->fp_status),
+                       float32_to_float64(src2, &env->fp_status),
+                       &env->fp_status);
 }
 
 void helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2)
 {
-    clear_float_exceptions(env);
     QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
                        float64_to_float128(src2, &env->fp_status),
                        &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 float32 helper_fnegs(float32 src)
@@ -137,48 +124,32 @@  F_HELPER(neg, q)
 /* Integer to float conversion.  */
 float32 helper_fitos(CPUSPARCState *env, int32_t src)
 {
-    /* Inexact error possible converting int to float.  */
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = int32_to_float32(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return int32_to_float32(src, &env->fp_status);
 }
 
 float64 helper_fitod(CPUSPARCState *env, int32_t src)
 {
-    /* No possible exceptions converting int to double.  */
     return int32_to_float64(src, &env->fp_status);
 }
 
 void helper_fitoq(CPUSPARCState *env, int32_t src)
 {
-    /* No possible exceptions converting int to long double.  */
     QT0 = int32_to_float128(src, &env->fp_status);
 }
 
 #ifdef TARGET_SPARC64
 float32 helper_fxtos(CPUSPARCState *env, int64_t src)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = int64_to_float32(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return int64_to_float32(src, &env->fp_status);
 }
 
 float64 helper_fxtod(CPUSPARCState *env, int64_t src)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = int64_to_float64(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return int64_to_float64(src, &env->fp_status);
 }
 
 void helper_fxtoq(CPUSPARCState *env, int64_t src)
 {
-    /* No possible exceptions converting long long to long double.  */
     QT0 = int64_to_float128(src, &env->fp_status);
 }
 #endif
@@ -187,108 +158,64 @@  void helper_fxtoq(CPUSPARCState *env, int64_t src)
 /* floating point conversion */
 float32 helper_fdtos(CPUSPARCState *env, float64 src)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = float64_to_float32(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_to_float32(src, &env->fp_status);
 }
 
 float64 helper_fstod(CPUSPARCState *env, float32 src)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float32_to_float64(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_to_float64(src, &env->fp_status);
 }
 
 float32 helper_fqtos(CPUSPARCState *env)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = float128_to_float32(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_float32(QT1, &env->fp_status);
 }
 
 void helper_fstoq(CPUSPARCState *env, float32 src)
 {
-    clear_float_exceptions(env);
     QT0 = float32_to_float128(src, &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 float64 helper_fqtod(CPUSPARCState *env)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float128_to_float64(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_float64(QT1, &env->fp_status);
 }
 
 void helper_fdtoq(CPUSPARCState *env, float64 src)
 {
-    clear_float_exceptions(env);
     QT0 = float64_to_float128(src, &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 /* Float to integer conversion.  */
 int32_t helper_fstoi(CPUSPARCState *env, float32 src)
 {
-    int32_t ret;
-    clear_float_exceptions(env);
-    ret = float32_to_int32_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_to_int32_round_to_zero(src, &env->fp_status);
 }
 
 int32_t helper_fdtoi(CPUSPARCState *env, float64 src)
 {
-    int32_t ret;
-    clear_float_exceptions(env);
-    ret = float64_to_int32_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_to_int32_round_to_zero(src, &env->fp_status);
 }
 
 int32_t helper_fqtoi(CPUSPARCState *env)
 {
-    int32_t ret;
-    clear_float_exceptions(env);
-    ret = float128_to_int32_round_to_zero(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
 }
 
 #ifdef TARGET_SPARC64
 int64_t helper_fstox(CPUSPARCState *env, float32 src)
 {
-    int64_t ret;
-    clear_float_exceptions(env);
-    ret = float32_to_int64_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_to_int64_round_to_zero(src, &env->fp_status);
 }
 
 int64_t helper_fdtox(CPUSPARCState *env, float64 src)
 {
-    int64_t ret;
-    clear_float_exceptions(env);
-    ret = float64_to_int64_round_to_zero(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_to_int64_round_to_zero(src, &env->fp_status);
 }
 
 int64_t helper_fqtox(CPUSPARCState *env)
 {
-    int64_t ret;
-    clear_float_exceptions(env);
-    ret = float128_to_int64_round_to_zero(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float128_to_int64_round_to_zero(QT1, &env->fp_status);
 }
 #endif
 
@@ -311,87 +238,79 @@  void helper_fabsq(CPUSPARCState *env)
 
 float32 helper_fsqrts(CPUSPARCState *env, float32 src)
 {
-    float32 ret;
-    clear_float_exceptions(env);
-    ret = float32_sqrt(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float32_sqrt(src, &env->fp_status);
 }
 
 float64 helper_fsqrtd(CPUSPARCState *env, float64 src)
 {
-    float64 ret;
-    clear_float_exceptions(env);
-    ret = float64_sqrt(src, &env->fp_status);
-    check_ieee_exceptions(env);
-    return ret;
+    return float64_sqrt(src, &env->fp_status);
 }
 
 void helper_fsqrtq(CPUSPARCState *env)
 {
-    clear_float_exceptions(env);
     QT0 = float128_sqrt(QT1, &env->fp_status);
-    check_ieee_exceptions(env);
 }
 
 #define GEN_FCMP(name, size, reg1, reg2, FS, E)                         \
-    void glue(helper_, name) (CPUSPARCState *env)                       \
+    target_ulong glue(helper_, name) (CPUSPARCState *env)               \
     {                                                                   \
         int ret;                                                        \
-        clear_float_exceptions(env);                                    \
+        target_ulong fsr;                                               \
         if (E) {                                                        \
             ret = glue(size, _compare)(reg1, reg2, &env->fp_status);    \
         } else {                                                        \
             ret = glue(size, _compare_quiet)(reg1, reg2,                \
                                              &env->fp_status);          \
         }                                                               \
-        check_ieee_exceptions(env);                                     \
+        fsr = helper_check_ieee_exceptions(env);                        \
         switch (ret) {                                                  \
         case float_relation_unordered:                                  \
-            env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                    \
-            env->fsr |= FSR_NVA;                                        \
+            fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
+            fsr |= FSR_NVA;                                             \
             break;                                                      \
         case float_relation_less:                                       \
-            env->fsr &= ~(FSR_FCC1) << FS;                              \
-            env->fsr |= FSR_FCC0 << FS;                                 \
+            fsr &= ~(FSR_FCC1) << FS;                                   \
+            fsr |= FSR_FCC0 << FS;                                      \
             break;                                                      \
         case float_relation_greater:                                    \
-            env->fsr &= ~(FSR_FCC0) << FS;                              \
-            env->fsr |= FSR_FCC1 << FS;                                 \
+            fsr &= ~(FSR_FCC0) << FS;                                   \
+            fsr |= FSR_FCC1 << FS;                                      \
             break;                                                      \
         default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                      \
             break;                                                      \
         }                                                               \
+        return fsr;                                                     \
     }
 #define GEN_FCMP_T(name, size, FS, E)                                   \
-    void glue(helper_, name)(CPUSPARCState *env, size src1, size src2)  \
+    target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\
     {                                                                   \
         int ret;                                                        \
-        clear_float_exceptions(env);                                    \
+        target_ulong fsr;                                               \
         if (E) {                                                        \
             ret = glue(size, _compare)(src1, src2, &env->fp_status);    \
         } else {                                                        \
             ret = glue(size, _compare_quiet)(src1, src2,                \
                                              &env->fp_status);          \
         }                                                               \
-        check_ieee_exceptions(env);                                     \
+        fsr = helper_check_ieee_exceptions(env);                        \
         switch (ret) {                                                  \
         case float_relation_unordered:                                  \
-            env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                    \
+            fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
             break;                                                      \
         case float_relation_less:                                       \
-            env->fsr &= ~(FSR_FCC1 << FS);                              \
-            env->fsr |= FSR_FCC0 << FS;                                 \
+            fsr &= ~(FSR_FCC1 << FS);                                   \
+            fsr |= FSR_FCC0 << FS;                                      \
             break;                                                      \
         case float_relation_greater:                                    \
-            env->fsr &= ~(FSR_FCC0 << FS);                              \
-            env->fsr |= FSR_FCC1 << FS;                                 \
+            fsr &= ~(FSR_FCC0 << FS);                                   \
+            fsr |= FSR_FCC1 << FS;                                      \
             break;                                                      \
         default:                                                        \
-            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
+            fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                      \
             break;                                                      \
         }                                                               \
+        return fsr;                                                     \
     }
 
 GEN_FCMP_T(fcmps, float32, 0, 0);
@@ -431,11 +350,11 @@  GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
 #undef GEN_FCMP_T
 #undef GEN_FCMP
 
-static inline void set_fsr(CPUSPARCState *env)
+static void set_fsr(CPUSPARCState *env, target_ulong fsr)
 {
     int rnd_mode;
 
-    switch (env->fsr & FSR_RD_MASK) {
+    switch (fsr & FSR_RD_MASK) {
     case FSR_RD_NEAREST:
         rnd_mode = float_round_nearest_even;
         break;
@@ -453,16 +372,20 @@  static inline void set_fsr(CPUSPARCState *env)
     set_float_rounding_mode(rnd_mode, &env->fp_status);
 }
 
-void helper_ldfsr(CPUSPARCState *env, uint32_t new_fsr)
+target_ulong helper_ldfsr(CPUSPARCState *env, target_ulong old_fsr,
+                          uint32_t new_fsr)
 {
-    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
-    set_fsr(env);
+    old_fsr = (new_fsr & FSR_LDFSR_MASK) | (old_fsr & FSR_LDFSR_OLDMASK);
+    set_fsr(env, old_fsr);
+    return old_fsr;
 }
 
 #ifdef TARGET_SPARC64
-void helper_ldxfsr(CPUSPARCState *env, uint64_t new_fsr)
+target_ulong helper_ldxfsr(CPUSPARCState *env, target_ulong old_fsr,
+                           uint64_t new_fsr)
 {
-    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
-    set_fsr(env);
+    old_fsr = (new_fsr & FSR_LDXFSR_MASK) | (old_fsr & FSR_LDXFSR_OLDMASK);
+    set_fsr(env, old_fsr);
+    return old_fsr;
 }
 #endif
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index b506706..caa2a89 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -49,86 +49,88 @@  DEF_HELPER_FLAGS_3(stqf, TCG_CALL_NO_WG, void, env, tl, int)
 DEF_HELPER_FLAGS_4(ld_asi, TCG_CALL_NO_WG, i64, env, tl, int, i32)
 DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, i32)
 #endif
-DEF_HELPER_2(ldfsr, void, env, i32)
+DEF_HELPER_FLAGS_1(check_ieee_exceptions, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_3(ldfsr, TCG_CALL_NO_RWG, tl, env, tl, i32)
 DEF_HELPER_FLAGS_1(fabss, TCG_CALL_NO_RWG_SE, f32, f32)
-DEF_HELPER_2(fsqrts, f32, env, f32)
-DEF_HELPER_2(fsqrtd, f64, env, f64)
-DEF_HELPER_3(fcmps, void, env, f32, f32)
-DEF_HELPER_3(fcmpd, void, env, f64, f64)
-DEF_HELPER_3(fcmpes, void, env, f32, f32)
-DEF_HELPER_3(fcmped, void, env, f64, f64)
-DEF_HELPER_1(fsqrtq, void, env)
-DEF_HELPER_1(fcmpq, void, env)
-DEF_HELPER_1(fcmpeq, void, env)
+DEF_HELPER_FLAGS_2(fsqrts, TCG_CALL_NO_RWG, f32, env, f32)
+DEF_HELPER_FLAGS_2(fsqrtd, TCG_CALL_NO_RWG, f64, env, f64)
+DEF_HELPER_FLAGS_3(fcmps, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpd, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpes, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmped, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_1(fsqrtq, TCG_CALL_NO_RWG, void, env)
+DEF_HELPER_FLAGS_1(fcmpq, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq, TCG_CALL_NO_WG, tl, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_2(ldxfsr, void, env, i64)
+DEF_HELPER_FLAGS_3(ldxfsr, TCG_CALL_NO_RWG, tl, env, tl, i64)
 DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_NO_RWG_SE, f64, f64)
-DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
-DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
-DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
-DEF_HELPER_3(fcmpd_fcc1, void, env, f64, f64)
-DEF_HELPER_3(fcmpd_fcc2, void, env, f64, f64)
-DEF_HELPER_3(fcmpd_fcc3, void, env, f64, f64)
-DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
-DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
-DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
-DEF_HELPER_3(fcmped_fcc1, void, env, f64, f64)
-DEF_HELPER_3(fcmped_fcc2, void, env, f64, f64)
-DEF_HELPER_3(fcmped_fcc3, void, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmps_fcc1, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmps_fcc2, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmps_fcc3, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpd_fcc1, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpd_fcc2, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpd_fcc3, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmpes_fcc1, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpes_fcc2, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmpes_fcc3, TCG_CALL_NO_WG, tl, env, f32, f32)
+DEF_HELPER_FLAGS_3(fcmped_fcc1, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmped_fcc2, TCG_CALL_NO_WG, tl, env, f64, f64)
+DEF_HELPER_FLAGS_3(fcmped_fcc3, TCG_CALL_NO_WG, tl, env, f64, f64)
 DEF_HELPER_FLAGS_1(fabsq, TCG_CALL_NO_RWG, void, env)
-DEF_HELPER_1(fcmpq_fcc1, void, env)
-DEF_HELPER_1(fcmpq_fcc2, void, env)
-DEF_HELPER_1(fcmpq_fcc3, void, env)
-DEF_HELPER_1(fcmpeq_fcc1, void, env)
-DEF_HELPER_1(fcmpeq_fcc2, void, env)
-DEF_HELPER_1(fcmpeq_fcc3, void, env)
+DEF_HELPER_FLAGS_1(fcmpq_fcc1, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpq_fcc2, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpq_fcc3, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq_fcc1, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq_fcc2, TCG_CALL_NO_WG, tl, env)
+DEF_HELPER_FLAGS_1(fcmpeq_fcc3, TCG_CALL_NO_WG, tl, env)
 #endif
 DEF_HELPER_2(raise_exception, noreturn, env, int)
-#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
+#define F_HELPER_0_1(name) \
+  DEF_HELPER_FLAGS_1(f ## name, TCG_CALL_NO_RWG, void, env)
 
-DEF_HELPER_3(faddd, f64, env, f64, f64)
-DEF_HELPER_3(fsubd, f64, env, f64, f64)
-DEF_HELPER_3(fmuld, f64, env, f64, f64)
-DEF_HELPER_3(fdivd, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fsubd, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fmuld, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fdivd, TCG_CALL_NO_RWG, f64, env, f64, f64)
 F_HELPER_0_1(addq)
 F_HELPER_0_1(subq)
 F_HELPER_0_1(mulq)
 F_HELPER_0_1(divq)
 
-DEF_HELPER_3(fadds, f32, env, f32, f32)
-DEF_HELPER_3(fsubs, f32, env, f32, f32)
-DEF_HELPER_3(fmuls, f32, env, f32, f32)
-DEF_HELPER_3(fdivs, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fadds, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fsubs, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fmuls, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fdivs, TCG_CALL_NO_RWG, f32, env, f32, f32)
 
-DEF_HELPER_3(fsmuld, f64, env, f32, f32)
-DEF_HELPER_3(fdmulq, void, env, f64, f64)
+DEF_HELPER_FLAGS_3(fsmuld, TCG_CALL_NO_RWG, f64, env, f32, f32)
+DEF_HELPER_FLAGS_3(fdmulq, TCG_CALL_NO_RWG, void, env, f64, f64)
 
 DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_NO_RWG_SE, f32, f32)
 DEF_HELPER_FLAGS_2(fitod, TCG_CALL_NO_RWG_SE, f64, env, s32)
 DEF_HELPER_FLAGS_2(fitoq, TCG_CALL_NO_RWG, void, env, s32)
 
-DEF_HELPER_2(fitos, f32, env, s32)
+DEF_HELPER_FLAGS_2(fitos, TCG_CALL_NO_RWG, f32, env, s32)
 
 #ifdef TARGET_SPARC64
 DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_NO_RWG_SE, f64, f64)
 DEF_HELPER_FLAGS_1(fnegq, TCG_CALL_NO_RWG, void, env)
-DEF_HELPER_2(fxtos, f32, env, s64)
-DEF_HELPER_2(fxtod, f64, env, s64)
+DEF_HELPER_FLAGS_2(fxtos, TCG_CALL_NO_RWG, f32, env, s64)
+DEF_HELPER_FLAGS_2(fxtod, TCG_CALL_NO_RWG, f64, env, s64)
 DEF_HELPER_FLAGS_2(fxtoq, TCG_CALL_NO_RWG, void, env, s64)
 #endif
-DEF_HELPER_2(fdtos, f32, env, f64)
-DEF_HELPER_2(fstod, f64, env, f32)
-DEF_HELPER_1(fqtos, f32, env)
-DEF_HELPER_2(fstoq, void, env, f32)
-DEF_HELPER_1(fqtod, f64, env)
-DEF_HELPER_2(fdtoq, void, env, f64)
-DEF_HELPER_2(fstoi, s32, env, f32)
-DEF_HELPER_2(fdtoi, s32, env, f64)
-DEF_HELPER_1(fqtoi, s32, env)
+DEF_HELPER_FLAGS_2(fdtos, TCG_CALL_NO_RWG, f32, env, f64)
+DEF_HELPER_FLAGS_2(fstod, TCG_CALL_NO_RWG, f64, env, f32)
+DEF_HELPER_FLAGS_1(fqtos, TCG_CALL_NO_RWG, f32, env)
+DEF_HELPER_FLAGS_2(fstoq, TCG_CALL_NO_RWG, void, env, f32)
+DEF_HELPER_FLAGS_1(fqtod, TCG_CALL_NO_RWG, f64, env)
+DEF_HELPER_FLAGS_2(fdtoq, TCG_CALL_NO_RWG, void, env, f64)
+DEF_HELPER_FLAGS_2(fstoi, TCG_CALL_NO_RWG, s32, env, f32)
+DEF_HELPER_FLAGS_2(fdtoi, TCG_CALL_NO_RWG, s32, env, f64)
+DEF_HELPER_FLAGS_1(fqtoi, TCG_CALL_NO_RWG, s32, env)
 #ifdef TARGET_SPARC64
-DEF_HELPER_2(fstox, s64, env, f32)
-DEF_HELPER_2(fdtox, s64, env, f64)
-DEF_HELPER_1(fqtox, s64, env)
+DEF_HELPER_FLAGS_2(fstox, TCG_CALL_NO_RWG, s64, env, f32)
+DEF_HELPER_FLAGS_2(fdtox, TCG_CALL_NO_RWG, s64, env, f64)
+DEF_HELPER_FLAGS_1(fqtox, TCG_CALL_NO_RWG, s64, env)
 
 DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index f1164a8..ab5b0b6 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1506,16 +1506,16 @@  static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmps_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1524,16 +1524,16 @@  static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpd_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpd_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpd_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpd_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1542,16 +1542,16 @@  static inline void gen_op_fcmpq(int fccno)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpq(cpu_env);
+        gen_helper_fcmpq(cpu_fsr, cpu_env);
         break;
     case 1:
-        gen_helper_fcmpq_fcc1(cpu_env);
+        gen_helper_fcmpq_fcc1(cpu_fsr, cpu_env);
         break;
     case 2:
-        gen_helper_fcmpq_fcc2(cpu_env);
+        gen_helper_fcmpq_fcc2(cpu_fsr, cpu_env);
         break;
     case 3:
-        gen_helper_fcmpq_fcc3(cpu_env);
+        gen_helper_fcmpq_fcc3(cpu_fsr, cpu_env);
         break;
     }
 }
@@ -1560,16 +1560,16 @@  static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmpes_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1578,16 +1578,16 @@  static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 1:
-        gen_helper_fcmped_fcc1(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped_fcc1(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 2:
-        gen_helper_fcmped_fcc2(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped_fcc2(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     case 3:
-        gen_helper_fcmped_fcc3(cpu_env, r_rs1, r_rs2);
+        gen_helper_fcmped_fcc3(cpu_fsr, cpu_env, r_rs1, r_rs2);
         break;
     }
 }
@@ -1596,16 +1596,16 @@  static inline void gen_op_fcmpeq(int fccno)
 {
     switch (fccno) {
     case 0:
-        gen_helper_fcmpeq(cpu_env);
+        gen_helper_fcmpeq(cpu_fsr, cpu_env);
         break;
     case 1:
-        gen_helper_fcmpeq_fcc1(cpu_env);
+        gen_helper_fcmpeq_fcc1(cpu_fsr, cpu_env);
         break;
     case 2:
-        gen_helper_fcmpeq_fcc2(cpu_env);
+        gen_helper_fcmpeq_fcc2(cpu_fsr, cpu_env);
         break;
     case 3:
-        gen_helper_fcmpeq_fcc3(cpu_env);
+        gen_helper_fcmpeq_fcc3(cpu_fsr, cpu_env);
         break;
     }
 }
@@ -1614,32 +1614,32 @@  static inline void gen_op_fcmpeq(int fccno)
 
 static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmps(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmpd(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmpd(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpq(int fccno)
 {
-    gen_helper_fcmpq(cpu_env);
+    gen_helper_fcmpq(cpu_fsr, cpu_env);
 }
 
 static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
 {
-    gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmpes(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
 {
-    gen_helper_fcmped(cpu_env, r_rs1, r_rs2);
+    gen_helper_fcmped(cpu_fsr, cpu_env, r_rs1, r_rs2);
 }
 
 static inline void gen_op_fcmpeq(int fccno)
 {
-    gen_helper_fcmpeq(cpu_env);
+    gen_helper_fcmpeq(cpu_fsr, cpu_env);
 }
 #endif
 
@@ -1675,6 +1675,7 @@  static inline void gen_fop_FF(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1702,6 +1703,7 @@  static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1731,6 +1733,7 @@  static inline void gen_fop_DD(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1760,6 +1763,7 @@  static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1815,6 +1819,7 @@  static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
     gen_op_load_fpr_QT1(QFPREG(rs));
 
     gen(cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
     gen_update_fprs_dirty(QFPREG(rd));
@@ -1840,6 +1845,7 @@  static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
     gen_op_load_fpr_QT1(QFPREG(rs2));
 
     gen(cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
     gen_update_fprs_dirty(QFPREG(rd));
@@ -1856,6 +1862,7 @@  static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1869,6 +1876,7 @@  static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
     src2 = gen_load_fpr_D(dc, rs2);
 
     gen(cpu_env, src1, src2);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_op_store_QT0_fpr(QFPREG(rd));
     gen_update_fprs_dirty(QFPREG(rd));
@@ -1885,6 +1893,7 @@  static inline void gen_fop_DF(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -1914,6 +1923,7 @@  static inline void gen_fop_FD(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env, src);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1927,6 +1937,7 @@  static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_F(dc);
 
     gen(dst, cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_F(dc, rd, dst);
 }
@@ -1940,6 +1951,7 @@  static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs,
     dst = gen_dest_fpr_D(dc, rd);
 
     gen(dst, cpu_env);
+    gen_helper_check_ieee_exceptions(cpu_fsr, cpu_env);
 
     gen_store_fpr_D(dc, rd, dst);
 }
@@ -5236,7 +5248,7 @@  static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     if (rd == 1) {
                         TCGv_i64 t64 = tcg_temp_new_i64();
                         tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx);
-                        gen_helper_ldxfsr(cpu_env, t64);
+                        gen_helper_ldxfsr(cpu_fsr, cpu_env, cpu_fsr, t64);
                         tcg_temp_free_i64(t64);
                         break;
                     }
@@ -5245,7 +5257,7 @@  static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     t0 = get_temp_tl(dc);
                     tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx);
                     tcg_gen_trunc_tl_i32(cpu_dst_32, t0);
-                    gen_helper_ldfsr(cpu_env, cpu_dst_32);
+                    gen_helper_ldfsr(cpu_fsr, cpu_env, cpu_fsr, cpu_dst_32);
                     break;
                 case 0x22:      /* ldqf, load quad fpreg */
                     {