diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-17 13:50:02 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-17 13:50:02 +0000 |
commit | cad3a37d3ef861a3a84b57b630b5ad1ed204ad5f (patch) | |
tree | a5252e9cffd31e0a2a2de7c0048b743292837b80 /target-i386 | |
parent | b6abf97df19a3c632ca6977c2056f8a675f3f3f0 (diff) | |
download | qemu-cad3a37d3ef861a3a84b57b630b5ad1ed204ad5f.zip qemu-cad3a37d3ef861a3a84b57b630b5ad1ed204ad5f.tar.gz qemu-cad3a37d3ef861a3a84b57b630b5ad1ed204ad5f.tar.bz2 |
converted adc, sbb, cmpxchg to TCG
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4471 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/ops_template.h | 14 | ||||
-rw-r--r-- | target-i386/ops_template_mem.h | 119 | ||||
-rw-r--r-- | target-i386/translate.c | 323 |
3 files changed, 151 insertions, 305 deletions
diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 81e1891..219f295 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -415,20 +415,6 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2); } -#undef MEM_WRITE -#include "ops_template_mem.h" - -#define MEM_WRITE 0 -#include "ops_template_mem.h" - -#if !defined(CONFIG_USER_ONLY) -#define MEM_WRITE 1 -#include "ops_template_mem.h" - -#define MEM_WRITE 2 -#include "ops_template_mem.h" -#endif - /* bit operations */ #if DATA_BITS >= 16 diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h deleted file mode 100644 index b69d29f..0000000 --- a/target-i386/ops_template_mem.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * i386 micro operations (included several times to generate - * different operand sizes) - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifdef MEM_WRITE - -#if MEM_WRITE == 0 - -#if DATA_BITS == 8 -#define MEM_SUFFIX b_raw -#elif DATA_BITS == 16 -#define MEM_SUFFIX w_raw -#elif DATA_BITS == 32 -#define MEM_SUFFIX l_raw -#elif DATA_BITS == 64 -#define MEM_SUFFIX q_raw -#endif - -#elif MEM_WRITE == 1 - -#if DATA_BITS == 8 -#define MEM_SUFFIX b_kernel -#elif DATA_BITS == 16 -#define MEM_SUFFIX w_kernel -#elif DATA_BITS == 32 -#define MEM_SUFFIX l_kernel -#elif DATA_BITS == 64 -#define MEM_SUFFIX q_kernel -#endif - -#elif MEM_WRITE == 2 - -#if DATA_BITS == 8 -#define MEM_SUFFIX b_user -#elif DATA_BITS == 16 -#define MEM_SUFFIX w_user -#elif DATA_BITS == 32 -#define MEM_SUFFIX l_user -#elif DATA_BITS == 64 -#define MEM_SUFFIX q_user -#endif - -#else - -#error invalid MEM_WRITE - -#endif - -#else - -#define MEM_SUFFIX SUFFIX - -#endif - -/* carry add/sub (we only need to set CC_OP differently) */ - -void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 + T1 + cf; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = T1; - CC_DST = T0; - CC_OP = CC_OP_ADDB + SHIFT + cf * 4; -} - -void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 - T1 - cf; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - CC_SRC = T1; - CC_DST = T0; - CC_OP = CC_OP_SUBB + SHIFT + cf * 4; -} - -void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) -{ - target_ulong src, dst; - - src = T0; - dst = EAX - T0; - if ((DATA_TYPE)dst == 0) { - T0 = T1; -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)(A0, T0); -#endif - } else { - EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); - } - CC_SRC = src; - CC_DST = dst; - FORCE_RET(); -} - -#undef MEM_SUFFIX -#undef MEM_WRITE diff --git a/target-i386/translate.c b/target-i386/translate.c index 660daae..6c35c9c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -498,65 +498,6 @@ static GenOpFunc *gen_op_cmov_reg_T1_T0[NB_OP_SIZES - 1][CPU_NB_REGS] = { #endif }; -#define DEF_ARITHC(SUFFIX)\ - {\ - gen_op_adcb ## SUFFIX ## _T0_T1_cc,\ - gen_op_sbbb ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - gen_op_adcw ## SUFFIX ## _T0_T1_cc,\ - gen_op_sbbw ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - gen_op_adcl ## SUFFIX ## _T0_T1_cc,\ - gen_op_sbbl ## SUFFIX ## _T0_T1_cc,\ - },\ - {\ - X86_64_ONLY(gen_op_adcq ## SUFFIX ## _T0_T1_cc),\ - X86_64_ONLY(gen_op_sbbq ## SUFFIX ## _T0_T1_cc),\ - }, - -static GenOpFunc *gen_op_arithc_T0_T1_cc[4][2] = { - DEF_ARITHC( ) -}; - -static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3 * 4][2] = { - DEF_ARITHC(_raw) -#ifndef CONFIG_USER_ONLY - DEF_ARITHC(_kernel) - DEF_ARITHC(_user) -#endif -}; - -static const int cc_op_arithb[8] = { - CC_OP_ADDB, - CC_OP_LOGICB, - CC_OP_ADDB, - CC_OP_SUBB, - CC_OP_LOGICB, - CC_OP_SUBB, - CC_OP_LOGICB, - CC_OP_SUBB, -}; - -#define DEF_CMPXCHG(SUFFIX)\ - gen_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc,\ - gen_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc,\ - gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc,\ - X86_64_ONLY(gen_op_cmpxchgq ## SUFFIX ## _T0_T1_EAX_cc), - -static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[4] = { - DEF_CMPXCHG( ) -}; - -static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3 * 4] = { - DEF_CMPXCHG(_raw) -#ifndef CONFIG_USER_ONLY - DEF_CMPXCHG(_kernel) - DEF_CMPXCHG(_user) -#endif -}; - static GenOpFunc *gen_op_btx_T0_T1_cc[3][4] = { [0] = { gen_op_btw_T0_T1_cc, @@ -1257,11 +1198,53 @@ static void *helper_fp_arith_STN_ST0[8] = { helper_fdiv_STN_ST0, }; +/* compute eflags.C to reg */ +static void gen_compute_eflags_c(TCGv reg) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_cc_op, 3); + tcg_gen_addi_i32(cpu_tmp2_i32, cpu_tmp2_i32, + (long)cc_table + offsetof(CCTable, compute_c)); + tcg_gen_ld_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp2_i32, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#else + tcg_gen_extu_i32_tl(cpu_tmp1_i64, cpu_cc_op); + tcg_gen_shli_i64(cpu_tmp1_i64, cpu_tmp1_i64, 4); + tcg_gen_addi_i64(cpu_tmp1_i64, cpu_tmp1_i64, + (long)cc_table + offsetof(CCTable, compute_c)); + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_tmp1_i64, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp1_i64, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#endif + tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); +} + +/* compute all eflags to cc_src */ +static void gen_compute_eflags(TCGv reg) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_cc_op, 3); + tcg_gen_addi_i32(cpu_tmp2_i32, cpu_tmp2_i32, + (long)cc_table + offsetof(CCTable, compute_all)); + tcg_gen_ld_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp2_i32, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#else + tcg_gen_extu_i32_tl(cpu_tmp1_i64, cpu_cc_op); + tcg_gen_shli_i64(cpu_tmp1_i64, cpu_tmp1_i64, 4); + tcg_gen_addi_i64(cpu_tmp1_i64, cpu_tmp1_i64, + (long)cc_table + offsetof(CCTable, compute_all)); + tcg_gen_ld_i64(cpu_tmp1_i64, cpu_tmp1_i64, 0); + tcg_gen_call(&tcg_ctx, cpu_tmp1_i64, TCG_CALL_PURE, + 1, &cpu_tmp2_i32, 0, NULL); +#endif + tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); +} + /* if d == OR_TMP0, it means memory operand (address in A0) */ static void gen_op(DisasContext *s1, int op, int ot, int d) { - GenOpFunc *gen_update_cc; - if (d != OR_TMP0) { gen_op_mov_TN_reg(ot, 0, d); } else { @@ -1269,104 +1252,90 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) } switch(op) { case OP_ADCL: + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + gen_compute_eflags_c(cpu_tmp4); + tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); + tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_ADDB + ot); + s1->cc_op = CC_OP_DYNAMIC; + break; case OP_SBBL: if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - if (d != OR_TMP0) { - gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + gen_compute_eflags_c(cpu_tmp4); + tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4); + if (d != OR_TMP0) gen_op_mov_reg_T0(ot, d); - } else { - gen_op_arithc_mem_T0_T1_cc[ot + s1->mem_index][op - OP_ADCL](); - } + else + gen_op_st_T0_A0(ot + s1->mem_index); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); + tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); + tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_SUBB + ot); s1->cc_op = CC_OP_DYNAMIC; - goto the_end; + break; case OP_ADDL: gen_op_addl_T0_T1(); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update2_cc(); s1->cc_op = CC_OP_ADDB + ot; - gen_update_cc = gen_op_update2_cc; break; case OP_SUBL: tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update2_cc(); s1->cc_op = CC_OP_SUBB + ot; - gen_update_cc = gen_op_update2_cc; break; default: case OP_ANDL: tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update1_cc(); s1->cc_op = CC_OP_LOGICB + ot; - gen_update_cc = gen_op_update1_cc; break; case OP_ORL: tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update1_cc(); s1->cc_op = CC_OP_LOGICB + ot; - gen_update_cc = gen_op_update1_cc; break; case OP_XORL: tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + if (d != OR_TMP0) + gen_op_mov_reg_T0(ot, d); + else + gen_op_st_T0_A0(ot + s1->mem_index); + gen_op_update1_cc(); s1->cc_op = CC_OP_LOGICB + ot; - gen_update_cc = gen_op_update1_cc; break; case OP_CMPL: gen_op_cmpl_T0_T1_cc(); s1->cc_op = CC_OP_SUBB + ot; - gen_update_cc = NULL; break; } - if (op != OP_CMPL) { - if (d != OR_TMP0) - gen_op_mov_reg_T0(ot, d); - else - gen_op_st_T0_A0(ot + s1->mem_index); - } - /* the flags update must happen after the memory write (precise - exception support) */ - if (gen_update_cc) - gen_update_cc(); - the_end: ; -} - -/* compute eflags.C to reg */ -static void gen_compute_eflags_c(TCGv reg) -{ -#if TCG_TARGET_REG_BITS == 32 - tcg_gen_shli_i32(cpu_tmp2_i32, cpu_cc_op, 3); - tcg_gen_addi_i32(cpu_tmp2_i32, cpu_tmp2_i32, - (long)cc_table + offsetof(CCTable, compute_c)); - tcg_gen_ld_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0); - tcg_gen_call(&tcg_ctx, cpu_tmp2_i32, TCG_CALL_PURE, - 1, ®, 0, NULL); -#else - tcg_gen_extu_i32_tl(cpu_tmp1_i64, cpu_cc_op); - tcg_gen_shli_i64(cpu_tmp1_i64, cpu_tmp1_i64, 4); - tcg_gen_addi_i64(cpu_tmp1_i64, cpu_tmp1_i64, - (long)cc_table + offsetof(CCTable, compute_c)); - tcg_gen_ld_i64(cpu_tmp1_i64, cpu_tmp1_i64, 0); - tcg_gen_call(&tcg_ctx, cpu_tmp1_i64, TCG_CALL_PURE, - 1, &cpu_tmp2_i32, 0, NULL); - tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); -#endif -} - -/* compute all eflags to cc_src */ -static void gen_compute_eflags(TCGv reg) -{ -#if TCG_TARGET_REG_BITS == 32 - tcg_gen_shli_i32(cpu_tmp2_i32, cpu_cc_op, 3); - tcg_gen_addi_i32(cpu_tmp2_i32, cpu_tmp2_i32, - (long)cc_table + offsetof(CCTable, compute_all)); - tcg_gen_ld_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0); - tcg_gen_call(&tcg_ctx, cpu_tmp2_i32, TCG_CALL_PURE, - 1, ®, 0, NULL); -#else - tcg_gen_extu_i32_tl(cpu_tmp1_i64, cpu_cc_op); - tcg_gen_shli_i64(cpu_tmp1_i64, cpu_tmp1_i64, 4); - tcg_gen_addi_i64(cpu_tmp1_i64, cpu_tmp1_i64, - (long)cc_table + offsetof(CCTable, compute_all)); - tcg_gen_ld_i64(cpu_tmp1_i64, cpu_tmp1_i64, 0); - tcg_gen_call(&tcg_ctx, cpu_tmp1_i64, TCG_CALL_PURE, - 1, &cpu_tmp2_i32, 0, NULL); - tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); -#endif } /* if d == OR_TMP0, it means memory operand (address in A0) */ @@ -1393,6 +1362,23 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_compute_eflags_c(cpu_cc_src); } +static void gen_extu(int ot, TCGv reg) +{ + switch(ot) { + case OT_BYTE: + tcg_gen_ext8u_tl(reg, reg); + break; + case OT_WORD: + tcg_gen_ext16u_tl(reg, reg); + break; + case OT_LONG: + tcg_gen_ext32u_tl(reg, reg); + break; + default: + break; + } +} + /* XXX: add faster immediate case */ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, int is_right, int is_arith) @@ -1433,19 +1419,7 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, tcg_gen_sar_tl(cpu_T3, cpu_T[0], cpu_tmp5); tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]); } else { - switch(ot) { - case OT_BYTE: - tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]); - break; - case OT_WORD: - tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]); - break; - case OT_LONG: - tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]); - break; - default: - break; - } + gen_extu(ot, cpu_T[0]); tcg_gen_shr_tl(cpu_T3, cpu_T[0], cpu_tmp5); tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]); } @@ -1516,19 +1490,7 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, else tcg_gen_mov_tl(cpu_tmp0, cpu_T[1]); - switch(ot) { - case OT_BYTE: - tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]); - break; - case OT_WORD: - tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]); - break; - case OT_LONG: - tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]); - break; - default: - break; - } + gen_extu(ot, cpu_T[0]); tcg_gen_mov_tl(cpu_T3, cpu_T[0]); data_bits = 8 << ot; @@ -4270,25 +4232,42 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0x1b0: case 0x1b1: /* cmpxchg Ev, Gv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag + OT_WORD; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - mod = (modrm >> 6) & 3; - gen_op_mov_TN_reg(ot, 1, reg); - if (mod == 3) { - rm = (modrm & 7) | REX_B(s); - gen_op_mov_TN_reg(ot, 0, rm); - gen_op_cmpxchg_T0_T1_EAX_cc[ot](); - gen_op_mov_reg_T0(ot, rm); - } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0(ot + s->mem_index); - gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot + s->mem_index](); + { + int label1; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag + OT_WORD; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + gen_op_mov_TN_reg(ot, 1, reg); + if (mod == 3) { + rm = (modrm & 7) | REX_B(s); + gen_op_mov_TN_reg(ot, 0, rm); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0(ot + s->mem_index); + rm = 0; /* avoid warning */ + } + label1 = gen_new_label(); + tcg_gen_ld_tl(cpu_T3, cpu_env, offsetof(CPUState, regs[R_EAX])); + tcg_gen_sub_tl(cpu_T3, cpu_T3, cpu_T[0]); + gen_extu(ot, cpu_T3); + tcg_gen_brcond_tl(TCG_COND_EQ, cpu_T3, tcg_const_tl(0), label1); + tcg_gen_mov_tl(cpu_T[1], cpu_T[0]); + gen_op_mov_reg_T0(ot, R_EAX); + gen_set_label(label1); + if (mod == 3) { + gen_op_mov_reg_T1(ot, rm); + } else { + gen_op_st_T1_A0(ot + s->mem_index); + } + tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T3); + s->cc_op = CC_OP_SUBB + ot; } - s->cc_op = CC_OP_SUBB + ot; break; case 0x1c7: /* cmpxchg8b */ modrm = ldub_code(s->pc++); |