Implement binary emitter for DecMem, IncMem, NegMem and NotMem.
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 4f73191..d57473f 100644 (file)
@@ -2251,7 +2251,6 @@ static void build_reg_map(void)
        reg_gp_map[REG_ESI] = 0x6;
        reg_gp_map[REG_EDI] = 0x7;
 
-       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;
@@ -2259,7 +2258,6 @@ static void build_reg_map(void)
        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;
@@ -2268,7 +2266,19 @@ static void build_reg_map(void)
        pnc_map_unsigned[pn_Cmp_Lg]    = 0x05;
 }
 
-#define GET_MODE(code) ((code) & 0xC0)
+static unsigned char pnc2cc(int pnc)
+{
+       unsigned char cc;
+       if (pnc == ia32_pn_Cmp_parity) {
+               cc = 0x0A;
+       } else if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) {
+               cc = pnc_map_unsigned[pnc & 0x07];
+       } else {
+               cc = pnc_map_signed[pnc & 0x07];
+       }
+       assert(cc != 0);
+       return cc;
+}
 
 /** Sign extension bit values for binops */
 enum SignExt {
@@ -2622,6 +2632,12 @@ static void bemit_unop_reg(const ir_node *node, unsigned char code, int input)
        bemit_unop(node, code, reg_gp_map[out->index], input);
 }
 
+static void bemit_unop_mem(const ir_node *node, unsigned char code, unsigned char ext)
+{
+       bemit8(code);
+       bemit_mod_am(ext, node);
+}
+
 static void bemit_immediate(const ir_node *node, bool relative)
 {
        const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
@@ -2648,6 +2664,37 @@ static void bemit_copy(const ir_node *copy)
        }
 }
 
+static void bemit_perm(const ir_node *node)
+{
+       const arch_register_t       *in0  = arch_get_irn_register(get_irn_n(node, 0));
+       const arch_register_t       *in1  = arch_get_irn_register(get_irn_n(node, 1));
+       const arch_register_class_t *cls0 = arch_register_get_class(in0);
+
+       assert(cls0 == arch_register_get_class(in1) && "Register class mismatch at Perm");
+
+       if (cls0 == &ia32_reg_classes[CLASS_ia32_gp]) {
+               if (in0->index == REG_EAX) {
+                       bemit8(0x90 + reg_gp_map[in1->index]);
+               } else if (in1->index == REG_EAX) {
+                       bemit8(0x90 + reg_gp_map[in0->index]);
+               } else {
+                       bemit8(0x87);
+                       bemit_modrr(in0, in1);
+               }
+       } else if (cls0 == &ia32_reg_classes[CLASS_ia32_xmm]) {
+               panic("unimplemented"); // TODO implement
+               //ia32_emitf(NULL, "\txorpd %R, %R\n", in1, in0);
+               //ia32_emitf(NULL, "\txorpd %R, %R\n", in0, in1);
+               //ia32_emitf(node, "\txorpd %R, %R\n", in1, in0);
+       } else if (cls0 == &ia32_reg_classes[CLASS_ia32_vfp]) {
+               /* is a NOP */
+       } else if (cls0 == &ia32_reg_classes[CLASS_ia32_st]) {
+               /* is a NOP */
+       } else {
+               panic("unexpected register class in be_Perm (%+F)", node);
+       }
+}
+
 static void bemit_xor0(const ir_node *node)
 {
        const arch_register_t *out = get_out_reg(node, 0);
@@ -2758,6 +2805,32 @@ static void bemit_inc(const ir_node *node)
        bemit8(0x40 + reg_gp_map[out->index]);
 }
 
+#define UNOPMEM(op, code, ext) \
+static void bemit_##op(const ir_node *node) \
+{ \
+       bemit_unop_mem(node, code, ext); \
+}
+
+UNOPMEM(notmem, 0xF7, 2)
+UNOPMEM(negmem, 0xF7, 3)
+UNOPMEM(incmem, 0xFF, 0)
+UNOPMEM(decmem, 0xFF, 1)
+
+static void bemit_set(const ir_node *node)
+{
+       pn_Cmp pnc;
+
+       bemit8(0x0F);
+
+       pnc = get_ia32_condcode(node);
+       pnc = determine_final_pnc(node, n_ia32_Set_eflags, pnc);
+       if (get_ia32_attr_const(node)->data.ins_permuted)
+               pnc = ia32_get_negated_pnc(pnc);
+
+       bemit8(0x90 + pnc2cc(pnc));
+       bemit_modru(get_out_reg(node, pn_ia32_Set_res), 2);
+}
+
 /**
  * Emit a Lea.
  */
