diff mbox

[v2,01/11] target-ppc: exceptions handling in icount mode

Message ID 20160915080959.3124.63067.stgit@PASHA-ISP (mailing list archive)
State New, archived
Headers show

Commit Message

Pavel Dovgalyuk Sept. 15, 2016, 8:09 a.m. UTC
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(-)

Comments

David Gibson Sept. 20, 2016, 5:51 a.m. UTC | #1
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)));             \
>
Pavel Dovgalyuk Sept. 20, 2016, 8:42 a.m. UTC | #2
> 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
Benjamin Herrenschmidt Sept. 20, 2016, 8:54 a.m. UTC | #3
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
David Gibson Sept. 20, 2016, 1:15 p.m. UTC | #4
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)));             \
> > >
> > 
>
diff mbox

Patch

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)));             \