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 + -
显示快捷键?