qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/11] icount/replay additions
@ 2016-09-15  8:09 Pavel Dovgalyuk
  2016-09-15  8:09 ` [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode Pavel Dovgalyuk
  2016-09-15  8:10 ` [Qemu-devel] [PATCH v2 02/11] record/replay: add network support Pavel Dovgalyuk
  0 siblings, 2 replies; 7+ messages in thread
From: Pavel Dovgalyuk @ 2016-09-15  8:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, mst, jasowang, quintela, agraf, pbonzini, david

This set of patches includes several fixes for replay and
adds network record/replay for network devices. It also makes possible
saving/restoring vmstate in replay mode.

Record and replay for network interactions is performed with the network filter.
Each backend must have its own instance of the replay filter as follows:
 -netdev user,id=net1 -device rtl8139,netdev=net1
 -object filter-replay,id=replay,netdev=net1

This patches add overlay option for blkreplay block driver. Using persistent
overlay file allows saving and reloading VM snapshots in replay mode.
Replay mechanism automatically creates one snapshot named 'replay_init' to
allow rewinding execution while replaying.
Overlay file may be specified as follows:
 -drive file=disk.qcow,if=none,id=img-direct 
 -drive driver=blkreplay,if=none,image=img-direct,overlay=overlay.qcow2,id=img-blkreplay 
 -device ide-hd,drive=img-blkreplay

This set of patches includes fixes and additions for icount and
record/replay implementation:
 - Fixing icount processing on exceptions in PPC
 - Enabling VM start/stop in replay mode
 - Adding network interaction record/replay
 - Adding overlay option for blkreplay filter
 - Fixes of the vmstate for several virtual devices

---

Pavel Dovgalyuk (11):
      target-ppc: exceptions handling in icount mode
      record/replay: add network support
      block: set snapshot option for block devices in blkreplay module
      block: don't make snapshots for filters
      replay: save/load initial state
      replay: move internal data to the structure
      replay: vmstate for replay module
      replay: allow replay stopping and restarting
      kvmvapic: fix state change handler
      pcspk: adding vmstate for save/restore
      integratorcp: adding vmstate for save/restore


 block/blkreplay.c            |  132 +++++++++++++++++++++++++++--
 block/snapshot.c             |    3 +
 cpus.c                       |    1 
 docs/replay.txt              |   22 +++++
 hw/arm/integratorcp.c        |   62 ++++++++++++++
 hw/audio/pcspk.c             |   17 +++-
 hw/i386/kvmvapic.c           |    1 
 include/sysemu/replay.h      |   26 ++++++
 net/Makefile.objs            |    1 
 net/filter-replay.c          |   90 ++++++++++++++++++++
 replay/Makefile.objs         |    2 
 replay/replay-events.c       |   21 ++++-
 replay/replay-internal.c     |   19 ++--
 replay/replay-internal.h     |   26 +++++-
 replay/replay-net.c          |  110 ++++++++++++++++++++++++
 replay/replay-snapshot.c     |   72 ++++++++++++++++
 replay/replay-time.c         |    2 
 replay/replay.c              |   17 ++--
 stubs/replay.c               |    5 +
 target-ppc/cpu.h             |    3 +
 target-ppc/excp_helper.c     |   38 ++++++--
 target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++--------------------
 target-ppc/helper.h          |    1 
 target-ppc/mem_helper.c      |    6 +
 target-ppc/misc_helper.c     |    8 +-
 target-ppc/mmu-hash64.c      |   12 +--
 target-ppc/mmu_helper.c      |   18 ++--
 target-ppc/timebase_helper.c |   21 ++---
 target-ppc/translate.c       |   76 +----------------
 vl.c                         |    9 ++
 30 files changed, 768 insertions(+), 245 deletions(-)
 create mode 100644 net/filter-replay.c
 create mode 100644 replay/replay-net.c
 create mode 100644 replay/replay-snapshot.c

-- 
Pavel Dovgalyuk

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

