Add infrastructure to raise an exception out of line.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/arm/tcg/translate.h | 20 +++++++++++++
target/arm/tcg/translate-a64.c | 2 ++
target/arm/tcg/translate.c | 53 ++++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+)
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 1479f5bf74..a40cbd4479 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -21,9 +21,25 @@ typedef struct DisasLabel {
target_ulong pc_save;
} DisasLabel;
+/*
+ * Emit an exception call out of line.
+ */
+typedef struct DisasDelayException {
+ struct DisasDelayException *next;
+ TCGLabel *lab;
+ target_long pc_curr;
+ target_long pc_save;
+ int condexec_mask;
+ int condexec_cond;
+ uint32_t excp;
+ uint32_t syn;
+ uint32_t target_el;
+} DisasDelayException;
+
typedef struct DisasContext {
DisasContextBase base;
const ARMISARegisters *isar;
+ DisasDelayException *delay_excp_list;
/* The address of the current instruction being translated. */
target_ulong pc_curr;
@@ -365,6 +381,10 @@ void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp,
uint32_t syn, uint32_t target_el);
void gen_exception_insn(DisasContext *s, target_long pc_diff,
int excp, uint32_t syn);
+TCGLabel *delay_exception_el(DisasContext *s, int excp,
+ uint32_t syn, uint32_t target_el);
+TCGLabel *delay_exception(DisasContext *s, int excp, uint32_t syn);
+void emit_delayed_exceptions(DisasContext *s);
/* Return state of Alternate Half-precision flag, caller frees result */
static inline TCGv_i32 get_ahp_flag(void)
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index ca1633540f..1175d37c87 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10562,6 +10562,8 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
break;
}
}
+
+ emit_delayed_exceptions(dc);
}
const TranslatorOps aarch64_translator_ops = {
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index f7d6d8ce19..c4dd3a747c 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -1090,6 +1090,57 @@ void gen_exception_insn(DisasContext *s, target_long pc_diff,
s->base.is_jmp = DISAS_NORETURN;
}
+TCGLabel *delay_exception_el(DisasContext *s, int excp,
+ uint32_t syn, uint32_t target_el)
+{
+ /* Use tcg_malloc for automatic release on longjmp out of translation. */
+ DisasDelayException *e = tcg_malloc(sizeof(DisasDelayException));
+
+ memset(e, 0, sizeof(*e));
+
+ /* Save enough of the current state to satisfy gen_exception_insn. */
+ e->pc_curr = s->pc_curr;
+ e->pc_save = s->pc_save;
+ if (!s->aarch64) {
+ e->condexec_cond = s->condexec_cond;
+ e->condexec_mask = s->condexec_mask;
+ }
+
+ e->excp = excp;
+ e->syn = syn;
+ e->target_el = target_el;
+
+ e->next = s->delay_excp_list;
+ s->delay_excp_list = e;
+
+ e->lab = gen_new_label();
+ return e->lab;
+}
+
+TCGLabel *delay_exception(DisasContext *s, int excp, uint32_t syn)
+{
+ return delay_exception_el(s, excp, syn, 0);
+}
+
+void emit_delayed_exceptions(DisasContext *s)
+{
+ for (DisasDelayException *e = s->delay_excp_list; e ; e = e->next) {
+ gen_set_label(e->lab);
+
+ /* Restore the insn state to satisfy gen_exception_insn. */
+ s->pc_curr = e->pc_curr;
+ s->pc_save = e->pc_save;
+ s->condexec_cond = e->condexec_cond;
+ s->condexec_mask = e->condexec_mask;
+
+ if (e->target_el) {
+ gen_exception_insn_el(s, 0, e->excp, e->syn, e->target_el);
+ } else {
+ gen_exception_insn(s, 0, e->excp, e->syn);
+ }
+ }
+}
+
static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
{
gen_set_condexec(s);
@@ -8107,6 +8158,8 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
gen_goto_tb(dc, 1, curr_insn_len(dc));
}
}
+
+ emit_delayed_exceptions(dc);
}
static const TranslatorOps arm_translator_ops = {
--
2.43.0