This patch improves exception handling in MIPS.
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.
v3 changes:
This patch stops translation when instruction which always generates exception
is translated. This improves the performance of the patched version compared
to original one.
Signed-off-by: Pavel Dovgalyuk
---
target-mips/cpu.h| 23 +++
target-mips/helper.h |1
target-mips/msa_helper.c | 158 +++-
target-mips/op_helper.c | 179 ++
target-mips/translate.c | 372 ++
5 files changed, 368 insertions(+), 365 deletions(-)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index f9d2b4c..44d6e29 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -1015,4 +1015,27 @@ static inline void cpu_mips_store_cause(CPUMIPSState
*env, target_ulong val)
}
#endif
+static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
+uint32_t exception,
+int error_code,
+uintptr_t pc)
+{
+CPUState *cs = CPU(mips_env_get_cpu(env));
+
+if (exception < EXCP_SC) {
+qemu_log("%s: %d %d\n", __func__, exception, error_code);
+}
+cs->exception_index = exception;
+env->error_code = error_code;
+
+cpu_loop_exit_restore(cs, pc);
+}
+
+static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
+uint32_t exception,
+uintptr_t pc)
+{
+do_raise_exception_err(env, exception, 0, pc);
+}
+
#endif /* !defined (__MIPS_CPU_H__) */
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 3bd0b02..50c699e 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -1,5 +1,6 @@
DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
DEF_HELPER_2(raise_exception, noreturn, env, i32)
+DEF_HELPER_1(raise_exception_debug, noreturn, env)
#ifdef TARGET_MIPS64
DEF_HELPER_4(sdl, void, env, tl, tl, int)
diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c
index 26ffdc7..b907b02 100644
--- a/target-mips/msa_helper.c
+++ b/target-mips/msa_helper.c
@@ -1352,7 +1352,7 @@ void helper_msa_ctcmsa(CPUMIPSState *env, target_ulong
elm, uint32_t cd)
/* check exception */
if ((GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED)
& GET_FP_CAUSE(env->active_tc.msacsr)) {
-helper_raise_exception(env, EXCP_MSAFPE);
+do_raise_exception(env, EXCP_MSAFPE, GETPC());
}
break;
}
@@ -1505,14 +1505,14 @@ static inline void clear_msacsr_cause(CPUMIPSState *env)
SET_FP_CAUSE(env->active_tc.msacsr, 0);
}
-static inline void check_msacsr_cause(CPUMIPSState *env)
+static inline void check_msacsr_cause(CPUMIPSState *env, uintptr_t retaddr)
{
if ((GET_FP_CAUSE(env->active_tc.msacsr) &
(GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED)) == 0) {
UPDATE_FP_FLAGS(env->active_tc.msacsr,
GET_FP_CAUSE(env->active_tc.msacsr));
} else {
-helper_raise_exception(env, EXCP_MSAFPE);
+do_raise_exception(env, EXCP_MSAFPE, retaddr);
}
}
@@ -1851,7 +1851,8 @@ static inline int32 float64_to_q32(float64 a,
float_status *status)
} while (0)
static inline void compare_af(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
@@ -1873,13 +1874,14 @@ static inline void compare_af(CPUMIPSState *env, wr_t
*pwd, wr_t *pws,
assert(0);
}
-check_msacsr_cause(env);
+check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_un(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
@@ -1903,13 +1905,14 @@ static inline void compare_un(CPUMIPSState *env, wr_t
*pwd, wr_t *pws,
assert(0);
}
-check_msacsr_cause(env);
+check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_eq(CPUMIPSState *env, wr_t *pwd, wr_t