* [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode
  2016-09-15  8:09 [Qemu-devel] [PATCH v2 00/11] icount/replay additions Pavel Dovgalyuk
@ 2016-09-15  8:09 ` Pavel Dovgalyuk
  2016-09-20  5:51   ` David Gibson
  2016-09-15  8:10 ` [Qemu-devel] [PATCH v2 02/11] record/replay: add network support Pavel Dovgalyuk
  1 sibling, 1 reply; 7+ messages in thread
From: Pavel Dovgalyuk @ 2016-09-15  8:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, mst, jasowang, quintela, agraf, pbonzini, david

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch fixes exception handling in PowerPC.
Instructions generate several types of exceptions.
When exception is generated, it breaks the execution of the current translation
block. Implementation of the exceptions handling does not correctly
restore icount for the instruction which caused the exception. In most cases
icount will be decreased by the value equal to the size of TB.
This patch passes pointer to the translation block internals to the exception
handler. It allows correct restoring of the icount value.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
---
 target-ppc/cpu.h             |    3 +
 target-ppc/excp_helper.c     |   38 ++++++--
 target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++--------------------
 target-ppc/helper.h          |    1 
 target-ppc/mem_helper.c      |    6 +
 target-ppc/misc_helper.c     |    8 +-
 target-ppc/mmu-hash64.c      |   12 +--
 target-ppc/mmu_helper.c      |   18 ++--
 target-ppc/timebase_helper.c |   21 ++---
 target-ppc/translate.c       |   76 +----------------
 10 files changed, 169 insertions(+), 206 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 786ab5c..95baae3 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2434,4 +2434,7 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
 PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
 
 void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
+void raise_exception_err(CPUPPCState *env, uint32_t exception,
+                         uint32_t error_code, uintptr_t pc);
+
 #endif /* PPC_CPU_H */
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index d6e1678..3da1c32 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -898,8 +898,8 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
 /*****************************************************************************/
 /* Exceptions processing helpers */
 
-void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
-                                uint32_t error_code)
+void raise_exception_err(CPUPPCState *env, uint32_t exception,
+                         uint32_t error_code, uintptr_t pc)
 {
     CPUState *cs = CPU(ppc_env_get_cpu(env));
 
@@ -908,15 +908,32 @@ void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
 #endif
     cs->exception_index = exception;
     env->error_code = error_code;
-    cpu_loop_exit(cs);
+    cpu_loop_exit_restore(cs, pc);
+}
+
+void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
+                                uint32_t error_code)
+{
+    raise_exception_err(env, exception, error_code, GETPC());
+}
+
+void helper_raise_exception_end(CPUPPCState *env, uint32_t exception,
+                                uint32_t error_code)
+{
+    raise_exception_err(env, exception, error_code, 0);
 }
 
 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
 {
-    helper_raise_exception_err(env, exception, 0);
+    raise_exception_err(env, exception, 0, GETPC());
 }
 
 #if !defined(CONFIG_USER_ONLY)
+static void raise_exception(CPUPPCState *env, uint32_t exception, uintptr_t pc)
+{
+    raise_exception_err(env, exception, 0, pc);
+}
+
 void helper_store_msr(CPUPPCState *env, target_ulong val)
 {
     CPUState *cs;
@@ -925,7 +942,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
     if (val != 0) {
         cs = CPU(ppc_env_get_cpu(env));
         cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
-        helper_raise_exception(env, val);
+        /* nip is updated by generated code */
+        raise_exception(env, val, 0);
     }
 }
 
@@ -1041,8 +1059,9 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_TRAP);
+        /* nip is updated in TB */
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_TRAP, 0);
     }
 }
 
@@ -1055,8 +1074,9 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_TRAP);
+        /* nip is updated in TB */
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_TRAP, 0);
     }
 }
 #endif
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index d9795d0..6eaa3f4 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -19,6 +19,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
+#include "exec/exec-all.h"
 
 #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
 #define float32_snan_to_qnan(x) ((x) | 0x00400000)
@@ -117,7 +118,7 @@ void helper_compute_fprf(CPUPPCState *env, uint64_t arg)
 
 /* Floating-point invalid operations exception */
 static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
-                                             int set_fpcc)
+                                             int set_fpcc, uintptr_t retaddr)
 {
     CPUState *cs = CPU(ppc_env_get_cpu(env));
     uint64_t ret = 0;
@@ -200,14 +201,14 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
         /* Update the floating-point enabled exception summary */
         env->fpscr |= 1 << FPSCR_FEX;
         if (msr_fe0 != 0 || msr_fe1 != 0) {
-            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                       POWERPC_EXCP_FP | op);
+            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                                POWERPC_EXCP_FP | op, retaddr);
         }
     }
     return ret;
 }
 
-static inline void float_zero_divide_excp(CPUPPCState *env)
+static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t retaddr)
 {
     env->fpscr |= 1 << FPSCR_ZX;
     env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
@@ -217,8 +218,8 @@ static inline void float_zero_divide_excp(CPUPPCState *env)
         /* Update the floating-point enabled exception summary */
         env->fpscr |= 1 << FPSCR_FEX;
         if (msr_fe0 != 0 || msr_fe1 != 0) {
-            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
+            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                                POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, retaddr);
         }
     }
 }
@@ -491,13 +492,13 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
     helper_store_fpscr(env, arg, mask);
 }
 
-void helper_float_check_status(CPUPPCState *env)
+static void do_float_check_status(CPUPPCState *env, uintptr_t retaddr)
 {
     CPUState *cs = CPU(ppc_env_get_cpu(env));
     int status = get_float_exception_flags(&env->fp_status);
 
     if (status & float_flag_divbyzero) {
-        float_zero_divide_excp(env);
+        float_zero_divide_excp(env, retaddr);
     } else if (status & float_flag_overflow) {
         float_overflow_excp(env);
     } else if (status & float_flag_underflow) {
@@ -510,12 +511,17 @@ void helper_float_check_status(CPUPPCState *env)
         (env->error_code & POWERPC_EXCP_FP)) {
         /* Differred floating-point exception after target FPR update */
         if (msr_fe0 != 0 || msr_fe1 != 0) {
-            helper_raise_exception_err(env, cs->exception_index,
-                                       env->error_code);
+            raise_exception_err(env, cs->exception_index,
+                                env->error_code, retaddr);
         }
     }
 }
 
+void helper_float_check_status(CPUPPCState *env)
+{
+    do_float_check_status(env, GETPC());
+}
+
 void helper_reset_fpstatus(CPUPPCState *env)
 {
     set_float_exception_flags(0, &env->fp_status);
@@ -532,12 +538,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
                  float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
         /* Magnitude subtraction of infinities */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN addition */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
     }
@@ -556,12 +562,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
                  float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
         /* Magnitude subtraction of infinities */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN subtraction */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
     }
@@ -580,12 +586,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
                  (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN multiplication */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
     }
@@ -604,15 +610,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely(float64_is_infinity(farg1.d) &&
                  float64_is_infinity(farg2.d))) {
         /* Division of infinity by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1, GETPC());
     } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
         /* Division of zero by zero */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN division */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
     }
@@ -631,16 +637,16 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)                   \
                                                                        \
     if (unlikely(env->fp_status.float_exception_flags)) {              \
         if (float64_is_any_nan(arg)) {                                 \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
             if (float64_is_signaling_nan(arg, &env->fp_status)) {      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());\
             }                                                          \
             farg.ll = nanval;                                          \
         } else if (env->fp_status.float_exception_flags &              \
                    float_flag_invalid) {                               \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
         }                                                              \
-        helper_float_check_status(env);                                \
+        do_float_check_status(env, GETPC());                           \
     }                                                                  \
     return farg.ll;                                                    \
  }
@@ -665,7 +671,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)       \
     } else {                                               \
         farg.d = cvtr(arg, &env->fp_status);               \
     }                                                      \
-    helper_float_check_status(env);                        \
+    do_float_check_status(env, GETPC());                   \
     return farg.ll;                                        \
 }
 
@@ -675,7 +681,7 @@ FPU_FCFI(fcfidu, uint64_to_float64, 0)
 FPU_FCFI(fcfidus, uint64_to_float32, 1)
 
 static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
-                              int rounding_mode)
+                              int rounding_mode, uint64_t retaddr)
 {
     CPU_DoubleU farg;
 
@@ -683,7 +689,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN round */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, retaddr);
         farg.ll = arg | 0x0008000000000000ULL;
     } else {
         int inexact = get_float_exception_flags(&env->fp_status) &
@@ -698,28 +704,28 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
             env->fp_status.float_exception_flags &= ~float_flag_inexact;
         }
     }
-    helper_float_check_status(env);
+    do_float_check_status(env, GETPC());
     return farg.ll;
 }
 
 uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
 {
-    return do_fri(env, arg, float_round_ties_away);
+    return do_fri(env, arg, float_round_ties_away, GETPC());
 }
 
 uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
 {
-    return do_fri(env, arg, float_round_to_zero);
+    return do_fri(env, arg, float_round_to_zero, GETPC());
 }
 
 uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
 {
-    return do_fri(env, arg, float_round_up);
+    return do_fri(env, arg, float_round_up, GETPC());
 }
 
 uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
 {
-    return do_fri(env, arg, float_round_down);
+    return do_fri(env, arg, float_round_down, GETPC());
 }
 
 /* fmadd - fmadd. */
@@ -735,13 +741,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
     if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
                  (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -753,7 +759,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -778,13 +784,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                  (float64_is_zero(farg1.d) &&
                   float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -796,7 +802,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -819,13 +825,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
     if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
                  (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -837,7 +843,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -864,13 +870,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                  (float64_is_zero(farg1.d) &&
                   float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -882,7 +888,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -905,7 +911,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN square root */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
     }
     f32 = float64_to_float32(farg.d, &env->fp_status);
     farg.d = float32_to_float64(f32, &env->fp_status);
@@ -923,12 +929,12 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
     if (unlikely(float64_is_any_nan(farg.d))) {
         if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
             /* sNaN reciprocal square root */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
             farg.ll = float64_snan_to_qnan(farg.ll);
         }
     } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
         /* Square root of a negative nonzero number */
-        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
+        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
     } else {
         farg.d = float64_sqrt(farg.d, &env->fp_status);
     }
@@ -944,7 +950,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN reciprocal */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
     }
     farg.d = float64_div(float64_one, farg.d, &env->fp_status);
     return farg.d;
@@ -960,7 +966,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN reciprocal */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
     }
     farg.d = float64_div(float64_one, farg.d, &env->fp_status);
     f32 = float64_to_float32(farg.d, &env->fp_status);
@@ -979,12 +985,12 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
     if (unlikely(float64_is_any_nan(farg.d))) {
         if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
             /* sNaN reciprocal square root */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
             farg.ll = float64_snan_to_qnan(farg.ll);
         }
     } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
         /* Reciprocal square root of a negative nonzero number */
-        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
+        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
     } else {
         farg.d = float64_sqrt(farg.d, &env->fp_status);
         farg.d = float64_div(float64_one, farg.d, &env->fp_status);
@@ -1103,7 +1109,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                  && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status)))) {
         /* sNaN comparison */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
     }
 }
 
@@ -1135,10 +1141,10 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
             float64_is_signaling_nan(farg2.d, &env->fp_status)) {
             /* sNaN comparison */
             fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
-                                  POWERPC_EXCP_FP_VXVC, 1);
+                                  POWERPC_EXCP_FP_VXVC, 1, GETPC());
         } else {
             /* qNaN comparison */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1, GETPC());
         }
     }
 }
@@ -1838,10 +1844,10 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                        \
                                                                              \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);    \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
             } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
                        tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
             }                                                                \
         }                                                                    \
                                                                              \
@@ -1854,7 +1860,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                        \
         }                                                                    \
     }                                                                        \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    do_float_check_status(env, GETPC());                                     \
 }
 
 VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
@@ -1893,10 +1899,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) ||        \
                 (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) {        \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf);    \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC());\
             } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
                        tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
             }                                                                \
         }                                                                    \
                                                                              \
@@ -1910,7 +1916,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    do_float_check_status(env, GETPC());                                     \
 }
 
 VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
@@ -1944,13 +1950,13 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
                                                                               \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {     \
             if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {       \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf);     \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf, GETPC());\
             } else if (tp##_is_zero(xa.fld) &&                                \
                 tp##_is_zero(xb.fld)) {                                       \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf);     \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf, GETPC());\
             } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||               \
                 tp##_is_signaling_nan(xb.fld, &tstat)) {                      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
             }                                                                 \
         }                                                                     \
                                                                               \
@@ -1964,7 +1970,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
     }                                                                         \
                                                                               \
     putVSR(xT(opcode), &xt, env);                                             \
-    helper_float_check_status(env);                                           \
+    do_float_check_status(env, GETPC());                                      \
 }
 
 VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
@@ -1991,7 +1997,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
                                                                               \
     for (i = 0; i < nels; i++) {                                              \
         if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
         }                                                                     \
         xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status);                 \
                                                                               \
@@ -2005,7 +2011,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
     }                                                                         \
                                                                               \
     putVSR(xT(opcode), &xt, env);                                             \
-    helper_float_check_status(env);                                           \
+    do_float_check_status(env, GETPC());                                      \
 }
 
 VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
@@ -2038,9 +2044,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
                                                                              \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
             } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
             }                                                                \
         }                                                                    \
                                                                              \
@@ -2054,7 +2060,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    do_float_check_status(env, GETPC());                                     \
 }
 
 VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
@@ -2088,9 +2094,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
                                                                              \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
             } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
             }                                                                \
         }                                                                    \
                                                                              \
@@ -2104,7 +2110,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    do_float_check_status(env, GETPC());                                     \
 }
 
 VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
@@ -2277,20 +2283,20 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
             if (tp##_is_signaling_nan(xa.fld, &tstat) ||                      \
                 tp##_is_signaling_nan(b->fld, &tstat) ||                      \
                 tp##_is_signaling_nan(c->fld, &tstat)) {                      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
                 tstat.float_exception_flags &= ~float_flag_invalid;           \
             }                                                                 \
             if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b->fld)) ||         \
                 (tp##_is_zero(xa.fld) && tp##_is_infinity(b->fld))) {         \
                 xt_out.fld = float64_to_##tp(fload_invalid_op_excp(env,       \
-                    POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status);          \
+                    POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC()), &env->fp_status); \
                 tstat.float_exception_flags &= ~float_flag_invalid;           \
             }                                                                 \
             if ((tstat.float_exception_flags & float_flag_invalid) &&         \
                 ((tp##_is_infinity(xa.fld) ||                                 \
                   tp##_is_infinity(b->fld)) &&                                \
                   tp##_is_infinity(c->fld))) {                                \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);     \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
             }                                                                 \
         }                                                                     \
                                                                               \
@@ -2303,7 +2309,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
         }                                                                     \
     }                                                                         \
     putVSR(xT(opcode), &xt_out, env);                                         \
-    helper_float_check_status(env);                                           \
+    do_float_check_status(env, GETPC());                                      \
 }
 
 #define MADD_FLGS 0
@@ -2360,10 +2366,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                      \
                  float64_is_any_nan(xb.VsrD(0)))) {                      \
         if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) ||     \
             float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) {     \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
         }                                                                \
         if (ordered) {                                                   \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);         \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
         }                                                                \
         cc = 1;                                                          \
     } else {                                                             \
@@ -2381,7 +2387,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                      \
     env->fpscr |= cc << FPSCR_FPRF;                                      \
     env->crf[BF(opcode)] = cc;                                           \
                                                                          \
-    helper_float_check_status(env);                                      \
+    do_float_check_status(env, GETPC());                                 \
 }
 
 VSX_SCALAR_CMP(xscmpodp, 1)
@@ -2408,12 +2414,12 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                         \
         xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status);                  \
         if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) ||        \
                      tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);            \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());   \
         }                                                                     \
     }                                                                         \
                                                                               \
     putVSR(xT(opcode), &xt, env);                                             \
-    helper_float_check_status(env);                                           \
+    do_float_check_status(env, GETPC());                                      \
 }
 
 VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
@@ -2448,10 +2454,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                       \
                      tp##_is_any_nan(xb.fld))) {                          \
             if (tp##_is_signaling_nan(xa.fld, &env->fp_status) ||         \
                 tp##_is_signaling_nan(xb.fld, &env->fp_status)) {         \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);    \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
             }                                                             \
             if (svxvc) {                                                  \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);      \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
             }                                                             \
             xt.fld = 0;                                                   \
             all_true = 0;                                                 \
@@ -2470,7 +2476,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                       \
     if ((opcode >> (31-21)) & 1) {                                        \
         env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0);       \
     }                                                                     \
-    helper_float_check_status(env);                                       \
+    do_float_check_status(env, GETPC());                                  \
  }
 
 VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
@@ -2502,7 +2508,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
         xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status);        \
         if (unlikely(stp##_is_signaling_nan(xb.sfld,               \
                                             &env->fp_status))) {   \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC()); \
             xt.tfld = ttp##_snan_to_qnan(xt.tfld);                 \
         }                                                          \
         if (sfprf) {                                               \
@@ -2512,7 +2518,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
     }                                                              \
                                                                    \
     putVSR(xT(opcode), &xt, env);                                  \
-    helper_float_check_status(env);                                \
+    do_float_check_status(env, GETPC());                           \
 }
 
 VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1)
@@ -2557,21 +2563,21 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     for (i = 0; i < nels; i++) {                                             \
         if (unlikely(stp##_is_any_nan(xb.sfld))) {                           \
             if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) {          \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
             }                                                                \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);            \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());   \
             xt.tfld = rnan;                                                  \
         } else {                                                             \
             xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld,                \
                           &env->fp_status);                                  \
             if (env->fp_status.float_exception_flags & float_flag_invalid) { \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);        \
+                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());\
             }                                                                \
         }                                                                    \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    do_float_check_status(env, GETPC());                                     \
 }
 
 VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \
@@ -2622,7 +2628,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                     \
     }                                                                   \
                                                                         \
     putVSR(xT(opcode), &xt, env);                                       \
-    helper_float_check_status(env);                                     \
+    do_float_check_status(env, GETPC());                                \
 }
 
 VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
@@ -2667,7 +2673,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                    \
     for (i = 0; i < nels; i++) {                                       \
         if (unlikely(tp##_is_signaling_nan(xb.fld,                     \
                                            &env->fp_status))) {        \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);     \
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
             xt.fld = tp##_snan_to_qnan(xb.fld);                        \
         } else {                                                       \
             xt.fld = tp##_round_to_int(xb.fld, &env->fp_status);       \
@@ -2686,7 +2692,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                    \
     }                                                                  \
                                                                        \
     putVSR(xT(opcode), &xt, env);                                      \
-    helper_float_check_status(env);                                    \
+    do_float_check_status(env, GETPC());                               \
 }
 
 VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
@@ -2714,6 +2720,6 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
     uint64_t xt = helper_frsp(env, xb);
 
     helper_compute_fprf(env, xt);
-    helper_float_check_status(env);
+    do_float_check_status(env, GETPC());
     return xt;
 }
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 1f5cfd0..34560f9 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -1,4 +1,5 @@
 DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
+DEF_HELPER_3(raise_exception_end, void, env, i32, i32)
 DEF_HELPER_2(raise_exception, void, env, i32)
 DEF_HELPER_4(tw, void, env, tl, tl, i32)
 #if defined(TARGET_PPC64)
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index e4ed377..5cee620 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -107,9 +107,9 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
         if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
                      lsw_reg_in_range(reg, num_used_regs, rb))) {
             env->nip += 4;     /* Compensate the "nip - 4" from gen_lswx() */
-            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                       POWERPC_EXCP_INVAL |
-                                       POWERPC_EXCP_INVAL_LSWX);
+            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                                POWERPC_EXCP_INVAL |
+                                POWERPC_EXCP_INVAL_LSWX, GETPC());
         } else {
             helper_lsw(env, addr, xer_bc, reg);
         }
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index cb5ebf5..6661650 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -39,7 +39,7 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
 
 #ifdef TARGET_PPC64
 static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
-                               uint32_t sprn, uint32_t cause)
+                               uint32_t sprn, uint32_t cause, uintptr_t retaddr)
 {
     qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
 
@@ -47,7 +47,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
     cause &= FSCR_IC_MASK;
     env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
 
-    helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
+    raise_exception_err(env, POWERPC_EXCP_FU, 0, retaddr);
 }
 #endif
 
@@ -59,7 +59,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
         /* Facility is enabled, continue */
         return;
     }
-    raise_fu_exception(env, bit, sprn, cause);
+    raise_fu_exception(env, bit, sprn, cause, GETPC());
 #endif
 }
 
@@ -71,7 +71,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
         /* Facility is enabled, continue */
         return;
     }
-    raise_fu_exception(env, bit, sprn, cause);
+    raise_fu_exception(env, bit, sprn, cause, GETPC());
 #endif
 }
 
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 5de1358..a1b27b0 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -241,8 +241,8 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
     PowerPCCPU *cpu = ppc_env_get_cpu(env);
 
     if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL, GETPC());
     }
 }
 
@@ -252,8 +252,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
     target_ulong rt = 0;
 
     if (ppc_load_slb_esid(cpu, rb, &rt) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL, GETPC());
     }
     return rt;
 }
@@ -276,8 +276,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
     target_ulong rt = 0;
 
     if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL, GETPC());
     }
     return rt;
 }
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 3eb3cd7..7cd9c2c 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -2598,9 +2598,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
     tlb = booke206_cur_tlb(env);
 
     if (!tlb) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     }
 
     /* check that we support the targeted size */
@@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
     size_ps = booke206_tlbnps(env, tlbn);
     if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
         !(size_ps & (1 << size_tlb))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     }
 
     if (msr_gs) {
@@ -2892,10 +2892,6 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
         ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
     }
     if (unlikely(ret != 0)) {
-        if (likely(retaddr)) {
-            /* now we have a real cpu fault */
-            cpu_restore_state(cs, retaddr);
-        }
-        helper_raise_exception_err(env, cs->exception_index, env->error_code);
+        raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
     }
 }
diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
index a07faa4..af328ca 100644
--- a/target-ppc/timebase_helper.c
+++ b/target-ppc/timebase_helper.c
@@ -19,6 +19,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
+#include "exec/exec-all.h"
 #include "qemu/log.h"
 
 /*****************************************************************************/
@@ -143,15 +144,15 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
 
     if (unlikely(env->dcr_env == NULL)) {
         qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     } else if (unlikely(ppc_dcr_read(env->dcr_env,
                                      (uint32_t)dcrn, &val) != 0)) {
         qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
                       (uint32_t)dcrn, (uint32_t)dcrn);
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
     }
     return val;
 }
@@ -160,14 +161,14 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val)
 {
     if (unlikely(env->dcr_env == NULL)) {
         qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL |
+                            POWERPC_EXCP_INVAL_INVAL, GETPC());
     } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
                                       (uint32_t)val) != 0)) {
         qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n",
                       (uint32_t)dcrn, (uint32_t)dcrn);
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
     }
 }
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 92030b6..0e16578 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -292,7 +292,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
     }
     t0 = tcg_const_i32(excp);
     t1 = tcg_const_i32(error);
-    gen_helper_raise_exception_err(cpu_env, t0, t1);
+    gen_helper_raise_exception_end(cpu_env, t0, t1);
     tcg_temp_free_i32(t0);
     tcg_temp_free_i32(t1);
     ctx->exception = (excp);
@@ -300,14 +300,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
 
 static void gen_exception(DisasContext *ctx, uint32_t excp)
 {
-    TCGv_i32 t0;
-    if (ctx->exception == POWERPC_EXCP_NONE) {
-        gen_update_nip(ctx, ctx->nip);
-    }
-    t0 = tcg_const_i32(excp);
-    gen_helper_raise_exception(cpu_env, t0);
-    tcg_temp_free_i32(t0);
-    ctx->exception = (excp);
+    gen_exception_err(ctx, excp, 0);
 }
 
 static void gen_debug_exception(DisasContext *ctx)
@@ -2149,8 +2142,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
                      cpu_fpr[rA(ctx->opcode)],                                \
@@ -2178,8 +2169,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
                      cpu_fpr[rA(ctx->opcode)],                                \
@@ -2206,8 +2195,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
                      cpu_fpr[rA(ctx->opcode)],                                \
@@ -2234,8 +2221,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
                        cpu_fpr[rB(ctx->opcode)]);                             \
@@ -2254,8 +2239,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
                        cpu_fpr[rB(ctx->opcode)]);                             \
@@ -2290,8 +2273,6 @@ static void gen_frsqrtes(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
                        cpu_fpr[rB(ctx->opcode)]);
@@ -2316,8 +2297,6 @@ static void gen_fsqrt(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
                      cpu_fpr[rB(ctx->opcode)]);
@@ -2333,8 +2312,6 @@ static void gen_fsqrts(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
                      cpu_fpr[rB(ctx->opcode)]);
@@ -2424,8 +2401,6 @@ static void gen_fcmpo(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     crf = tcg_const_i32(crfD(ctx->opcode));
     gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
@@ -2442,8 +2417,6 @@ static void gen_fcmpu(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     crf = tcg_const_i32(crfD(ctx->opcode));
     gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
@@ -2613,8 +2586,6 @@ static void gen_mtfsb0(DisasContext *ctx)
     gen_reset_fpstatus();
     if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
         TCGv_i32 t0;
-        /* NIP cannot be restored if the memory exception comes from an helper */
-        gen_update_nip(ctx, ctx->nip - 4);
         t0 = tcg_const_i32(crb);
         gen_helper_fpscr_clrbit(cpu_env, t0);
         tcg_temp_free_i32(t0);
@@ -2639,8 +2610,6 @@ static void gen_mtfsb1(DisasContext *ctx)
     /* XXX: we pretend we can only do IEEE floating-point computations */
     if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
         TCGv_i32 t0;
-        /* NIP cannot be restored if the memory exception comes from an helper */
-        gen_update_nip(ctx, ctx->nip - 4);
         t0 = tcg_const_i32(crb);
         gen_helper_fpscr_setbit(cpu_env, t0);
         tcg_temp_free_i32(t0);
@@ -2670,8 +2639,6 @@ static void gen_mtfsf(DisasContext *ctx)
         gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     if (l) {
         t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
@@ -2706,8 +2673,6 @@ static void gen_mtfsfi(DisasContext *ctx)
         return;
     }
     sh = (8 * w) + 7 - bf;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
     t1 = tcg_const_i32(1 << sh);
@@ -2790,8 +2755,6 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
     TCGLabel *l1 = gen_new_label();
     TCGv t0 = tcg_temp_new();
     TCGv_i32 t1, t2;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     tcg_gen_andi_tl(t0, EA, mask);
     tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
     t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
@@ -3261,8 +3224,6 @@ static void gen_lmw(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     t1 = tcg_const_i32(rD(ctx->opcode));
     gen_addr_imm_index(ctx, t0, 0);
@@ -3277,8 +3238,6 @@ static void gen_stmw(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     t1 = tcg_const_i32(rS(ctx->opcode));
     gen_addr_imm_index(ctx, t0, 0);
@@ -3312,8 +3271,6 @@ static void gen_lswi(DisasContext *ctx)
         return;
     }
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_register(ctx, t0);
     t1 = tcg_const_i32(nb);
@@ -3330,8 +3287,6 @@ static void gen_lswx(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1, t2, t3;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
     t1 = tcg_const_i32(rD(ctx->opcode));
@@ -3351,8 +3306,6 @@ static void gen_stswi(DisasContext *ctx)
     TCGv_i32 t1, t2;
     int nb = NB(ctx->opcode);
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_register(ctx, t0);
     if (nb == 0)
@@ -3371,8 +3324,6 @@ static void gen_stswx(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1, t2;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
     t1 = tcg_temp_new_i32();
@@ -4306,7 +4257,7 @@ static void gen_tw(DisasContext *ctx)
 {
     TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_stop_exception(ctx);
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -4318,7 +4269,7 @@ static void gen_twi(DisasContext *ctx)
     TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
     TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_stop_exception(ctx);
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
@@ -4330,7 +4281,7 @@ static void gen_td(DisasContext *ctx)
 {
     TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_stop_exception(ctx);
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -4342,7 +4293,7 @@ static void gen_tdi(DisasContext *ctx)
     TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
     TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_stop_exception(ctx);
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
@@ -4768,8 +4719,6 @@ static void gen_dcbz(DisasContext *ctx)
     int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
 
     gen_set_access_type(ctx, ACCESS_CACHE);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     tcgv_addr = tcg_temp_new();
     tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
 
@@ -4812,8 +4761,6 @@ static void gen_icbi(DisasContext *ctx)
 {
     TCGv t0;
     gen_set_access_type(ctx, ACCESS_CACHE);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
     gen_helper_icbi(cpu_env, t0);
@@ -5299,8 +5246,6 @@ static void gen_lscbx(DisasContext *ctx)
     TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
 
     gen_addr_reg_index(ctx, t0);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
     tcg_temp_free_i32(t1);
     tcg_temp_free_i32(t2);
@@ -6386,8 +6331,6 @@ static void gen_mtdcrx(DisasContext *ctx)
 /* mfdcrux (PPC 460) : user-mode access to DCR */
 static void gen_mfdcrux(DisasContext *ctx)
 {
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
                         cpu_gpr[rA(ctx->opcode)]);
     /* Note: Rc update flag set leads to undefined state of Rc0 */
@@ -6396,8 +6339,6 @@ static void gen_mfdcrux(DisasContext *ctx)
 /* mtdcrux (PPC 460) : user-mode access to DCR */
 static void gen_mtdcrux(DisasContext *ctx)
 {
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
                          cpu_gpr[rS(ctx->opcode)]);
     /* Note: Rc update flag set leads to undefined state of Rc0 */
@@ -8027,8 +7968,6 @@ static void gen_##name(DisasContext * ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_VSXU);                                \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     opc = tcg_const_i32(ctx->opcode);                                         \
     gen_helper_##name(cpu_env, opc);                                          \
     tcg_temp_free_i32(opc);                                                   \
@@ -8041,9 +7980,6 @@ static void gen_##name(DisasContext * ctx)                    \
         gen_exception(ctx, POWERPC_EXCP_VSXU);                \
         return;                                               \
     }                                                         \
-    /* NIP cannot be restored if the exception comes */       \
-    /* from a helper. */                                      \
-    gen_update_nip(ctx, ctx->nip - 4);                        \
                                                               \
     gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
                       cpu_vsrh(xB(ctx->opcode)));             \

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

* [Qemu-devel] [PATCH v2 02/11] record/replay: add network support
  2016-09-15  8:09 [Qemu-devel] [PATCH v2 00/11] icount/replay additions Pavel Dovgalyuk
  2016-09-15  8:09 ` [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode Pavel Dovgalyuk
@ 2016-09-15  8:10 ` Pavel Dovgalyuk
  1 sibling, 0 replies; 7+ messages in thread
From: Pavel Dovgalyuk @ 2016-09-15  8:10 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, mst, jasowang, quintela, agraf, pbonzini, david

This patch adds support of recording and replaying network packets in
irount rr mode.

Record and replay for network interactions is performed with the network filter.
Each backend must have its own instance of the replay filter as follows:
 -netdev user,id=net1 -device rtl8139,netdev=net1
 -object filter-replay,id=replay,netdev=net1

Replay network filter is used to record and replay network packets. While
recording the virtual machine this filter puts all packets coming from
the outer world into the log. In replay mode packets from the log are
injected into the network device. All interactions with network backend
in replay mode are disabled.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
---
 docs/replay.txt          |   14 ++++++
 include/sysemu/replay.h  |   12 +++++
 net/Makefile.objs        |    1 
 net/filter-replay.c      |   90 ++++++++++++++++++++++++++++++++++++++
 replay/Makefile.objs     |    1 
 replay/replay-events.c   |   11 +++++
 replay/replay-internal.h |   10 ++++
 replay/replay-net.c      |  110 ++++++++++++++++++++++++++++++++++++++++++++++
 replay/replay.c          |    2 -
 vl.c                     |    3 +
 10 files changed, 252 insertions(+), 2 deletions(-)
 create mode 100644 net/filter-replay.c
 create mode 100644 replay/replay-net.c

diff --git a/docs/replay.txt b/docs/replay.txt
index 779c6c0..347b2ff 100644
--- a/docs/replay.txt
+++ b/docs/replay.txt
@@ -195,3 +195,17 @@ Queue is flushed at checkpoints and information about processed requests
 is recorded to the log. In replay phase the queue is matched with
 events read from the log. Therefore block devices requests are processed
 deterministically.
+
+Network devices
+---------------
+
+Record and replay for network interactions is performed with the network filter.
+Each backend must have its own instance of the replay filter as follows:
+ -netdev user,id=net1 -device rtl8139,netdev=net1
+ -object filter-replay,id=replay,netdev=net1
+
+Replay network filter is used to record and replay network packets. While
+recording the virtual machine this filter puts all packets coming from
+the outer world into the log. In replay mode packets from the log are
+injected into the network device. All interactions with network backend
+in replay mode are disabled.
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 0a88393..a408633 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -39,6 +39,8 @@ enum ReplayCheckpoint {
 };
 typedef enum ReplayCheckpoint ReplayCheckpoint;
 
+typedef struct ReplayNetState ReplayNetState;
+
 extern ReplayMode replay_mode;
 
 /* Replay process control functions */
@@ -133,4 +135,14 @@ void replay_char_read_all_save_error(int res);
 /*! Writes character read_all execution result into the replay log. */
 void replay_char_read_all_save_buf(uint8_t *buf, int offset);
 
+/* Network */
+
+/*! Registers replay network filter attached to some backend. */
+ReplayNetState *replay_register_net(NetFilterState *nfs);
+/*! Unregisters replay network filter. */
+void replay_unregister_net(ReplayNetState *rns);
+/*! Called to write network packet to the replay log. */
+void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
+                             const struct iovec *iov, int iovcnt);
+
 #endif
diff --git a/net/Makefile.objs b/net/Makefile.objs
index b7c22fd..f787ba4 100644
--- a/net/Makefile.objs
+++ b/net/Makefile.objs
@@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o
 common-obj-y += filter.o
 common-obj-y += filter-buffer.o
 common-obj-y += filter-mirror.o
+common-obj-y += filter-replay.o
diff --git a/net/filter-replay.c b/net/filter-replay.c
new file mode 100644
index 0000000..7d93dc9
--- /dev/null
+++ b/net/filter-replay.c
@@ -0,0 +1,90 @@
+/*
+ * filter-replay.c
+ *
+ * Copyright (c) 2010-2016 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "clients.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "qemu/iov.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "qapi/visitor.h"
+#include "net/filter.h"
+#include "sysemu/replay.h"
+
+#define TYPE_FILTER_REPLAY "filter-replay"
+
+#define FILTER_REPLAY(obj) \
+    OBJECT_CHECK(NetFilterReplayState, (obj), TYPE_FILTER_REPLAY)
+
+struct NetFilterReplayState {
+    NetFilterState nfs;
+    ReplayNetState *rns;
+};
+typedef struct NetFilterReplayState NetFilterReplayState;
+
+static ssize_t filter_replay_receive_iov(NetFilterState *nf, NetClientState *sndr,
+                                         unsigned flags, const struct iovec *iov,
+                                         int iovcnt, NetPacketSent *sent_cb)
+{
+    NetFilterReplayState *nfrs = FILTER_REPLAY(nf);
+    switch (replay_mode) {
+    case REPLAY_MODE_RECORD:
+        if (nf->netdev == sndr) {
+            replay_net_packet_event(nfrs->rns, flags, iov, iovcnt);
+            return iov_size(iov, iovcnt);
+        }
+        return 0;
+    case REPLAY_MODE_PLAY:
+        /* Drop all packets in replay mode.
+           Packets from the log will be injected by the replay module. */
+        return iov_size(iov, iovcnt);
+    default:
+        /* Pass all the packets. */
+        return 0;
+    }
+}
+
+static void filter_replay_instance_init(Object *obj)
+{
+    NetFilterReplayState *nfrs = FILTER_REPLAY(obj);
+    nfrs->rns = replay_register_net(&nfrs->nfs);
+}
+
+static void filter_replay_instance_finalize(Object *obj)
+{
+    NetFilterReplayState *nfrs = FILTER_REPLAY(obj);
+    replay_unregister_net(nfrs->rns);
+}
+
+static void filter_replay_class_init(ObjectClass *oc, void *data)
+{
+    NetFilterClass *nfc = NETFILTER_CLASS(oc);
+
+    nfc->receive_iov = filter_replay_receive_iov;
+}
+
+static const TypeInfo filter_replay_info = {
+    .name = TYPE_FILTER_REPLAY,
+    .parent = TYPE_NETFILTER,
+    .class_init = filter_replay_class_init,
+    .instance_init = filter_replay_instance_init,
+    .instance_finalize = filter_replay_instance_finalize,
+    .instance_size = sizeof(NetFilterReplayState),
+};
+
+static void filter_replay_register_types(void)
+{
+    type_register_static(&filter_replay_info);
+}
+
+type_init(filter_replay_register_types);
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index fcb3f74..f55a6b5 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -4,3 +4,4 @@ common-obj-y += replay-events.o
 common-obj-y += replay-time.o
 common-obj-y += replay-input.o
 common-obj-y += replay-char.o
+common-obj-y += replay-net.o
diff --git a/replay/replay-events.c b/replay/replay-events.c
index 3807245..9ce9e51 100644
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -54,6 +54,9 @@ static void replay_run_event(Event *event)
     case REPLAY_ASYNC_EVENT_BLOCK:
         aio_bh_call(event->opaque);
         break;
+    case REPLAY_ASYNC_EVENT_NET:
+        replay_event_net_run(event->opaque);
+        break;
     default:
         error_report("Replay: invalid async event ID (%d) in the queue",
                     event->event_kind);
@@ -189,6 +192,9 @@ static void replay_save_event(Event *event, int checkpoint)
         case REPLAY_ASYNC_EVENT_BLOCK:
             replay_put_qword(event->id);
             break;
+        case REPLAY_ASYNC_EVENT_NET:
+            replay_event_net_save(event->opaque);
+            break;
         default:
             error_report("Unknown ID %" PRId64 " of replay event", event->id);
             exit(1);
@@ -252,6 +258,11 @@ static Event *replay_read_event(int checkpoint)
             read_id = replay_get_qword();
         }
         break;
+    case REPLAY_ASYNC_EVENT_NET:
+        event = g_malloc0(sizeof(Event));
+        event->event_kind = read_event_kind;
+        event->opaque = replay_event_net_load();
+        return event;
     default:
         error_report("Unknown ID %d of replay event", read_event_kind);
         exit(1);
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index efbf14c..d28cfb7 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -50,6 +50,7 @@ enum ReplayAsyncEventKind {
     REPLAY_ASYNC_EVENT_INPUT_SYNC,
     REPLAY_ASYNC_EVENT_CHAR_READ,
     REPLAY_ASYNC_EVENT_BLOCK,
+    REPLAY_ASYNC_EVENT_NET,
     REPLAY_ASYNC_COUNT
 };
 
@@ -155,4 +156,13 @@ void replay_event_char_read_save(void *opaque);
 /*! Reads char event read from the file. */
 void *replay_event_char_read_load(void);
 
+/* Network devices */
+
+/*! Called to run network event. */
+void replay_event_net_run(void *opaque);
+/*! Writes network event to the file. */
+void replay_event_net_save(void *opaque);
+/*! Reads network from the file. */
+void *replay_event_net_load(void);
+
 #endif
diff --git a/replay/replay-net.c b/replay/replay-net.c
new file mode 100644
index 0000000..e3ba0f2
--- /dev/null
+++ b/replay/replay-net.c
@@ -0,0 +1,110 @@
+/*
+ * replay-net.c
+ *
+ * Copyright (c) 2010-2016 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "sysemu/sysemu.h"
+#include "net/net.h"
+#include "net/filter.h"
+#include "qemu/iov.h"
+
+struct ReplayNetState {
+    NetFilterState *nfs;
+    int id;
+};
+
+typedef struct NetEvent {
+    uint8_t id;
+    uint32_t flags;
+    uint8_t *data;
+    size_t size;
+} NetEvent;
+
+static NetFilterState **network_filters;
+static int network_filters_count;
+
+ReplayNetState *replay_register_net(NetFilterState *nfs)
+{
+    ReplayNetState *rns = g_new0(ReplayNetState, 1);
+    rns->nfs = nfs;
+    rns->id = network_filters_count++;
+    network_filters = g_realloc(network_filters,
+                                network_filters_count * sizeof(*network_filters));
+    network_filters[network_filters_count - 1] = nfs;
+    return rns;
+}
+
+void replay_unregister_net(ReplayNetState *rns)
+{
+    network_filters[rns->id] = NULL;
+    g_free(rns);
+}
+
+void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
+                             const struct iovec *iov, int iovcnt)
+{
+    NetEvent *event;
+    int i;
+
+    event = g_new(NetEvent, 1);
+    event->flags = flags;
+    event->data = g_malloc(iov_size(iov, iovcnt));
+    event->size = 0;
+    event->id = rns->id;
+
+    for (i = 0; i < iovcnt; i++) {
+        size_t len = iov[i].iov_len;
+
+        memcpy(event->data + event->size, iov[i].iov_base, len);
+        event->size += len;
+    }
+
+    replay_add_event(REPLAY_ASYNC_EVENT_NET, event, NULL, 0);
+}
+
+void replay_event_net_run(void *opaque)
+{
+    NetEvent *event = opaque;
+    struct iovec iov = {
+        .iov_base = (void *)event->data,
+        .iov_len = event->size
+    };
+
+    assert(event->id < network_filters_count);
+
+    qemu_netfilter_pass_to_next(network_filters[event->id]->netdev,
+        event->flags, &iov, 1, network_filters[event->id]);
+
+    g_free(event->data);
+    g_free(event);
+}
+
+void replay_event_net_save(void *opaque)
+{
+    NetEvent *event = opaque;
+
+    replay_put_byte(event->id);
+    replay_put_dword(event->flags);
+    replay_put_array(event->data, event->size);
+}
+
+void *replay_event_net_load(void)
+{
+    NetEvent *event = g_new(NetEvent, 1);
+
+    event->id = replay_get_byte();
+    event->flags = replay_get_dword();
+    replay_get_array_alloc(&event->data, &event->size);
+
+    return event;
+}
diff --git a/replay/replay.c b/replay/replay.c
index 167fd29..e040f6f 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -21,7 +21,7 @@
 
 /* Current version of the replay mechanism.
    Increase it when file format changes. */
-#define REPLAY_VERSION              0xe02004
+#define REPLAY_VERSION              0xe02005
 /* Size of replay log header */
 #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
 
diff --git a/vl.c b/vl.c
index b3c80d5..4c58a27 100644
--- a/vl.c
+++ b/vl.c
@@ -2806,7 +2806,8 @@ static bool object_create_initial(const char *type)
     if (g_str_equal(type, "filter-buffer") ||
         g_str_equal(type, "filter-dump") ||
         g_str_equal(type, "filter-mirror") ||
-        g_str_equal(type, "filter-redirector")) {
+        g_str_equal(type, "filter-redirector") ||
+        g_str_equal(type, "filter-replay")) {
         return false;
     }
 

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

* Re: [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode
  2016-09-15  8:09 ` [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode Pavel Dovgalyuk
@ 2016-09-20  5:51   ` David Gibson
  2016-09-20  8:42     ` Pavel Dovgalyuk
  0 siblings, 1 reply; 7+ messages in thread
From: David Gibson @ 2016-09-20  5:51 UTC (permalink / raw)
  To: Pavel Dovgalyuk
  Cc: qemu-devel, peter.maydell, mst, jasowang, quintela, agraf,
	pbonzini, benh

[-- Attachment #1: Type: text/plain, Size: 76690 bytes --]

On Thu, Sep 15, 2016 at 11:09:59AM +0300, Pavel Dovgalyuk wrote:
> From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
> 
> This patch fixes exception handling in PowerPC.
> Instructions generate several types of exceptions.
> When exception is generated, it breaks the execution of the current translation
> block. Implementation of the exceptions handling does not correctly
> restore icount for the instruction which caused the exception. In most cases
> icount will be decreased by the value equal to the size of TB.
> This patch passes pointer to the translation block internals to the exception
> handler. It allows correct restoring of the icount value.
> 
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>

I'm not really confident reviewing changes in this area.

I've CCed Ben Herrenshmidt, who did some work on the exception
handling recently.  Ben, if you get a chance can you please review
this change.

> ---
>  target-ppc/cpu.h             |    3 +
>  target-ppc/excp_helper.c     |   38 ++++++--
>  target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++--------------------
>  target-ppc/helper.h          |    1 
>  target-ppc/mem_helper.c      |    6 +
>  target-ppc/misc_helper.c     |    8 +-
>  target-ppc/mmu-hash64.c      |   12 +--
>  target-ppc/mmu_helper.c      |   18 ++--
>  target-ppc/timebase_helper.c |   21 ++---
>  target-ppc/translate.c       |   76 +----------------
>  10 files changed, 169 insertions(+), 206 deletions(-)
> 
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 786ab5c..95baae3 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -2434,4 +2434,7 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
>  PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
>  
>  void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
> +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> +                         uint32_t error_code, uintptr_t pc);
> +
>  #endif /* PPC_CPU_H */
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index d6e1678..3da1c32 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -898,8 +898,8 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
>  /*****************************************************************************/
>  /* Exceptions processing helpers */
>  
> -void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> -                                uint32_t error_code)
> +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> +                         uint32_t error_code, uintptr_t pc)
>  {
>      CPUState *cs = CPU(ppc_env_get_cpu(env));
>  
> @@ -908,15 +908,32 @@ void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
>  #endif
>      cs->exception_index = exception;
>      env->error_code = error_code;
> -    cpu_loop_exit(cs);
> +    cpu_loop_exit_restore(cs, pc);
> +}
> +
> +void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> +                                uint32_t error_code)
> +{
> +    raise_exception_err(env, exception, error_code, GETPC());
> +}
> +
> +void helper_raise_exception_end(CPUPPCState *env, uint32_t exception,
> +                                uint32_t error_code)
> +{
> +    raise_exception_err(env, exception, error_code, 0);

I'm struggling to see how raising an exception with a return address
of 0 could ever be useful...

>  }
>  
>  void helper_raise_exception(CPUPPCState *env, uint32_t exception)
>  {
> -    helper_raise_exception_err(env, exception, 0);
> +    raise_exception_err(env, exception, 0, GETPC());
>  }
>  
>  #if !defined(CONFIG_USER_ONLY)
> +static void raise_exception(CPUPPCState *env, uint32_t exception, uintptr_t pc)
> +{
> +    raise_exception_err(env, exception, 0, pc);
> +}
> +
>  void helper_store_msr(CPUPPCState *env, target_ulong val)
>  {
>      CPUState *cs;
> @@ -925,7 +942,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
>      if (val != 0) {
>          cs = CPU(ppc_env_get_cpu(env));
>          cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> -        helper_raise_exception(env, val);
> +        /* nip is updated by generated code */
> +        raise_exception(env, val, 0);
>      }
>  }
>  
> @@ -1041,8 +1059,9 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
>                    ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
>                    ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
>                    ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_TRAP);
> +        /* nip is updated in TB */
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_TRAP, 0);
>      }
>  }
>  
> @@ -1055,8 +1074,9 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
>                    ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
>                    ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
>                    ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_TRAP);
> +        /* nip is updated in TB */
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_TRAP, 0);
>      }
>  }
>  #endif
> diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
> index d9795d0..6eaa3f4 100644
> --- a/target-ppc/fpu_helper.c
> +++ b/target-ppc/fpu_helper.c
> @@ -19,6 +19,7 @@
>  #include "qemu/osdep.h"
>  #include "cpu.h"
>  #include "exec/helper-proto.h"
> +#include "exec/exec-all.h"
>  
>  #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
>  #define float32_snan_to_qnan(x) ((x) | 0x00400000)
> @@ -117,7 +118,7 @@ void helper_compute_fprf(CPUPPCState *env, uint64_t arg)
>  
>  /* Floating-point invalid operations exception */
>  static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
> -                                             int set_fpcc)
> +                                             int set_fpcc, uintptr_t retaddr)
>  {
>      CPUState *cs = CPU(ppc_env_get_cpu(env));
>      uint64_t ret = 0;
> @@ -200,14 +201,14 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
>          /* Update the floating-point enabled exception summary */
>          env->fpscr |= 1 << FPSCR_FEX;
>          if (msr_fe0 != 0 || msr_fe1 != 0) {
> -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                       POWERPC_EXCP_FP | op);
> +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                                POWERPC_EXCP_FP | op, retaddr);
>          }
>      }
>      return ret;
>  }
>  
> -static inline void float_zero_divide_excp(CPUPPCState *env)
> +static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t retaddr)
>  {
>      env->fpscr |= 1 << FPSCR_ZX;
>      env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
> @@ -217,8 +218,8 @@ static inline void float_zero_divide_excp(CPUPPCState *env)
>          /* Update the floating-point enabled exception summary */
>          env->fpscr |= 1 << FPSCR_FEX;
>          if (msr_fe0 != 0 || msr_fe1 != 0) {
> -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
> +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                                POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, retaddr);
>          }
>      }
>  }
> @@ -491,13 +492,13 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
>      helper_store_fpscr(env, arg, mask);
>  }
>  
> -void helper_float_check_status(CPUPPCState *env)
> +static void do_float_check_status(CPUPPCState *env, uintptr_t retaddr)
>  {
>      CPUState *cs = CPU(ppc_env_get_cpu(env));
>      int status = get_float_exception_flags(&env->fp_status);
>  
>      if (status & float_flag_divbyzero) {
> -        float_zero_divide_excp(env);
> +        float_zero_divide_excp(env, retaddr);
>      } else if (status & float_flag_overflow) {
>          float_overflow_excp(env);
>      } else if (status & float_flag_underflow) {
> @@ -510,12 +511,17 @@ void helper_float_check_status(CPUPPCState *env)
>          (env->error_code & POWERPC_EXCP_FP)) {
>          /* Differred floating-point exception after target FPR update */
>          if (msr_fe0 != 0 || msr_fe1 != 0) {
> -            helper_raise_exception_err(env, cs->exception_index,
> -                                       env->error_code);
> +            raise_exception_err(env, cs->exception_index,
> +                                env->error_code, retaddr);
>          }
>      }
>  }
>  
> +void helper_float_check_status(CPUPPCState *env)
> +{
> +    do_float_check_status(env, GETPC());
> +}
> +
>  void helper_reset_fpstatus(CPUPPCState *env)
>  {
>      set_float_exception_flags(0, &env->fp_status);
> @@ -532,12 +538,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
>      if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
>                   float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
>          /* Magnitude subtraction of infinities */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
>              /* sNaN addition */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
>      }
> @@ -556,12 +562,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
>      if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
>                   float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
>          /* Magnitude subtraction of infinities */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
>              /* sNaN subtraction */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
>      }
> @@ -580,12 +586,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
>      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
>                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
>          /* Multiplication of zero by infinity */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
>              /* sNaN multiplication */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
>      }
> @@ -604,15 +610,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
>      if (unlikely(float64_is_infinity(farg1.d) &&
>                   float64_is_infinity(farg2.d))) {
>          /* Division of infinity by infinity */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1, GETPC());
>      } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
>          /* Division of zero by zero */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
>              /* sNaN division */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
>      }
> @@ -631,16 +637,16 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)                   \
>                                                                         \
>      if (unlikely(env->fp_status.float_exception_flags)) {              \
>          if (float64_is_any_nan(arg)) {                                 \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
>              if (float64_is_signaling_nan(arg, &env->fp_status)) {      \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());\
>              }                                                          \
>              farg.ll = nanval;                                          \
>          } else if (env->fp_status.float_exception_flags &              \
>                     float_flag_invalid) {                               \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
>          }                                                              \
> -        helper_float_check_status(env);                                \
> +        do_float_check_status(env, GETPC());                           \
>      }                                                                  \
>      return farg.ll;                                                    \
>   }
> @@ -665,7 +671,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)       \
>      } else {                                               \
>          farg.d = cvtr(arg, &env->fp_status);               \
>      }                                                      \
> -    helper_float_check_status(env);                        \
> +    do_float_check_status(env, GETPC());                   \
>      return farg.ll;                                        \
>  }
>  
> @@ -675,7 +681,7 @@ FPU_FCFI(fcfidu, uint64_to_float64, 0)
>  FPU_FCFI(fcfidus, uint64_to_float32, 1)
>  
>  static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> -                              int rounding_mode)
> +                              int rounding_mode, uint64_t retaddr)
>  {
>      CPU_DoubleU farg;
>  
> @@ -683,7 +689,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
>  
>      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
>          /* sNaN round */
> -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, retaddr);
>          farg.ll = arg | 0x0008000000000000ULL;
>      } else {
>          int inexact = get_float_exception_flags(&env->fp_status) &
> @@ -698,28 +704,28 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
>              env->fp_status.float_exception_flags &= ~float_flag_inexact;
>          }
>      }
> -    helper_float_check_status(env);
> +    do_float_check_status(env, GETPC());
>      return farg.ll;
>  }
>  
>  uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
>  {
> -    return do_fri(env, arg, float_round_ties_away);
> +    return do_fri(env, arg, float_round_ties_away, GETPC());
>  }
>  
>  uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
>  {
> -    return do_fri(env, arg, float_round_to_zero);
> +    return do_fri(env, arg, float_round_to_zero, GETPC());
>  }
>  
>  uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
>  {
> -    return do_fri(env, arg, float_round_up);
> +    return do_fri(env, arg, float_round_up, GETPC());
>  }
>  
>  uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
>  {
> -    return do_fri(env, arg, float_round_down);
> +    return do_fri(env, arg, float_round_down, GETPC());
>  }
>  
>  /* fmadd - fmadd. */
> @@ -735,13 +741,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
>                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
>          /* Multiplication of zero by infinity */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
>              /* sNaN operation */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          /* This is the way the PowerPC specification defines it */
>          float128 ft0_128, ft1_128;
> @@ -753,7 +759,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>                       float64_is_infinity(farg3.d) &&
>                       float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
>              /* Magnitude subtraction of infinities */
> -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
>          } else {
>              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
>              ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
> @@ -778,13 +784,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>                   (float64_is_zero(farg1.d) &&
>                    float64_is_infinity(farg2.d)))) {
>          /* Multiplication of zero by infinity */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
>              /* sNaN operation */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          /* This is the way the PowerPC specification defines it */
>          float128 ft0_128, ft1_128;
> @@ -796,7 +802,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>                       float64_is_infinity(farg3.d) &&
>                       float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
>              /* Magnitude subtraction of infinities */
> -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
>          } else {
>              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
>              ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
> @@ -819,13 +825,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
>                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
>          /* Multiplication of zero by infinity */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
>              /* sNaN operation */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          /* This is the way the PowerPC specification defines it */
>          float128 ft0_128, ft1_128;
> @@ -837,7 +843,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>                       float64_is_infinity(farg3.d) &&
>                       float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
>              /* Magnitude subtraction of infinities */
> -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
>          } else {
>              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
>              ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
> @@ -864,13 +870,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>                   (float64_is_zero(farg1.d) &&
>                    float64_is_infinity(farg2.d)))) {
>          /* Multiplication of zero by infinity */
> -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
>      } else {
>          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
>              /* sNaN operation */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>          }
>          /* This is the way the PowerPC specification defines it */
>          float128 ft0_128, ft1_128;
> @@ -882,7 +888,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>                       float64_is_infinity(farg3.d) &&
>                       float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
>              /* Magnitude subtraction of infinities */
> -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
>          } else {
>              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
>              ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
> @@ -905,7 +911,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
>  
>      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
>          /* sNaN square root */
> -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>      }
>      f32 = float64_to_float32(farg.d, &env->fp_status);
>      farg.d = float32_to_float64(f32, &env->fp_status);
> @@ -923,12 +929,12 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
>      if (unlikely(float64_is_any_nan(farg.d))) {
>          if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
>              /* sNaN reciprocal square root */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>              farg.ll = float64_snan_to_qnan(farg.ll);
>          }
>      } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
>          /* Square root of a negative nonzero number */
> -        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
> +        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
>      } else {
>          farg.d = float64_sqrt(farg.d, &env->fp_status);
>      }
> @@ -944,7 +950,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
>  
>      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
>          /* sNaN reciprocal */
> -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>      }
>      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
>      return farg.d;
> @@ -960,7 +966,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
>  
>      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
>          /* sNaN reciprocal */
> -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>      }
>      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
>      f32 = float64_to_float32(farg.d, &env->fp_status);
> @@ -979,12 +985,12 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
>      if (unlikely(float64_is_any_nan(farg.d))) {
>          if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
>              /* sNaN reciprocal square root */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>              farg.ll = float64_snan_to_qnan(farg.ll);
>          }
>      } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
>          /* Reciprocal square root of a negative nonzero number */
> -        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
> +        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
>      } else {
>          farg.d = float64_sqrt(farg.d, &env->fp_status);
>          farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> @@ -1103,7 +1109,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>                   && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
>                       float64_is_signaling_nan(farg2.d, &env->fp_status)))) {
>          /* sNaN comparison */
> -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
>      }
>  }
>  
> @@ -1135,10 +1141,10 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
>              float64_is_signaling_nan(farg2.d, &env->fp_status)) {
>              /* sNaN comparison */
>              fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
> -                                  POWERPC_EXCP_FP_VXVC, 1);
> +                                  POWERPC_EXCP_FP_VXVC, 1, GETPC());
>          } else {
>              /* qNaN comparison */
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1, GETPC());
>          }
>      }
>  }
> @@ -1838,10 +1844,10 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                        \
>                                                                               \
>          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
>              if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {      \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);    \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
>              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
>                         tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
>              }                                                                \
>          }                                                                    \
>                                                                               \
> @@ -1854,7 +1860,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                        \
>          }                                                                    \
>      }                                                                        \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    do_float_check_status(env, GETPC());                                     \
>  }
>  
>  VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
> @@ -1893,10 +1899,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
>              if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) ||        \
>                  (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) {        \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf);    \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC());\
>              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
>                         tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
>              }                                                                \
>          }                                                                    \
>                                                                               \
> @@ -1910,7 +1916,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    do_float_check_status(env, GETPC());                                     \
>  }
>  
>  VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
> @@ -1944,13 +1950,13 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>                                                                                \
>          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {     \
>              if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {       \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf);     \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf, GETPC());\
>              } else if (tp##_is_zero(xa.fld) &&                                \
>                  tp##_is_zero(xb.fld)) {                                       \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf);     \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf, GETPC());\
>              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||               \
>                  tp##_is_signaling_nan(xb.fld, &tstat)) {                      \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
>              }                                                                 \
>          }                                                                     \
>                                                                                \
> @@ -1964,7 +1970,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>      }                                                                         \
>                                                                                \
>      putVSR(xT(opcode), &xt, env);                                             \
> -    helper_float_check_status(env);                                           \
> +    do_float_check_status(env, GETPC());                                      \
>  }
>  
>  VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
> @@ -1991,7 +1997,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>                                                                                \
>      for (i = 0; i < nels; i++) {                                              \
>          if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
>          }                                                                     \
>          xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status);                 \
>                                                                                \
> @@ -2005,7 +2011,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>      }                                                                         \
>                                                                                \
>      putVSR(xT(opcode), &xt, env);                                             \
> -    helper_float_check_status(env);                                           \
> +    do_float_check_status(env, GETPC());                                      \
>  }
>  
>  VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
> @@ -2038,9 +2044,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>                                                                               \
>          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
>              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
>              } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
>              }                                                                \
>          }                                                                    \
>                                                                               \
> @@ -2054,7 +2060,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    do_float_check_status(env, GETPC());                                     \
>  }
>  
>  VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
> @@ -2088,9 +2094,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>                                                                               \
>          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
>              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
>              } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
>              }                                                                \
>          }                                                                    \
>                                                                               \
> @@ -2104,7 +2110,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    do_float_check_status(env, GETPC());                                     \
>  }
>  
>  VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
> @@ -2277,20 +2283,20 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>              if (tp##_is_signaling_nan(xa.fld, &tstat) ||                      \
>                  tp##_is_signaling_nan(b->fld, &tstat) ||                      \
>                  tp##_is_signaling_nan(c->fld, &tstat)) {                      \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
>                  tstat.float_exception_flags &= ~float_flag_invalid;           \
>              }                                                                 \
>              if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b->fld)) ||         \
>                  (tp##_is_zero(xa.fld) && tp##_is_infinity(b->fld))) {         \
>                  xt_out.fld = float64_to_##tp(fload_invalid_op_excp(env,       \
> -                    POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status);          \
> +                    POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC()), &env->fp_status); \
>                  tstat.float_exception_flags &= ~float_flag_invalid;           \
>              }                                                                 \
>              if ((tstat.float_exception_flags & float_flag_invalid) &&         \
>                  ((tp##_is_infinity(xa.fld) ||                                 \
>                    tp##_is_infinity(b->fld)) &&                                \
>                    tp##_is_infinity(c->fld))) {                                \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);     \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
>              }                                                                 \
>          }                                                                     \
>                                                                                \
> @@ -2303,7 +2309,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>          }                                                                     \
>      }                                                                         \
>      putVSR(xT(opcode), &xt_out, env);                                         \
> -    helper_float_check_status(env);                                           \
> +    do_float_check_status(env, GETPC());                                      \
>  }
>  
>  #define MADD_FLGS 0
> @@ -2360,10 +2366,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                      \
>                   float64_is_any_nan(xb.VsrD(0)))) {                      \
>          if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) ||     \
>              float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) {     \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
>          }                                                                \
>          if (ordered) {                                                   \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);         \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
>          }                                                                \
>          cc = 1;                                                          \
>      } else {                                                             \
> @@ -2381,7 +2387,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                      \
>      env->fpscr |= cc << FPSCR_FPRF;                                      \
>      env->crf[BF(opcode)] = cc;                                           \
>                                                                           \
> -    helper_float_check_status(env);                                      \
> +    do_float_check_status(env, GETPC());                                 \
>  }
>  
>  VSX_SCALAR_CMP(xscmpodp, 1)
> @@ -2408,12 +2414,12 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                         \
>          xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status);                  \
>          if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) ||        \
>                       tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);            \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());   \
>          }                                                                     \
>      }                                                                         \
>                                                                                \
>      putVSR(xT(opcode), &xt, env);                                             \
> -    helper_float_check_status(env);                                           \
> +    do_float_check_status(env, GETPC());                                      \
>  }
>  
>  VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
> @@ -2448,10 +2454,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                       \
>                       tp##_is_any_nan(xb.fld))) {                          \
>              if (tp##_is_signaling_nan(xa.fld, &env->fp_status) ||         \
>                  tp##_is_signaling_nan(xb.fld, &env->fp_status)) {         \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);    \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
>              }                                                             \
>              if (svxvc) {                                                  \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);      \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
>              }                                                             \
>              xt.fld = 0;                                                   \
>              all_true = 0;                                                 \
> @@ -2470,7 +2476,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                       \
>      if ((opcode >> (31-21)) & 1) {                                        \
>          env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0);       \
>      }                                                                     \
> -    helper_float_check_status(env);                                       \
> +    do_float_check_status(env, GETPC());                                  \
>   }
>  
>  VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
> @@ -2502,7 +2508,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
>          xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status);        \
>          if (unlikely(stp##_is_signaling_nan(xb.sfld,               \
>                                              &env->fp_status))) {   \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC()); \
>              xt.tfld = ttp##_snan_to_qnan(xt.tfld);                 \
>          }                                                          \
>          if (sfprf) {                                               \
> @@ -2512,7 +2518,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
>      }                                                              \
>                                                                     \
>      putVSR(xT(opcode), &xt, env);                                  \
> -    helper_float_check_status(env);                                \
> +    do_float_check_status(env, GETPC());                           \
>  }
>  
>  VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1)
> @@ -2557,21 +2563,21 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      for (i = 0; i < nels; i++) {                                             \
>          if (unlikely(stp##_is_any_nan(xb.sfld))) {                           \
>              if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) {          \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
>              }                                                                \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);            \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());   \
>              xt.tfld = rnan;                                                  \
>          } else {                                                             \
>              xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld,                \
>                            &env->fp_status);                                  \
>              if (env->fp_status.float_exception_flags & float_flag_invalid) { \
> -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);        \
> +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());\
>              }                                                                \
>          }                                                                    \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    do_float_check_status(env, GETPC());                                     \
>  }
>  
>  VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \
> @@ -2622,7 +2628,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                     \
>      }                                                                   \
>                                                                          \
>      putVSR(xT(opcode), &xt, env);                                       \
> -    helper_float_check_status(env);                                     \
> +    do_float_check_status(env, GETPC());                                \
>  }
>  
>  VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
> @@ -2667,7 +2673,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                    \
>      for (i = 0; i < nels; i++) {                                       \
>          if (unlikely(tp##_is_signaling_nan(xb.fld,                     \
>                                             &env->fp_status))) {        \
> -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);     \
> +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
>              xt.fld = tp##_snan_to_qnan(xb.fld);                        \
>          } else {                                                       \
>              xt.fld = tp##_round_to_int(xb.fld, &env->fp_status);       \
> @@ -2686,7 +2692,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                    \
>      }                                                                  \
>                                                                         \
>      putVSR(xT(opcode), &xt, env);                                      \
> -    helper_float_check_status(env);                                    \
> +    do_float_check_status(env, GETPC());                               \
>  }
>  
>  VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
> @@ -2714,6 +2720,6 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
>      uint64_t xt = helper_frsp(env, xb);
>  
>      helper_compute_fprf(env, xt);
> -    helper_float_check_status(env);
> +    do_float_check_status(env, GETPC());
>      return xt;
>  }
> diff --git a/target-ppc/helper.h b/target-ppc/helper.h
> index 1f5cfd0..34560f9 100644
> --- a/target-ppc/helper.h
> +++ b/target-ppc/helper.h
> @@ -1,4 +1,5 @@
>  DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
> +DEF_HELPER_3(raise_exception_end, void, env, i32, i32)
>  DEF_HELPER_2(raise_exception, void, env, i32)
>  DEF_HELPER_4(tw, void, env, tl, tl, i32)
>  #if defined(TARGET_PPC64)
> diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> index e4ed377..5cee620 100644
> --- a/target-ppc/mem_helper.c
> +++ b/target-ppc/mem_helper.c
> @@ -107,9 +107,9 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
>          if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
>                       lsw_reg_in_range(reg, num_used_regs, rb))) {
>              env->nip += 4;     /* Compensate the "nip - 4" from gen_lswx() */
> -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                       POWERPC_EXCP_INVAL |
> -                                       POWERPC_EXCP_INVAL_LSWX);
> +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                                POWERPC_EXCP_INVAL |
> +                                POWERPC_EXCP_INVAL_LSWX, GETPC());
>          } else {
>              helper_lsw(env, addr, xer_bc, reg);
>          }
> diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
> index cb5ebf5..6661650 100644
> --- a/target-ppc/misc_helper.c
> +++ b/target-ppc/misc_helper.c
> @@ -39,7 +39,7 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
>  
>  #ifdef TARGET_PPC64
>  static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
> -                               uint32_t sprn, uint32_t cause)
> +                               uint32_t sprn, uint32_t cause, uintptr_t retaddr)
>  {
>      qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
>  
> @@ -47,7 +47,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
>      cause &= FSCR_IC_MASK;
>      env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
>  
> -    helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
> +    raise_exception_err(env, POWERPC_EXCP_FU, 0, retaddr);
>  }
>  #endif
>  
> @@ -59,7 +59,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
>          /* Facility is enabled, continue */
>          return;
>      }
> -    raise_fu_exception(env, bit, sprn, cause);
> +    raise_fu_exception(env, bit, sprn, cause, GETPC());
>  #endif
>  }
>  
> @@ -71,7 +71,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
>          /* Facility is enabled, continue */
>          return;
>      }
> -    raise_fu_exception(env, bit, sprn, cause);
> +    raise_fu_exception(env, bit, sprn, cause, GETPC());
>  #endif
>  }
>  
> diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
> index 5de1358..a1b27b0 100644
> --- a/target-ppc/mmu-hash64.c
> +++ b/target-ppc/mmu-hash64.c
> @@ -241,8 +241,8 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
>      PowerPCCPU *cpu = ppc_env_get_cpu(env);
>  
>      if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL, GETPC());
>      }
>  }
>  
> @@ -252,8 +252,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
>      target_ulong rt = 0;
>  
>      if (ppc_load_slb_esid(cpu, rb, &rt) < 0) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL, GETPC());
>      }
>      return rt;
>  }
> @@ -276,8 +276,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
>      target_ulong rt = 0;
>  
>      if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL, GETPC());
>      }
>      return rt;
>  }
> diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
> index 3eb3cd7..7cd9c2c 100644
> --- a/target-ppc/mmu_helper.c
> +++ b/target-ppc/mmu_helper.c
> @@ -2598,9 +2598,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
>      tlb = booke206_cur_tlb(env);
>  
>      if (!tlb) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL |
> -                                   POWERPC_EXCP_INVAL_INVAL);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL |
> +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
>      }
>  
>      /* check that we support the targeted size */
> @@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
>      size_ps = booke206_tlbnps(env, tlbn);
>      if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
>          !(size_ps & (1 << size_tlb))) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL |
> -                                   POWERPC_EXCP_INVAL_INVAL);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL |
> +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
>      }
>  
>      if (msr_gs) {
> @@ -2892,10 +2892,6 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
>          ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
>      }
>      if (unlikely(ret != 0)) {
> -        if (likely(retaddr)) {
> -            /* now we have a real cpu fault */
> -            cpu_restore_state(cs, retaddr);
> -        }
> -        helper_raise_exception_err(env, cs->exception_index, env->error_code);
> +        raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
>      }
>  }
> diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
> index a07faa4..af328ca 100644
> --- a/target-ppc/timebase_helper.c
> +++ b/target-ppc/timebase_helper.c
> @@ -19,6 +19,7 @@
>  #include "qemu/osdep.h"
>  #include "cpu.h"
>  #include "exec/helper-proto.h"
> +#include "exec/exec-all.h"
>  #include "qemu/log.h"
>  
>  /*****************************************************************************/
> @@ -143,15 +144,15 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
>  
>      if (unlikely(env->dcr_env == NULL)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL |
> -                                   POWERPC_EXCP_INVAL_INVAL);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL |
> +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
>      } else if (unlikely(ppc_dcr_read(env->dcr_env,
>                                       (uint32_t)dcrn, &val) != 0)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
>                        (uint32_t)dcrn, (uint32_t)dcrn);
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
>      }
>      return val;
>  }
> @@ -160,14 +161,14 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val)
>  {
>      if (unlikely(env->dcr_env == NULL)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL |
> -                                   POWERPC_EXCP_INVAL_INVAL);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL |
> +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
>      } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
>                                        (uint32_t)val) != 0)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n",
>                        (uint32_t)dcrn, (uint32_t)dcrn);
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> +                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
>      }
>  }
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index 92030b6..0e16578 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -292,7 +292,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
>      }
>      t0 = tcg_const_i32(excp);
>      t1 = tcg_const_i32(error);
> -    gen_helper_raise_exception_err(cpu_env, t0, t1);
> +    gen_helper_raise_exception_end(cpu_env, t0, t1);
>      tcg_temp_free_i32(t0);
>      tcg_temp_free_i32(t1);
>      ctx->exception = (excp);
> @@ -300,14 +300,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
>  
>  static void gen_exception(DisasContext *ctx, uint32_t excp)
>  {
> -    TCGv_i32 t0;
> -    if (ctx->exception == POWERPC_EXCP_NONE) {
> -        gen_update_nip(ctx, ctx->nip);
> -    }
> -    t0 = tcg_const_i32(excp);
> -    gen_helper_raise_exception(cpu_env, t0);
> -    tcg_temp_free_i32(t0);
> -    ctx->exception = (excp);
> +    gen_exception_err(ctx, excp, 0);
>  }
>  
>  static void gen_debug_exception(DisasContext *ctx)
> @@ -2149,8 +2142,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
>          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
>          return;                                                               \
>      }                                                                         \
> -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> -    gen_update_nip(ctx, ctx->nip - 4);                                        \
>      gen_reset_fpstatus();                                                     \
>      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
>                       cpu_fpr[rA(ctx->opcode)],                                \
> @@ -2178,8 +2169,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
>          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
>          return;                                                               \
>      }                                                                         \
> -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> -    gen_update_nip(ctx, ctx->nip - 4);                                        \
>      gen_reset_fpstatus();                                                     \
>      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
>                       cpu_fpr[rA(ctx->opcode)],                                \
> @@ -2206,8 +2195,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
>          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
>          return;                                                               \
>      }                                                                         \
> -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> -    gen_update_nip(ctx, ctx->nip - 4);                                        \
>      gen_reset_fpstatus();                                                     \
>      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
>                       cpu_fpr[rA(ctx->opcode)],                                \
> @@ -2234,8 +2221,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
>          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
>          return;                                                               \
>      }                                                                         \
> -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> -    gen_update_nip(ctx, ctx->nip - 4);                                        \
>      gen_reset_fpstatus();                                                     \
>      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
>                         cpu_fpr[rB(ctx->opcode)]);                             \
> @@ -2254,8 +2239,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
>          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
>          return;                                                               \
>      }                                                                         \
> -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> -    gen_update_nip(ctx, ctx->nip - 4);                                        \
>      gen_reset_fpstatus();                                                     \
>      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
>                         cpu_fpr[rB(ctx->opcode)]);                             \
> @@ -2290,8 +2273,6 @@ static void gen_frsqrtes(DisasContext *ctx)
>          gen_exception(ctx, POWERPC_EXCP_FPU);
>          return;
>      }
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_reset_fpstatus();
>      gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
>                         cpu_fpr[rB(ctx->opcode)]);
> @@ -2316,8 +2297,6 @@ static void gen_fsqrt(DisasContext *ctx)
>          gen_exception(ctx, POWERPC_EXCP_FPU);
>          return;
>      }
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_reset_fpstatus();
>      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
>                       cpu_fpr[rB(ctx->opcode)]);
> @@ -2333,8 +2312,6 @@ static void gen_fsqrts(DisasContext *ctx)
>          gen_exception(ctx, POWERPC_EXCP_FPU);
>          return;
>      }
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_reset_fpstatus();
>      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
>                       cpu_fpr[rB(ctx->opcode)]);
> @@ -2424,8 +2401,6 @@ static void gen_fcmpo(DisasContext *ctx)
>          gen_exception(ctx, POWERPC_EXCP_FPU);
>          return;
>      }
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_reset_fpstatus();
>      crf = tcg_const_i32(crfD(ctx->opcode));
>      gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
> @@ -2442,8 +2417,6 @@ static void gen_fcmpu(DisasContext *ctx)
>          gen_exception(ctx, POWERPC_EXCP_FPU);
>          return;
>      }
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_reset_fpstatus();
>      crf = tcg_const_i32(crfD(ctx->opcode));
>      gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
> @@ -2613,8 +2586,6 @@ static void gen_mtfsb0(DisasContext *ctx)
>      gen_reset_fpstatus();
>      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
>          TCGv_i32 t0;
> -        /* NIP cannot be restored if the memory exception comes from an helper */
> -        gen_update_nip(ctx, ctx->nip - 4);
>          t0 = tcg_const_i32(crb);
>          gen_helper_fpscr_clrbit(cpu_env, t0);
>          tcg_temp_free_i32(t0);
> @@ -2639,8 +2610,6 @@ static void gen_mtfsb1(DisasContext *ctx)
>      /* XXX: we pretend we can only do IEEE floating-point computations */
>      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
>          TCGv_i32 t0;
> -        /* NIP cannot be restored if the memory exception comes from an helper */
> -        gen_update_nip(ctx, ctx->nip - 4);
>          t0 = tcg_const_i32(crb);
>          gen_helper_fpscr_setbit(cpu_env, t0);
>          tcg_temp_free_i32(t0);
> @@ -2670,8 +2639,6 @@ static void gen_mtfsf(DisasContext *ctx)
>          gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
>          return;
>      }
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_reset_fpstatus();
>      if (l) {
>          t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
> @@ -2706,8 +2673,6 @@ static void gen_mtfsfi(DisasContext *ctx)
>          return;
>      }
>      sh = (8 * w) + 7 - bf;
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_reset_fpstatus();
>      t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
>      t1 = tcg_const_i32(1 << sh);
> @@ -2790,8 +2755,6 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
>      TCGLabel *l1 = gen_new_label();
>      TCGv t0 = tcg_temp_new();
>      TCGv_i32 t1, t2;
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      tcg_gen_andi_tl(t0, EA, mask);
>      tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
>      t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
> @@ -3261,8 +3224,6 @@ static void gen_lmw(DisasContext *ctx)
>      TCGv t0;
>      TCGv_i32 t1;
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      t1 = tcg_const_i32(rD(ctx->opcode));
>      gen_addr_imm_index(ctx, t0, 0);
> @@ -3277,8 +3238,6 @@ static void gen_stmw(DisasContext *ctx)
>      TCGv t0;
>      TCGv_i32 t1;
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      t1 = tcg_const_i32(rS(ctx->opcode));
>      gen_addr_imm_index(ctx, t0, 0);
> @@ -3312,8 +3271,6 @@ static void gen_lswi(DisasContext *ctx)
>          return;
>      }
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_register(ctx, t0);
>      t1 = tcg_const_i32(nb);
> @@ -3330,8 +3287,6 @@ static void gen_lswx(DisasContext *ctx)
>      TCGv t0;
>      TCGv_i32 t1, t2, t3;
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_reg_index(ctx, t0);
>      t1 = tcg_const_i32(rD(ctx->opcode));
> @@ -3351,8 +3306,6 @@ static void gen_stswi(DisasContext *ctx)
>      TCGv_i32 t1, t2;
>      int nb = NB(ctx->opcode);
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_register(ctx, t0);
>      if (nb == 0)
> @@ -3371,8 +3324,6 @@ static void gen_stswx(DisasContext *ctx)
>      TCGv t0;
>      TCGv_i32 t1, t2;
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_reg_index(ctx, t0);
>      t1 = tcg_temp_new_i32();
> @@ -4306,7 +4257,7 @@ static void gen_tw(DisasContext *ctx)
>  {
>      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_stop_exception(ctx);
>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -4318,7 +4269,7 @@ static void gen_twi(DisasContext *ctx)
>      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
>      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_stop_exception(ctx);
>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);
> @@ -4330,7 +4281,7 @@ static void gen_td(DisasContext *ctx)
>  {
>      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_stop_exception(ctx);
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -4342,7 +4293,7 @@ static void gen_tdi(DisasContext *ctx)
>      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
>      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_stop_exception(ctx);
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);
> @@ -4768,8 +4719,6 @@ static void gen_dcbz(DisasContext *ctx)
>      int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
>  
>      gen_set_access_type(ctx, ACCESS_CACHE);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      tcgv_addr = tcg_temp_new();
>      tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
>  
> @@ -4812,8 +4761,6 @@ static void gen_icbi(DisasContext *ctx)
>  {
>      TCGv t0;
>      gen_set_access_type(ctx, ACCESS_CACHE);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_reg_index(ctx, t0);
>      gen_helper_icbi(cpu_env, t0);
> @@ -5299,8 +5246,6 @@ static void gen_lscbx(DisasContext *ctx)
>      TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
>  
>      gen_addr_reg_index(ctx, t0);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
>      tcg_temp_free_i32(t1);
>      tcg_temp_free_i32(t2);
> @@ -6386,8 +6331,6 @@ static void gen_mtdcrx(DisasContext *ctx)
>  /* mfdcrux (PPC 460) : user-mode access to DCR */
>  static void gen_mfdcrux(DisasContext *ctx)
>  {
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
>                          cpu_gpr[rA(ctx->opcode)]);
>      /* Note: Rc update flag set leads to undefined state of Rc0 */
> @@ -6396,8 +6339,6 @@ static void gen_mfdcrux(DisasContext *ctx)
>  /* mtdcrux (PPC 460) : user-mode access to DCR */
>  static void gen_mtdcrux(DisasContext *ctx)
>  {
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
>                           cpu_gpr[rS(ctx->opcode)]);
>      /* Note: Rc update flag set leads to undefined state of Rc0 */
> @@ -8027,8 +7968,6 @@ static void gen_##name(DisasContext * ctx)                                    \
>          gen_exception(ctx, POWERPC_EXCP_VSXU);                                \
>          return;                                                               \
>      }                                                                         \
> -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> -    gen_update_nip(ctx, ctx->nip - 4);                                        \
>      opc = tcg_const_i32(ctx->opcode);                                         \
>      gen_helper_##name(cpu_env, opc);                                          \
>      tcg_temp_free_i32(opc);                                                   \
> @@ -8041,9 +7980,6 @@ static void gen_##name(DisasContext * ctx)                    \
>          gen_exception(ctx, POWERPC_EXCP_VSXU);                \
>          return;                                               \
>      }                                                         \
> -    /* NIP cannot be restored if the exception comes */       \
> -    /* from a helper. */                                      \
> -    gen_update_nip(ctx, ctx->nip - 4);                        \
>                                                                \
>      gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
>                        cpu_vsrh(xB(ctx->opcode)));             \
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode
  2016-09-20  5:51   ` David Gibson
@ 2016-09-20  8:42     ` Pavel Dovgalyuk
  2016-09-20  8:54       ` Benjamin Herrenschmidt
  2016-09-20 13:15       ` 'David Gibson'
  0 siblings, 2 replies; 7+ messages in thread
