X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_emitter.c;h=522c79554fdf1d2af122fe24166f3954d80e5b24;hb=ef668aa395ab2cb4b3fb4066a8fa4c65c05aabf6;hp=0bbc29ca090538904e297495e71183779e2825d8;hpb=6fad1812031f0457c843aa36bc9f90f252e0b269;p=libfirm diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 0bbc29ca0..522c79554 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -2251,19 +2251,21 @@ static void build_reg_map(void) reg_gp_map[REG_ESI] = 0x6; reg_gp_map[REG_EDI] = 0x7; - pnc_map_signed[pn_Cmp_Eq] = 0x04; - pnc_map_signed[pn_Cmp_Lt] = 0x0C; - pnc_map_signed[pn_Cmp_Le] = 0x0E; - pnc_map_signed[pn_Cmp_Gt] = 0x0F; - pnc_map_signed[pn_Cmp_Ge] = 0x0D; - pnc_map_signed[pn_Cmp_Ne] = 0x05; - - pnc_map_unsigned[pn_Cmp_Eq] = 0x04; - pnc_map_unsigned[pn_Cmp_Lt] = 0x02; - pnc_map_unsigned[pn_Cmp_Le] = 0x06; - pnc_map_unsigned[pn_Cmp_Gt] = 0x07; - pnc_map_unsigned[pn_Cmp_Ge] = 0x03; - pnc_map_unsigned[pn_Cmp_Ne] = 0x05; + pnc_map_signed[pn_Cmp_False] = 0xFF; + pnc_map_signed[pn_Cmp_Eq] = 0x04; + pnc_map_signed[pn_Cmp_Lt] = 0x0C; + pnc_map_signed[pn_Cmp_Le] = 0x0E; + pnc_map_signed[pn_Cmp_Gt] = 0x0F; + pnc_map_signed[pn_Cmp_Ge] = 0x0D; + pnc_map_signed[pn_Cmp_Lg] = 0x05; + + pnc_map_unsigned[pn_Cmp_False] = 0xFF; + pnc_map_unsigned[pn_Cmp_Eq] = 0x04; + pnc_map_unsigned[pn_Cmp_Lt] = 0x02; + pnc_map_unsigned[pn_Cmp_Le] = 0x06; + pnc_map_unsigned[pn_Cmp_Gt] = 0x07; + pnc_map_unsigned[pn_Cmp_Ge] = 0x03; + pnc_map_unsigned[pn_Cmp_Lg] = 0x05; } #define GET_MODE(code) ((code) & 0xC0) @@ -2287,12 +2289,8 @@ enum Mod { /** create REG encoding for ModR/M */ #define ENC_REG(x) ((x) << 3) -/** create Base encoding for SIB */ -#define ENC_BASE(x) (x) -/** create Index encoding for SIB */ -#define ENC_INDEX(x) ((x) << 3) -/** create Scale encoding for SIB */ -#define ENC_SCALE(x) ((x) << 6) +/** create encoding for a SIB byte */ +#define ENC_SIB(scale, index, base) ((scale) << 6 | (index) << 3 | (base)) /* Node: The following routines are supposed to append bytes, words, dwords to the output stream. @@ -2358,7 +2356,8 @@ static void bemit_jmp_destination(const ir_node *dest_block) { be_emit_cstring("\t.long "); ia32_emit_block_name(dest_block); - be_emit_cstring(" - . - 4"); + be_emit_cstring(" - . - 4\n"); + be_emit_write_line(); } /* end emit routines, all emitters following here should only use the functions @@ -2416,53 +2415,6 @@ static unsigned get_signed_imm_size(int offset) } } -/** - * Emit a binop with a immediate operand. - * - * @param node the node to emit - * @param opcode_eax the opcode for the op eax, imm variant - * @param opcode the opcode for the reg, imm variant - * @param ruval the opcode extension for opcode - */ -static void bemit_binop_with_imm( - const ir_node *node, - unsigned char opcode_ax, - unsigned char opcode, unsigned char ruval) -{ - /* Use in-reg, because some instructions (cmp, test) have no out-reg. */ - const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left); - const ir_node *op = get_irn_n(node, n_ia32_binary_right); - const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(op); - unsigned size; - - if (attr->symconst != NULL) - size = 4; - else { - /* check for sign extension */ - size = get_signed_imm_size(attr->offset); - } - - switch (size) { - case 1: - bemit8(opcode | SIGNEXT_IMM); - bemit_modru(reg, ruval); - bemit8((unsigned char)attr->offset); - return; - case 2: - case 4: - /* check for eax variant: this variant is shorter for 32bit immediates only */ - if (reg->index == REG_EAX) { - bemit8(opcode_ax); - } else { - bemit8(opcode); - bemit_modru(reg, ruval); - } - bemit_entity(attr->symconst, attr->sc_sign, attr->offset, false); - return; - } - panic("invalid imm size?!?"); -} - /** * Emit an address mode. * @@ -2481,6 +2433,7 @@ static void bemit_mod_am(unsigned reg, const ir_node *node) unsigned sib = 0; unsigned emitoffs = 0; bool emitsib = false; + unsigned base_enc; /* set the mod part depending on displacement */ if (ent != NULL) { @@ -2497,53 +2450,41 @@ static void bemit_mod_am(unsigned reg, const ir_node *node) emitoffs = 32; } - /* determine if we need a SIB byte */ + if (has_base) { + const arch_register_t *base_reg = arch_get_irn_register(base); + base_enc = reg_gp_map[base_reg->index]; + } else { + /* Use the EBP encoding + MOD_IND if NO base register. There is + * always a 32bit offset present in this case. */ + modrm = MOD_IND; + base_enc = 0x05; + emitoffs = 32; + } + + /* Determine if we need a SIB byte. */ if (has_index) { - int scale; const arch_register_t *reg_index = arch_get_irn_register(index); - assert(reg_index->index != REG_ESP); - sib |= ENC_INDEX(reg_gp_map[reg_index->index]); - - if (has_base) { - const arch_register_t *base_reg = arch_get_irn_register(base); - sib |= ENC_BASE(reg_gp_map[base_reg->index]); - } else { - /* use the EBP encoding if NO base register */ - sib |= 0x05; - } - - scale = get_ia32_am_scale(node); + int scale = get_ia32_am_scale(node); assert(scale < 4); - sib |= ENC_SCALE(scale); + /* R/M set to ESP means SIB in 32bit mode. */ + modrm |= ENC_RM(0x04); + sib = ENC_SIB(scale, reg_gp_map[reg_index->index], base_enc); emitsib = true; - } - - /* determine modrm byte */ - if (emitsib) { - /* R/M set to ESP means SIB in 32bit mode */ - modrm |= ENC_RM(0x04); - } else if (has_base) { - const arch_register_t *base_reg = arch_get_irn_register(base); - if (base_reg->index == REG_ESP) { - /* for the above reason we are forced to emit a sib when base is - * ESP. Only the base is used, index must be ESP too, which means no - * index. */ - sib = ENC_BASE(0x04) | ENC_INDEX(0x04); - emitsib = true; - - /* we are forced to emit a 8bit offset as EBP base without - offset is a special case for SIB without base register */ - } else if (base_reg->index == REG_EBP && emitoffs == 0) { - assert(GET_MODE(modrm) == MOD_IND); - emitoffs = 8; + } else if (base_enc == 0x04) { + /* for the above reason we are forced to emit a SIB when base is ESP. + * Only the base is used, index must be ESP too, which means no index. + */ + modrm |= ENC_RM(0x04); + sib = ENC_SIB(0, 0x04, 0x04); + emitsib = true; + } else { + modrm |= ENC_RM(base_enc); + /* We are forced to emit an 8bit offset as EBP base without offset is a + * special case for SIB without base register. */ + if (base_enc == 0x05 && emitoffs == 0) { modrm |= MOD_IND_BYTE_OFS; + emitoffs = 8; } - - modrm |= ENC_RM(reg_gp_map[base_reg->index]); - } else { - /* only displacement: Use EBP + disp encoding in 32bit mode */ - emitoffs = 32; - modrm = ENC_RM(0x05); } modrm |= ENC_REG(reg); @@ -2560,6 +2501,66 @@ static void bemit_mod_am(unsigned reg, const ir_node *node) } } +/** + * Emit a binop with a immediate operand. + * + * @param node the node to emit + * @param opcode_eax the opcode for the op eax, imm variant + * @param opcode the opcode for the reg, imm variant + * @param ruval the opcode extension for opcode + */ +static void bemit_binop_with_imm( + const ir_node *node, + unsigned char opcode_ax, + unsigned char opcode, unsigned char ruval) +{ + /* Use in-reg, because some instructions (cmp, test) have no out-reg. */ + const ir_node *op = get_irn_n(node, n_ia32_binary_right); + const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(op); + unsigned size; + + /* Some instructions (test) have no short form with 32bit value + 8bit + * immediate. */ + if (attr->symconst != NULL || opcode & SIGNEXT_IMM) { + size = 4; + } else { + /* check for sign extension */ + size = get_signed_imm_size(attr->offset); + } + + switch (size) { + case 1: + bemit8(opcode | SIGNEXT_IMM); + /* cmp has this special mode */ + if (get_ia32_op_type(node) == ia32_AddrModeS) { + bemit_mod_am(ruval, node); + } else { + const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left); + bemit_modru(reg, ruval); + } + bemit8((unsigned char)attr->offset); + return; + case 2: + case 4: + /* check for eax variant: this variant is shorter for 32bit immediates only */ + if (get_ia32_op_type(node) == ia32_AddrModeS) { + bemit8(opcode); + bemit_mod_am(ruval, node); + } else { + const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left); + if (reg->index == REG_EAX) { + bemit8(opcode_ax); + } else { + bemit8(opcode); + bemit_modru(reg, ruval); + } + } + bemit_entity(attr->symconst, attr->sc_sign, attr->offset, false); + return; + } + panic("invalid imm size?!?"); +} + /** * Emits a binop. */ @@ -2627,9 +2628,8 @@ static void bemit_immediate(const ir_node *node, bool relative) static void bemit_copy(const ir_node *copy) { - const ir_node *op = be_get_Copy_op(copy); - const arch_register_t *in = arch_get_irn_register(op); - const arch_register_t *out = arch_get_irn_register(copy); + const arch_register_t *in = get_in_reg(copy, 0); + const arch_register_t *out = get_out_reg(copy, 0); if (in == out || is_unknown_reg(in)) return; @@ -2669,15 +2669,16 @@ static void bemit_ ## op(const ir_node *node) { \ bemit_binop(node, op ## _codes); \ } -/* insn def eax,imm imm */ -BINOP(add, 0x01, 0x05, 0x81, 0 ) -BINOP(or, 0x09, 0x0D, 0x81, 1 ) -BINOP(adc, 0x11, 0x15, 0x81, 2 ) -BINOP(sbb, 0x19, 0x1D, 0x81, 3 ) -BINOP(and, 0x21, 0x25, 0x81, 4 ) -BINOP(sub, 0x29, 0x2D, 0x81, 5 ) -BINOP(xor, 0x31, 0x35, 0x81, 6 ) -BINOP(cmp, 0x39, 0x3D, 0x81, 7 ) +/* insn def eax,imm imm */ +BINOP(add, 0x01, 0x05, 0x81, 0) +BINOP(or, 0x09, 0x0D, 0x81, 1) +BINOP(adc, 0x11, 0x15, 0x81, 2) +BINOP(sbb, 0x19, 0x1D, 0x81, 3) +BINOP(and, 0x21, 0x25, 0x81, 4) +BINOP(sub, 0x29, 0x2D, 0x81, 5) +BINOP(xor, 0x31, 0x35, 0x81, 6) +BINOP(cmp, 0x39, 0x3D, 0x81, 7) +BINOP(test, 0x85, 0xA9, 0xF7, 0) /** * Creates a function for an Unop with code /ext encoding. @@ -2687,14 +2688,15 @@ static void bemit_ ## op(const ir_node *node) { \ bemit_unop(node, code, ext, input); \ } -UNOP(not, 0xF7, 2, n_ia32_unary_op) -UNOP(neg, 0xF7, 3, n_ia32_unary_op) -UNOP(mul, 0xF7, 4, n_ia32_binary_right) -UNOP(imul1op, 0xF7, 5, n_ia32_binary_right) -UNOP(div, 0xF7, 6, n_ia32_unary_op) -UNOP(idiv, 0xF7, 7, n_ia32_unary_op) +UNOP(not, 0xF7, 2, n_ia32_Not_val) +UNOP(neg, 0xF7, 3, n_ia32_Neg_val) +UNOP(mul, 0xF7, 4, n_ia32_Mul_right) +UNOP(imul1op, 0xF7, 5, n_ia32_IMul1OP_right) +UNOP(div, 0xF7, 6, n_ia32_Div_divisor) +UNOP(idiv, 0xF7, 7, n_ia32_IDiv_divisor) -UNOP(ijmp, 0xFF, 4, n_ia32_unary_op) +/* TODO: am support for IJmp */ +UNOP(ijmp, 0xFF, 4, n_ia32_IJmp_target) #define SHIFT(op, ext) \ static void bemit_##op(const ir_node *node) \ @@ -2862,9 +2864,12 @@ static void bemit_push(const ir_node *node) bemit_immediate(value, false); break; } - } else { + } else if (is_ia32_NoReg_GP(value)) { bemit8(0xFF); bemit_mod_am(6, node); + } else { + const arch_register_t *reg = get_in_reg(node, n_ia32_Push_val); + bemit8(0x50 + reg_gp_map[reg->index]); } } @@ -2874,12 +2879,13 @@ static void bemit_push(const ir_node *node) static void bemit_pop(const ir_node *node) { const arch_register_t *reg = get_out_reg(node, pn_ia32_Pop_res); - if (get_ia32_op_type(node) == ia32_Normal) - bemit8(0x58 + reg_gp_map[reg->index]); - else { - bemit8(0x8F); - bemit_mod_am(0, node); - } + bemit8(0x58 + reg_gp_map[reg->index]); +} + +static void bemit_popmem(const ir_node *node) +{ + bemit8(0x8F); + bemit_mod_am(0, node); } static void bemit_call(const ir_node *node) @@ -2926,6 +2932,7 @@ static void bemit_jcc(int pnc, const ir_node *dest_block) cc = pnc_map_signed[pnc & 0x07]; } } + assert(cc != 0xFF); bemit8(0x0F); bemit8(0x80 + cc); @@ -3084,6 +3091,7 @@ static void ia32_register_binary_emitters(void) /* benode emitter */ register_emitter(op_be_Copy, bemit_copy); + register_emitter(op_be_CopyKeep, bemit_copy); register_emitter(op_be_IncSP, bemit_incsp); register_emitter(op_be_Return, bemit_return); register_emitter(op_ia32_Adc, bemit_adc); @@ -3110,6 +3118,8 @@ static void ia32_register_binary_emitters(void) register_emitter(op_ia32_Not, bemit_not); register_emitter(op_ia32_Or, bemit_or); register_emitter(op_ia32_Pop, bemit_pop); + register_emitter(op_ia32_PopEbp, bemit_pop); + register_emitter(op_ia32_PopMem, bemit_popmem); register_emitter(op_ia32_Push, bemit_push); register_emitter(op_ia32_RepPrefix, bemit_rep); register_emitter(op_ia32_Rol, bemit_rol); @@ -3122,6 +3132,7 @@ static void ia32_register_binary_emitters(void) register_emitter(op_ia32_Stc, bemit_stc); register_emitter(op_ia32_Store, bemit_store); register_emitter(op_ia32_Sub, bemit_sub); + register_emitter(op_ia32_Test, bemit_test); register_emitter(op_ia32_Xor, bemit_xor); register_emitter(op_ia32_Xor0, bemit_xor0);