Commit cad3a37d authored by Fabrice Bellard's avatar Fabrice Bellard
Browse files

converted adc, sbb, cmpxchg to TCG

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4471 c046a42c-6fe2-441c-8c8c-71466251a162
parent b6abf97d
Loading
Loading
Loading
Loading
+0 −14
Original line number Diff line number Diff line
@@ -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

target-i386/ops_template_mem.h

deleted100644 → 0
+0 −119
Original line number Diff line number Diff line
/*
 *  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
+151 −172
Original line number Diff line number Diff line
@@ -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, &reg, 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, &reg, 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,6 +4232,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
        break;
    case 0x1b0:
    case 0x1b1: /* cmpxchg Ev, Gv */
        {
            int label1;

            if ((b & 1) == 0)
                ot = OT_BYTE;
            else
@@ -4281,14 +4246,28 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
            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, &reg_addr, &offset_addr);
                gen_op_ld_T0_A0(ot + s->mem_index);
            gen_op_cmpxchg_mem_T0_T1_EAX_cc[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;
        }
        break;
    case 0x1c7: /* cmpxchg8b */
        modrm = ldub_code(s->pc++);