Implement binary emitter for Leave.
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 9fd9439..757c039 100644 (file)
@@ -2634,8 +2634,8 @@ static void bemit_copy(const ir_node *copy)
                panic("NIY");
        } else {
                assert(arch_register_get_class(in) == &ia32_reg_classes[CLASS_ia32_gp]);
-               bemit8(0x89);
-               bemit_modrr(out, in);
+               bemit8(0x8B);
+               bemit_modrr(in, out);
        }
 }
 
@@ -2701,7 +2701,6 @@ BINOP(sbb,  0x1B, 0x1D, 0x81, 3)
 BINOP(and,  0x23, 0x25, 0x81, 4)
 BINOP(sub,  0x2B, 0x2D, 0x81, 5)
 BINOP(xor,  0x33, 0x35, 0x81, 6)
-BINOP(cmp,  0x3B, 0x3D, 0x81, 7)
 BINOP(test, 0x85, 0xA9, 0xF7, 0)
 
 #define BINOPMEM(op, ext) \
@@ -2820,6 +2819,148 @@ SHIFT(shl, 4)
 SHIFT(shr, 5)
 SHIFT(sar, 7)
 
+static void bemit_shld(const ir_node *node)
+{
+       const arch_register_t *in  = get_in_reg(node, n_ia32_ShlD_val_low);
+       const arch_register_t *out = get_out_reg(node, pn_ia32_ShlD_res);
+       ir_node *count = get_irn_n(node, n_ia32_ShlD_count);
+       bemit8(0x0F);
+       if (is_ia32_Immediate(count)) {
+               bemit8(0xA4);
+               bemit_modrr(out, in);
+               bemit8(get_ia32_immediate_attr_const(count)->offset);
+       } else {
+               bemit8(0xA5);
+               bemit_modrr(out, in);
+       }
+}
+
+static void bemit_shrd(const ir_node *node)
+{
+       const arch_register_t *in  = get_in_reg(node, n_ia32_ShrD_val_low);
+       const arch_register_t *out = get_out_reg(node, pn_ia32_ShrD_res);
+       ir_node *count = get_irn_n(node, n_ia32_ShrD_count);
+       bemit8(0x0F);
+       if (is_ia32_Immediate(count)) {
+               bemit8(0xAC);
+               bemit_modrr(out, in);
+               bemit8(get_ia32_immediate_attr_const(count)->offset);
+       } else {
+               bemit8(0xAD);
+               bemit_modrr(out, in);
+       }
+}
+
+static void bemit_cmov(const ir_node *node)
+{
+       const ia32_attr_t     *attr         = get_ia32_attr_const(node);
+       int                    ins_permuted = attr->data.ins_permuted;
+       const arch_register_t *out          = arch_irn_get_register(node, pn_ia32_res);
+       pn_Cmp                 pnc          = get_ia32_condcode(node);
+       const arch_register_t *in_true;
+       const arch_register_t *in_false;
+
+       pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);
+
+       in_true  = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_true));
+       in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_false));
+
+       /* should be same constraint fullfilled? */
+       if (out == in_false) {
+               /* yes -> nothing to do */
+       } else if (out == in_true) {
+               assert(get_ia32_op_type(node) == ia32_Normal);
+               ins_permuted = !ins_permuted;
+               in_true      = in_false;
+       } else {
+               /* we need a mov */
+               bemit8(0x8B); // mov %in_false, %out
+               bemit_modrr(in_false, out);
+       }
+
+       if (ins_permuted)
+               pnc = ia32_get_negated_pnc(pnc);
+
+       /* TODO: handling of Nans isn't correct yet */
+
+       bemit8(0x0F);
+       bemit8(0x40 + pnc2cc(pnc));
+       if (get_ia32_op_type(node) == ia32_Normal) {
+               bemit_modrr(in_true, out);
+       } else {
+               bemit_mod_am(reg_gp_map[out->index], node);
+       }
+}
+
+static void bemit_cmp(const ir_node *node)
+{
+       unsigned  ls_size = get_mode_size_bits(get_ia32_ls_mode(node));
+       ir_node  *right;
+
+       if (ls_size == 16)
+               bemit8(0x66);
+
+       right = get_irn_n(node, n_ia32_binary_right);
+       if (is_ia32_Immediate(right)) {
+               /* 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;
+
+               if (attr->symconst != NULL) {
+                       size = 4;
+               } else {
+                       /* check for sign extension */
+                       size = get_signed_imm_size(attr->offset);
+               }
+
+               switch (size) {
+                       case 1:
+                               bemit8(0x81 | SIGNEXT_IMM);
+                               /* cmp has this special mode */
+                               if (get_ia32_op_type(node) == ia32_AddrModeS) {
+                                       bemit_mod_am(7, node);
+                               } else {
+                                       const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left);
+                                       bemit_modru(reg, 7);
+                               }
+                               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(0x81);
+                                       bemit_mod_am(7, node);
+                               } else {
+                                       const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left);
+                                       if (reg->index == REG_EAX) {
+                                               bemit8(0x3D);
+                                       } else {
+                                               bemit8(0x81);
+                                               bemit_modru(reg, 7);
+                                       }
+                               }
+                               if (ls_size == 16) {
+                                       bemit16(attr->offset);
+                               } else {
+                                       bemit_entity(attr->symconst, attr->sc_sign, attr->offset, false);
+                               }
+                               return;
+               }
+               panic("invalid imm size?!?");
+       } else {
+               const arch_register_t *out = get_in_reg(node, n_ia32_binary_left);
+               bemit8(0x3B);
+               if (get_ia32_op_type(node) == ia32_Normal) {
+                       const arch_register_t *op2 = get_in_reg(node, n_ia32_binary_right);
+                       bemit_modrr(op2, out);
+               } else {
+                       bemit_mod_am(reg_gp_map[out->index], node);
+               }
+       }
+}
+
 static void bemit_cmp8bit(const ir_node *node)
 {
        ir_node *right = get_irn_n(node, n_ia32_binary_right);
@@ -2849,6 +2990,35 @@ static void bemit_cmp8bit(const ir_node *node)
        }
 }
 
