mirror of https://github.com/xemu-project/xemu.git
target/i386: remove duplicate prefix decoding
Now that a bulk of opcodes go through the new decoder, it is sensible to do some cleanup. Go immediately through disas_insn_new and only jump back after parsing the prefixes. disas_insn() now only contains the three sigsetjmp cases, and they are more easily managed if they are inlined into i386_tr_translate_insn. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
ef309ec2a6
commit
d4e6d40c36
|
@ -2219,22 +2219,31 @@ illegal:
|
|||
* Convert one instruction. s->base.is_jmp is set if the translation must
|
||||
* be stopped.
|
||||
*/
|
||||
static void disas_insn_new(DisasContext *s, CPUState *cpu, int b)
|
||||
static void disas_insn(DisasContext *s, CPUState *cpu)
|
||||
{
|
||||
CPUX86State *env = cpu_env(cpu);
|
||||
bool first = true;
|
||||
X86DecodedInsn decode;
|
||||
X86DecodeFunc decode_func = decode_root;
|
||||
uint8_t cc_live;
|
||||
uint8_t cc_live, b;
|
||||
|
||||
s->pc = s->base.pc_next;
|
||||
s->override = -1;
|
||||
s->popl_esp_hack = 0;
|
||||
#ifdef TARGET_X86_64
|
||||
s->rex_r = 0;
|
||||
s->rex_x = 0;
|
||||
s->rex_b = 0;
|
||||
#endif
|
||||
s->rip_offset = 0; /* for relative ip address */
|
||||
s->vex_l = 0;
|
||||
s->vex_v = 0;
|
||||
s->vex_w = false;
|
||||
s->has_modrm = false;
|
||||
s->prefix = 0;
|
||||
|
||||
next_byte:
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
b = x86_ldub_code(env, s);
|
||||
}
|
||||
b = x86_ldub_code(env, s);
|
||||
|
||||
/* Collect prefixes. */
|
||||
switch (b) {
|
||||
case 0xf3:
|
||||
|
@ -2346,10 +2355,6 @@ static void disas_insn_new(DisasContext *s, CPUState *cpu, int b)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
if (b >= 0x100) {
|
||||
b -= 0x100;
|
||||
decode_func = do_decode_0F;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2378,6 +2383,40 @@ static void disas_insn_new(DisasContext *s, CPUState *cpu, int b)
|
|||
}
|
||||
}
|
||||
|
||||
/* Go back to old decoder for unconverted opcodes. */
|
||||
if (!(s->prefix & PREFIX_VEX)) {
|
||||
if ((b & ~7) == 0xd8) {
|
||||
if (!disas_insn_x87(s, cpu, b)) {
|
||||
goto unknown_op;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (b == 0x0f) {
|
||||
b = x86_ldub_code(env, s);
|
||||
switch (b) {
|
||||
case 0x00 ... 0x03: /* mostly privileged instructions */
|
||||
case 0x05 ... 0x09:
|
||||
case 0x0d: /* 3DNow! prefetch */
|
||||
case 0x18 ... 0x23: /* prefetch, MPX, mov from/to CR and DR */
|
||||
case 0x30 ... 0x35: /* more privileged instructions */
|
||||
case 0xa2 ... 0xa5: /* CPUID, BT, SHLD */
|
||||
case 0xaa ... 0xae: /* RSM, SHRD, grp15 */
|
||||
case 0xb0 ... 0xb1: /* cmpxchg */
|
||||
case 0xb3: /* btr */
|
||||
case 0xb8: /* integer ops */
|
||||
case 0xba ... 0xbd: /* integer ops */
|
||||
case 0xc0 ... 0xc1: /* xadd */
|
||||
case 0xc7: /* grp9 */
|
||||
disas_insn_old(s, cpu, b + 0x100);
|
||||
return;
|
||||
default:
|
||||
decode_func = do_decode_0F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(&decode, 0, sizeof(decode));
|
||||
decode.cc_op = -1;
|
||||
decode.b = b;
|
||||
|
|
|
@ -2451,10 +2451,6 @@ static void gen_sty_env_A0(DisasContext *s, int offset, bool align)
|
|||
tcg_gen_qemu_st_i128(t, s->tmp0, mem_index, mop);
|
||||
}
|
||||
|
||||
#include "decode-new.h"
|
||||
#include "emit.c.inc"
|
||||
#include "decode-new.c.inc"
|
||||
|
||||
static void gen_cmpxchg8b(DisasContext *s, CPUX86State *env, int modrm)
|
||||
{
|
||||
TCGv_i64 cmp, val, old;
|
||||
|
@ -3117,183 +3113,6 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void disas_insn_old(DisasContext *s, CPUState *cpu, int b);
|
||||
|
||||
/* convert one instruction. s->base.is_jmp is set if the translation must
|
||||
be stopped. Return the next pc value */
|
||||
static bool disas_insn(DisasContext *s, CPUState *cpu)
|
||||
{
|
||||
CPUX86State *env = cpu_env(cpu);
|
||||
int b, prefixes;
|
||||
MemOp aflag, dflag;
|
||||
bool orig_cc_op_dirty = s->cc_op_dirty;
|
||||
CCOp orig_cc_op = s->cc_op;
|
||||
target_ulong orig_pc_save = s->pc_save;
|
||||
|
||||
s->pc = s->base.pc_next;
|
||||
s->override = -1;
|
||||
s->popl_esp_hack = 0;
|
||||
#ifdef TARGET_X86_64
|
||||
s->rex_r = 0;
|
||||
s->rex_x = 0;
|
||||
s->rex_b = 0;
|
||||
#endif
|
||||
s->rip_offset = 0; /* for relative ip address */
|
||||
s->vex_l = 0;
|
||||
s->vex_v = 0;
|
||||
s->vex_w = false;
|
||||
switch (sigsetjmp(s->jmpbuf, 0)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
gen_exception_gpf(s);
|
||||
return true;
|
||||
case 2:
|
||||
/* Restore state that may affect the next instruction. */
|
||||
s->pc = s->base.pc_next;
|
||||
/*
|
||||
* TODO: These save/restore can be removed after the table-based
|
||||
* decoder is complete; we will be decoding the insn completely
|
||||
* before any code generation that might affect these variables.
|
||||
*/
|
||||
s->cc_op_dirty = orig_cc_op_dirty;
|
||||
s->cc_op = orig_cc_op;
|
||||
s->pc_save = orig_pc_save;
|
||||
/* END TODO */
|
||||
s->base.num_insns--;
|
||||
tcg_remove_ops_after(s->prev_insn_end);
|
||||
s->base.insn_start = s->prev_insn_start;
|
||||
s->base.is_jmp = DISAS_TOO_MANY;
|
||||
return false;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
prefixes = 0;
|
||||
|
||||
next_byte:
|
||||
s->prefix = prefixes;
|
||||
b = x86_ldub_code(env, s);
|
||||
/* Collect prefixes. */
|
||||
switch (b) {
|
||||
case 0x0f:
|
||||
b = x86_ldub_code(env, s) + 0x100;
|
||||
break;
|
||||
case 0xf3:
|
||||
prefixes |= PREFIX_REPZ;
|
||||
prefixes &= ~PREFIX_REPNZ;
|
||||
goto next_byte;
|
||||
case 0xf2:
|
||||
prefixes |= PREFIX_REPNZ;
|
||||
prefixes &= ~PREFIX_REPZ;
|
||||
goto next_byte;
|
||||
case 0xf0:
|
||||
prefixes |= PREFIX_LOCK;
|
||||
goto next_byte;
|
||||
case 0x2e:
|
||||
s->override = R_CS;
|
||||
goto next_byte;
|
||||
case 0x36:
|
||||
s->override = R_SS;
|
||||
goto next_byte;
|
||||
case 0x3e:
|
||||
s->override = R_DS;
|
||||
goto next_byte;
|
||||
case 0x26:
|
||||
s->override = R_ES;
|
||||
goto next_byte;
|
||||
case 0x64:
|
||||
s->override = R_FS;
|
||||
goto next_byte;
|
||||
case 0x65:
|
||||
s->override = R_GS;
|
||||
goto next_byte;
|
||||
case 0x66:
|
||||
prefixes |= PREFIX_DATA;
|
||||
goto next_byte;
|
||||
case 0x67:
|
||||
prefixes |= PREFIX_ADR;
|
||||
goto next_byte;
|
||||
#ifdef TARGET_X86_64
|
||||
case 0x40 ... 0x4f:
|
||||
if (CODE64(s)) {
|
||||
/* REX prefix */
|
||||
prefixes |= PREFIX_REX;
|
||||
s->vex_w = (b >> 3) & 1;
|
||||
s->rex_r = (b & 0x4) << 1;
|
||||
s->rex_x = (b & 0x2) << 2;
|
||||
s->rex_b = (b & 0x1) << 3;
|
||||
goto next_byte;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 0xc5: /* 2-byte VEX */
|
||||
case 0xc4: /* 3-byte VEX */
|
||||
if (CODE32(s) && !VM86(s)) {
|
||||
int vex2 = x86_ldub_code(env, s);
|
||||
s->pc--; /* rewind the advance_pc() x86_ldub_code() did */
|
||||
|
||||
if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) {
|
||||
/* 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b,
|
||||
otherwise the instruction is LES or LDS. */
|
||||
break;
|
||||
}
|
||||
disas_insn_new(s, cpu, b);
|
||||
return s->pc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Post-process prefixes. */
|
||||
if (CODE64(s)) {
|
||||
/* In 64-bit mode, the default data size is 32-bit. Select 64-bit
|
||||
data with rex_w, and 16-bit data with 0x66; rex_w takes precedence
|
||||
over 0x66 if both are present. */
|
||||
dflag = (REX_W(s) ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32);
|
||||
/* In 64-bit mode, 0x67 selects 32-bit addressing. */
|
||||
aflag = (prefixes & PREFIX_ADR ? MO_32 : MO_64);
|
||||
} else {
|
||||
/* In 16/32-bit mode, 0x66 selects the opposite data size. */
|
||||
if (CODE32(s) ^ ((prefixes & PREFIX_DATA) != 0)) {
|
||||
dflag = MO_32;
|
||||
} else {
|
||||
dflag = MO_16;
|
||||
}
|
||||
/* In 16/32-bit mode, 0x67 selects the opposite addressing. */
|
||||
if (CODE32(s) ^ ((prefixes & PREFIX_ADR) != 0)) {
|
||||
aflag = MO_32;
|
||||
} else {
|
||||
aflag = MO_16;
|
||||
}
|
||||
}
|
||||
|
||||
s->prefix = prefixes;
|
||||
s->aflag = aflag;
|
||||
s->dflag = dflag;
|
||||
|
||||
switch (b) {
|
||||
case 0 ... 0xd7:
|
||||
case 0xe0 ... 0xff:
|
||||
case 0x10e ... 0x117:
|
||||
case 0x128 ... 0x12f:
|
||||
case 0x138 ... 0x19f:
|
||||
case 0x1a0 ... 0x1a1:
|
||||
case 0x1a8 ... 0x1a9:
|
||||
case 0x1af:
|
||||
case 0x1b2:
|
||||
case 0x1b4 ... 0x1b7:
|
||||
case 0x1be ... 0x1bf:
|
||||
case 0x1c2 ... 0x1c6:
|
||||
case 0x1c8 ... 0x1ff:
|
||||
disas_insn_new(s, cpu, b);
|
||||
break;
|
||||
default:
|
||||
disas_insn_old(s, cpu, b);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
|
||||
{
|
||||
CPUX86State *env = cpu_env(cpu);
|
||||
|
@ -3502,14 +3321,6 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
|
|||
}
|
||||
break;
|
||||
|
||||
/************************/
|
||||
/* floats */
|
||||
case 0xd8 ... 0xdf:
|
||||
if (!disas_insn_x87(s, cpu, b)) {
|
||||
goto unknown_op;
|
||||
}
|
||||
break;
|
||||
|
||||
/************************/
|
||||
/* bit operations */
|
||||
case 0x1ba: /* bt/bts/btr/btc Gv, im */
|
||||
|
@ -4759,7 +4570,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
|
|||
set_cc_op(s, CC_OP_POPCNT);
|
||||
break;
|
||||
default:
|
||||
goto unknown_op;
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return;
|
||||
illegal_op:
|
||||
|
@ -4769,6 +4580,10 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
|
|||
gen_unknown_opcode(env, s);
|
||||
}
|
||||
|
||||
#include "decode-new.h"
|
||||
#include "emit.c.inc"
|
||||
#include "decode-new.c.inc"
|
||||
|
||||
void tcg_x86_init(void)
|
||||
{
|
||||
static const char reg_names[CPU_NB_REGS][4] = {
|
||||
|
@ -4890,7 +4705,6 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
|
|||
|
||||
dc->cc_op = CC_OP_DYNAMIC;
|
||||
dc->cc_op_dirty = false;
|
||||
dc->popl_esp_hack = 0;
|
||||
/* select memory access functions */
|
||||
dc->mem_index = cpu_mmu_index(cpu, false);
|
||||
dc->cpuid_features = env->features[FEAT_1_EDX];
|
||||
|
@ -4942,6 +4756,9 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
|||
static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
bool orig_cc_op_dirty = dc->cc_op_dirty;
|
||||
CCOp orig_cc_op = dc->cc_op;
|
||||
target_ulong orig_pc_save = dc->pc_save;
|
||||
|
||||
#ifdef TARGET_VSYSCALL_PAGE
|
||||
/*
|
||||
|
@ -4954,23 +4771,51 @@ static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (disas_insn(dc, cpu)) {
|
||||
target_ulong pc_next = dc->pc;
|
||||
dc->base.pc_next = pc_next;
|
||||
switch (sigsetjmp(dc->jmpbuf, 0)) {
|
||||
case 0:
|
||||
disas_insn(dc, cpu);
|
||||
break;
|
||||
case 1:
|
||||
gen_exception_gpf(dc);
|
||||
break;
|
||||
case 2:
|
||||
/* Restore state that may affect the next instruction. */
|
||||
dc->pc = dc->base.pc_next;
|
||||
/*
|
||||
* TODO: These save/restore can be removed after the table-based
|
||||
* decoder is complete; we will be decoding the insn completely
|
||||
* before any code generation that might affect these variables.
|
||||
*/
|
||||
dc->cc_op_dirty = orig_cc_op_dirty;
|
||||
dc->cc_op = orig_cc_op;
|
||||
dc->pc_save = orig_pc_save;
|
||||
/* END TODO */
|
||||
dc->base.num_insns--;
|
||||
tcg_remove_ops_after(dc->prev_insn_end);
|
||||
dc->base.insn_start = dc->prev_insn_start;
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (dc->base.is_jmp == DISAS_NEXT) {
|
||||
if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) {
|
||||
/*
|
||||
* If single step mode, we generate only one instruction and
|
||||
* generate an exception.
|
||||
* If irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
|
||||
* the flag and abort the translation to give the irqs a
|
||||
* chance to happen.
|
||||
*/
|
||||
dc->base.is_jmp = DISAS_EOB_NEXT;
|
||||
} else if (!is_same_page(&dc->base, pc_next)) {
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
}
|
||||
/*
|
||||
* Instruction decoding completed (possibly with #GP if the
|
||||
* 15-byte boundary was exceeded).
|
||||
*/
|
||||
dc->base.pc_next = dc->pc;
|
||||
if (dc->base.is_jmp == DISAS_NEXT) {
|
||||
if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) {
|
||||
/*
|
||||
* If single step mode, we generate only one instruction and
|
||||
* generate an exception.
|
||||
* If irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
|
||||
* the flag and abort the translation to give the irqs a
|
||||
* chance to happen.
|
||||
*/
|
||||
dc->base.is_jmp = DISAS_EOB_NEXT;
|
||||
} else if (!is_same_page(&dc->base, dc->base.pc_next)) {
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue