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)
/** 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.
{
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
}
}
-/**
- * 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.
*
unsigned sib = 0;
unsigned emitoffs = 0;
bool emitsib = false;
+ unsigned base_enc;
/* set the mod part depending on displacement */
if (ent != NULL) {
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);
}
}
+/**
+ * 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.
*/
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;
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.
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) \
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]);
}
}
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)
cc = pnc_map_signed[pnc & 0x07];
}
}
+ assert(cc != 0xFF);
bemit8(0x0F);
bemit8(0x80 + cc);
/* 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);
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);
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);