+static void bemit_test8bit(const ir_node *node)
+{
+       ir_node *right = get_irn_n(node, n_ia32_Test8Bit_right);
+       if (is_ia32_Immediate(right)) {
+               if (get_ia32_op_type(node) == ia32_Normal) {
+                       const arch_register_t *out = get_in_reg(node, n_ia32_Test8Bit_left);
+                       if (out->index == REG_EAX) {
+                               bemit8(0xA8);
+                       } else {
+                               bemit8(0xF6);
+                               bemit_modru(out, 0);
+                       }
+               } else {
+                       bemit8(0xF6);
+                       bemit_mod_am(0, node);
+               }
+               bemit8(get_ia32_immediate_attr_const(right)->offset);
+       } else {
+               bemit8(0x84);
+               const arch_register_t *out = get_in_reg(node, n_ia32_Test8Bit_left);
+               if (get_ia32_op_type(node) == ia32_Normal) {
+                       const arch_register_t *in = get_in_reg(node, n_ia32_Test8Bit_right);
+                       bemit_modrr(out, in);
+               } else {
+                       bemit_mod_am(reg_gp_map[out->index], node);
+               }
+       }
+}
+
 static void bemit_imul(const ir_node *node)
 {
        ir_node *right = get_irn_n(node, n_ia32_IMul_right);
@@ -2944,19 +3114,20 @@ static void bemit_ ## op(const ir_node *node) { \
 //EMIT_SINGLEOP(aaa,  0x37)
 //EMIT_SINGLEOP(aas,  0x3F)
 //EMIT_SINGLEOP(nop,  0x90)
-EMIT_SINGLEOP(cwtl, 0x98)
-EMIT_SINGLEOP(cltd, 0x99)
+EMIT_SINGLEOP(cwtl,  0x98)
+EMIT_SINGLEOP(cltd,  0x99)
 //EMIT_SINGLEOP(fwait, 0x9B)
-EMIT_SINGLEOP(sahf, 0x9E)
+EMIT_SINGLEOP(sahf,  0x9E)
 //EMIT_SINGLEOP(popf, 0x9D)
-EMIT_SINGLEOP(int3, 0xCC)
+EMIT_SINGLEOP(leave, 0xC9)
+EMIT_SINGLEOP(int3,  0xCC)
 //EMIT_SINGLEOP(iret, 0xCF)
 //EMIT_SINGLEOP(xlat, 0xD7)
 //EMIT_SINGLEOP(lock, 0xF0)
-EMIT_SINGLEOP(rep,  0xF3)
+EMIT_SINGLEOP(rep,   0xF3)
 //EMIT_SINGLEOP(halt, 0xF4)
-EMIT_SINGLEOP(cmc,  0xF5)
-EMIT_SINGLEOP(stc,  0xF9)
+EMIT_SINGLEOP(cmc,   0xF5)
+EMIT_SINGLEOP(stc,   0xF9)
 //EMIT_SINGLEOP(cli,  0xFA)
 //EMIT_SINGLEOP(sti,  0xFB)
 //EMIT_SINGLEOP(std,  0xFD)
@@ -3600,10 +3771,22 @@ static void bemit_ftstfnstsw(const ir_node *node)
        bemit_fnstsw();
 }
 