@@ -2769,7 +2842,7 @@ static void bemit_lea(const ir_node *node)
 }
 
 /**
- * Emit a single optcode.
+ * Emit a single opcode.
  */
 #define EMIT_SINGLEOP(op, code)                 \
 static void bemit_ ## op(const ir_node *node) { \
@@ -2953,19 +3026,7 @@ static void bemit_jump(const ir_node *node)
 
 static void bemit_jcc(int pnc, const ir_node *dest_block)
 {
-       unsigned char cc;
-
-       if (pnc == ia32_pn_Cmp_parity) {
-               cc = 0x0A;
-       } else {
-               if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) {
-                       cc = pnc_map_unsigned[pnc & 0x07];
-               } else {
-                       cc = pnc_map_signed[pnc & 0x07];
-               }
-       }
-       assert(cc != 0xFF);
-
+       unsigned char cc = pnc2cc(pnc);
        bemit8(0x0F);
        bemit8(0x80 + cc);
        bemit_jmp_destination(dest_block);
@@ -3125,6 +3186,7 @@ static void ia32_register_binary_emitters(void)
        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_Perm,           bemit_perm);
        register_emitter(op_be_Return,         bemit_return);
        register_emitter(op_ia32_Adc,          bemit_adc);
        register_emitter(op_ia32_Add,          bemit_add);
@@ -3135,23 +3197,27 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_Cmc,          bemit_cmc);
        register_emitter(op_ia32_Cmp,          bemit_cmp);
        register_emitter(op_ia32_Const,        bemit_mov_const);
-       register_emitter(op_ia32_Conv_I2I,     bemit_conv_i2i);
        register_emitter(op_ia32_Conv_I2I8Bit, bemit_conv_i2i);
+       register_emitter(op_ia32_Conv_I2I,     bemit_conv_i2i);
        register_emitter(op_ia32_Cwtl,         bemit_cwtl);
        register_emitter(op_ia32_Dec,          bemit_dec);
+       register_emitter(op_ia32_DecMem,       bemit_decmem);
        register_emitter(op_ia32_Div,          bemit_div);
        register_emitter(op_ia32_IDiv,         bemit_idiv);
        register_emitter(op_ia32_IJmp,         bemit_ijmp);
        register_emitter(op_ia32_IMul1OP,      bemit_imul1op);
        register_emitter(op_ia32_IMul,         bemit_imul);
        register_emitter(op_ia32_Inc,          bemit_inc);
+       register_emitter(op_ia32_IncMem,       bemit_incmem);
        register_emitter(op_ia32_Jcc,          bemit_ia32_jcc);
        register_emitter(op_ia32_Jmp,          bemit_jump);
        register_emitter(op_ia32_Lea,          bemit_lea);
        register_emitter(op_ia32_Load,         bemit_load);
        register_emitter(op_ia32_Mul,          bemit_mul);
        register_emitter(op_ia32_Neg,          bemit_neg);
+       register_emitter(op_ia32_NegMem,       bemit_negmem);
        register_emitter(op_ia32_Not,          bemit_not);
+       register_emitter(op_ia32_NotMem,       bemit_notmem);
        register_emitter(op_ia32_Or,           bemit_or);
        register_emitter(op_ia32_Pop,          bemit_pop);
        register_emitter(op_ia32_PopEbp,       bemit_pop);
@@ -3163,15 +3229,16 @@ static void ia32_register_binary_emitters(void)
        register_emitter(op_ia32_Sahf,         bemit_sahf);
        register_emitter(op_ia32_Sar,          bemit_sar);
        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_Shr,          bemit_shr);
        register_emitter(op_ia32_Stc,          bemit_stc);
-       register_emitter(op_ia32_Store,        bemit_store);
        register_emitter(op_ia32_Store8Bit,    bemit_store);
+       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);
+       register_emitter(op_ia32_Xor,          bemit_xor);
 
        /* ignore the following nodes */
        register_emitter(op_ia32_ProduceVal,   emit_Nothing);