Copied from target-i386
Signed-off-by: Laurent Vivier
---
target-m68k/cpu.h | 5 +-
target-m68k/translate.c | 121 +---
2 files changed, 86 insertions(+), 40 deletions(-)
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index d3acd33..8dafaab 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -130,7 +130,7 @@ int cpu_m68k_exec(CPUState *cpu);
int cpu_m68k_signal_handler(int host_signum, void *pinfo,
void *puc);
-enum {
+typedef enum {
CC_OP_DYNAMIC, /* Use env->cc_op */
CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */
CC_OP_LOGICB, /* CC_DEST = result, CC_SRC = unused */
@@ -151,7 +151,8 @@ enum {
CC_OP_SHIFTB, /* CC_DEST = result, CC_SRC = carry */
CC_OP_SHIFTW, /* CC_DEST = result, CC_SRC = carry */
CC_OP_SHIFT, /* CC_DEST = result, CC_SRC = carry */
-};
+CC_OP_NB,
+} CCOp;
#define CCF_C 0x01
#define CCF_V 0x02
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 16f09ca..82c22b2 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -131,7 +131,7 @@ typedef struct DisasContext {
target_ulong insn_pc; /* Start of the current instruction. */
target_ulong pc;
int is_jmp;
-int cc_op;
+CCOp cc_op; /* Current CC operation */
int user;
uint32_t fpcr;
struct TranslationBlock *tb;
@@ -173,6 +173,53 @@ typedef void (*disas_proc)(CPUM68KState *env, DisasContext
*s, uint16_t insn);
uint16_t insn)
#endif
+enum {
+USES_CC_DST = 1,
+USES_CC_SRC = 2,
+};
+
+static const uint8_t cc_op_live[CC_OP_NB] = {
+[CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC,
+[CC_OP_FLAGS] = USES_CC_DST,
+[CC_OP_LOGICB ... CC_OP_LOGIC] = USES_CC_DST,
+[CC_OP_ADDB ... CC_OP_ADD] = USES_CC_DST | USES_CC_SRC,
+[CC_OP_SUBB ... CC_OP_SUB] = USES_CC_DST | USES_CC_SRC,
+[CC_OP_ADDXB ... CC_OP_ADDX] = USES_CC_DST | USES_CC_SRC,
+[CC_OP_SUBXB ... CC_OP_SUBX] = USES_CC_DST | USES_CC_SRC,
+[CC_OP_SHIFTB ... CC_OP_SHIFT] = USES_CC_DST | USES_CC_SRC,
+};
+
+static void set_cc_op(DisasContext *s, CCOp op)
+{
+int dead;
+
+if (s->cc_op == op) {
+return;
+}
+
+/* Discard CC computation that will no longer be used. */
+
+dead = cc_op_live[s->cc_op] & ~cc_op_live[op];
+if (dead & USES_CC_DST) {
+tcg_gen_discard_i32(QREG_CC_DEST);
+}
+if (dead & USES_CC_SRC) {
+tcg_gen_discard_i32(QREG_CC_SRC);
+}
+if (s->cc_op == CC_OP_DYNAMIC) {
+tcg_gen_discard_i32(QREG_CC_OP);
+}
+s->cc_op = op;
+}
+
+/* Update the CPU env CC_OP state. */
+static inline void update_cc_op(DisasContext *s)
+{
+if (s->cc_op != CC_OP_DYNAMIC) {
+tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
+}
+}
+
/* Generate a load from the specified address. Narrow values are
sign extended to full register width. */
static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
@@ -409,31 +456,28 @@ static TCGv gen_lea_indexed(CPUM68KState *env,
DisasContext *s, TCGv base)
return add;
}
-/* Update the CPU env CC_OP state. */
-static inline void gen_flush_cc_op(DisasContext *s)
-{
-if (s->cc_op != CC_OP_DYNAMIC)
-tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
-}
-
/* Evaluate all the CC flags. */
+
static inline void gen_flush_flags(DisasContext *s)
{
if (s->cc_op == CC_OP_FLAGS)
return;
-gen_flush_cc_op(s);
-gen_helper_flush_flags(QREG_CC_DEST, cpu_env, QREG_CC_OP);
-s->cc_op = CC_OP_FLAGS;
+if (s->cc_op == CC_OP_DYNAMIC) {
+gen_helper_flush_flags(QREG_CC_DEST, cpu_env, QREG_CC_OP);
+} else {
+gen_helper_flush_flags(QREG_CC_DEST, cpu_env, tcg_const_i32(s->cc_op));
+}
+set_cc_op(s, CC_OP_FLAGS);
}
#define SET_CC_OP(opsize, op) do { \
switch (opsize) { \
case OS_BYTE: \
-s->cc_op = CC_OP_##op##B; break; \
+set_cc_op(s, CC_OP_##op##B); break; \
case OS_WORD: \
-s->cc_op = CC_OP_##op##W; break; \
+set_cc_op(s, CC_OP_##op##W); break; \
case OS_LONG: \
-s->cc_op = CC_OP_##op; break; \
+set_cc_op(s, CC_OP_##op); break; \
default: \
abort(); \
} \
@@ -716,7 +760,7 @@ static void gen_jmpcc(DisasContext *s, int cond, TCGLabel
*l1)
/* TODO: Optimize compare/branch pairs rather than always flushing
flag state to CC_OP_FLAGS. */
gen_flush_flags(s);
-gen_flush_cc_op(s);
+update_cc_op(s);
switch (cond) {
case 0: /* T */
tcg_gen_br(l1);
@@ -833,7 +877,7 @@ DISAS_INSN(scc)
/* Force a TB lookup after an instruction that changes the CPU state. */
static void gen_lookup_tb(DisasContext *s)
{
-gen_flush_cc_op(s);
+update_cc_op(s);
tcg_gen_movi_i32(QREG_PC, s->pc);
s->is_jmp = DISAS_UPDATE;
}
@@ -841,7 +885,7 @@ static void gen_lookup_tb(DisasContext *s)
/* Generate a jump to an immediate