tcg-target.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,215 行 · 第 1/3 页

C
1,215
字号
/* * Tiny Code Generator for QEMU * * Copyright (c) 2008 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */const char *tcg_target_reg_names[TCG_TARGET_NB_REGS] = {    "%eax",    "%ecx",    "%edx",    "%ebx",    "%esp",    "%ebp",    "%esi",    "%edi",};int tcg_target_reg_alloc_order[] = {    TCG_REG_EAX,    TCG_REG_EDX,    TCG_REG_ECX,    TCG_REG_EBX,    TCG_REG_ESI,    TCG_REG_EDI,    TCG_REG_EBP,    TCG_REG_ESP,};const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };static uint8_t *tb_ret_addr;static void patch_reloc(uint8_t *code_ptr, int type,                         tcg_target_long value, tcg_target_long addend){    value += addend;    switch(type) {    case R_386_32:        *(uint32_t *)code_ptr = value;        break;    case R_386_PC32:        *(uint32_t *)code_ptr = value - (long)code_ptr;        break;    default:        tcg_abort();    }}/* maximum number of register used for input function arguments */static inline int tcg_target_get_call_iarg_regs_count(int flags){    flags &= TCG_CALL_TYPE_MASK;    switch(flags) {    case TCG_CALL_TYPE_STD:        return 0;    case TCG_CALL_TYPE_REGPARM_1:    case TCG_CALL_TYPE_REGPARM_2:    case TCG_CALL_TYPE_REGPARM:        return flags - TCG_CALL_TYPE_REGPARM_1 + 1;    default:        tcg_abort();    }}/* parse target specific constraints */int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str){    const char *ct_str;    ct_str = *pct_str;    switch(ct_str[0]) {    case 'a':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX);        break;    case 'b':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX);        break;    case 'c':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX);        break;    case 'd':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX);        break;    case 'S':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI);        break;    case 'D':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI);        break;    case 'q':        ct->ct |= TCG_CT_REG;        tcg_regset_set32(ct->u.regs, 0, 0xf);        break;    case 'r':        ct->ct |= TCG_CT_REG;        tcg_regset_set32(ct->u.regs, 0, 0xff);        break;        /* qemu_ld/st address constraint */    case 'L':        ct->ct |= TCG_CT_REG;        tcg_regset_set32(ct->u.regs, 0, 0xff);        tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);        tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX);        break;    default:        return -1;    }    ct_str++;    *pct_str = ct_str;    return 0;}/* test if a constant matches the constraint */static inline int tcg_target_const_match(tcg_target_long val,                                         const TCGArgConstraint *arg_ct){    int ct;    ct = arg_ct->ct;    if (ct & TCG_CT_CONST)        return 1;    else        return 0;}#define ARITH_ADD 0#define ARITH_OR  1#define ARITH_ADC 2#define ARITH_SBB 3#define ARITH_AND 4#define ARITH_SUB 5#define ARITH_XOR 6#define ARITH_CMP 7#define SHIFT_SHL 4#define SHIFT_SHR 5#define SHIFT_SAR 7#define JCC_JMP (-1)#define JCC_JO  0x0#define JCC_JNO 0x1#define JCC_JB  0x2#define JCC_JAE 0x3#define JCC_JE  0x4#define JCC_JNE 0x5#define JCC_JBE 0x6#define JCC_JA  0x7#define JCC_JS  0x8#define JCC_JNS 0x9#define JCC_JP  0xa#define JCC_JNP 0xb#define JCC_JL  0xc#define JCC_JGE 0xd#define JCC_JLE 0xe#define JCC_JG  0xf#define P_EXT   0x100 /* 0x0f opcode prefix */static const uint8_t tcg_cond_to_jcc[10] = {    [TCG_COND_EQ] = JCC_JE,    [TCG_COND_NE] = JCC_JNE,    [TCG_COND_LT] = JCC_JL,    [TCG_COND_GE] = JCC_JGE,    [TCG_COND_LE] = JCC_JLE,    [TCG_COND_GT] = JCC_JG,    [TCG_COND_LTU] = JCC_JB,    [TCG_COND_GEU] = JCC_JAE,    [TCG_COND_LEU] = JCC_JBE,    [TCG_COND_GTU] = JCC_JA,};static inline void tcg_out_opc(TCGContext *s, int opc){    if (opc & P_EXT)        tcg_out8(s, 0x0f);    tcg_out8(s, opc);}static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm){    tcg_out_opc(s, opc);    tcg_out8(s, 0xc0 | (r << 3) | rm);}/* rm == -1 means no register index */static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm,                                         int32_t offset){    tcg_out_opc(s, opc);    if (rm == -1) {        tcg_out8(s, 0x05 | (r << 3));        tcg_out32(s, offset);    } else if (offset == 0 && rm != TCG_REG_EBP) {        if (rm == TCG_REG_ESP) {            tcg_out8(s, 0x04 | (r << 3));            tcg_out8(s, 0x24);        } else {            tcg_out8(s, 0x00 | (r << 3) | rm);        }    } else if ((int8_t)offset == offset) {        if (rm == TCG_REG_ESP) {            tcg_out8(s, 0x44 | (r << 3));            tcg_out8(s, 0x24);        } else {            tcg_out8(s, 0x40 | (r << 3) | rm);        }        tcg_out8(s, offset);    } else {        if (rm == TCG_REG_ESP) {            tcg_out8(s, 0x84 | (r << 3));            tcg_out8(s, 0x24);        } else {            tcg_out8(s, 0x80 | (r << 3) | rm);        }        tcg_out32(s, offset);    }}static inline void tcg_out_mov(TCGContext *s, int ret, int arg){    if (arg != ret)        tcg_out_modrm(s, 0x8b, ret, arg);}static inline void tcg_out_movi(TCGContext *s, TCGType type,                                int ret, int32_t arg){    if (arg == 0) {        /* xor r0,r0 */        tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret);    } else {        tcg_out8(s, 0xb8 + ret);        tcg_out32(s, arg);    }}static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,                              int arg1, tcg_target_long arg2){    /* movl */    tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2);}static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,                              int arg1, tcg_target_long arg2){    /* movl */    tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2);}static inline void tgen_arithi(TCGContext *s, int c, int r0, int32_t val){    if (val == (int8_t)val) {        tcg_out_modrm(s, 0x83, c, r0);        tcg_out8(s, val);    } else {        tcg_out_modrm(s, 0x81, c, r0);        tcg_out32(s, val);    }}void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val){    if (val != 0)        tgen_arithi(s, ARITH_ADD, reg, val);}static void tcg_out_jxx(TCGContext *s, int opc, int label_index){    int32_t val, val1;    TCGLabel *l = &s->labels[label_index];        if (l->has_value) {        val = l->u.value - (tcg_target_long)s->code_ptr;        val1 = val - 2;        if ((int8_t)val1 == val1) {            if (opc == -1)                tcg_out8(s, 0xeb);            else                tcg_out8(s, 0x70 + opc);            tcg_out8(s, val1);        } else {            if (opc == -1) {                tcg_out8(s, 0xe9);                tcg_out32(s, val - 5);            } else {                tcg_out8(s, 0x0f);                tcg_out8(s, 0x80 + opc);                tcg_out32(s, val - 6);            }        }    } else {        if (opc == -1) {            tcg_out8(s, 0xe9);        } else {            tcg_out8(s, 0x0f);            tcg_out8(s, 0x80 + opc);        }        tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4);        s->code_ptr += 4;    }}static void tcg_out_brcond(TCGContext *s, int cond,                            TCGArg arg1, TCGArg arg2, int const_arg2,                           int label_index){    int c;    if (const_arg2) {        if (arg2 == 0) {            /* use test */            switch(cond) {            case TCG_COND_EQ:                c = JCC_JE;                break;            case TCG_COND_NE:                c = JCC_JNE;                break;            case TCG_COND_LT:                c = JCC_JS;                break;            case TCG_COND_GE:                c = JCC_JNS;                break;            default:                goto do_cmpi;            }            /* test r, r */            tcg_out_modrm(s, 0x85, arg1, arg1);            tcg_out_jxx(s, c, label_index);        } else {        do_cmpi:            tgen_arithi(s, ARITH_CMP, arg1, arg2);            tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index);        }    } else {        tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1);        tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index);    }}/* XXX: we implement it at the target level to avoid having to   handle cross basic blocks temporaries */static void tcg_out_brcond2(TCGContext *s,                            const TCGArg *args, const int *const_args){    int label_next;    label_next = gen_new_label();    switch(args[4]) {    case TCG_COND_EQ:        tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next);        tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]);        break;    case TCG_COND_NE:        tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]);        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]);        break;    case TCG_COND_LT:        tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);        tcg_out_brcond(s, TCG_COND_LT, args[0], args[2], const_args[2], args[5]);        break;    case TCG_COND_LE:        tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);        tcg_out_brcond(s, TCG_COND_LE, args[0], args[2], const_args[2], args[5]);        break;    case TCG_COND_GT:        tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);        tcg_out_brcond(s, TCG_COND_GT, args[0], args[2], const_args[2], args[5]);        break;    case TCG_COND_GE:        tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);        tcg_out_brcond(s, TCG_COND_GE, args[0], args[2], const_args[2], args[5]);        break;    case TCG_COND_LTU:        tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]);        tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], label_next);        tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?