From: Pavel Dovgalyuk @ 2016-09-20  8:42 UTC (permalink / raw)
  To: 'David Gibson', 'Pavel Dovgalyuk'
  Cc: qemu-devel, peter.maydell, mst, jasowang, quintela, agraf,
	pbonzini, benh

> From: David Gibson [mailto:david@gibson.dropbear.id.au]
> On Thu, Sep 15, 2016 at 11:09:59AM +0300, Pavel Dovgalyuk wrote:
> > From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
> >
> > This patch fixes exception handling in PowerPC.
> > Instructions generate several types of exceptions.
> > When exception is generated, it breaks the execution of the current translation
> > block. Implementation of the exceptions handling does not correctly
> > restore icount for the instruction which caused the exception. In most cases
> > icount will be decreased by the value equal to the size of TB.
> > This patch passes pointer to the translation block internals to the exception
> > handler. It allows correct restoring of the icount value.
> >
> > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> 
> I'm not really confident reviewing changes in this area.
> 
> I've CCed Ben Herrenshmidt, who did some work on the exception
> handling recently.  

Thanks.
It seems that most of these changes were already upstreamed from some other patch.
That's why I removed this one from the updated series.

> 
> > ---
> >  target-ppc/cpu.h             |    3 +
> >  target-ppc/excp_helper.c     |   38 ++++++--
> >  target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++--------------------
> >  target-ppc/helper.h          |    1
> >  target-ppc/mem_helper.c      |    6 +
> >  target-ppc/misc_helper.c     |    8 +-
> >  target-ppc/mmu-hash64.c      |   12 +--
> >  target-ppc/mmu_helper.c      |   18 ++--
> >  target-ppc/timebase_helper.c |   21 ++---
> >  target-ppc/translate.c       |   76 +----------------
> >  10 files changed, 169 insertions(+), 206 deletions(-)
> >
> > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> > index 786ab5c..95baae3 100644
> > --- a/target-ppc/cpu.h
> > +++ b/target-ppc/cpu.h
> > @@ -2434,4 +2434,7 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
> >  PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
> >
> >  void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
> > +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> > +                         uint32_t error_code, uintptr_t pc);
> > +
> >  #endif /* PPC_CPU_H */
> > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> > index d6e1678..3da1c32 100644
> > --- a/target-ppc/excp_helper.c
> > +++ b/target-ppc/excp_helper.c
> > @@ -898,8 +898,8 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
> >  /*****************************************************************************/
> >  /* Exceptions processing helpers */
> >
> > -void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> > -                                uint32_t error_code)
> > +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> > +                         uint32_t error_code, uintptr_t pc)
> >  {
> >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> >
> > @@ -908,15 +908,32 @@ void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> >  #endif
> >      cs->exception_index = exception;
> >      env->error_code = error_code;
> > -    cpu_loop_exit(cs);
> > +    cpu_loop_exit_restore(cs, pc);
> > +}
> > +
> > +void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> > +                                uint32_t error_code)
> > +{
> > +    raise_exception_err(env, exception, error_code, GETPC());
> > +}
> > +
> > +void helper_raise_exception_end(CPUPPCState *env, uint32_t exception,
> > +                                uint32_t error_code)
> > +{
> > +    raise_exception_err(env, exception, error_code, 0);
> 
> I'm struggling to see how raising an exception with a return address
> of 0 could ever be useful...
> 
> >  }
> >
> >  void helper_raise_exception(CPUPPCState *env, uint32_t exception)
> >  {
> > -    helper_raise_exception_err(env, exception, 0);
> > +    raise_exception_err(env, exception, 0, GETPC());
> >  }
> >
> >  #if !defined(CONFIG_USER_ONLY)
> > +static void raise_exception(CPUPPCState *env, uint32_t exception, uintptr_t pc)
> > +{
> > +    raise_exception_err(env, exception, 0, pc);
> > +}
> > +
> >  void helper_store_msr(CPUPPCState *env, target_ulong val)
> >  {
> >      CPUState *cs;
> > @@ -925,7 +942,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
> >      if (val != 0) {
> >          cs = CPU(ppc_env_get_cpu(env));
> >          cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> > -        helper_raise_exception(env, val);
> > +        /* nip is updated by generated code */
> > +        raise_exception(env, val, 0);
> >      }
> >  }
> >
> > @@ -1041,8 +1059,9 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
> >                    ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
> >                    ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
> >                    ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_TRAP);
> > +        /* nip is updated in TB */
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_TRAP, 0);
> >      }
> >  }
> >
> > @@ -1055,8 +1074,9 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
> >                    ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
> >                    ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
> >                    ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_TRAP);
> > +        /* nip is updated in TB */
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_TRAP, 0);
> >      }
> >  }
> >  #endif
> > diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
> > index d9795d0..6eaa3f4 100644
> > --- a/target-ppc/fpu_helper.c
> > +++ b/target-ppc/fpu_helper.c
> > @@ -19,6 +19,7 @@
> >  #include "qemu/osdep.h"
> >  #include "cpu.h"
> >  #include "exec/helper-proto.h"
> > +#include "exec/exec-all.h"
> >
> >  #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
> >  #define float32_snan_to_qnan(x) ((x) | 0x00400000)
> > @@ -117,7 +118,7 @@ void helper_compute_fprf(CPUPPCState *env, uint64_t arg)
> >
> >  /* Floating-point invalid operations exception */
> >  static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
> > -                                             int set_fpcc)
> > +                                             int set_fpcc, uintptr_t retaddr)
> >  {
> >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> >      uint64_t ret = 0;
> > @@ -200,14 +201,14 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
> >          /* Update the floating-point enabled exception summary */
> >          env->fpscr |= 1 << FPSCR_FEX;
> >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                       POWERPC_EXCP_FP | op);
> > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                                POWERPC_EXCP_FP | op, retaddr);
> >          }
> >      }
> >      return ret;
> >  }
> >
> > -static inline void float_zero_divide_excp(CPUPPCState *env)
> > +static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t retaddr)
> >  {
> >      env->fpscr |= 1 << FPSCR_ZX;
> >      env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
> > @@ -217,8 +218,8 @@ static inline void float_zero_divide_excp(CPUPPCState *env)
> >          /* Update the floating-point enabled exception summary */
> >          env->fpscr |= 1 << FPSCR_FEX;
> >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
> > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                                POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, retaddr);
> >          }
> >      }
> >  }
> > @@ -491,13 +492,13 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
> >      helper_store_fpscr(env, arg, mask);
> >  }
> >
> > -void helper_float_check_status(CPUPPCState *env)
> > +static void do_float_check_status(CPUPPCState *env, uintptr_t retaddr)
> >  {
> >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> >      int status = get_float_exception_flags(&env->fp_status);
> >
> >      if (status & float_flag_divbyzero) {
> > -        float_zero_divide_excp(env);
> > +        float_zero_divide_excp(env, retaddr);
> >      } else if (status & float_flag_overflow) {
> >          float_overflow_excp(env);
> >      } else if (status & float_flag_underflow) {
> > @@ -510,12 +511,17 @@ void helper_float_check_status(CPUPPCState *env)
> >          (env->error_code & POWERPC_EXCP_FP)) {
> >          /* Differred floating-point exception after target FPR update */
> >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > -            helper_raise_exception_err(env, cs->exception_index,
> > -                                       env->error_code);
> > +            raise_exception_err(env, cs->exception_index,
> > +                                env->error_code, retaddr);
> >          }
> >      }
> >  }
> >
> > +void helper_float_check_status(CPUPPCState *env)
> > +{
> > +    do_float_check_status(env, GETPC());
> > +}
> > +
> >  void helper_reset_fpstatus(CPUPPCState *env)
> >  {
> >      set_float_exception_flags(0, &env->fp_status);
> > @@ -532,12 +538,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> >      if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
> >                   float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
> >          /* Magnitude subtraction of infinities */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> >              /* sNaN addition */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
> >      }
> > @@ -556,12 +562,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> >      if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
> >                   float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
> >          /* Magnitude subtraction of infinities */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> >              /* sNaN subtraction */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
> >      }
> > @@ -580,12 +586,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> >      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
> >                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
> >          /* Multiplication of zero by infinity */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> >              /* sNaN multiplication */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
> >      }
> > @@ -604,15 +610,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> >      if (unlikely(float64_is_infinity(farg1.d) &&
> >                   float64_is_infinity(farg2.d))) {
> >          /* Division of infinity by infinity */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1, GETPC());
> >      } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
> >          /* Division of zero by zero */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> >              /* sNaN division */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
> >      }
> > @@ -631,16 +637,16 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)
> \
> >                                                                         \
> >      if (unlikely(env->fp_status.float_exception_flags)) {              \
> >          if (float64_is_any_nan(arg)) {                                 \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
> >              if (float64_is_signaling_nan(arg, &env->fp_status)) {      \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());\
> >              }                                                          \
> >              farg.ll = nanval;                                          \
> >          } else if (env->fp_status.float_exception_flags &              \
> >                     float_flag_invalid) {                               \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
> >          }                                                              \
> > -        helper_float_check_status(env);                                \
> > +        do_float_check_status(env, GETPC());                           \
> >      }                                                                  \
> >      return farg.ll;                                                    \
> >   }
> > @@ -665,7 +671,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)       \
> >      } else {                                               \
> >          farg.d = cvtr(arg, &env->fp_status);               \
> >      }                                                      \
> > -    helper_float_check_status(env);                        \
> > +    do_float_check_status(env, GETPC());                   \
> >      return farg.ll;                                        \
> >  }
> >
> > @@ -675,7 +681,7 @@ FPU_FCFI(fcfidu, uint64_to_float64, 0)
> >  FPU_FCFI(fcfidus, uint64_to_float32, 1)
> >
> >  static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> > -                              int rounding_mode)
> > +                              int rounding_mode, uint64_t retaddr)
> >  {
> >      CPU_DoubleU farg;
> >
> > @@ -683,7 +689,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> >
> >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> >          /* sNaN round */
> > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, retaddr);
> >          farg.ll = arg | 0x0008000000000000ULL;
> >      } else {
> >          int inexact = get_float_exception_flags(&env->fp_status) &
> > @@ -698,28 +704,28 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> >              env->fp_status.float_exception_flags &= ~float_flag_inexact;
> >          }
> >      }
> > -    helper_float_check_status(env);
> > +    do_float_check_status(env, GETPC());
> >      return farg.ll;
> >  }
> >
> >  uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
> >  {
> > -    return do_fri(env, arg, float_round_ties_away);
> > +    return do_fri(env, arg, float_round_ties_away, GETPC());
> >  }
> >
> >  uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
> >  {
> > -    return do_fri(env, arg, float_round_to_zero);
> > +    return do_fri(env, arg, float_round_to_zero, GETPC());
> >  }
> >
> >  uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
> >  {
> > -    return do_fri(env, arg, float_round_up);
> > +    return do_fri(env, arg, float_round_up, GETPC());
> >  }
> >
> >  uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
> >  {
> > -    return do_fri(env, arg, float_round_down);
> > +    return do_fri(env, arg, float_round_down, GETPC());
> >  }
> >
> >  /* fmadd - fmadd. */
> > @@ -735,13 +741,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
> >                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
> >          /* Multiplication of zero by infinity */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> >              /* sNaN operation */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          /* This is the way the PowerPC specification defines it */
> >          float128 ft0_128, ft1_128;
> > @@ -753,7 +759,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >                       float64_is_infinity(farg3.d) &&
> >                       float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
> >              /* Magnitude subtraction of infinities */
> > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> >          } else {
> >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> >              ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
> > @@ -778,13 +784,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >                   (float64_is_zero(farg1.d) &&
> >                    float64_is_infinity(farg2.d)))) {
> >          /* Multiplication of zero by infinity */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> >              /* sNaN operation */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          /* This is the way the PowerPC specification defines it */
> >          float128 ft0_128, ft1_128;
> > @@ -796,7 +802,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >                       float64_is_infinity(farg3.d) &&
> >                       float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
> >              /* Magnitude subtraction of infinities */
> > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> >          } else {
> >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> >              ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
> > @@ -819,13 +825,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
> >                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
> >          /* Multiplication of zero by infinity */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> >              /* sNaN operation */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          /* This is the way the PowerPC specification defines it */
> >          float128 ft0_128, ft1_128;
> > @@ -837,7 +843,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >                       float64_is_infinity(farg3.d) &&
> >                       float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
> >              /* Magnitude subtraction of infinities */
> > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> >          } else {
> >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> >              ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
> > @@ -864,13 +870,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >                   (float64_is_zero(farg1.d) &&
> >                    float64_is_infinity(farg2.d)))) {
> >          /* Multiplication of zero by infinity */
> > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> >      } else {
> >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> >              /* sNaN operation */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >          }
> >          /* This is the way the PowerPC specification defines it */
> >          float128 ft0_128, ft1_128;
> > @@ -882,7 +888,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >                       float64_is_infinity(farg3.d) &&
> >                       float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
> >              /* Magnitude subtraction of infinities */
> > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> >          } else {
> >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> >              ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
> > @@ -905,7 +911,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
> >
> >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> >          /* sNaN square root */
> > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >      }
> >      f32 = float64_to_float32(farg.d, &env->fp_status);
> >      farg.d = float32_to_float64(f32, &env->fp_status);
> > @@ -923,12 +929,12 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
> >      if (unlikely(float64_is_any_nan(farg.d))) {
> >          if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> >              /* sNaN reciprocal square root */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >              farg.ll = float64_snan_to_qnan(farg.ll);
> >          }
> >      } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
> >          /* Square root of a negative nonzero number */
> > -        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
> > +        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
> >      } else {
> >          farg.d = float64_sqrt(farg.d, &env->fp_status);
> >      }
> > @@ -944,7 +950,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
> >
> >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> >          /* sNaN reciprocal */
> > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >      }
> >      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> >      return farg.d;
> > @@ -960,7 +966,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
> >
> >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> >          /* sNaN reciprocal */
> > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >      }
> >      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> >      f32 = float64_to_float32(farg.d, &env->fp_status);
> > @@ -979,12 +985,12 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
> >      if (unlikely(float64_is_any_nan(farg.d))) {
> >          if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> >              /* sNaN reciprocal square root */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >              farg.ll = float64_snan_to_qnan(farg.ll);
> >          }
> >      } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
> >          /* Reciprocal square root of a negative nonzero number */
> > -        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
> > +        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
> >      } else {
> >          farg.d = float64_sqrt(farg.d, &env->fp_status);
> >          farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> > @@ -1103,7 +1109,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >                   && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> >                       float64_is_signaling_nan(farg2.d, &env->fp_status)))) {
> >          /* sNaN comparison */
> > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> >      }
> >  }
> >
> > @@ -1135,10 +1141,10 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> >              float64_is_signaling_nan(farg2.d, &env->fp_status)) {
> >              /* sNaN comparison */
> >              fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
> > -                                  POWERPC_EXCP_FP_VXVC, 1);
> > +                                  POWERPC_EXCP_FP_VXVC, 1, GETPC());
> >          } else {
> >              /* qNaN comparison */
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1, GETPC());
> >          }
> >      }
> >  }
> > @@ -1838,10 +1844,10 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)
> \
> >                                                                               \
> >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> >              if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {      \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);    \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
> >              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
> >                         tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> >              }                                                                \
> >          }                                                                    \
> >                                                                               \
> > @@ -1854,7 +1860,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)
> \
> >          }                                                                    \
> >      }                                                                        \
> >      putVSR(xT(opcode), &xt, env);                                            \
> > -    helper_float_check_status(env);                                          \
> > +    do_float_check_status(env, GETPC());                                     \
> >  }
> >
> >  VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
> > @@ -1893,10 +1899,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> >              if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) ||        \
> >                  (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) {        \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf);    \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC());\
> >              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
> >                         tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> >              }                                                                \
> >          }                                                                    \
> >                                                                               \
> > @@ -1910,7 +1916,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      }                                                                        \
> >                                                                               \
> >      putVSR(xT(opcode), &xt, env);                                            \
> > -    helper_float_check_status(env);                                          \
> > +    do_float_check_status(env, GETPC());                                     \
> >  }
> >
> >  VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
> > @@ -1944,13 +1950,13 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >                                                                                \
> >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {     \
> >              if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {       \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf);     \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf, GETPC());\
> >              } else if (tp##_is_zero(xa.fld) &&                                \
> >                  tp##_is_zero(xb.fld)) {                                       \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf);     \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf, GETPC());\
> >              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||               \
> >                  tp##_is_signaling_nan(xb.fld, &tstat)) {                      \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> >              }                                                                 \
> >          }                                                                     \
> >                                                                                \
> > @@ -1964,7 +1970,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      }                                                                         \
> >                                                                                \
> >      putVSR(xT(opcode), &xt, env);                                             \
> > -    helper_float_check_status(env);                                           \
> > +    do_float_check_status(env, GETPC());                                      \
> >  }
> >
> >  VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
> > @@ -1991,7 +1997,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >                                                                                \
> >      for (i = 0; i < nels; i++) {                                              \
> >          if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> >          }                                                                     \
> >          xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status);                 \
> >                                                                                \
> > @@ -2005,7 +2011,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      }                                                                         \
> >                                                                                \
> >      putVSR(xT(opcode), &xt, env);                                             \
> > -    helper_float_check_status(env);                                           \
> > +    do_float_check_status(env, GETPC());                                      \
> >  }
> >
> >  VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
> > @@ -2038,9 +2044,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >                                                                               \
> >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> >              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
> >              } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> >              }                                                                \
> >          }                                                                    \
> >                                                                               \
> > @@ -2054,7 +2060,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      }                                                                        \
> >                                                                               \
> >      putVSR(xT(opcode), &xt, env);                                            \
> > -    helper_float_check_status(env);                                          \
> > +    do_float_check_status(env, GETPC());                                     \
> >  }
> >
> >  VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
> > @@ -2088,9 +2094,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >                                                                               \
> >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> >              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
> >              } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> >              }                                                                \
> >          }                                                                    \
> >                                                                               \
> > @@ -2104,7 +2110,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      }                                                                        \
> >                                                                               \
> >      putVSR(xT(opcode), &xt, env);                                            \
> > -    helper_float_check_status(env);                                          \
> > +    do_float_check_status(env, GETPC());                                     \
> >  }
> >
> >  VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
> > @@ -2277,20 +2283,20 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >              if (tp##_is_signaling_nan(xa.fld, &tstat) ||                      \
> >                  tp##_is_signaling_nan(b->fld, &tstat) ||                      \
> >                  tp##_is_signaling_nan(c->fld, &tstat)) {                      \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> >                  tstat.float_exception_flags &= ~float_flag_invalid;           \
> >              }                                                                 \
> >              if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b->fld)) ||         \
> >                  (tp##_is_zero(xa.fld) && tp##_is_infinity(b->fld))) {         \
> >                  xt_out.fld = float64_to_##tp(fload_invalid_op_excp(env,       \
> > -                    POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status);          \
> > +                    POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC()), &env->fp_status); \
> >                  tstat.float_exception_flags &= ~float_flag_invalid;           \
> >              }                                                                 \
> >              if ((tstat.float_exception_flags & float_flag_invalid) &&         \
> >                  ((tp##_is_infinity(xa.fld) ||                                 \
> >                    tp##_is_infinity(b->fld)) &&                                \
> >                    tp##_is_infinity(c->fld))) {                                \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);     \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
> >              }                                                                 \
> >          }                                                                     \
> >                                                                                \
> > @@ -2303,7 +2309,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >          }                                                                     \
> >      }                                                                         \
> >      putVSR(xT(opcode), &xt_out, env);                                         \
> > -    helper_float_check_status(env);                                           \
> > +    do_float_check_status(env, GETPC());                                      \
> >  }
> >
> >  #define MADD_FLGS 0
> > @@ -2360,10 +2366,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >                   float64_is_any_nan(xb.VsrD(0)))) {                      \
> >          if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) ||     \
> >              float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) {     \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> >          }                                                                \
> >          if (ordered) {                                                   \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);         \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
> >          }                                                                \
> >          cc = 1;                                                          \
> >      } else {                                                             \
> > @@ -2381,7 +2387,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      env->fpscr |= cc << FPSCR_FPRF;                                      \
> >      env->crf[BF(opcode)] = cc;                                           \
> >                                                                           \
> > -    helper_float_check_status(env);                                      \
> > +    do_float_check_status(env, GETPC());                                 \
> >  }
> >
> >  VSX_SCALAR_CMP(xscmpodp, 1)
> > @@ -2408,12 +2414,12 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)
> \
> >          xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status);                  \
> >          if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) ||        \
> >                       tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);            \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());   \
> >          }                                                                     \
> >      }                                                                         \
> >                                                                                \
> >      putVSR(xT(opcode), &xt, env);                                             \
> > -    helper_float_check_status(env);                                           \
> > +    do_float_check_status(env, GETPC());                                      \
> >  }
> >
> >  VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
> > @@ -2448,10 +2454,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >                       tp##_is_any_nan(xb.fld))) {                          \
> >              if (tp##_is_signaling_nan(xa.fld, &env->fp_status) ||         \
> >                  tp##_is_signaling_nan(xb.fld, &env->fp_status)) {         \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);    \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> >              }                                                             \
> >              if (svxvc) {                                                  \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);      \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
> >              }                                                             \
> >              xt.fld = 0;                                                   \
> >              all_true = 0;                                                 \
> > @@ -2470,7 +2476,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      if ((opcode >> (31-21)) & 1) {                                        \
> >          env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0);       \
> >      }                                                                     \
> > -    helper_float_check_status(env);                                       \
> > +    do_float_check_status(env, GETPC());                                  \
> >   }
> >
> >  VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
> > @@ -2502,7 +2508,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
> >          xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status);        \
> >          if (unlikely(stp##_is_signaling_nan(xb.sfld,               \
> >                                              &env->fp_status))) {   \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC()); \
> >              xt.tfld = ttp##_snan_to_qnan(xt.tfld);                 \
> >          }                                                          \
> >          if (sfprf) {                                               \
> > @@ -2512,7 +2518,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
> >      }                                                              \
> >                                                                     \
> >      putVSR(xT(opcode), &xt, env);                                  \
> > -    helper_float_check_status(env);                                \
> > +    do_float_check_status(env, GETPC());                           \
> >  }
> >
> >  VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1)
> > @@ -2557,21 +2563,21 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      for (i = 0; i < nels; i++) {                                             \
> >          if (unlikely(stp##_is_any_nan(xb.sfld))) {                           \
> >              if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) {          \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> >              }                                                                \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);            \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());   \
> >              xt.tfld = rnan;                                                  \
> >          } else {                                                             \
> >              xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld,                \
> >                            &env->fp_status);                                  \
> >              if (env->fp_status.float_exception_flags & float_flag_invalid) { \
> > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);        \
> > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());\
> >              }                                                                \
> >          }                                                                    \
> >      }                                                                        \
> >                                                                               \
> >      putVSR(xT(opcode), &xt, env);                                            \
> > -    helper_float_check_status(env);                                          \
> > +    do_float_check_status(env, GETPC());                                     \
> >  }
> >
> >  VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \
> > @@ -2622,7 +2628,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      }                                                                   \
> >                                                                          \
> >      putVSR(xT(opcode), &xt, env);                                       \
> > -    helper_float_check_status(env);                                     \
> > +    do_float_check_status(env, GETPC());                                \
> >  }
> >
> >  VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
> > @@ -2667,7 +2673,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      for (i = 0; i < nels; i++) {                                       \
> >          if (unlikely(tp##_is_signaling_nan(xb.fld,                     \
> >                                             &env->fp_status))) {        \
> > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);     \
> > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> >              xt.fld = tp##_snan_to_qnan(xb.fld);                        \
> >          } else {                                                       \
> >              xt.fld = tp##_round_to_int(xb.fld, &env->fp_status);       \
> > @@ -2686,7 +2692,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> \
> >      }                                                                  \
> >                                                                         \
> >      putVSR(xT(opcode), &xt, env);                                      \
> > -    helper_float_check_status(env);                                    \
> > +    do_float_check_status(env, GETPC());                               \
> >  }
> >
> >  VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
> > @@ -2714,6 +2720,6 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
> >      uint64_t xt = helper_frsp(env, xb);
> >
> >      helper_compute_fprf(env, xt);
> > -    helper_float_check_status(env);
> > +    do_float_check_status(env, GETPC());
> >      return xt;
> >  }
> > diff --git a/target-ppc/helper.h b/target-ppc/helper.h
> > index 1f5cfd0..34560f9 100644
> > --- a/target-ppc/helper.h
> > +++ b/target-ppc/helper.h
> > @@ -1,4 +1,5 @@
> >  DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
> > +DEF_HELPER_3(raise_exception_end, void, env, i32, i32)
> >  DEF_HELPER_2(raise_exception, void, env, i32)
> >  DEF_HELPER_4(tw, void, env, tl, tl, i32)
> >  #if defined(TARGET_PPC64)
> > diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> > index e4ed377..5cee620 100644
> > --- a/target-ppc/mem_helper.c
> > +++ b/target-ppc/mem_helper.c
> > @@ -107,9 +107,9 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
> >          if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
> >                       lsw_reg_in_range(reg, num_used_regs, rb))) {
> >              env->nip += 4;     /* Compensate the "nip - 4" from gen_lswx() */
> > -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                       POWERPC_EXCP_INVAL |
> > -                                       POWERPC_EXCP_INVAL_LSWX);
> > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                                POWERPC_EXCP_INVAL |
> > +                                POWERPC_EXCP_INVAL_LSWX, GETPC());
> >          } else {
> >              helper_lsw(env, addr, xer_bc, reg);
> >          }
> > diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
> > index cb5ebf5..6661650 100644
> > --- a/target-ppc/misc_helper.c
> > +++ b/target-ppc/misc_helper.c
> > @@ -39,7 +39,7 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
> >
> >  #ifdef TARGET_PPC64
> >  static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
> > -                               uint32_t sprn, uint32_t cause)
> > +                               uint32_t sprn, uint32_t cause, uintptr_t retaddr)
> >  {
> >      qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
> >
> > @@ -47,7 +47,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
> >      cause &= FSCR_IC_MASK;
> >      env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
> >
> > -    helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
> > +    raise_exception_err(env, POWERPC_EXCP_FU, 0, retaddr);
> >  }
> >  #endif
> >
> > @@ -59,7 +59,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
> >          /* Facility is enabled, continue */
> >          return;
> >      }
> > -    raise_fu_exception(env, bit, sprn, cause);
> > +    raise_fu_exception(env, bit, sprn, cause, GETPC());
> >  #endif
> >  }
> >
> > @@ -71,7 +71,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
> >          /* Facility is enabled, continue */
> >          return;
> >      }
> > -    raise_fu_exception(env, bit, sprn, cause);
> > +    raise_fu_exception(env, bit, sprn, cause, GETPC());
> >  #endif
> >  }
> >
> > diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
> > index 5de1358..a1b27b0 100644
> > --- a/target-ppc/mmu-hash64.c
> > +++ b/target-ppc/mmu-hash64.c
> > @@ -241,8 +241,8 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong
> rs)
> >      PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >
> >      if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0) {
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL, GETPC());
> >      }
> >  }
> >
> > @@ -252,8 +252,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
> >      target_ulong rt = 0;
> >
> >      if (ppc_load_slb_esid(cpu, rb, &rt) < 0) {
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL, GETPC());
> >      }
> >      return rt;
> >  }
> > @@ -276,8 +276,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
> >      target_ulong rt = 0;
> >
> >      if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) {
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL, GETPC());
> >      }
> >      return rt;
> >  }
> > diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
> > index 3eb3cd7..7cd9c2c 100644
> > --- a/target-ppc/mmu_helper.c
> > +++ b/target-ppc/mmu_helper.c
> > @@ -2598,9 +2598,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
> >      tlb = booke206_cur_tlb(env);
> >
> >      if (!tlb) {
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > -                                   POWERPC_EXCP_INVAL_INVAL);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL |
> > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> >      }
> >
> >      /* check that we support the targeted size */
> > @@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
> >      size_ps = booke206_tlbnps(env, tlbn);
> >      if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
> >          !(size_ps & (1 << size_tlb))) {
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > -                                   POWERPC_EXCP_INVAL_INVAL);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL |
> > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> >      }
> >
> >      if (msr_gs) {
> > @@ -2892,10 +2892,6 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType
> access_type,
> >          ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
> >      }
> >      if (unlikely(ret != 0)) {
> > -        if (likely(retaddr)) {
> > -            /* now we have a real cpu fault */
> > -            cpu_restore_state(cs, retaddr);
> > -        }
> > -        helper_raise_exception_err(env, cs->exception_index, env->error_code);
> > +        raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
> >      }
> >  }
> > diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
> > index a07faa4..af328ca 100644
> > --- a/target-ppc/timebase_helper.c
> > +++ b/target-ppc/timebase_helper.c
> > @@ -19,6 +19,7 @@
> >  #include "qemu/osdep.h"
> >  #include "cpu.h"
> >  #include "exec/helper-proto.h"
> > +#include "exec/exec-all.h"
> >  #include "qemu/log.h"
> >
> >  /*****************************************************************************/
> > @@ -143,15 +144,15 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
> >
> >      if (unlikely(env->dcr_env == NULL)) {
> >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > -                                   POWERPC_EXCP_INVAL_INVAL);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL |
> > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> >      } else if (unlikely(ppc_dcr_read(env->dcr_env,
> >                                       (uint32_t)dcrn, &val) != 0)) {
> >          qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
> >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
> >      }
> >      return val;
> >  }
> > @@ -160,14 +161,14 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn,
> target_ulong val)
> >  {
> >      if (unlikely(env->dcr_env == NULL)) {
> >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > -                                   POWERPC_EXCP_INVAL_INVAL);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL |
> > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> >      } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
> >                                        (uint32_t)val) != 0)) {
> >          qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n",
> >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > +                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
> >      }
> >  }
> > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > index 92030b6..0e16578 100644
> > --- a/target-ppc/translate.c
> > +++ b/target-ppc/translate.c
> > @@ -292,7 +292,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t
> error)
> >      }
> >      t0 = tcg_const_i32(excp);
> >      t1 = tcg_const_i32(error);
> > -    gen_helper_raise_exception_err(cpu_env, t0, t1);
> > +    gen_helper_raise_exception_end(cpu_env, t0, t1);
> >      tcg_temp_free_i32(t0);
> >      tcg_temp_free_i32(t1);
> >      ctx->exception = (excp);
> > @@ -300,14 +300,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp,
> uint32_t error)
> >
> >  static void gen_exception(DisasContext *ctx, uint32_t excp)
> >  {
> > -    TCGv_i32 t0;
> > -    if (ctx->exception == POWERPC_EXCP_NONE) {
> > -        gen_update_nip(ctx, ctx->nip);
> > -    }
> > -    t0 = tcg_const_i32(excp);
> > -    gen_helper_raise_exception(cpu_env, t0);
> > -    tcg_temp_free_i32(t0);
> > -    ctx->exception = (excp);
> > +    gen_exception_err(ctx, excp, 0);
> >  }
> >
> >  static void gen_debug_exception(DisasContext *ctx)
> > @@ -2149,8 +2142,6 @@ static void gen_f##name(DisasContext *ctx)
> \
> >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> >          return;                                                               \
> >      }                                                                         \
> > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> >      gen_reset_fpstatus();                                                     \
> >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
> >                       cpu_fpr[rA(ctx->opcode)],                                \
> > @@ -2178,8 +2169,6 @@ static void gen_f##name(DisasContext *ctx)
> \
> >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> >          return;                                                               \
> >      }                                                                         \
> > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> >      gen_reset_fpstatus();                                                     \
> >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
> >                       cpu_fpr[rA(ctx->opcode)],                                \
> > @@ -2206,8 +2195,6 @@ static void gen_f##name(DisasContext *ctx)
> \
> >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> >          return;                                                               \
> >      }                                                                         \
> > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> >      gen_reset_fpstatus();                                                     \
> >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
> >                       cpu_fpr[rA(ctx->opcode)],                                \
> > @@ -2234,8 +2221,6 @@ static void gen_f##name(DisasContext *ctx)
> \
> >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> >          return;                                                               \
> >      }                                                                         \
> > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> >      gen_reset_fpstatus();                                                     \
> >      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
> >                         cpu_fpr[rB(ctx->opcode)]);                             \
> > @@ -2254,8 +2239,6 @@ static void gen_f##name(DisasContext *ctx)
> \
> >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> >          return;                                                               \
> >      }                                                                         \
> > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> >      gen_reset_fpstatus();                                                     \
> >      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
> >                         cpu_fpr[rB(ctx->opcode)]);                             \
> > @@ -2290,8 +2273,6 @@ static void gen_frsqrtes(DisasContext *ctx)
> >          gen_exception(ctx, POWERPC_EXCP_FPU);
> >          return;
> >      }
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_reset_fpstatus();
> >      gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
> >                         cpu_fpr[rB(ctx->opcode)]);
> > @@ -2316,8 +2297,6 @@ static void gen_fsqrt(DisasContext *ctx)
> >          gen_exception(ctx, POWERPC_EXCP_FPU);
> >          return;
> >      }
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_reset_fpstatus();
> >      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
> >                       cpu_fpr[rB(ctx->opcode)]);
> > @@ -2333,8 +2312,6 @@ static void gen_fsqrts(DisasContext *ctx)
> >          gen_exception(ctx, POWERPC_EXCP_FPU);
> >          return;
> >      }
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_reset_fpstatus();
> >      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
> >                       cpu_fpr[rB(ctx->opcode)]);
> > @@ -2424,8 +2401,6 @@ static void gen_fcmpo(DisasContext *ctx)
> >          gen_exception(ctx, POWERPC_EXCP_FPU);
> >          return;
> >      }
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_reset_fpstatus();
> >      crf = tcg_const_i32(crfD(ctx->opcode));
> >      gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
> > @@ -2442,8 +2417,6 @@ static void gen_fcmpu(DisasContext *ctx)
> >          gen_exception(ctx, POWERPC_EXCP_FPU);
> >          return;
> >      }
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_reset_fpstatus();
> >      crf = tcg_const_i32(crfD(ctx->opcode));
> >      gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
> > @@ -2613,8 +2586,6 @@ static void gen_mtfsb0(DisasContext *ctx)
> >      gen_reset_fpstatus();
> >      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
> >          TCGv_i32 t0;
> > -        /* NIP cannot be restored if the memory exception comes from an helper */
> > -        gen_update_nip(ctx, ctx->nip - 4);
> >          t0 = tcg_const_i32(crb);
> >          gen_helper_fpscr_clrbit(cpu_env, t0);
> >          tcg_temp_free_i32(t0);
> > @@ -2639,8 +2610,6 @@ static void gen_mtfsb1(DisasContext *ctx)
> >      /* XXX: we pretend we can only do IEEE floating-point computations */
> >      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
> >          TCGv_i32 t0;
> > -        /* NIP cannot be restored if the memory exception comes from an helper */
> > -        gen_update_nip(ctx, ctx->nip - 4);
> >          t0 = tcg_const_i32(crb);
> >          gen_helper_fpscr_setbit(cpu_env, t0);
> >          tcg_temp_free_i32(t0);
> > @@ -2670,8 +2639,6 @@ static void gen_mtfsf(DisasContext *ctx)
> >          gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
> >          return;
> >      }
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_reset_fpstatus();
> >      if (l) {
> >          t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
> > @@ -2706,8 +2673,6 @@ static void gen_mtfsfi(DisasContext *ctx)
> >          return;
> >      }
> >      sh = (8 * w) + 7 - bf;
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_reset_fpstatus();
> >      t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
> >      t1 = tcg_const_i32(1 << sh);
> > @@ -2790,8 +2755,6 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int
> mask)
> >      TCGLabel *l1 = gen_new_label();
> >      TCGv t0 = tcg_temp_new();
> >      TCGv_i32 t1, t2;
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      tcg_gen_andi_tl(t0, EA, mask);
> >      tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
> >      t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
> > @@ -3261,8 +3224,6 @@ static void gen_lmw(DisasContext *ctx)
> >      TCGv t0;
> >      TCGv_i32 t1;
> >      gen_set_access_type(ctx, ACCESS_INT);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      t0 = tcg_temp_new();
> >      t1 = tcg_const_i32(rD(ctx->opcode));
> >      gen_addr_imm_index(ctx, t0, 0);
> > @@ -3277,8 +3238,6 @@ static void gen_stmw(DisasContext *ctx)
> >      TCGv t0;
> >      TCGv_i32 t1;
> >      gen_set_access_type(ctx, ACCESS_INT);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      t0 = tcg_temp_new();
> >      t1 = tcg_const_i32(rS(ctx->opcode));
> >      gen_addr_imm_index(ctx, t0, 0);
> > @@ -3312,8 +3271,6 @@ static void gen_lswi(DisasContext *ctx)
> >          return;
> >      }
> >      gen_set_access_type(ctx, ACCESS_INT);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      t0 = tcg_temp_new();
> >      gen_addr_register(ctx, t0);
> >      t1 = tcg_const_i32(nb);
> > @@ -3330,8 +3287,6 @@ static void gen_lswx(DisasContext *ctx)
> >      TCGv t0;
> >      TCGv_i32 t1, t2, t3;
> >      gen_set_access_type(ctx, ACCESS_INT);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      t0 = tcg_temp_new();
> >      gen_addr_reg_index(ctx, t0);
> >      t1 = tcg_const_i32(rD(ctx->opcode));
> > @@ -3351,8 +3306,6 @@ static void gen_stswi(DisasContext *ctx)
> >      TCGv_i32 t1, t2;
> >      int nb = NB(ctx->opcode);
> >      gen_set_access_type(ctx, ACCESS_INT);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      t0 = tcg_temp_new();
> >      gen_addr_register(ctx, t0);
> >      if (nb == 0)
> > @@ -3371,8 +3324,6 @@ static void gen_stswx(DisasContext *ctx)
> >      TCGv t0;
> >      TCGv_i32 t1, t2;
> >      gen_set_access_type(ctx, ACCESS_INT);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      t0 = tcg_temp_new();
> >      gen_addr_reg_index(ctx, t0);
> >      t1 = tcg_temp_new_i32();
> > @@ -4306,7 +4257,7 @@ static void gen_tw(DisasContext *ctx)
> >  {
> >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_stop_exception(ctx);
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -4318,7 +4269,7 @@ static void gen_twi(DisasContext *ctx)
> >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_stop_exception(ctx);
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> > @@ -4330,7 +4281,7 @@ static void gen_td(DisasContext *ctx)
> >  {
> >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_stop_exception(ctx);
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -4342,7 +4293,7 @@ static void gen_tdi(DisasContext *ctx)
> >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_stop_exception(ctx);
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> > @@ -4768,8 +4719,6 @@ static void gen_dcbz(DisasContext *ctx)
> >      int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
> >
> >      gen_set_access_type(ctx, ACCESS_CACHE);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      tcgv_addr = tcg_temp_new();
> >      tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
> >
> > @@ -4812,8 +4761,6 @@ static void gen_icbi(DisasContext *ctx)
> >  {
> >      TCGv t0;
> >      gen_set_access_type(ctx, ACCESS_CACHE);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      t0 = tcg_temp_new();
> >      gen_addr_reg_index(ctx, t0);
> >      gen_helper_icbi(cpu_env, t0);
> > @@ -5299,8 +5246,6 @@ static void gen_lscbx(DisasContext *ctx)
> >      TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
> >
> >      gen_addr_reg_index(ctx, t0);
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
> >      tcg_temp_free_i32(t1);
> >      tcg_temp_free_i32(t2);
> > @@ -6386,8 +6331,6 @@ static void gen_mtdcrx(DisasContext *ctx)
> >  /* mfdcrux (PPC 460) : user-mode access to DCR */
> >  static void gen_mfdcrux(DisasContext *ctx)
> >  {
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
> >                          cpu_gpr[rA(ctx->opcode)]);
> >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> > @@ -6396,8 +6339,6 @@ static void gen_mfdcrux(DisasContext *ctx)
> >  /* mtdcrux (PPC 460) : user-mode access to DCR */
> >  static void gen_mtdcrux(DisasContext *ctx)
> >  {
> > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
> >                           cpu_gpr[rS(ctx->opcode)]);
> >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> > @@ -8027,8 +7968,6 @@ static void gen_##name(DisasContext * ctx)
> \
> >          gen_exception(ctx, POWERPC_EXCP_VSXU);                                \
> >          return;                                                               \
> >      }                                                                         \
> > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> >      opc = tcg_const_i32(ctx->opcode);                                         \
> >      gen_helper_##name(cpu_env, opc);                                          \
> >      tcg_temp_free_i32(opc);                                                   \
> > @@ -8041,9 +7980,6 @@ static void gen_##name(DisasContext * ctx)                    \
> >          gen_exception(ctx, POWERPC_EXCP_VSXU);                \
> >          return;                                               \
> >      }                                                         \
> > -    /* NIP cannot be restored if the exception comes */       \
> > -    /* from a helper. */                                      \
> > -    gen_update_nip(ctx, ctx->nip - 4);                        \
> >                                                                \
> >      gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
> >                        cpu_vsrh(xB(ctx->opcode)));             \
> >
> 
> --
> David Gibson			| I'll have my music baroque, and my code
> david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
> 				| _way_ _around_!
> http://www.ozlabs.org/~dgibson

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