-static void bemit_fucomfnstsw(const ir_node *node)
+static void bemit_fucomi(const ir_node *node)
 {
-       (void)node;
+       const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
+       bemit8(0xDB); // fucomi
+       bemit8(0xE8 + attr->x87[1]->index);
+}
+
+static void bemit_fucomip(const ir_node *node)
+{
+       const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
+       bemit8(0xDF); // fucomip
+       bemit8(0xE8 + attr->x87[1]->index);
+}
 
+static void bemit_fucomfnstsw(const ir_node *node)
+{
        const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
        bemit8(0xDD); // fucom
        bemit8(0xE0 + attr->x87[1]->index);
@@ -3612,8 +3795,6 @@ static void bemit_fucomfnstsw(const ir_node *node)
 
 static void bemit_fucompfnstsw(const ir_node *node)
 {
-       (void)node;
-
        const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
        bemit8(0xDD); // fucomp
        bemit8(0xE8 + attr->x87[1]->index);
@@ -3668,6 +3849,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_AndMem,        bemit_andmem);
        register_emitter(op_ia32_AndMem8Bit,    bemit_andmem8bit);
        register_emitter(op_ia32_Breakpoint,    bemit_int3);
+       register_emitter(op_ia32_CMov,          bemit_cmov);
        register_emitter(op_ia32_Call,          bemit_call);
        register_emitter(op_ia32_Cltd,          bemit_cltd);
        register_emitter(op_ia32_Cmc,           bemit_cmc);
@@ -3685,7 +3867,9 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_FnstCW,        bemit_fnstcw);
        register_emitter(op_ia32_FtstFnstsw,    bemit_ftstfnstsw);
        register_emitter(op_ia32_FucomFnstsw,   bemit_fucomfnstsw);
+       register_emitter(op_ia32_Fucomi,        bemit_fucomi);
        register_emitter(op_ia32_FucompFnstsw,  bemit_fucompfnstsw);
+       register_emitter(op_ia32_Fucompi,       bemit_fucomip);
        register_emitter(op_ia32_FucomppFnstsw, bemit_fucomppfnstsw);
        register_emitter(op_ia32_IDiv,          bemit_idiv);
        register_emitter(op_ia32_IJmp,          bemit_ijmp);
@@ -3697,6 +3881,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_Jmp,           bemit_jump);
        register_emitter(op_ia32_LdTls,         bemit_ldtls);
        register_emitter(op_ia32_Lea,           bemit_lea);
+       register_emitter(op_ia32_Leave,         bemit_leave);
        register_emitter(op_ia32_Load,          bemit_load);
        register_emitter(op_ia32_Mul,           bemit_mul);
        register_emitter(op_ia32_Neg,           bemit_neg);
@@ -3721,8 +3906,10 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_Sbb,           bemit_sbb);
        register_emitter(op_ia32_Set,           bemit_set);
        register_emitter(op_ia32_Shl,           bemit_shl);
+       register_emitter(op_ia32_ShlD,          bemit_shld);
        register_emitter(op_ia32_ShlMem,        bemit_shlmem);
        register_emitter(op_ia32_Shr,           bemit_shr);
+       register_emitter(op_ia32_ShrD,          bemit_shrd);
        register_emitter(op_ia32_ShrMem,        bemit_shrmem);
        register_emitter(op_ia32_Stc,           bemit_stc);
        register_emitter(op_ia32_Store,         bemit_store);
@@ -3732,6 +3919,7 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_SubMem8Bit,    bemit_submem8bit);
        register_emitter(op_ia32_SubSP,         bemit_subsp);
        register_emitter(op_ia32_Test,          bemit_test);
+       register_emitter(op_ia32_Test8Bit,      bemit_test8bit);
        register_emitter(op_ia32_Xor,           bemit_xor);
        register_emitter(op_ia32_Xor0,          bemit_xor0);
        register_emitter(op_ia32_XorMem,        bemit_xormem);