Allow applying sign and zero extension to T1 load and T0 writeback. T1 load is useful for some cases where the tables are hacked to put the sign extended operand in T0; T0 writeback is used for APX ZU instructions.
Reviewed-by: Richard Henderson <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> --- target/i386/tcg/decode-new.h | 15 +++++++++++---- target/i386/tcg/decode-new.c.inc | 21 +++++++++++---------- target/i386/tcg/emit.c.inc | 16 ++++++++++------ 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/target/i386/tcg/decode-new.h b/target/i386/tcg/decode-new.h index 25f7d2215ee..1b5a91b4f46 100644 --- a/target/i386/tcg/decode-new.h +++ b/target/i386/tcg/decode-new.h @@ -148,6 +148,12 @@ typedef enum X86OpUnit { X86_OP_MMX, /* address in either s->ptrX or s->A0 depending on has_ea */ } X86OpUnit; +typedef enum X86OpExt { + X86_EXT_None, + X86_EXT_Signed, + X86_EXT_Unsigned, +} X86OpExt; + typedef enum X86InsnCheck { /* Illegal or exclusive to 64-bit mode */ X86_CHECK_i64 = 1, @@ -226,10 +232,6 @@ typedef enum X86InsnSpecial { */ X86_SPECIAL_MMX, - /* When loaded into s->T0, register operand 1 is zero/sign extended. */ - X86_SPECIAL_SExtT0, - X86_SPECIAL_ZExtT0, - /* Memory operand size of MOV from segment register is MO_16 */ X86_SPECIAL_Op0_Mw, } X86InsnSpecial; @@ -300,6 +302,10 @@ struct X86OpEntry { X86OpSize s3:8; X86InsnSpecial special:8; + X86OpExt ext0:2; + X86OpExt ext1:2; + X86OpExt ext2:2; + unsigned :2; X86CPUIDFeature cpuid:8; unsigned vex_class:8; X86VEXSpecial vex_special:8; @@ -314,6 +320,7 @@ typedef struct X86DecodedOp { int8_t n; MemOp ot; /* For b/c/d/p/s/q/v/w/y/z */ X86OpUnit unit; + X86OpExt ext; bool has_ea; int offset; /* For MMX and SSE */ diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index 26f6d6277be..07a627af5cf 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -233,8 +233,12 @@ #define op0_Rd .special = X86_SPECIAL_Op0_Rd, #define op2_Ry .special = X86_SPECIAL_Op2_Ry, #define avx_movx .special = X86_SPECIAL_AVXExtMov, -#define sextT0 .special = X86_SPECIAL_SExtT0, -#define zextT0 .special = X86_SPECIAL_ZExtT0, +#define sextwT0 .ext0 = X86_EXT_Signed, +#define zextwT0 .ext0 = X86_EXT_Unsigned, +#define sextT0 .ext1 = X86_EXT_Signed, +#define zextT0 .ext1 = X86_EXT_Unsigned, +#define sextT1 .ext2 = X86_EXT_Signed, +#define zextT1 .ext2 = X86_EXT_Unsigned, #define op0_Mw .special = X86_SPECIAL_Op0_Mw, #define btEvGv .special = X86_SPECIAL_BitTest, @@ -1614,9 +1618,9 @@ static void decode_group2(DisasContext *s, CPUX86State *env, X86OpEntry *entry, int op = (get_modrm(s, env) >> 3) & 7; entry->gen = group2_gen[op]; if (op == 7) { - entry->special = X86_SPECIAL_SExtT0; + entry->ext1 = X86_EXT_Signed; } else { - entry->special = X86_SPECIAL_ZExtT0; + entry->ext1 = X86_EXT_Unsigned; } } @@ -2528,16 +2532,19 @@ static bool decode_ops(DisasContext *s, CPUX86State *env, X86DecodeFunc decode_f !decode_op(s, env, decode, &decode->op[0], e->op0, decode->b)) { return false; } + decode->op[0].ext = e->ext0; if (e->op1 != X86_TYPE_None && !decode_op(s, env, decode, &decode->op[1], e->op1, decode->b)) { return false; } + decode->op[1].ext = e->ext1; if (e->op2 != X86_TYPE_None && !decode_op(s, env, decode, &decode->op[2], e->op2, decode->b)) { return false; } + decode->op[2].ext = e->ext2; if (e->op3 != X86_TYPE_None) { decode->immediate = insn_get_signed(env, s, MO_8); @@ -3079,12 +3086,6 @@ static void disas_insn(DisasContext *s, CPUState *cpu) } break; - case X86_SPECIAL_SExtT0: - case X86_SPECIAL_ZExtT0: - /* Handled in gen_load. */ - assert(decode.op[1].unit == X86_OP_INT); - break; - case X86_SPECIAL_Op0_Mw: assert(decode.op[0].unit == X86_OP_INT); if (decode.op[0].has_ea) { diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index c83ab809408..54dc23ca624 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -266,23 +266,21 @@ static void gen_load(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv v) #endif case X86_OP_INT: if (op->has_ea) { - if (v == s->T0 && decode->e.special == X86_SPECIAL_SExtT0) { + if (op->ext == X86_EXT_Signed) { gen_op_ld_v(s, op->ot | MO_SIGN, v, s->A0); } else { gen_op_ld_v(s, op->ot, v, s->A0); } - } else if (op->ot < MO_TL && v == s->T0 && - (decode->e.special == X86_SPECIAL_SExtT0 || - decode->e.special == X86_SPECIAL_ZExtT0)) { + } else if (op->ot < MO_TL && op->ext != X86_EXT_None) { if (op->ot == MO_8 && byte_reg_is_xH(s, op->n)) { - if (decode->e.special == X86_SPECIAL_SExtT0) { + if (op->ext == X86_EXT_Signed) { tcg_gen_sextract_tl(v, cpu_regs[op->n - 4], 8, 8); } else { tcg_gen_extract_tl(v, cpu_regs[op->n - 4], 8, 8); } } else { - if (decode->e.special == X86_SPECIAL_SExtT0) { + if (op->ext == X86_EXT_Signed) { tcg_gen_ext_tl(v, cpu_regs[op->n], op->ot | MO_SIGN); } else { tcg_gen_ext_tl(v, cpu_regs[op->n], op->ot); @@ -347,6 +345,12 @@ static void gen_writeback(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv case X86_OP_INT: if (op->has_ea) { gen_op_st_v(s, op->ot, v, s->A0); + } else if (op->ot < MO_TL && op->ext != X86_EXT_None) { + if (op->ext == X86_EXT_Signed) { + tcg_gen_ext_tl(cpu_regs[op->n], v, op->ot | MO_SIGN); + } else { + tcg_gen_ext_tl(cpu_regs[op->n], v, op->ot); + } } else { gen_op_mov_reg_v(s, op->ot, op->n, v); } -- 2.55.0