* Re: [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode
  2016-09-20  8:42     ` Pavel Dovgalyuk
@ 2016-09-20  8:54       ` Benjamin Herrenschmidt
  2016-09-20 13:15       ` 'David Gibson'
  1 sibling, 0 replies; 7+ messages in thread
From: Benjamin Herrenschmidt @ 2016-09-20  8:54 UTC (permalink / raw)
  To: Pavel Dovgalyuk, 'David Gibson',
	'Pavel Dovgalyuk'
  Cc: qemu-devel, peter.maydell, mst, jasowang, quintela, agraf,
	pbonzini

On Tue, 2016-09-20 at 11:42 +0300, Pavel Dovgalyuk wrote:
> > 
> > From: David Gibson [mailto:david@gibson.dropbear.id.au]
> > On Thu, Sep 15, 2016 at 11:09:59AM +0300, Pavel Dovgalyuk wrote:
> > > 
> > > From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
> > > 
> > > This patch fixes exception handling in PowerPC.
> > > Instructions generate several types of exceptions.
> > > When exception is generated, it breaks the execution of the
> > > current translation
> > > block. Implementation of the exceptions handling does not
> > > correctly
> > > restore icount for the instruction which caused the exception. In
> > > most cases
> > > icount will be decreased by the value equal to the size of TB.
> > > This patch passes pointer to the translation block internals to
> > > the exception
> > > handler. It allows correct restoring of the icount value.
> > > 
> > > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> > 
> > I'm not really confident reviewing changes in this area.
> > 
> > I've CCd Ben Herrenshmidt, who did some work on the exception
> > handling recently.  

Hrm.. Isn't this something that gets fixed by rth's patch to properly
fix GET_RA ?

Ie. it should be legit to pass "0" for the PC if we have updated
nip manually ... I'm not sure I get what you are doing here.


> Thanks.
> It seems that most of these changes were already upstreamed from some
> other patch.
> That's why I removed this one from the updated series.
> 
> > 
> > 
> > > 
> > > ---
> > >  target-ppc/cpu.h             |    3 +
> > >  target-ppc/excp_helper.c     |   38 ++++++--
> > >  target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++----
> > > ----------------
> > >  target-ppc/helper.h          |    1
> > >  target-ppc/mem_helper.c      |    6 +
> > >  target-ppc/misc_helper.c     |    8 +-
> > >  target-ppc/mmu-hash64.c      |   12 +--
> > >  target-ppc/mmu_helper.c      |   18 ++--
> > >  target-ppc/timebase_helper.c |   21 ++---
> > >  target-ppc/translate.c       |   76 +----------------
> > >  10 files changed, 169 insertions(+), 206 deletions(-)
> > > 
> > > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> > > index 786ab5c..95baae3 100644
> > > --- a/target-ppc/cpu.h
> > > +++ b/target-ppc/cpu.h
> > > @@ -2434,4 +2434,7 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
> > >  PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
> > > 
> > >  void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t
> > > *mem_buf, int len);
> > > +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> > > +                         uint32_t error_code, uintptr_t pc);
> > > +
> > >  #endif /* PPC_CPU_H */
> > > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> > > index d6e1678..3da1c32 100644
> > > --- a/target-ppc/excp_helper.c
> > > +++ b/target-ppc/excp_helper.c
> > > @@ -898,8 +898,8 @@ static void cpu_dump_rfi(target_ulong RA,
> > > target_ulong msr)
> > >  /***************************************************************
> > > **************/
> > >  /* Exceptions processing helpers */
> > > 
> > > -void helper_raise_exception_err(CPUPPCState *env, uint32_t
> > > exception,
> > > -                                uint32_t error_code)
> > > +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> > > +                         uint32_t error_code, uintptr_t pc)
> > >  {
> > >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> > > 
> > > @@ -908,15 +908,32 @@ void helper_raise_exception_err(CPUPPCState
> > > *env, uint32_t exception,
> > >  #endif
> > >      cs->exception_index = exception;
> > >      env->error_code = error_code;
> > > -    cpu_loop_exit(cs);
> > > +    cpu_loop_exit_restore(cs, pc);
> > > +}
> > > +
> > > +void helper_raise_exception_err(CPUPPCState *env, uint32_t
> > > exception,
> > > +                                uint32_t error_code)
> > > +{
> > > +    raise_exception_err(env, exception, error_code, GETPC());
> > > +}
> > > +
> > > +void helper_raise_exception_end(CPUPPCState *env, uint32_t
> > > exception,
> > > +                                uint32_t error_code)
> > > +{
> > > +    raise_exception_err(env, exception, error_code, 0);
> > 
> > I'm struggling to see how raising an exception with a return
> > address
> > of 0 could ever be useful...
> > 
> > > 
> > >  }
> > > 
> > >  void helper_raise_exception(CPUPPCState *env, uint32_t
> > > exception)
> > >  {
> > > -    helper_raise_exception_err(env, exception, 0);
> > > +    raise_exception_err(env, exception, 0, GETPC());
> > >  }
> > > 
> > >  #if !defined(CONFIG_USER_ONLY)
> > > +static void raise_exception(CPUPPCState *env, uint32_t
> > > exception, uintptr_t pc)
> > > +{
> > > +    raise_exception_err(env, exception, 0, pc);
> > > +}
> > > +
> > >  void helper_store_msr(CPUPPCState *env, target_ulong val)
> > >  {
> > >      CPUState *cs;
> > > @@ -925,7 +942,8 @@ void helper_store_msr(CPUPPCState *env,
> > > target_ulong val)
> > >      if (val != 0) {
> > >          cs = CPU(ppc_env_get_cpu(env));
> > >          cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> > > -        helper_raise_exception(env, val);
> > > +        /* nip is updated by generated code */
> > > +        raise_exception(env, val, 0);
> > >      }
> > >  }
> > > 
> > > @@ -1041,8 +1059,9 @@ void helper_tw(CPUPPCState *env,
> > > target_ulong arg1, target_ulong arg2,
> > >                    ((int32_t)arg1 == (int32_t)arg2 && (flags &
> > > 0x04)) ||
> > >                    ((uint32_t)arg1 < (uint32_t)arg2 && (flags &
> > > 0x02)) ||
> > >                    ((uint32_t)arg1 > (uint32_t)arg2 && (flags &
> > > 0x01))))) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_TRAP);
> > > +        /* nip is updated in TB */
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_TRAP, 0);
> > >      }
> > >  }
> > > 
> > > @@ -1055,8 +1074,9 @@ void helper_td(CPUPPCState *env,
> > > target_ulong arg1, target_ulong arg2,
> > >                    ((int64_t)arg1 == (int64_t)arg2 && (flags &
> > > 0x04)) ||
> > >                    ((uint64_t)arg1 < (uint64_t)arg2 && (flags &
> > > 0x02)) ||
> > >                    ((uint64_t)arg1 > (uint64_t)arg2 && (flags &
> > > 0x01))))) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_TRAP);
> > > +        /* nip is updated in TB */
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_TRAP, 0);
> > >      }
> > >  }
> > >  #endif
> > > diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
> > > index d9795d0..6eaa3f4 100644
> > > --- a/target-ppc/fpu_helper.c
> > > +++ b/target-ppc/fpu_helper.c
> > > @@ -19,6 +19,7 @@
> > >  #include "qemu/osdep.h"
> > >  #include "cpu.h"
> > >  #include "exec/helper-proto.h"
> > > +#include "exec/exec-all.h"
> > > 
> > >  #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
> > >  #define float32_snan_to_qnan(x) ((x) | 0x00400000)
> > > @@ -117,7 +118,7 @@ void helper_compute_fprf(CPUPPCState *env,
> > > uint64_t arg)
> > > 
> > >  /* Floating-point invalid operations exception */
> > >  static inline uint64_t fload_invalid_op_excp(CPUPPCState *env,
> > > int op,
> > > -                                             int set_fpcc)
> > > +                                             int set_fpcc,
> > > uintptr_t retaddr)
> > >  {
> > >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> > >      uint64_t ret = 0;
> > > @@ -200,14 +201,14 @@ static inline uint64_t
> > > fload_invalid_op_excp(CPUPPCState *env, int op,
> > >          /* Update the floating-point enabled exception summary
> > > */
> > >          env->fpscr |= 1 << FPSCR_FEX;
> > >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > > -            helper_raise_exception_err(env,
> > > POWERPC_EXCP_PROGRAM,
> > > -                                       POWERPC_EXCP_FP | op);
> > > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                                POWERPC_EXCP_FP | op, retaddr);
> > >          }
> > >      }
> > >      return ret;
> > >  }
> > > 
> > > -static inline void float_zero_divide_excp(CPUPPCState *env)
> > > +static inline void float_zero_divide_excp(CPUPPCState *env,
> > > uintptr_t retaddr)
> > >  {
> > >      env->fpscr |= 1 << FPSCR_ZX;
> > >      env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
> > > @@ -217,8 +218,8 @@ static inline void
> > > float_zero_divide_excp(CPUPPCState *env)
> > >          /* Update the floating-point enabled exception summary
> > > */
> > >          env->fpscr |= 1 << FPSCR_FEX;
> > >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > > -            helper_raise_exception_err(env,
> > > POWERPC_EXCP_PROGRAM,
> > > -                                       POWERPC_EXCP_FP |
> > > POWERPC_EXCP_FP_ZX);
> > > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                                POWERPC_EXCP_FP |
> > > POWERPC_EXCP_FP_ZX, retaddr);
> > >          }
> > >      }
> > >  }
> > > @@ -491,13 +492,13 @@ void store_fpscr(CPUPPCState *env, uint64_t
> > > arg, uint32_t mask)
> > >      helper_store_fpscr(env, arg, mask);
> > >  }
> > > 
> > > -void helper_float_check_status(CPUPPCState *env)
> > > +static void do_float_check_status(CPUPPCState *env, uintptr_t
> > > retaddr)
> > >  {
> > >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> > >      int status = get_float_exception_flags(&env->fp_status);
> > > 
> > >      if (status & float_flag_divbyzero) {
> > > -        float_zero_divide_excp(env);
> > > +        float_zero_divide_excp(env, retaddr);
> > >      } else if (status & float_flag_overflow) {
> > >          float_overflow_excp(env);
> > >      } else if (status & float_flag_underflow) {
> > > @@ -510,12 +511,17 @@ void helper_float_check_status(CPUPPCState
> > > *env)
> > >          (env->error_code & POWERPC_EXCP_FP)) {
> > >          /* Differred floating-point exception after target FPR
> > > update */
> > >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > > -            helper_raise_exception_err(env, cs->exception_index,
> > > -                                       env->error_code);
> > > +            raise_exception_err(env, cs->exception_index,
> > > +                                env->error_code, retaddr);
> > >          }
> > >      }
> > >  }
> > > 
> > > +void helper_float_check_status(CPUPPCState *env)
> > > +{
> > > +    do_float_check_status(env, GETPC());
> > > +}
> > > +
> > >  void helper_reset_fpstatus(CPUPPCState *env)
> > >  {
> > >      set_float_exception_flags(0, &env->fp_status);
> > > @@ -532,12 +538,12 @@ uint64_t helper_fadd(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2)
> > >      if (unlikely(float64_is_infinity(farg1.d) &&
> > > float64_is_infinity(farg2.d) &&
> > >                   float64_is_neg(farg1.d) !=
> > > float64_is_neg(farg2.d))) {
> > >          /* Magnitude subtraction of infinities */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status))) {
> > >              /* sNaN addition */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          farg1.d = float64_add(farg1.d, farg2.d, &env-
> > > >fp_status);
> > >      }
> > > @@ -556,12 +562,12 @@ uint64_t helper_fsub(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2)
> > >      if (unlikely(float64_is_infinity(farg1.d) &&
> > > float64_is_infinity(farg2.d) &&
> > >                   float64_is_neg(farg1.d) ==
> > > float64_is_neg(farg2.d))) {
> > >          /* Magnitude subtraction of infinities */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status))) {
> > >              /* sNaN subtraction */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          farg1.d = float64_sub(farg1.d, farg2.d, &env-
> > > >fp_status);
> > >      }
> > > @@ -580,12 +586,12 @@ uint64_t helper_fmul(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2)
> > >      if (unlikely((float64_is_infinity(farg1.d) &&
> > > float64_is_zero(farg2.d)) ||
> > >                   (float64_is_zero(farg1.d) &&
> > > float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status))) {
> > >              /* sNaN multiplication */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          farg1.d = float64_mul(farg1.d, farg2.d, &env-
> > > >fp_status);
> > >      }
> > > @@ -604,15 +610,15 @@ uint64_t helper_fdiv(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2)
> > >      if (unlikely(float64_is_infinity(farg1.d) &&
> > >                   float64_is_infinity(farg2.d))) {
> > >          /* Division of infinity by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIDI, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIDI, 1, GETPC());
> > >      } else if (unlikely(float64_is_zero(farg1.d) &&
> > > float64_is_zero(farg2.d))) {
> > >          /* Division of zero by zero */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXZDZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXZDZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status))) {
> > >              /* sNaN division */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          farg1.d = float64_div(farg1.d, farg2.d, &env-
> > > >fp_status);
> > >      }
> > > @@ -631,16 +637,16 @@ uint64_t helper_##op(CPUPPCState *env,
> > > uint64_t arg)
> > \
> > > 
> > >                                                                  
> > >        \
> > >      if (unlikely(env->fp_status.float_exception_flags))
> > > {              \
> > >          if (float64_is_any_nan(arg))
> > > {                                 \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI,
> > > 1);      \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1,
> > > GETPC());\
> > >              if (float64_is_signaling_nan(arg, &env->fp_status))
> > > {      \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, 1); \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, 1, GETPC());\
> > >              }                                                   
> > >        \
> > >              farg.ll =
> > > nanval;                                          \
> > >          } else if (env->fp_status.float_exception_flags
> > > &              \
> > >                     float_flag_invalid)
> > > {                               \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI,
> > > 1);      \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1,
> > > GETPC());\
> > >          }                                                       
> > >        \
> > > -        helper_float_check_status(env);                         
> > >        \
> > > +        do_float_check_status(env,
> > > GETPC());                           \
> > >      }                                                           
> > >        \
> > >      return
> > > farg.ll;                                                    \
> > >   }
> > > @@ -665,7 +671,7 @@ uint64_t helper_##op(CPUPPCState *env,
> > > uint64_t arg)       \
> > >      } else {                                               \
> > >          farg.d = cvtr(arg, &env->fp_status);               \
> > >      }                                                      \
> > > -    helper_float_check_status(env);                        \
> > > +    do_float_check_status(env, GETPC());                   \
> > >      return farg.ll;                                        \
> > >  }
> > > 
> > > @@ -675,7 +681,7 @@ FPU_FCFI(fcfidu, uint64_to_float64, 0)
> > >  FPU_FCFI(fcfidus, uint64_to_float32, 1)
> > > 
> > >  static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> > > -                              int rounding_mode)
> > > +                              int rounding_mode, uint64_t
> > > retaddr)
> > >  {
> > >      CPU_DoubleU farg;
> > > 
> > > @@ -683,7 +689,7 @@ static inline uint64_t do_fri(CPUPPCState
> > > *env, uint64_t arg,
> > > 
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env-
> > > >fp_status))) {
> > >          /* sNaN round */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1,
> > > retaddr);
> > >          farg.ll = arg | 0x0008000000000000ULL;
> > >      } else {
> > >          int inexact = get_float_exception_flags(&env->fp_status) 
> > > &
> > > @@ -698,28 +704,28 @@ static inline uint64_t do_fri(CPUPPCState
> > > *env, uint64_t arg,
> > >              env->fp_status.float_exception_flags &=
> > > ~float_flag_inexact;
> > >          }
> > >      }
> > > -    helper_float_check_status(env);
> > > +    do_float_check_status(env, GETPC());
> > >      return farg.ll;
> > >  }
> > > 
> > >  uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_ties_away);
> > > +    return do_fri(env, arg, float_round_ties_away, GETPC());
> > >  }
> > > 
> > >  uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_to_zero);
> > > +    return do_fri(env, arg, float_round_to_zero, GETPC());
> > >  }
> > > 
> > >  uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_up);
> > > +    return do_fri(env, arg, float_round_up, GETPC());
> > >  }
> > > 
> > >  uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_down);
> > > +    return do_fri(env, arg, float_round_down, GETPC());
> > >  }
> > > 
> > >  /* fmadd - fmadd. */
> > > @@ -735,13 +741,13 @@ uint64_t helper_fmadd(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >      if (unlikely((float64_is_infinity(farg1.d) &&
> > > float64_is_zero(farg2.d)) ||
> > >                   (float64_is_zero(farg1.d) &&
> > > float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env-
> > > >fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it
> > > */
> > >          float128 ft0_128, ft1_128;
> > > @@ -753,7 +759,7 @@ uint64_t helper_fmadd(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) !=
> > > float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env-
> > > >fp_status);
> > >              ft0_128 = float128_add(ft0_128, ft1_128, &env-
> > > >fp_status);
> > > @@ -778,13 +784,13 @@ uint64_t helper_fmsub(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >                   (float64_is_zero(farg1.d) &&
> > >                    float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env-
> > > >fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it
> > > */
> > >          float128 ft0_128, ft1_128;
> > > @@ -796,7 +802,7 @@ uint64_t helper_fmsub(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) ==
> > > float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env-
> > > >fp_status);
> > >              ft0_128 = float128_sub(ft0_128, ft1_128, &env-
> > > >fp_status);
> > > @@ -819,13 +825,13 @@ uint64_t helper_fnmadd(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >      if (unlikely((float64_is_infinity(farg1.d) &&
> > > float64_is_zero(farg2.d)) ||
> > >                   (float64_is_zero(farg1.d) &&
> > > float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env-
> > > >fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it
> > > */
> > >          float128 ft0_128, ft1_128;
> > > @@ -837,7 +843,7 @@ uint64_t helper_fnmadd(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) !=
> > > float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env-
> > > >fp_status);
> > >              ft0_128 = float128_add(ft0_128, ft1_128, &env-
> > > >fp_status);
> > > @@ -864,13 +870,13 @@ uint64_t helper_fnmsub(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >                   (float64_is_zero(farg1.d) &&
> > >                    float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env-
> > > >fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it
> > > */
> > >          float128 ft0_128, ft1_128;
> > > @@ -882,7 +888,7 @@ uint64_t helper_fnmsub(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) ==
> > > float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env-
> > > >fp_status);
> > >              ft0_128 = float128_sub(ft0_128, ft1_128, &env-
> > > >fp_status);
> > > @@ -905,7 +911,7 @@ uint64_t helper_frsp(CPUPPCState *env,
> > > uint64_t arg)
> > > 
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env-
> > > >fp_status))) {
> > >          /* sNaN square root */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1,
> > > GETPC());
> > >      }
> > >      f32 = float64_to_float32(farg.d, &env->fp_status);
> > >      farg.d = float32_to_float64(f32, &env->fp_status);
> > > @@ -923,12 +929,12 @@ uint64_t helper_fsqrt(CPUPPCState *env,
> > > uint64_t arg)
> > >      if (unlikely(float64_is_any_nan(farg.d))) {
> > >          if (unlikely(float64_is_signaling_nan(farg.d, &env-
> > > >fp_status))) {
> > >              /* sNaN reciprocal square root */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >              farg.ll = float64_snan_to_qnan(farg.ll);
> > >          }
> > >      } else if (unlikely(float64_is_neg(farg.d) &&
> > > !float64_is_zero(farg.d))) {
> > >          /* Square root of a negative nonzero number */
> > > -        farg.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, 1);
> > > +        farg.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
> > >      } else {
> > >          farg.d = float64_sqrt(farg.d, &env->fp_status);
> > >      }
> > > @@ -944,7 +950,7 @@ uint64_t helper_fre(CPUPPCState *env,
> > > uint64_t arg)
> > > 
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env-
> > > >fp_status))) {
> > >          /* sNaN reciprocal */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1,
> > > GETPC());
> > >      }
> > >      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> > >      return farg.d;
> > > @@ -960,7 +966,7 @@ uint64_t helper_fres(CPUPPCState *env,
> > > uint64_t arg)
> > > 
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env-
> > > >fp_status))) {
> > >          /* sNaN reciprocal */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1,
> > > GETPC());
> > >      }
> > >      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> > >      f32 = float64_to_float32(farg.d, &env->fp_status);
> > > @@ -979,12 +985,12 @@ uint64_t helper_frsqrte(CPUPPCState *env,
> > > uint64_t arg)
> > >      if (unlikely(float64_is_any_nan(farg.d))) {
> > >          if (unlikely(float64_is_signaling_nan(farg.d, &env-
> > > >fp_status))) {
> > >              /* sNaN reciprocal square root */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 1, GETPC());
> > >              farg.ll = float64_snan_to_qnan(farg.ll);
> > >          }
> > >      } else if (unlikely(float64_is_neg(farg.d) &&
> > > !float64_is_zero(farg.d))) {
> > >          /* Reciprocal square root of a negative nonzero number
> > > */
> > > -        farg.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, 1);
> > > +        farg.ll = fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
> > >      } else {
> > >          farg.d = float64_sqrt(farg.d, &env->fp_status);
> > >          farg.d = float64_div(float64_one, farg.d, &env-
> > > >fp_status);
> > > @@ -1103,7 +1109,7 @@ void helper_fcmpu(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >                   && (float64_is_signaling_nan(farg1.d, &env-
> > > >fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env-
> > > >fp_status)))) {
> > >          /* sNaN comparison */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1,
> > > GETPC());
> > >      }
> > >  }
> > > 
> > > @@ -1135,10 +1141,10 @@ void helper_fcmpo(CPUPPCState *env,
> > > uint64_t arg1, uint64_t arg2,
> > >              float64_is_signaling_nan(farg2.d, &env->fp_status))
> > > {
> > >              /* sNaN comparison */
> > >              fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
> > > -                                  POWERPC_EXCP_FP_VXVC, 1);
> > > +                                  POWERPC_EXCP_FP_VXVC, 1,
> > > GETPC());
> > >          } else {
> > >              /* qNaN comparison */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1,
> > > GETPC());
> > >          }
> > >      }
> > >  }
> > > @@ -1838,10 +1844,10 @@ void helper_##name(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >                                                                  
> > >              \
> > >          if (unlikely(tstat.float_exception_flags &
> > > float_flag_invalid)) {    \
> > >              if (tp##_is_infinity(xa.fld) &&
> > > tp##_is_infinity(xb.fld)) {      \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, sfprf);    \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xa.fld, &tstat)
> > > ||              \
> > >                         tp##_is_signaling_nan(xb.fld, &tstat))
> > > {              \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                   
> > >              \
> > >          }                                                       
> > >              \
> > >                                                                  
> > >              \
> > > @@ -1854,7 +1860,7 @@ void helper_##name(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >          }                                                       
> > >              \
> > >      }                                                           
> > >              \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                            \
> > > -    helper_float_check_status(env);                             
> > >              \
> > > +    do_float_check_status(env,
> > > GETPC());                                     \
> > >  }
> > > 
> > >  VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
> > > @@ -1893,10 +1899,10 @@ void helper_##op(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >          if (unlikely(tstat.float_exception_flags &
> > > float_flag_invalid)) {    \
> > >              if ((tp##_is_infinity(xa.fld) &&
> > > tp##_is_zero(xb.fld)) ||        \
> > >                  (tp##_is_infinity(xb.fld) &&
> > > tp##_is_zero(xa.fld))) {        \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, sfprf);    \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xa.fld, &tstat)
> > > ||              \
> > >                         tp##_is_signaling_nan(xb.fld, &tstat))
> > > {              \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                   
> > >              \
> > >          }                                                       
> > >              \
> > >                                                                  
> > >              \
> > > @@ -1910,7 +1916,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      }                                                           
> > >              \
> > >                                                                  
> > >              \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                            \
> > > -    helper_float_check_status(env);                             
> > >              \
> > > +    do_float_check_status(env,
> > > GETPC());                                     \
> > >  }
> > > 
> > >  VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
> > > @@ -1944,13 +1950,13 @@ void helper_##op(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >                                                                  
> > >               \
> > >          if (unlikely(tstat.float_exception_flags &
> > > float_flag_invalid)) {     \
> > >              if (tp##_is_infinity(xa.fld) &&
> > > tp##_is_infinity(xb.fld)) {       \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIDI, sfprf);     \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXIDI, sfprf, GETPC());\
> > >              } else if (tp##_is_zero(xa.fld)
> > > &&                                \
> > >                  tp##_is_zero(xb.fld))
> > > {                                       \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXZDZ, sfprf);     \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXZDZ, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xa.fld, &tstat)
> > > ||               \
> > >                  tp##_is_signaling_nan(xb.fld, &tstat))
> > > {                      \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                   
> > >               \
> > >          }                                                       
> > >               \
> > >                                                                  
> > >               \
> > > @@ -1964,7 +1970,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      }                                                           
> > >               \
> > >                                                                  
> > >               \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                             \
> > > -    helper_float_check_status(env);                             
> > >               \
> > > +    do_float_check_status(env,
> > > GETPC());                                      \
> > >  }
> > > 
> > >  VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
> > > @@ -1991,7 +1997,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >                                                                  
> > >               \
> > >      for (i = 0; i < nels; i++)
> > > {                                              \
> > >          if (unlikely(tp##_is_signaling_nan(xb.fld, &env-
> > > >fp_status))) {       \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >          }                                                       
> > >               \
> > >          xt.fld = tp##_div(tp##_one, xb.fld, &env-
> > > >fp_status);                 \
> > >                                                                  
> > >               \
> > > @@ -2005,7 +2011,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      }                                                           
> > >               \
> > >                                                                  
> > >               \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                             \
> > > -    helper_float_check_status(env);                             
> > >               \
> > > +    do_float_check_status(env,
> > > GETPC());                                      \
> > >  }
> > > 
> > >  VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
> > > @@ -2038,9 +2044,9 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >                                                                  
> > >              \
> > >          if (unlikely(tstat.float_exception_flags &
> > > float_flag_invalid)) {    \
> > >              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld))
> > > {              \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xb.fld, &tstat))
> > > {              \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                   
> > >              \
> > >          }                                                       
> > >              \
> > >                                                                  
> > >              \
> > > @@ -2054,7 +2060,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      }                                                           
> > >              \
> > >                                                                  
> > >              \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                            \
> > > -    helper_float_check_status(env);                             
> > >              \
> > > +    do_float_check_status(env,
> > > GETPC());                                     \
> > >  }
> > > 
> > >  VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
> > > @@ -2088,9 +2094,9 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >                                                                  
> > >              \
> > >          if (unlikely(tstat.float_exception_flags &
> > > float_flag_invalid)) {    \
> > >              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld))
> > > {              \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xb.fld, &tstat))
> > > {              \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                   
> > >              \
> > >          }                                                       
> > >              \
> > >                                                                  
> > >              \
> > > @@ -2104,7 +2110,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      }                                                           
> > >              \
> > >                                                                  
> > >              \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                            \
> > > -    helper_float_check_status(env);                             
> > >              \
> > > +    do_float_check_status(env,
> > > GETPC());                                     \
> > >  }
> > > 
> > >  VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
> > > @@ -2277,20 +2283,20 @@ void helper_##op(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >              if (tp##_is_signaling_nan(xa.fld, &tstat)
> > > ||                      \
> > >                  tp##_is_signaling_nan(b->fld, &tstat)
> > > ||                      \
> > >                  tp##_is_signaling_nan(c->fld, &tstat))
> > > {                      \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >                  tstat.float_exception_flags &=
> > > ~float_flag_invalid;           \
> > >              }                                                   
> > >               \
> > >              if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b-
> > > >fld)) ||         \
> > >                  (tp##_is_zero(xa.fld) && tp##_is_infinity(b-
> > > >fld))) {         \
> > >                  xt_out.fld =
> > > float64_to_##tp(fload_invalid_op_excp(env,       \
> > > -                    POWERPC_EXCP_FP_VXIMZ, sfprf), &env-
> > > >fp_status);          \
> > > +                    POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC()),
> > > &env->fp_status); \
> > >                  tstat.float_exception_flags &=
> > > ~float_flag_invalid;           \
> > >              }                                                   
> > >               \
> > >              if ((tstat.float_exception_flags &
> > > float_flag_invalid) &&         \
> > >                  ((tp##_is_infinity(xa.fld)
> > > ||                                 \
> > >                    tp##_is_infinity(b->fld))
> > > &&                                \
> > >                    tp##_is_infinity(c->fld)))
> > > {                                \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, sfprf);     \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
> > >              }                                                   
> > >               \
> > >          }                                                       
> > >               \
> > >                                                                  
> > >               \
> > > @@ -2303,7 +2309,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >          }                                                       
> > >               \
> > >      }                                                           
> > >               \
> > >      putVSR(xT(opcode), &xt_out,
> > > env);                                         \
> > > -    helper_float_check_status(env);                             
> > >               \
> > > +    do_float_check_status(env,
> > > GETPC());                                      \
> > >  }
> > > 
> > >  #define MADD_FLGS 0
> > > @@ -2360,10 +2366,10 @@ void helper_##op(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >                   float64_is_any_nan(xb.VsrD(0))))
> > > {                      \
> > >          if (float64_is_signaling_nan(xa.VsrD(0), &env-
> > > >fp_status) ||     \
> > >              float64_is_signaling_nan(xb.VsrD(0), &env-
> > > >fp_status)) {     \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0);       \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0, GETPC());\
> > >          }                                                       
> > >          \
> > >          if (ordered)
> > > {                                                   \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC,
> > > 0);         \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0,
> > > GETPC());\
> > >          }                                                       
> > >          \
> > >          cc =
> > > 1;                                                          \
> > >      } else
> > > {                                                             \
> > > @@ -2381,7 +2387,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      env->fpscr |= cc <<
> > > FPSCR_FPRF;                                      \
> > >      env->crf[BF(opcode)] =
> > > cc;                                           \
> > >                                                                  
> > >          \
> > > -    helper_float_check_status(env);                             
> > >          \
> > > +    do_float_check_status(env,
> > > GETPC());                                 \
> > >  }
> > > 
> > >  VSX_SCALAR_CMP(xscmpodp, 1)
> > > @@ -2408,12 +2414,12 @@ void helper_##name(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >          xt.fld = tp##_##op(xa.fld, xb.fld, &env-
> > > >fp_status);                  \
> > >          if (unlikely(tp##_is_signaling_nan(xa.fld, &env-
> > > >fp_status) ||        \
> > >                       tp##_is_signaling_nan(xb.fld, &env-
> > > >fp_status))) {       \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0);            \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0, GETPC());   \
> > >          }                                                       
> > >               \
> > >      }                                                           
> > >               \
> > >                                                                  
> > >               \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                             \
> > > -    helper_float_check_status(env);                             
> > >               \
> > > +    do_float_check_status(env,
> > > GETPC());                                      \
> > >  }
> > > 
> > >  VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
> > > @@ -2448,10 +2454,10 @@ void helper_##op(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >                       tp##_is_any_nan(xb.fld)))
> > > {                          \
> > >              if (tp##_is_signaling_nan(xa.fld, &env->fp_status)
> > > ||         \
> > >                  tp##_is_signaling_nan(xb.fld, &env->fp_status))
> > > {         \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, 0);    \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> > >              }                                                   
> > >           \
> > >              if (svxvc)
> > > {                                                  \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC,
> > > 0);      \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC,
> > > 0, GETPC());\
> > >              }                                                   
> > >           \
> > >              xt.fld =
> > > 0;                                                   \
> > >              all_true =
> > > 0;                                                 \
> > > @@ -2470,7 +2476,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      if ((opcode >> (31-21)) & 1)
> > > {                                        \
> > >          env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 :
> > > 0);       \
> > >      }                                                           
> > >           \
> > > -    helper_float_check_status(env);                             
> > >           \
> > > +    do_float_check_status(env,
> > > GETPC());                                  \
> > >   }
> > > 
> > >  VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
> > > @@ -2502,7 +2508,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)                \
> > >          xt.tfld = stp##_to_##ttp(xb.sfld, &env-
> > > >fp_status);        \
> > >          if
> > > (unlikely(stp##_is_signaling_nan(xb.sfld,               \
> > >                                              &env->fp_status)))
> > > {   \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0); \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0, GETPC()); \
> > >              xt.tfld =
> > > ttp##_snan_to_qnan(xt.tfld);                 \
> > >          }                                                       
> > >    \
> > >          if (sfprf)
> > > {                                               \
> > > @@ -2512,7 +2518,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)                \
> > >      }                                                           
> > >    \
> > >                                                                  
> > >    \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                  \
> > > -    helper_float_check_status(env);                             
> > >    \
> > > +    do_float_check_status(env,
> > > GETPC());                           \
> > >  }
> > > 
> > >  VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0),
> > > VsrW(0), 1)
> > > @@ -2557,21 +2563,21 @@ void helper_##op(CPUPPCState *env,
> > > uint32_t opcode)
> > \
> > > 
> > >      for (i = 0; i < nels; i++)
> > > {                                             \
> > >          if (unlikely(stp##_is_any_nan(xb.sfld)))
> > > {                           \
> > >              if (stp##_is_signaling_nan(xb.sfld, &env-
> > > >fp_status)) {          \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, 0);       \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> > >              }                                                   
> > >              \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI,
> > > 0);            \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0,
> > > GETPC());   \
> > >              xt.tfld =
> > > rnan;                                                  \
> > >          } else
> > > {                                                             \
> > >              xt.tfld =
> > > stp##_to_##ttp##_round_to_zero(xb.sfld,                \
> > >                            &env-
> > > >fp_status);                                  \
> > >              if (env->fp_status.float_exception_flags &
> > > float_flag_invalid) { \
> > > -                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXCVI, 0);        \
> > > +                fload_invalid_op_excp(env,
> > > POWERPC_EXCP_FP_VXCVI, 0, GETPC());\
> > >              }                                                   
> > >              \
> > >          }                                                       
> > >              \
> > >      }                                                           
> > >              \
> > >                                                                  
> > >              \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                            \
> > > -    helper_float_check_status(env);                             
> > >              \
> > > +    do_float_check_status(env,
> > > GETPC());                                     \
> > >  }
> > > 
> > >  VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0),
> > > VsrD(0), \
> > > @@ -2622,7 +2628,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      }                                                           
> > >         \
> > >                                                                  
> > >         \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                       \
> > > -    helper_float_check_status(env);                             
> > >         \
> > > +    do_float_check_status(env,
> > > GETPC());                                \
> > >  }
> > > 
> > >  VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0),
> > > VsrD(0), 1, 0)
> > > @@ -2667,7 +2673,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      for (i = 0; i < nels; i++)
> > > {                                       \
> > >          if
> > > (unlikely(tp##_is_signaling_nan(xb.fld,                     \
> > >                                             &env->fp_status)))
> > > {        \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0);     \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN,
> > > 0, GETPC());\
> > >              xt.fld =
> > > tp##_snan_to_qnan(xb.fld);                        \
> > >          } else
> > > {                                                       \
> > >              xt.fld = tp##_round_to_int(xb.fld, &env-
> > > >fp_status);       \
> > > @@ -2686,7 +2692,7 @@ void helper_##op(CPUPPCState *env, uint32_t
> > > opcode)
> > \
> > > 
> > >      }                                                           
> > >        \
> > >                                                                  
> > >        \
> > >      putVSR(xT(opcode), &xt,
> > > env);                                      \
> > > -    helper_float_check_status(env);                             
> > >        \
> > > +    do_float_check_status(env,
> > > GETPC());                               \
> > >  }
> > > 
> > >  VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
> > > @@ -2714,6 +2720,6 @@ uint64_t helper_xsrsp(CPUPPCState *env,
> > > uint64_t xb)
> > >      uint64_t xt = helper_frsp(env, xb);
> > > 
> > >      helper_compute_fprf(env, xt);
> > > -    helper_float_check_status(env);
> > > +    do_float_check_status(env, GETPC());
> > >      return xt;
> > >  }
> > > diff --git a/target-ppc/helper.h b/target-ppc/helper.h
> > > index 1f5cfd0..34560f9 100644
> > > --- a/target-ppc/helper.h
> > > +++ b/target-ppc/helper.h
> > > @@ -1,4 +1,5 @@
> > >  DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
> > > +DEF_HELPER_3(raise_exception_end, void, env, i32, i32)
> > >  DEF_HELPER_2(raise_exception, void, env, i32)
> > >  DEF_HELPER_4(tw, void, env, tl, tl, i32)
> > >  #if defined(TARGET_PPC64)
> > > diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> > > index e4ed377..5cee620 100644
> > > --- a/target-ppc/mem_helper.c
> > > +++ b/target-ppc/mem_helper.c
> > > @@ -107,9 +107,9 @@ void helper_lswx(CPUPPCState *env,
> > > target_ulong addr, uint32_t reg,
> > >          if (unlikely((ra != 0 && lsw_reg_in_range(reg,
> > > num_used_regs, ra)) ||
> > >                       lsw_reg_in_range(reg, num_used_regs, rb)))
> > > {
> > >              env->nip += 4;     /* Compensate the "nip - 4" from
> > > gen_lswx() */
> > > -            helper_raise_exception_err(env,
> > > POWERPC_EXCP_PROGRAM,
> > > -                                       POWERPC_EXCP_INVAL |
> > > -                                       POWERPC_EXCP_INVAL_LSWX);
> > > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                                POWERPC_EXCP_INVAL |
> > > +                                POWERPC_EXCP_INVAL_LSWX,
> > > GETPC());
> > >          } else {
> > >              helper_lsw(env, addr, xer_bc, reg);
> > >          }
> > > diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
> > > index cb5ebf5..6661650 100644
> > > --- a/target-ppc/misc_helper.c
> > > +++ b/target-ppc/misc_helper.c
> > > @@ -39,7 +39,7 @@ void helper_store_dump_spr(CPUPPCState *env,
> > > uint32_t sprn)
> > > 
> > >  #ifdef TARGET_PPC64
> > >  static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
> > > -                               uint32_t sprn, uint32_t cause)
> > > +                               uint32_t sprn, uint32_t cause,
> > > uintptr_t retaddr)
> > >  {
> > >      qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n",
> > > sprn, bit);
> > > 
> > > @@ -47,7 +47,7 @@ static void raise_fu_exception(CPUPPCState
> > > *env, uint32_t bit,
> > >      cause &= FSCR_IC_MASK;
> > >      env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
> > > 
> > > -    helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
> > > +    raise_exception_err(env, POWERPC_EXCP_FU, 0, retaddr);
> > >  }
> > >  #endif
> > > 
> > > @@ -59,7 +59,7 @@ void helper_fscr_facility_check(CPUPPCState
> > > *env, uint32_t bit,
> > >          /* Facility is enabled, continue */
> > >          return;
> > >      }
> > > -    raise_fu_exception(env, bit, sprn, cause);
> > > +    raise_fu_exception(env, bit, sprn, cause, GETPC());
> > >  #endif
> > >  }
> > > 
> > > @@ -71,7 +71,7 @@ void helper_msr_facility_check(CPUPPCState
> > > *env, uint32_t bit,
> > >          /* Facility is enabled, continue */
> > >          return;
> > >      }
> > > -    raise_fu_exception(env, bit, sprn, cause);
> > > +    raise_fu_exception(env, bit, sprn, cause, GETPC());
> > >  #endif
> > >  }
> > > 
> > > diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
> > > index 5de1358..a1b27b0 100644
> > > --- a/target-ppc/mmu-hash64.c
> > > +++ b/target-ppc/mmu-hash64.c
> > > @@ -241,8 +241,8 @@ void helper_store_slb(CPUPPCState *env,
> > > target_ulong rb, target_ulong
> > rs)
> > > 
> > >      PowerPCCPU *cpu = ppc_env_get_cpu(env);
> > > 
> > >      if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0)
> > > {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL, GETPC());
> > >      }
> > >  }
> > > 
> > > @@ -252,8 +252,8 @@ target_ulong helper_load_slb_esid(CPUPPCState
> > > *env, target_ulong rb)
> > >      target_ulong rt = 0;
> > > 
> > >      if (ppc_load_slb_esid(cpu, rb, &rt) < 0) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL, GETPC());
> > >      }
> > >      return rt;
> > >  }
> > > @@ -276,8 +276,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState
> > > *env, target_ulong rb)
> > >      target_ulong rt = 0;
> > > 
> > >      if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL, GETPC());
> > >      }
> > >      return rt;
> > >  }
> > > diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
> > > index 3eb3cd7..7cd9c2c 100644
> > > --- a/target-ppc/mmu_helper.c
> > > +++ b/target-ppc/mmu_helper.c
> > > @@ -2598,9 +2598,9 @@ void helper_booke206_tlbwe(CPUPPCState
> > > *env)
> > >      tlb = booke206_cur_tlb(env);
> > > 
> > >      if (!tlb) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      }
> > > 
> > >      /* check that we support the targeted size */
> > > @@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState
> > > *env)
> > >      size_ps = booke206_tlbnps(env, tlbn);
> > >      if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg &
> > > TLBnCFG_AVAIL) &&
> > >          !(size_ps & (1 << size_tlb))) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      }
> > > 
> > >      if (msr_gs) {
> > > @@ -2892,10 +2892,6 @@ void tlb_fill(CPUState *cs, target_ulong
> > > addr, MMUAccessType
> > access_type,
> > > 
> > >          ret = cpu_ppc_handle_mmu_fault(env, addr, access_type,
> > > mmu_idx);
> > >      }
> > >      if (unlikely(ret != 0)) {
> > > -        if (likely(retaddr)) {
> > > -            /* now we have a real cpu fault */
> > > -            cpu_restore_state(cs, retaddr);
> > > -        }
> > > -        helper_raise_exception_err(env, cs->exception_index,
> > > env->error_code);
> > > +        raise_exception_err(env, cs->exception_index, env-
> > > >error_code, retaddr);
> > >      }
> > >  }
> > > diff --git a/target-ppc/timebase_helper.c b/target-
> > > ppc/timebase_helper.c
> > > index a07faa4..af328ca 100644
> > > --- a/target-ppc/timebase_helper.c
> > > +++ b/target-ppc/timebase_helper.c
> > > @@ -19,6 +19,7 @@
> > >  #include "qemu/osdep.h"
> > >  #include "cpu.h"
> > >  #include "exec/helper-proto.h"
> > > +#include "exec/exec-all.h"
> > >  #include "qemu/log.h"
> > > 
> > >  /***************************************************************
> > > **************/
> > > @@ -143,15 +144,15 @@ target_ulong helper_load_dcr(CPUPPCState
> > > *env, target_ulong dcrn)
> > > 
> > >      if (unlikely(env->dcr_env == NULL)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      } else if (unlikely(ppc_dcr_read(env->dcr_env,
> > >                                       (uint32_t)dcrn, &val) !=
> > > 0)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d
> > > %03x\n",
> > >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > POWERPC_EXCP_PRIV_REG);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > POWERPC_EXCP_PRIV_REG, GETPC());
> > >      }
> > >      return val;
> > >  }
> > > @@ -160,14 +161,14 @@ void helper_store_dcr(CPUPPCState *env,
> > > target_ulong dcrn,
> > target_ulong val)
> > > 
> > >  {
> > >      if (unlikely(env->dcr_env == NULL)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      } else if (unlikely(ppc_dcr_write(env->dcr_env,
> > > (uint32_t)dcrn,
> > >                                        (uint32_t)val) != 0)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d
> > > %03x\n",
> > >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > POWERPC_EXCP_PRIV_REG);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > POWERPC_EXCP_PRIV_REG, GETPC());
> > >      }
> > >  }
> > > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > > index 92030b6..0e16578 100644
> > > --- a/target-ppc/translate.c
> > > +++ b/target-ppc/translate.c
> > > @@ -292,7 +292,7 @@ static void gen_exception_err(DisasContext
> > > *ctx, uint32_t excp, uint32_t
> > error)
> > > 
> > >      }
> > >      t0 = tcg_const_i32(excp);
> > >      t1 = tcg_const_i32(error);
> > > -    gen_helper_raise_exception_err(cpu_env, t0, t1);
> > > +    gen_helper_raise_exception_end(cpu_env, t0, t1);
> > >      tcg_temp_free_i32(t0);
> > >      tcg_temp_free_i32(t1);
> > >      ctx->exception = (excp);
> > > @@ -300,14 +300,7 @@ static void gen_exception_err(DisasContext
> > > *ctx, uint32_t excp,
> > uint32_t error)
> > > 
> > > 
> > >  static void gen_exception(DisasContext *ctx, uint32_t excp)
> > >  {
> > > -    TCGv_i32 t0;
> > > -    if (ctx->exception == POWERPC_EXCP_NONE) {
> > > -        gen_update_nip(ctx, ctx->nip);
> > > -    }
> > > -    t0 = tcg_const_i32(excp);
> > > -    gen_helper_raise_exception(cpu_env, t0);
> > > -    tcg_temp_free_i32(t0);
> > > -    ctx->exception = (excp);
> > > +    gen_exception_err(ctx, excp, 0);
> > >  }
> > > 
> > >  static void gen_debug_exception(DisasContext *ctx)
> > > @@ -2149,8 +2142,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > > 
> > >          gen_exception(ctx,
> > > POWERPC_EXCP_FPU);                                 \
> > >          return;                                                 
> > >               \
> > >      }                                                           
> > >               \
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip -
> > > 4);                                        \
> > >      gen_reset_fpstatus();                                       
> > >               \
> > >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)],
> > > cpu_env,                       \
> > >                       cpu_fpr[rA(ctx-
> > > >opcode)],                                \
> > > @@ -2178,8 +2169,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > > 
> > >          gen_exception(ctx,
> > > POWERPC_EXCP_FPU);                                 \
> > >          return;                                                 
> > >               \
> > >      }                                                           
> > >               \
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip -
> > > 4);                                        \
> > >      gen_reset_fpstatus();                                       
> > >               \
> > >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)],
> > > cpu_env,                       \
> > >                       cpu_fpr[rA(ctx-
> > > >opcode)],                                \
> > > @@ -2206,8 +2195,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > > 
> > >          gen_exception(ctx,
> > > POWERPC_EXCP_FPU);                                 \
> > >          return;                                                 
> > >               \
> > >      }                                                           
> > >               \
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip -
> > > 4);                                        \
> > >      gen_reset_fpstatus();                                       
> > >               \
> > >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)],
> > > cpu_env,                       \
> > >                       cpu_fpr[rA(ctx-
> > > >opcode)],                                \
> > > @@ -2234,8 +2221,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > > 
> > >          gen_exception(ctx,
> > > POWERPC_EXCP_FPU);                                 \
> > >          return;                                                 
> > >               \
> > >      }                                                           
> > >               \
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip -
> > > 4);                                        \
> > >      gen_reset_fpstatus();                                       
> > >               \
> > >      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)],
> > > cpu_env,                     \
> > >                         cpu_fpr[rB(ctx-
> > > >opcode)]);                             \
> > > @@ -2254,8 +2239,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > > 
> > >          gen_exception(ctx,
> > > POWERPC_EXCP_FPU);                                 \
> > >          return;                                                 
> > >               \
> > >      }                                                           
> > >               \
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip -
> > > 4);                                        \
> > >      gen_reset_fpstatus();                                       
> > >               \
> > >      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)],
> > > cpu_env,                     \
> > >                         cpu_fpr[rB(ctx-
> > > >opcode)]);                             \
> > > @@ -2290,8 +2273,6 @@ static void gen_frsqrtes(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
> > >                         cpu_fpr[rB(ctx->opcode)]);
> > > @@ -2316,8 +2297,6 @@ static void gen_fsqrt(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
> > >                       cpu_fpr[rB(ctx->opcode)]);
> > > @@ -2333,8 +2312,6 @@ static void gen_fsqrts(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
> > >                       cpu_fpr[rB(ctx->opcode)]);
> > > @@ -2424,8 +2401,6 @@ static void gen_fcmpo(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      crf = tcg_const_i32(crfD(ctx->opcode));
> > >      gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
> > > @@ -2442,8 +2417,6 @@ static void gen_fcmpu(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      crf = tcg_const_i32(crfD(ctx->opcode));
> > >      gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
> > > @@ -2613,8 +2586,6 @@ static void gen_mtfsb0(DisasContext *ctx)
> > >      gen_reset_fpstatus();
> > >      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
> > >          TCGv_i32 t0;
> > > -        /* NIP cannot be restored if the memory exception comes
> > > from an helper */
> > > -        gen_update_nip(ctx, ctx->nip - 4);
> > >          t0 = tcg_const_i32(crb);
> > >          gen_helper_fpscr_clrbit(cpu_env, t0);
> > >          tcg_temp_free_i32(t0);
> > > @@ -2639,8 +2610,6 @@ static void gen_mtfsb1(DisasContext *ctx)
> > >      /* XXX: we pretend we can only do IEEE floating-point
> > > computations */
> > >      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb !=
> > > FPSCR_NI)) {
> > >          TCGv_i32 t0;
> > > -        /* NIP cannot be restored if the memory exception comes
> > > from an helper */
> > > -        gen_update_nip(ctx, ctx->nip - 4);
> > >          t0 = tcg_const_i32(crb);
> > >          gen_helper_fpscr_setbit(cpu_env, t0);
> > >          tcg_temp_free_i32(t0);
> > > @@ -2670,8 +2639,6 @@ static void gen_mtfsf(DisasContext *ctx)
> > >          gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      if (l) {
> > >          t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ?
> > > 0xffff : 0xff);
> > > @@ -2706,8 +2673,6 @@ static void gen_mtfsfi(DisasContext *ctx)
> > >          return;
> > >      }
> > >      sh = (8 * w) + 7 - bf;
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 *
> > > sh));
> > >      t1 = tcg_const_i32(1 << sh);
> > > @@ -2790,8 +2755,6 @@ static inline void
> > > gen_check_align(DisasContext *ctx, TCGv EA, int
> > mask)
> > > 
> > >      TCGLabel *l1 = gen_new_label();
> > >      TCGv t0 = tcg_temp_new();
> > >      TCGv_i32 t1, t2;
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      tcg_gen_andi_tl(t0, EA, mask);
> > >      tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
> > >      t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
> > > @@ -3261,8 +3224,6 @@ static void gen_lmw(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      t1 = tcg_const_i32(rD(ctx->opcode));
> > >      gen_addr_imm_index(ctx, t0, 0);
> > > @@ -3277,8 +3238,6 @@ static void gen_stmw(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      t1 = tcg_const_i32(rS(ctx->opcode));
> > >      gen_addr_imm_index(ctx, t0, 0);
> > > @@ -3312,8 +3271,6 @@ static void gen_lswi(DisasContext *ctx)
> > >          return;
> > >      }
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_register(ctx, t0);
> > >      t1 = tcg_const_i32(nb);
> > > @@ -3330,8 +3287,6 @@ static void gen_lswx(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1, t2, t3;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_reg_index(ctx, t0);
> > >      t1 = tcg_const_i32(rD(ctx->opcode));
> > > @@ -3351,8 +3306,6 @@ static void gen_stswi(DisasContext *ctx)
> > >      TCGv_i32 t1, t2;
> > >      int nb = NB(ctx->opcode);
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_register(ctx, t0);
> > >      if (nb == 0)
> > > @@ -3371,8 +3324,6 @@ static void gen_stswx(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1, t2;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_reg_index(ctx, t0);
> > >      t1 = tcg_temp_new_i32();
> > > @@ -4306,7 +4257,7 @@ static void gen_tw(DisasContext *ctx)
> > >  {
> > >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception
> > > */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > > cpu_gpr[rB(ctx->opcode)],
> > >                    t0);
> > >      tcg_temp_free_i32(t0);
> > > @@ -4318,7 +4269,7 @@ static void gen_twi(DisasContext *ctx)
> > >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> > >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception
> > > */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> > >      tcg_temp_free(t0);
> > >      tcg_temp_free_i32(t1);
> > > @@ -4330,7 +4281,7 @@ static void gen_td(DisasContext *ctx)
> > >  {
> > >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception
> > > */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > > cpu_gpr[rB(ctx->opcode)],
> > >                    t0);
> > >      tcg_temp_free_i32(t0);
> > > @@ -4342,7 +4293,7 @@ static void gen_tdi(DisasContext *ctx)
> > >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> > >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception
> > > */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> > >      tcg_temp_free(t0);
> > >      tcg_temp_free_i32(t1);
> > > @@ -4768,8 +4719,6 @@ static void gen_dcbz(DisasContext *ctx)
> > >      int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
> > > 
> > >      gen_set_access_type(ctx, ACCESS_CACHE);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      tcgv_addr = tcg_temp_new();
> > >      tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
> > > 
> > > @@ -4812,8 +4761,6 @@ static void gen_icbi(DisasContext *ctx)
> > >  {
> > >      TCGv t0;
> > >      gen_set_access_type(ctx, ACCESS_CACHE);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_reg_index(ctx, t0);
> > >      gen_helper_icbi(cpu_env, t0);
> > > @@ -5299,8 +5246,6 @@ static void gen_lscbx(DisasContext *ctx)
> > >      TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
> > > 
> > >      gen_addr_reg_index(ctx, t0);
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
> > >      tcg_temp_free_i32(t1);
> > >      tcg_temp_free_i32(t2);
> > > @@ -6386,8 +6331,6 @@ static void gen_mtdcrx(DisasContext *ctx)
> > >  /* mfdcrux (PPC 460) : user-mode access to DCR */
> > >  static void gen_mfdcrux(DisasContext *ctx)
> > >  {
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
> > >                          cpu_gpr[rA(ctx->opcode)]);
> > >      /* Note: Rc update flag set leads to undefined state of Rc0
> > > */
> > > @@ -6396,8 +6339,6 @@ static void gen_mfdcrux(DisasContext *ctx)
> > >  /* mtdcrux (PPC 460) : user-mode access to DCR */
> > >  static void gen_mtdcrux(DisasContext *ctx)
> > >  {
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > >                           cpu_gpr[rS(ctx->opcode)]);
> > >      /* Note: Rc update flag set leads to undefined state of Rc0
> > > */
> > > @@ -8027,8 +7968,6 @@ static void gen_##name(DisasContext * ctx)
> > \
> > > 
> > >          gen_exception(ctx,
> > > POWERPC_EXCP_VSXU);                                \
> > >          return;                                                 
> > >               \
> > >      }                                                           
> > >               \
> > > -    /* NIP cannot be restored if the memory exception comes from
> > > an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip -
> > > 4);                                        \
> > >      opc = tcg_const_i32(ctx-
> > > >opcode);                                         \
> > >      gen_helper_##name(cpu_env,
> > > opc);                                          \
> > >      tcg_temp_free_i32(opc);                                     
> > >               \
> > > @@ -8041,9 +7980,6 @@ static void gen_##name(DisasContext *
> > > ctx)                    \
> > >          gen_exception(ctx, POWERPC_EXCP_VSXU);                \
> > >          return;                                               \
> > >      }                                                         \
> > > -    /* NIP cannot be restored if the exception comes */       \
> > > -    /* from a helper. */                                      \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                        \
> > >                                                                \
> > >      gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
> > >                        cpu_vsrh(xB(ctx->opcode)));             \
> > > 
> > 
> > --
> > David Gibson			| I'll have my music baroque,
> > and my code
> > david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT
> > _the_ _other_
> > 				| _way_ _around_!
> > http://www.ozlabs.org/~dgibson

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

* Re: [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode
  2016-09-20  8:42     ` Pavel Dovgalyuk
  2016-09-20  8:54       ` Benjamin Herrenschmidt
@ 2016-09-20 13:15       ` 'David Gibson'
  1 sibling, 0 replies; 7+ messages in thread
From: 'David Gibson' @ 2016-09-20 13:15 UTC (permalink / raw)
  To: Pavel Dovgalyuk
  Cc: 'Pavel Dovgalyuk', qemu-devel, peter.maydell, mst,
	jasowang, quintela, agraf, pbonzini, benh

[-- Attachment #1: Type: text/plain, Size: 81796 bytes --]

On Tue, Sep 20, 2016 at 11:42:38AM +0300, Pavel Dovgalyuk wrote:
> > From: David Gibson [mailto:david@gibson.dropbear.id.au]
> > On Thu, Sep 15, 2016 at 11:09:59AM +0300, Pavel Dovgalyuk wrote:
> > > From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
> > >
> > > This patch fixes exception handling in PowerPC.
> > > Instructions generate several types of exceptions.
> > > When exception is generated, it breaks the execution of the current translation
> > > block. Implementation of the exceptions handling does not correctly
> > > restore icount for the instruction which caused the exception. In most cases
> > > icount will be decreased by the value equal to the size of TB.
> > > This patch passes pointer to the translation block internals to the exception
> > > handler. It allows correct restoring of the icount value.
> > >
> > > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> > 
> > I'm not really confident reviewing changes in this area.
> > 
> > I've CCed Ben Herrenshmidt, who did some work on the exception
> > handling recently.  
> 
> Thanks.
> It seems that most of these changes were already upstreamed from some other patch.
> That's why I removed this one from the updated series.

Oh, ok.  I'm not following the icount or replay stuff, so I didn't
notice - I just saw I'd been CCed on a patch touching ppc stuff.

> 
> > 
> > > ---
> > >  target-ppc/cpu.h             |    3 +
> > >  target-ppc/excp_helper.c     |   38 ++++++--
> > >  target-ppc/fpu_helper.c      |  192 ++++++++++++++++++++++--------------------
> > >  target-ppc/helper.h          |    1
> > >  target-ppc/mem_helper.c      |    6 +
> > >  target-ppc/misc_helper.c     |    8 +-
> > >  target-ppc/mmu-hash64.c      |   12 +--
> > >  target-ppc/mmu_helper.c      |   18 ++--
> > >  target-ppc/timebase_helper.c |   21 ++---
> > >  target-ppc/translate.c       |   76 +----------------
> > >  10 files changed, 169 insertions(+), 206 deletions(-)
> > >
> > > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> > > index 786ab5c..95baae3 100644
> > > --- a/target-ppc/cpu.h
> > > +++ b/target-ppc/cpu.h
> > > @@ -2434,4 +2434,7 @@ int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
> > >  PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
> > >
> > >  void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
> > > +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> > > +                         uint32_t error_code, uintptr_t pc);
> > > +
> > >  #endif /* PPC_CPU_H */
> > > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> > > index d6e1678..3da1c32 100644
> > > --- a/target-ppc/excp_helper.c
> > > +++ b/target-ppc/excp_helper.c
> > > @@ -898,8 +898,8 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
> > >  /*****************************************************************************/
> > >  /* Exceptions processing helpers */
> > >
> > > -void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> > > -                                uint32_t error_code)
> > > +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> > > +                         uint32_t error_code, uintptr_t pc)
> > >  {
> > >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> > >
> > > @@ -908,15 +908,32 @@ void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> > >  #endif
> > >      cs->exception_index = exception;
> > >      env->error_code = error_code;
> > > -    cpu_loop_exit(cs);
> > > +    cpu_loop_exit_restore(cs, pc);
> > > +}
> > > +
> > > +void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> > > +                                uint32_t error_code)
> > > +{
> > > +    raise_exception_err(env, exception, error_code, GETPC());
> > > +}
> > > +
> > > +void helper_raise_exception_end(CPUPPCState *env, uint32_t exception,
> > > +                                uint32_t error_code)
> > > +{
> > > +    raise_exception_err(env, exception, error_code, 0);
> > 
> > I'm struggling to see how raising an exception with a return address
> > of 0 could ever be useful...
> > 
> > >  }
> > >
> > >  void helper_raise_exception(CPUPPCState *env, uint32_t exception)
> > >  {
> > > -    helper_raise_exception_err(env, exception, 0);
> > > +    raise_exception_err(env, exception, 0, GETPC());
> > >  }
> > >
> > >  #if !defined(CONFIG_USER_ONLY)
> > > +static void raise_exception(CPUPPCState *env, uint32_t exception, uintptr_t pc)
> > > +{
> > > +    raise_exception_err(env, exception, 0, pc);
> > > +}
> > > +
> > >  void helper_store_msr(CPUPPCState *env, target_ulong val)
> > >  {
> > >      CPUState *cs;
> > > @@ -925,7 +942,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
> > >      if (val != 0) {
> > >          cs = CPU(ppc_env_get_cpu(env));
> > >          cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> > > -        helper_raise_exception(env, val);
> > > +        /* nip is updated by generated code */
> > > +        raise_exception(env, val, 0);
> > >      }
> > >  }
> > >
> > > @@ -1041,8 +1059,9 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
> > >                    ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
> > >                    ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
> > >                    ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_TRAP);
> > > +        /* nip is updated in TB */
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_TRAP, 0);
> > >      }
> > >  }
> > >
> > > @@ -1055,8 +1074,9 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
> > >                    ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
> > >                    ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
> > >                    ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_TRAP);
> > > +        /* nip is updated in TB */
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_TRAP, 0);
> > >      }
> > >  }
> > >  #endif
> > > diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
> > > index d9795d0..6eaa3f4 100644
> > > --- a/target-ppc/fpu_helper.c
> > > +++ b/target-ppc/fpu_helper.c
> > > @@ -19,6 +19,7 @@
> > >  #include "qemu/osdep.h"
> > >  #include "cpu.h"
> > >  #include "exec/helper-proto.h"
> > > +#include "exec/exec-all.h"
> > >
> > >  #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
> > >  #define float32_snan_to_qnan(x) ((x) | 0x00400000)
> > > @@ -117,7 +118,7 @@ void helper_compute_fprf(CPUPPCState *env, uint64_t arg)
> > >
> > >  /* Floating-point invalid operations exception */
> > >  static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
> > > -                                             int set_fpcc)
> > > +                                             int set_fpcc, uintptr_t retaddr)
> > >  {
> > >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> > >      uint64_t ret = 0;
> > > @@ -200,14 +201,14 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
> > >          /* Update the floating-point enabled exception summary */
> > >          env->fpscr |= 1 << FPSCR_FEX;
> > >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > > -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                       POWERPC_EXCP_FP | op);
> > > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                                POWERPC_EXCP_FP | op, retaddr);
> > >          }
> > >      }
> > >      return ret;
> > >  }
> > >
> > > -static inline void float_zero_divide_excp(CPUPPCState *env)
> > > +static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t retaddr)
> > >  {
> > >      env->fpscr |= 1 << FPSCR_ZX;
> > >      env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
> > > @@ -217,8 +218,8 @@ static inline void float_zero_divide_excp(CPUPPCState *env)
> > >          /* Update the floating-point enabled exception summary */
> > >          env->fpscr |= 1 << FPSCR_FEX;
> > >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > > -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
> > > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                                POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, retaddr);
> > >          }
> > >      }
> > >  }
> > > @@ -491,13 +492,13 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
> > >      helper_store_fpscr(env, arg, mask);
> > >  }
> > >
> > > -void helper_float_check_status(CPUPPCState *env)
> > > +static void do_float_check_status(CPUPPCState *env, uintptr_t retaddr)
> > >  {
> > >      CPUState *cs = CPU(ppc_env_get_cpu(env));
> > >      int status = get_float_exception_flags(&env->fp_status);
> > >
> > >      if (status & float_flag_divbyzero) {
> > > -        float_zero_divide_excp(env);
> > > +        float_zero_divide_excp(env, retaddr);
> > >      } else if (status & float_flag_overflow) {
> > >          float_overflow_excp(env);
> > >      } else if (status & float_flag_underflow) {
> > > @@ -510,12 +511,17 @@ void helper_float_check_status(CPUPPCState *env)
> > >          (env->error_code & POWERPC_EXCP_FP)) {
> > >          /* Differred floating-point exception after target FPR update */
> > >          if (msr_fe0 != 0 || msr_fe1 != 0) {
> > > -            helper_raise_exception_err(env, cs->exception_index,
> > > -                                       env->error_code);
> > > +            raise_exception_err(env, cs->exception_index,
> > > +                                env->error_code, retaddr);
> > >          }
> > >      }
> > >  }
> > >
> > > +void helper_float_check_status(CPUPPCState *env)
> > > +{
> > > +    do_float_check_status(env, GETPC());
> > > +}
> > > +
> > >  void helper_reset_fpstatus(CPUPPCState *env)
> > >  {
> > >      set_float_exception_flags(0, &env->fp_status);
> > > @@ -532,12 +538,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> > >      if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
> > >                   float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
> > >          /* Magnitude subtraction of infinities */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> > >              /* sNaN addition */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
> > >      }
> > > @@ -556,12 +562,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> > >      if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
> > >                   float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
> > >          /* Magnitude subtraction of infinities */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> > >              /* sNaN subtraction */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
> > >      }
> > > @@ -580,12 +586,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> > >      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
> > >                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> > >              /* sNaN multiplication */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
> > >      }
> > > @@ -604,15 +610,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
> > >      if (unlikely(float64_is_infinity(farg1.d) &&
> > >                   float64_is_infinity(farg2.d))) {
> > >          /* Division of infinity by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1, GETPC());
> > >      } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
> > >          /* Division of zero by zero */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status))) {
> > >              /* sNaN division */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
> > >      }
> > > @@ -631,16 +637,16 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)
> > \
> > >                                                                         \
> > >      if (unlikely(env->fp_status.float_exception_flags)) {              \
> > >          if (float64_is_any_nan(arg)) {                                 \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
> > >              if (float64_is_signaling_nan(arg, &env->fp_status)) {      \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());\
> > >              }                                                          \
> > >              farg.ll = nanval;                                          \
> > >          } else if (env->fp_status.float_exception_flags &              \
> > >                     float_flag_invalid) {                               \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1, GETPC());\
> > >          }                                                              \
> > > -        helper_float_check_status(env);                                \
> > > +        do_float_check_status(env, GETPC());                           \
> > >      }                                                                  \
> > >      return farg.ll;                                                    \
> > >   }
> > > @@ -665,7 +671,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)       \
> > >      } else {                                               \
> > >          farg.d = cvtr(arg, &env->fp_status);               \
> > >      }                                                      \
> > > -    helper_float_check_status(env);                        \
> > > +    do_float_check_status(env, GETPC());                   \
> > >      return farg.ll;                                        \
> > >  }
> > >
> > > @@ -675,7 +681,7 @@ FPU_FCFI(fcfidu, uint64_to_float64, 0)
> > >  FPU_FCFI(fcfidus, uint64_to_float32, 1)
> > >
> > >  static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> > > -                              int rounding_mode)
> > > +                              int rounding_mode, uint64_t retaddr)
> > >  {
> > >      CPU_DoubleU farg;
> > >
> > > @@ -683,7 +689,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> > >
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> > >          /* sNaN round */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, retaddr);
> > >          farg.ll = arg | 0x0008000000000000ULL;
> > >      } else {
> > >          int inexact = get_float_exception_flags(&env->fp_status) &
> > > @@ -698,28 +704,28 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
> > >              env->fp_status.float_exception_flags &= ~float_flag_inexact;
> > >          }
> > >      }
> > > -    helper_float_check_status(env);
> > > +    do_float_check_status(env, GETPC());
> > >      return farg.ll;
> > >  }
> > >
> > >  uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_ties_away);
> > > +    return do_fri(env, arg, float_round_ties_away, GETPC());
> > >  }
> > >
> > >  uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_to_zero);
> > > +    return do_fri(env, arg, float_round_to_zero, GETPC());
> > >  }
> > >
> > >  uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_up);
> > > +    return do_fri(env, arg, float_round_up, GETPC());
> > >  }
> > >
> > >  uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
> > >  {
> > > -    return do_fri(env, arg, float_round_down);
> > > +    return do_fri(env, arg, float_round_down, GETPC());
> > >  }
> > >
> > >  /* fmadd - fmadd. */
> > > @@ -735,13 +741,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
> > >                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it */
> > >          float128 ft0_128, ft1_128;
> > > @@ -753,7 +759,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> > >              ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
> > > @@ -778,13 +784,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >                   (float64_is_zero(farg1.d) &&
> > >                    float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it */
> > >          float128 ft0_128, ft1_128;
> > > @@ -796,7 +802,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> > >              ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
> > > @@ -819,13 +825,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >      if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
> > >                   (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it */
> > >          float128 ft0_128, ft1_128;
> > > @@ -837,7 +843,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> > >              ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
> > > @@ -864,13 +870,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >                   (float64_is_zero(farg1.d) &&
> > >                    float64_is_infinity(farg2.d)))) {
> > >          /* Multiplication of zero by infinity */
> > > -        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
> > > +        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1, GETPC());
> > >      } else {
> > >          if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg3.d, &env->fp_status))) {
> > >              /* sNaN operation */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >          }
> > >          /* This is the way the PowerPC specification defines it */
> > >          float128 ft0_128, ft1_128;
> > > @@ -882,7 +888,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >                       float64_is_infinity(farg3.d) &&
> > >                       float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
> > >              /* Magnitude subtraction of infinities */
> > > -            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
> > > +            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1, GETPC());
> > >          } else {
> > >              ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
> > >              ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
> > > @@ -905,7 +911,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
> > >
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> > >          /* sNaN square root */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >      }
> > >      f32 = float64_to_float32(farg.d, &env->fp_status);
> > >      farg.d = float32_to_float64(f32, &env->fp_status);
> > > @@ -923,12 +929,12 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
> > >      if (unlikely(float64_is_any_nan(farg.d))) {
> > >          if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> > >              /* sNaN reciprocal square root */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >              farg.ll = float64_snan_to_qnan(farg.ll);
> > >          }
> > >      } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
> > >          /* Square root of a negative nonzero number */
> > > -        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
> > > +        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
> > >      } else {
> > >          farg.d = float64_sqrt(farg.d, &env->fp_status);
> > >      }
> > > @@ -944,7 +950,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
> > >
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> > >          /* sNaN reciprocal */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >      }
> > >      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> > >      return farg.d;
> > > @@ -960,7 +966,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
> > >
> > >      if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> > >          /* sNaN reciprocal */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >      }
> > >      farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> > >      f32 = float64_to_float32(farg.d, &env->fp_status);
> > > @@ -979,12 +985,12 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
> > >      if (unlikely(float64_is_any_nan(farg.d))) {
> > >          if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
> > >              /* sNaN reciprocal square root */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >              farg.ll = float64_snan_to_qnan(farg.ll);
> > >          }
> > >      } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
> > >          /* Reciprocal square root of a negative nonzero number */
> > > -        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
> > > +        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1, GETPC());
> > >      } else {
> > >          farg.d = float64_sqrt(farg.d, &env->fp_status);
> > >          farg.d = float64_div(float64_one, farg.d, &env->fp_status);
> > > @@ -1103,7 +1109,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >                   && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
> > >                       float64_is_signaling_nan(farg2.d, &env->fp_status)))) {
> > >          /* sNaN comparison */
> > > -        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
> > > +        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1, GETPC());
> > >      }
> > >  }
> > >
> > > @@ -1135,10 +1141,10 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
> > >              float64_is_signaling_nan(farg2.d, &env->fp_status)) {
> > >              /* sNaN comparison */
> > >              fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
> > > -                                  POWERPC_EXCP_FP_VXVC, 1);
> > > +                                  POWERPC_EXCP_FP_VXVC, 1, GETPC());
> > >          } else {
> > >              /* qNaN comparison */
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1, GETPC());
> > >          }
> > >      }
> > >  }
> > > @@ -1838,10 +1844,10 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)
> > \
> > >                                                                               \
> > >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> > >              if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {      \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);    \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
> > >                         tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                                \
> > >          }                                                                    \
> > >                                                                               \
> > > @@ -1854,7 +1860,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)
> > \
> > >          }                                                                    \
> > >      }                                                                        \
> > >      putVSR(xT(opcode), &xt, env);                                            \
> > > -    helper_float_check_status(env);                                          \
> > > +    do_float_check_status(env, GETPC());                                     \
> > >  }
> > >
> > >  VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
> > > @@ -1893,10 +1899,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> > >              if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) ||        \
> > >                  (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) {        \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf);    \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
> > >                         tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                                \
> > >          }                                                                    \
> > >                                                                               \
> > > @@ -1910,7 +1916,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      }                                                                        \
> > >                                                                               \
> > >      putVSR(xT(opcode), &xt, env);                                            \
> > > -    helper_float_check_status(env);                                          \
> > > +    do_float_check_status(env, GETPC());                                     \
> > >  }
> > >
> > >  VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
> > > @@ -1944,13 +1950,13 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >                                                                                \
> > >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {     \
> > >              if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {       \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf);     \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf, GETPC());\
> > >              } else if (tp##_is_zero(xa.fld) &&                                \
> > >                  tp##_is_zero(xb.fld)) {                                       \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf);     \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||               \
> > >                  tp##_is_signaling_nan(xb.fld, &tstat)) {                      \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                                 \
> > >          }                                                                     \
> > >                                                                                \
> > > @@ -1964,7 +1970,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      }                                                                         \
> > >                                                                                \
> > >      putVSR(xT(opcode), &xt, env);                                             \
> > > -    helper_float_check_status(env);                                           \
> > > +    do_float_check_status(env, GETPC());                                      \
> > >  }
> > >
> > >  VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
> > > @@ -1991,7 +1997,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >                                                                                \
> > >      for (i = 0; i < nels; i++) {                                              \
> > >          if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >          }                                                                     \
> > >          xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status);                 \
> > >                                                                                \
> > > @@ -2005,7 +2011,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      }                                                                         \
> > >                                                                                \
> > >      putVSR(xT(opcode), &xt, env);                                             \
> > > -    helper_float_check_status(env);                                           \
> > > +    do_float_check_status(env, GETPC());                                      \
> > >  }
> > >
> > >  VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
> > > @@ -2038,9 +2044,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >                                                                               \
> > >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> > >              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                                \
> > >          }                                                                    \
> > >                                                                               \
> > > @@ -2054,7 +2060,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      }                                                                        \
> > >                                                                               \
> > >      putVSR(xT(opcode), &xt, env);                                            \
> > > -    helper_float_check_status(env);                                          \
> > > +    do_float_check_status(env, GETPC());                                     \
> > >  }
> > >
> > >  VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
> > > @@ -2088,9 +2094,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >                                                                               \
> > >          if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
> > >              if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf, GETPC());\
> > >              } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >              }                                                                \
> > >          }                                                                    \
> > >                                                                               \
> > > @@ -2104,7 +2110,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      }                                                                        \
> > >                                                                               \
> > >      putVSR(xT(opcode), &xt, env);                                            \
> > > -    helper_float_check_status(env);                                          \
> > > +    do_float_check_status(env, GETPC());                                     \
> > >  }
> > >
> > >  VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
> > > @@ -2277,20 +2283,20 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >              if (tp##_is_signaling_nan(xa.fld, &tstat) ||                      \
> > >                  tp##_is_signaling_nan(b->fld, &tstat) ||                      \
> > >                  tp##_is_signaling_nan(c->fld, &tstat)) {                      \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf, GETPC());\
> > >                  tstat.float_exception_flags &= ~float_flag_invalid;           \
> > >              }                                                                 \
> > >              if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b->fld)) ||         \
> > >                  (tp##_is_zero(xa.fld) && tp##_is_infinity(b->fld))) {         \
> > >                  xt_out.fld = float64_to_##tp(fload_invalid_op_excp(env,       \
> > > -                    POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status);          \
> > > +                    POWERPC_EXCP_FP_VXIMZ, sfprf, GETPC()), &env->fp_status); \
> > >                  tstat.float_exception_flags &= ~float_flag_invalid;           \
> > >              }                                                                 \
> > >              if ((tstat.float_exception_flags & float_flag_invalid) &&         \
> > >                  ((tp##_is_infinity(xa.fld) ||                                 \
> > >                    tp##_is_infinity(b->fld)) &&                                \
> > >                    tp##_is_infinity(c->fld))) {                                \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);     \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf, GETPC());\
> > >              }                                                                 \
> > >          }                                                                     \
> > >                                                                                \
> > > @@ -2303,7 +2309,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >          }                                                                     \
> > >      }                                                                         \
> > >      putVSR(xT(opcode), &xt_out, env);                                         \
> > > -    helper_float_check_status(env);                                           \
> > > +    do_float_check_status(env, GETPC());                                      \
> > >  }
> > >
> > >  #define MADD_FLGS 0
> > > @@ -2360,10 +2366,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >                   float64_is_any_nan(xb.VsrD(0)))) {                      \
> > >          if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) ||     \
> > >              float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) {     \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> > >          }                                                                \
> > >          if (ordered) {                                                   \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);         \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
> > >          }                                                                \
> > >          cc = 1;                                                          \
> > >      } else {                                                             \
> > > @@ -2381,7 +2387,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      env->fpscr |= cc << FPSCR_FPRF;                                      \
> > >      env->crf[BF(opcode)] = cc;                                           \
> > >                                                                           \
> > > -    helper_float_check_status(env);                                      \
> > > +    do_float_check_status(env, GETPC());                                 \
> > >  }
> > >
> > >  VSX_SCALAR_CMP(xscmpodp, 1)
> > > @@ -2408,12 +2414,12 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)
> > \
> > >          xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status);                  \
> > >          if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) ||        \
> > >                       tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);            \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());   \
> > >          }                                                                     \
> > >      }                                                                         \
> > >                                                                                \
> > >      putVSR(xT(opcode), &xt, env);                                             \
> > > -    helper_float_check_status(env);                                           \
> > > +    do_float_check_status(env, GETPC());                                      \
> > >  }
> > >
> > >  VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
> > > @@ -2448,10 +2454,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >                       tp##_is_any_nan(xb.fld))) {                          \
> > >              if (tp##_is_signaling_nan(xa.fld, &env->fp_status) ||         \
> > >                  tp##_is_signaling_nan(xb.fld, &env->fp_status)) {         \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);    \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> > >              }                                                             \
> > >              if (svxvc) {                                                  \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);      \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0, GETPC());\
> > >              }                                                             \
> > >              xt.fld = 0;                                                   \
> > >              all_true = 0;                                                 \
> > > @@ -2470,7 +2476,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      if ((opcode >> (31-21)) & 1) {                                        \
> > >          env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0);       \
> > >      }                                                                     \
> > > -    helper_float_check_status(env);                                       \
> > > +    do_float_check_status(env, GETPC());                                  \
> > >   }
> > >
> > >  VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
> > > @@ -2502,7 +2508,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
> > >          xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status);        \
> > >          if (unlikely(stp##_is_signaling_nan(xb.sfld,               \
> > >                                              &env->fp_status))) {   \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC()); \
> > >              xt.tfld = ttp##_snan_to_qnan(xt.tfld);                 \
> > >          }                                                          \
> > >          if (sfprf) {                                               \
> > > @@ -2512,7 +2518,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
> > >      }                                                              \
> > >                                                                     \
> > >      putVSR(xT(opcode), &xt, env);                                  \
> > > -    helper_float_check_status(env);                                \
> > > +    do_float_check_status(env, GETPC());                           \
> > >  }
> > >
> > >  VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1)
> > > @@ -2557,21 +2563,21 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      for (i = 0; i < nels; i++) {                                             \
> > >          if (unlikely(stp##_is_any_nan(xb.sfld))) {                           \
> > >              if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) {          \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> > >              }                                                                \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);            \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());   \
> > >              xt.tfld = rnan;                                                  \
> > >          } else {                                                             \
> > >              xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld,                \
> > >                            &env->fp_status);                                  \
> > >              if (env->fp_status.float_exception_flags & float_flag_invalid) { \
> > > -                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);        \
> > > +                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0, GETPC());\
> > >              }                                                                \
> > >          }                                                                    \
> > >      }                                                                        \
> > >                                                                               \
> > >      putVSR(xT(opcode), &xt, env);                                            \
> > > -    helper_float_check_status(env);                                          \
> > > +    do_float_check_status(env, GETPC());                                     \
> > >  }
> > >
> > >  VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \
> > > @@ -2622,7 +2628,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      }                                                                   \
> > >                                                                          \
> > >      putVSR(xT(opcode), &xt, env);                                       \
> > > -    helper_float_check_status(env);                                     \
> > > +    do_float_check_status(env, GETPC());                                \
> > >  }
> > >
> > >  VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
> > > @@ -2667,7 +2673,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      for (i = 0; i < nels; i++) {                                       \
> > >          if (unlikely(tp##_is_signaling_nan(xb.fld,                     \
> > >                                             &env->fp_status))) {        \
> > > -            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);     \
> > > +            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0, GETPC());\
> > >              xt.fld = tp##_snan_to_qnan(xb.fld);                        \
> > >          } else {                                                       \
> > >              xt.fld = tp##_round_to_int(xb.fld, &env->fp_status);       \
> > > @@ -2686,7 +2692,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)
> > \
> > >      }                                                                  \
> > >                                                                         \
> > >      putVSR(xT(opcode), &xt, env);                                      \
> > > -    helper_float_check_status(env);                                    \
> > > +    do_float_check_status(env, GETPC());                               \
> > >  }
> > >
> > >  VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
> > > @@ -2714,6 +2720,6 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
> > >      uint64_t xt = helper_frsp(env, xb);
> > >
> > >      helper_compute_fprf(env, xt);
> > > -    helper_float_check_status(env);
> > > +    do_float_check_status(env, GETPC());
> > >      return xt;
> > >  }
> > > diff --git a/target-ppc/helper.h b/target-ppc/helper.h
> > > index 1f5cfd0..34560f9 100644
> > > --- a/target-ppc/helper.h
> > > +++ b/target-ppc/helper.h
> > > @@ -1,4 +1,5 @@
> > >  DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
> > > +DEF_HELPER_3(raise_exception_end, void, env, i32, i32)
> > >  DEF_HELPER_2(raise_exception, void, env, i32)
> > >  DEF_HELPER_4(tw, void, env, tl, tl, i32)
> > >  #if defined(TARGET_PPC64)
> > > diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> > > index e4ed377..5cee620 100644
> > > --- a/target-ppc/mem_helper.c
> > > +++ b/target-ppc/mem_helper.c
> > > @@ -107,9 +107,9 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
> > >          if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
> > >                       lsw_reg_in_range(reg, num_used_regs, rb))) {
> > >              env->nip += 4;     /* Compensate the "nip - 4" from gen_lswx() */
> > > -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                       POWERPC_EXCP_INVAL |
> > > -                                       POWERPC_EXCP_INVAL_LSWX);
> > > +            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                                POWERPC_EXCP_INVAL |
> > > +                                POWERPC_EXCP_INVAL_LSWX, GETPC());
> > >          } else {
> > >              helper_lsw(env, addr, xer_bc, reg);
> > >          }
> > > diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
> > > index cb5ebf5..6661650 100644
> > > --- a/target-ppc/misc_helper.c
> > > +++ b/target-ppc/misc_helper.c
> > > @@ -39,7 +39,7 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
> > >
> > >  #ifdef TARGET_PPC64
> > >  static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
> > > -                               uint32_t sprn, uint32_t cause)
> > > +                               uint32_t sprn, uint32_t cause, uintptr_t retaddr)
> > >  {
> > >      qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
> > >
> > > @@ -47,7 +47,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
> > >      cause &= FSCR_IC_MASK;
> > >      env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
> > >
> > > -    helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
> > > +    raise_exception_err(env, POWERPC_EXCP_FU, 0, retaddr);
> > >  }
> > >  #endif
> > >
> > > @@ -59,7 +59,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
> > >          /* Facility is enabled, continue */
> > >          return;
> > >      }
> > > -    raise_fu_exception(env, bit, sprn, cause);
> > > +    raise_fu_exception(env, bit, sprn, cause, GETPC());
> > >  #endif
> > >  }
> > >
> > > @@ -71,7 +71,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
> > >          /* Facility is enabled, continue */
> > >          return;
> > >      }
> > > -    raise_fu_exception(env, bit, sprn, cause);
> > > +    raise_fu_exception(env, bit, sprn, cause, GETPC());
> > >  #endif
> > >  }
> > >
> > > diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
> > > index 5de1358..a1b27b0 100644
> > > --- a/target-ppc/mmu-hash64.c
> > > +++ b/target-ppc/mmu-hash64.c
> > > @@ -241,8 +241,8 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong
> > rs)
> > >      PowerPCCPU *cpu = ppc_env_get_cpu(env);
> > >
> > >      if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL, GETPC());
> > >      }
> > >  }
> > >
> > > @@ -252,8 +252,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
> > >      target_ulong rt = 0;
> > >
> > >      if (ppc_load_slb_esid(cpu, rb, &rt) < 0) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL, GETPC());
> > >      }
> > >      return rt;
> > >  }
> > > @@ -276,8 +276,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
> > >      target_ulong rt = 0;
> > >
> > >      if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL, GETPC());
> > >      }
> > >      return rt;
> > >  }
> > > diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
> > > index 3eb3cd7..7cd9c2c 100644
> > > --- a/target-ppc/mmu_helper.c
> > > +++ b/target-ppc/mmu_helper.c
> > > @@ -2598,9 +2598,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
> > >      tlb = booke206_cur_tlb(env);
> > >
> > >      if (!tlb) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      }
> > >
> > >      /* check that we support the targeted size */
> > > @@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
> > >      size_ps = booke206_tlbnps(env, tlbn);
> > >      if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
> > >          !(size_ps & (1 << size_tlb))) {
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      }
> > >
> > >      if (msr_gs) {
> > > @@ -2892,10 +2892,6 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType
> > access_type,
> > >          ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
> > >      }
> > >      if (unlikely(ret != 0)) {
> > > -        if (likely(retaddr)) {
> > > -            /* now we have a real cpu fault */
> > > -            cpu_restore_state(cs, retaddr);
> > > -        }
> > > -        helper_raise_exception_err(env, cs->exception_index, env->error_code);
> > > +        raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
> > >      }
> > >  }
> > > diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
> > > index a07faa4..af328ca 100644
> > > --- a/target-ppc/timebase_helper.c
> > > +++ b/target-ppc/timebase_helper.c
> > > @@ -19,6 +19,7 @@
> > >  #include "qemu/osdep.h"
> > >  #include "cpu.h"
> > >  #include "exec/helper-proto.h"
> > > +#include "exec/exec-all.h"
> > >  #include "qemu/log.h"
> > >
> > >  /*****************************************************************************/
> > > @@ -143,15 +144,15 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
> > >
> > >      if (unlikely(env->dcr_env == NULL)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      } else if (unlikely(ppc_dcr_read(env->dcr_env,
> > >                                       (uint32_t)dcrn, &val) != 0)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
> > >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
> > >      }
> > >      return val;
> > >  }
> > > @@ -160,14 +161,14 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn,
> > target_ulong val)
> > >  {
> > >      if (unlikely(env->dcr_env == NULL)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL |
> > > -                                   POWERPC_EXCP_INVAL_INVAL);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL |
> > > +                            POWERPC_EXCP_INVAL_INVAL, GETPC());
> > >      } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
> > >                                        (uint32_t)val) != 0)) {
> > >          qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n",
> > >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> > > +        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > > +                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG, GETPC());
> > >      }
> > >  }
> > > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > > index 92030b6..0e16578 100644
> > > --- a/target-ppc/translate.c
> > > +++ b/target-ppc/translate.c
> > > @@ -292,7 +292,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t
> > error)
> > >      }
> > >      t0 = tcg_const_i32(excp);
> > >      t1 = tcg_const_i32(error);
> > > -    gen_helper_raise_exception_err(cpu_env, t0, t1);
> > > +    gen_helper_raise_exception_end(cpu_env, t0, t1);
> > >      tcg_temp_free_i32(t0);
> > >      tcg_temp_free_i32(t1);
> > >      ctx->exception = (excp);
> > > @@ -300,14 +300,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp,
> > uint32_t error)
> > >
> > >  static void gen_exception(DisasContext *ctx, uint32_t excp)
> > >  {
> > > -    TCGv_i32 t0;
> > > -    if (ctx->exception == POWERPC_EXCP_NONE) {
> > > -        gen_update_nip(ctx, ctx->nip);
> > > -    }
> > > -    t0 = tcg_const_i32(excp);
> > > -    gen_helper_raise_exception(cpu_env, t0);
> > > -    tcg_temp_free_i32(t0);
> > > -    ctx->exception = (excp);
> > > +    gen_exception_err(ctx, excp, 0);
> > >  }
> > >
> > >  static void gen_debug_exception(DisasContext *ctx)
> > > @@ -2149,8 +2142,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> > >          return;                                                               \
> > >      }                                                                         \
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> > >      gen_reset_fpstatus();                                                     \
> > >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
> > >                       cpu_fpr[rA(ctx->opcode)],                                \
> > > @@ -2178,8 +2169,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> > >          return;                                                               \
> > >      }                                                                         \
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> > >      gen_reset_fpstatus();                                                     \
> > >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
> > >                       cpu_fpr[rA(ctx->opcode)],                                \
> > > @@ -2206,8 +2195,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> > >          return;                                                               \
> > >      }                                                                         \
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> > >      gen_reset_fpstatus();                                                     \
> > >      gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
> > >                       cpu_fpr[rA(ctx->opcode)],                                \
> > > @@ -2234,8 +2221,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> > >          return;                                                               \
> > >      }                                                                         \
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> > >      gen_reset_fpstatus();                                                     \
> > >      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
> > >                         cpu_fpr[rB(ctx->opcode)]);                             \
> > > @@ -2254,8 +2239,6 @@ static void gen_f##name(DisasContext *ctx)
> > \
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
> > >          return;                                                               \
> > >      }                                                                         \
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> > >      gen_reset_fpstatus();                                                     \
> > >      gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
> > >                         cpu_fpr[rB(ctx->opcode)]);                             \
> > > @@ -2290,8 +2273,6 @@ static void gen_frsqrtes(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
> > >                         cpu_fpr[rB(ctx->opcode)]);
> > > @@ -2316,8 +2297,6 @@ static void gen_fsqrt(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
> > >                       cpu_fpr[rB(ctx->opcode)]);
> > > @@ -2333,8 +2312,6 @@ static void gen_fsqrts(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
> > >                       cpu_fpr[rB(ctx->opcode)]);
> > > @@ -2424,8 +2401,6 @@ static void gen_fcmpo(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      crf = tcg_const_i32(crfD(ctx->opcode));
> > >      gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
> > > @@ -2442,8 +2417,6 @@ static void gen_fcmpu(DisasContext *ctx)
> > >          gen_exception(ctx, POWERPC_EXCP_FPU);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      crf = tcg_const_i32(crfD(ctx->opcode));
> > >      gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
> > > @@ -2613,8 +2586,6 @@ static void gen_mtfsb0(DisasContext *ctx)
> > >      gen_reset_fpstatus();
> > >      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
> > >          TCGv_i32 t0;
> > > -        /* NIP cannot be restored if the memory exception comes from an helper */
> > > -        gen_update_nip(ctx, ctx->nip - 4);
> > >          t0 = tcg_const_i32(crb);
> > >          gen_helper_fpscr_clrbit(cpu_env, t0);
> > >          tcg_temp_free_i32(t0);
> > > @@ -2639,8 +2610,6 @@ static void gen_mtfsb1(DisasContext *ctx)
> > >      /* XXX: we pretend we can only do IEEE floating-point computations */
> > >      if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
> > >          TCGv_i32 t0;
> > > -        /* NIP cannot be restored if the memory exception comes from an helper */
> > > -        gen_update_nip(ctx, ctx->nip - 4);
> > >          t0 = tcg_const_i32(crb);
> > >          gen_helper_fpscr_setbit(cpu_env, t0);
> > >          tcg_temp_free_i32(t0);
> > > @@ -2670,8 +2639,6 @@ static void gen_mtfsf(DisasContext *ctx)
> > >          gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
> > >          return;
> > >      }
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      if (l) {
> > >          t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
> > > @@ -2706,8 +2673,6 @@ static void gen_mtfsfi(DisasContext *ctx)
> > >          return;
> > >      }
> > >      sh = (8 * w) + 7 - bf;
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_reset_fpstatus();
> > >      t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
> > >      t1 = tcg_const_i32(1 << sh);
> > > @@ -2790,8 +2755,6 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int
> > mask)
> > >      TCGLabel *l1 = gen_new_label();
> > >      TCGv t0 = tcg_temp_new();
> > >      TCGv_i32 t1, t2;
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      tcg_gen_andi_tl(t0, EA, mask);
> > >      tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
> > >      t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
> > > @@ -3261,8 +3224,6 @@ static void gen_lmw(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      t1 = tcg_const_i32(rD(ctx->opcode));
> > >      gen_addr_imm_index(ctx, t0, 0);
> > > @@ -3277,8 +3238,6 @@ static void gen_stmw(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      t1 = tcg_const_i32(rS(ctx->opcode));
> > >      gen_addr_imm_index(ctx, t0, 0);
> > > @@ -3312,8 +3271,6 @@ static void gen_lswi(DisasContext *ctx)
> > >          return;
> > >      }
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_register(ctx, t0);
> > >      t1 = tcg_const_i32(nb);
> > > @@ -3330,8 +3287,6 @@ static void gen_lswx(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1, t2, t3;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_reg_index(ctx, t0);
> > >      t1 = tcg_const_i32(rD(ctx->opcode));
> > > @@ -3351,8 +3306,6 @@ static void gen_stswi(DisasContext *ctx)
> > >      TCGv_i32 t1, t2;
> > >      int nb = NB(ctx->opcode);
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_register(ctx, t0);
> > >      if (nb == 0)
> > > @@ -3371,8 +3324,6 @@ static void gen_stswx(DisasContext *ctx)
> > >      TCGv t0;
> > >      TCGv_i32 t1, t2;
> > >      gen_set_access_type(ctx, ACCESS_INT);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_reg_index(ctx, t0);
> > >      t1 = tcg_temp_new_i32();
> > > @@ -4306,7 +4257,7 @@ static void gen_tw(DisasContext *ctx)
> > >  {
> > >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
> > >                    t0);
> > >      tcg_temp_free_i32(t0);
> > > @@ -4318,7 +4269,7 @@ static void gen_twi(DisasContext *ctx)
> > >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> > >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> > >      tcg_temp_free(t0);
> > >      tcg_temp_free_i32(t1);
> > > @@ -4330,7 +4281,7 @@ static void gen_td(DisasContext *ctx)
> > >  {
> > >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
> > >                    t0);
> > >      tcg_temp_free_i32(t0);
> > > @@ -4342,7 +4293,7 @@ static void gen_tdi(DisasContext *ctx)
> > >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> > >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > >      /* Update the nip since this might generate a trap exception */
> > > -    gen_update_nip(ctx, ctx->nip);
> > > +    gen_stop_exception(ctx);
> > >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> > >      tcg_temp_free(t0);
> > >      tcg_temp_free_i32(t1);
> > > @@ -4768,8 +4719,6 @@ static void gen_dcbz(DisasContext *ctx)
> > >      int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
> > >
> > >      gen_set_access_type(ctx, ACCESS_CACHE);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      tcgv_addr = tcg_temp_new();
> > >      tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
> > >
> > > @@ -4812,8 +4761,6 @@ static void gen_icbi(DisasContext *ctx)
> > >  {
> > >      TCGv t0;
> > >      gen_set_access_type(ctx, ACCESS_CACHE);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      t0 = tcg_temp_new();
> > >      gen_addr_reg_index(ctx, t0);
> > >      gen_helper_icbi(cpu_env, t0);
> > > @@ -5299,8 +5246,6 @@ static void gen_lscbx(DisasContext *ctx)
> > >      TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
> > >
> > >      gen_addr_reg_index(ctx, t0);
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
> > >      tcg_temp_free_i32(t1);
> > >      tcg_temp_free_i32(t2);
> > > @@ -6386,8 +6331,6 @@ static void gen_mtdcrx(DisasContext *ctx)
> > >  /* mfdcrux (PPC 460) : user-mode access to DCR */
> > >  static void gen_mfdcrux(DisasContext *ctx)
> > >  {
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
> > >                          cpu_gpr[rA(ctx->opcode)]);
> > >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> > > @@ -6396,8 +6339,6 @@ static void gen_mfdcrux(DisasContext *ctx)
> > >  /* mtdcrux (PPC 460) : user-mode access to DCR */
> > >  static void gen_mtdcrux(DisasContext *ctx)
> > >  {
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */
> > > -    gen_update_nip(ctx, ctx->nip - 4);
> > >      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > >                           cpu_gpr[rS(ctx->opcode)]);
> > >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> > > @@ -8027,8 +7968,6 @@ static void gen_##name(DisasContext * ctx)
> > \
> > >          gen_exception(ctx, POWERPC_EXCP_VSXU);                                \
> > >          return;                                                               \
> > >      }                                                                         \
> > > -    /* NIP cannot be restored if the memory exception comes from an helper */ \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                                        \
> > >      opc = tcg_const_i32(ctx->opcode);                                         \
> > >      gen_helper_##name(cpu_env, opc);                                          \
> > >      tcg_temp_free_i32(opc);                                                   \
> > > @@ -8041,9 +7980,6 @@ static void gen_##name(DisasContext * ctx)                    \
> > >          gen_exception(ctx, POWERPC_EXCP_VSXU);                \
> > >          return;                                               \
> > >      }                                                         \
> > > -    /* NIP cannot be restored if the exception comes */       \
> > > -    /* from a helper. */                                      \
> > > -    gen_update_nip(ctx, ctx->nip - 4);                        \
> > >                                                                \
> > >      gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
> > >                        cpu_vsrh(xB(ctx->opcode)));             \
> > >
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

end of thread, other threads:[~2016-09-20 14:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-09-15  8:09 [Qemu-devel] [PATCH v2 00/11] icount/replay additions Pavel Dovgalyuk
2016-09-15  8:09 ` [Qemu-devel] [PATCH v2 01/11] target-ppc: exceptions handling in icount mode Pavel Dovgalyuk
2016-09-20  5:51   ` David Gibson
2016-09-20  8:42     ` Pavel Dovgalyuk
2016-09-20  8:54       ` Benjamin Herrenschmidt
2016-09-20 13:15       ` 'David Gibson'
2016-09-15  8:10 ` [Qemu-devel] [PATCH v2 02/11] record/replay: add network support Pavel Dovgalyuk

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