change spiller and related interface to use ir_graph* instead of be_irg_t*
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 8d0399c..d8481b7 100644 (file)
  * @brief       This file implements the ia32 node emitter.
  * @author      Christian Wuerdig, Matthias Braun
  * @version     $Id$
+ *
+ * Summary table for x86 floatingpoint compares:
+ *   pnc_Eq  => !P && E
+ *   pnc_Lt  => !P && B
+ *   pnc_Le  => !P && BE
+ *   pnc_Gt  => A
+ *   pnc_Ge  => AE
+ *   pnc_Lg  => P || NE
+ *   pnc_Leg => NP  (ordered)
+ *   pnc_Uo  => P
+ *   pnc_Ue  => E
+ *   pnc_Ul  => B
+ *   pnc_Ule => BE
+ *   pnc_Ug  => P || A
+ *   pnc_Uge => P || AE
+ *   pnc_Ne  => NE
  */
 #include "config.h"
 
@@ -54,6 +70,7 @@
 #include "../be_dbgout.h"
 
 #include "ia32_emitter.h"
+#include "ia32_common_transform.h"
 #include "gen_ia32_emitter.h"
 #include "gen_ia32_regalloc_if.h"
 #include "ia32_nodes_attr.h"
@@ -64,8 +81,6 @@
 
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
-#define BLOCK_PREFIX ".L"
-
 #define SNPRINTF_BUF_LEN 128
 
 static const ia32_isa_t *isa;
@@ -143,20 +158,6 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int pos)
        if (reg == &ia32_gp_regs[REG_GP_NOREG])
                panic("trying to emit noreg for %+F input %d", irn, pos);
 
-       /* in case of unknown register: just return a valid register */
-       if (reg == &ia32_gp_regs[REG_GP_UKNWN]) {
-               const arch_register_req_t *req = arch_get_register_req(irn, pos);
-
-               if (arch_register_req_is(req, limited)) {
-                       /* in case of limited requirements: get the first allowed register */
-                       unsigned idx = rbitset_next(req->limited, 0, 1);
-                       reg = arch_register_for_index(req->cls, idx);
-               } else {
-                       /* otherwise get first register in class */
-                       reg = arch_register_for_index(req->cls, 0);
-               }
-       }
-
        return reg;
 }
 
@@ -201,7 +202,7 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos)
 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
 {
        static unsigned long id = 0;
-       snprintf(buf, buflen, "%s%lu", prefix, ++id);
+       snprintf(buf, buflen, "%s%s%lu", be_gas_get_private_prefix(), prefix, ++id);
        return buf;
 }
 
@@ -420,13 +421,16 @@ void ia32_emit_x87_mode_suffix(const ir_node *node)
 
        if (mode_is_float(mode)) {
                switch (get_mode_size_bits(mode)) {
-                       case 32: be_emit_char('s'); return;
-                       case 64: be_emit_char('l'); return;
-                       case 80:
-                       case 96: be_emit_char('t'); return;
+                       case  32: be_emit_char('s'); return;
+                       case  64: be_emit_char('l'); return;
+                       /* long doubles have different sizes due to alignment on different
+                        * platforms. */
+                       case  80:
+                       case  96:
+                       case 128: be_emit_char('t'); return;
                }
        } else {
-               assert(mode_is_int(mode));
+               assert(mode_is_int(mode) || mode_is_reference(mode));
                switch (get_mode_size_bits(mode)) {
                        case 16: be_emit_char('s');     return;
                        case 32: be_emit_char('l');     return;
@@ -441,7 +445,7 @@ void ia32_emit_x87_mode_suffix(const ir_node *node)
 static char get_xmm_mode_suffix(ir_mode *mode)
 {
        assert(mode_is_float(mode));
-       switch(get_mode_size_bits(mode)) {
+       switch (get_mode_size_bits(mode)) {
        case 32: return 's';
        case 64: return 'd';
        default: panic("Invalid XMM mode");
@@ -493,27 +497,13 @@ static ir_node *get_cfop_target_block(const ir_node *irn)
        return get_irn_link(irn);
 }
 
-/**
- * Emits a block label for the given block.
- */
-static void ia32_emit_block_name(const ir_node *block)
-{
-       if (has_Block_entity(block)) {
-               ir_entity *entity = get_Block_entity(block);
-               be_gas_emit_entity(entity);
-       } else {
-               be_emit_cstring(BLOCK_PREFIX);
-               be_emit_irprintf("%ld", get_irn_node_nr(block));
-       }
-}
-
 /**
  * Emits the target label for a control flow node.
  */
 static void ia32_emit_cfop_target(const ir_node *node)
 {
        ir_node *block = get_cfop_target_block(node);
-       ia32_emit_block_name(block);
+       be_gas_emit_block_name(block);
 }
 
 /*
@@ -682,8 +672,8 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
                        break;
 
                ++fmt;
-               while (1) {
-                       switch(*fmt) {
+               for (;;) {
+                       switch (*fmt) {
                        case '*': mod |= EMIT_ALTERNATE_AM; break;
                        case '#': mod |= EMIT_RESPECT_LS;   break;
                        case 'l': mod |= EMIT_LONG;         break;
@@ -860,7 +850,7 @@ void ia32_emit_binop(const ir_node *node)
  */
 void ia32_emit_x87_binop(const ir_node *node)
 {
-       switch(get_ia32_op_type(node)) {
+       switch (get_ia32_op_type(node)) {
                case ia32_Normal:
                        {
                                const ia32_x87_attr_t *x87_attr = get_ia32_x87_attr_const(node);
@@ -1002,16 +992,10 @@ static pn_Cmp ia32_get_negated_pnc(pn_Cmp pnc)
        return get_negated_pnc(pnc, mode);
 }
 
-void ia32_emit_cmp_suffix_node(const ir_node *node,
-                               int flags_pos)
+void ia32_emit_cmp_suffix_node(const ir_node *node, int flags_pos)
 {
-       const ia32_attr_t *attr = get_ia32_attr_const(node);
-
        pn_Cmp pnc = get_ia32_condcode(node);
-
        pnc = determine_final_pnc(node, flags_pos, pnc);
-       if (attr->data.ins_permuted)
-               pnc = ia32_get_negated_pnc(pnc);
 
        ia32_emit_cmp_suffix(pnc);
 }
@@ -1063,7 +1047,6 @@ static void emit_ia32_Jcc(const ir_node *node)
        int            need_parity_label = 0;
        const ir_node *proj_true;
        const ir_node *proj_false;
-       const ir_node *block;
        pn_Cmp         pnc = get_ia32_condcode(node);
 
        pnc = determine_final_pnc(node, 0, pnc);
@@ -1075,8 +1058,6 @@ static void emit_ia32_Jcc(const ir_node *node)
        proj_false = get_proj(node, pn_ia32_Jcc_false);
        assert(proj_false && "Jcc without false Proj");
 
-       block      = get_nodes_block(node);
-
        if (can_be_fallthrough(proj_true)) {
                /* exchange both proj's so the second one can be omitted */
                const ir_node *t = proj_true;
@@ -1191,7 +1172,9 @@ static void emit_ia32_CMovcc(const ir_node *node)
 
        pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc);
        /* although you can't set ins_permuted in the constructor it might still
-          be set by memory operand folding */
+        * be set by memory operand folding
+        * Permuting inputs of a cmov means the condition is negated!
+        */
        if (attr->data.ins_permuted)
                pnc = ia32_get_negated_pnc(pnc);
 
@@ -1284,7 +1267,7 @@ static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node)
        const ir_edge_t    *edge;
 
        /* fill the table structure */
-       get_unique_label(tbl->label, SNPRINTF_BUF_LEN, ".TBL_");
+       get_unique_label(tbl->label, SNPRINTF_BUF_LEN, "TBL_");
        tbl->defProj      = NULL;
        tbl->num_branches = get_irn_n_edges(node) - 1;
        tbl->branches     = XMALLOCNZ(branch_t, tbl->num_branches);
@@ -1412,7 +1395,7 @@ static const char* emit_asm_operand(const ir_node *node, const char *s)
        c = *(++s);
 
        /* parse modifiers */
-       switch(c) {
+       switch (c) {
        case 0:
                ir_fprintf(stderr, "Warning: asm text (%+F) ends with %%\n", node);
                be_emit_char('%');
@@ -1491,7 +1474,7 @@ static const char* emit_asm_operand(const ir_node *node, const char *s)
        /* emit it */
        if (modifier != 0) {
                be_emit_char('%');
-               switch(modifier) {
+               switch (modifier) {
                case 'b':
                        reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
                        break;
@@ -1532,7 +1515,7 @@ static void emit_ia32_Asm(const ir_node *node)
        if (s[0] != '\t')
                be_emit_char('\t');
 
-       while(*s != 0) {
+       while (*s != 0) {
                if (*s == '%') {
                        s = emit_asm_operand(node, s);
                } else {
@@ -1684,16 +1667,6 @@ static void emit_be_IncSP(const ir_node *node)
        }
 }
 
-static inline bool is_unknown_reg(const arch_register_t *reg)
-{
-       if(reg == &ia32_gp_regs[REG_GP_UKNWN]
-                       || reg == &ia32_xmm_regs[REG_XMM_UKNWN]
-                       || reg == &ia32_vfp_regs[REG_VFP_UKNWN])
-               return true;
-
-       return false;
-}
-
 /**
  * Emits code for Copy/CopyKeep.
  */
@@ -1705,8 +1678,6 @@ static void Copy_emitter(const ir_node *node, const ir_node *op)
        if (in == out) {
                return;
        }
-       if (is_unknown_reg(in))
-               return;
        /* copies of vf nodes aren't real... */
        if (arch_register_get_class(in) == &ia32_reg_classes[CLASS_ia32_vfp])
                return;
@@ -1878,10 +1849,14 @@ static void emit_ia32_ClimbFrame(const ir_node *node)
 
        ia32_emitf(node, "\tmovl %S0, %D0\n");
        ia32_emitf(node, "\tmovl $%u, %S1\n", attr->count);
-       ia32_emitf(NULL, BLOCK_PREFIX "%ld:\n", get_irn_node_nr(node));
+       be_gas_emit_block_name(node);
+       be_emit_cstring(":\n");
+       be_emit_write_line();
        ia32_emitf(node, "\tmovl (%D0), %D0\n");
        ia32_emitf(node, "\tdec %S1\n");
-       ia32_emitf(node, "\tjnz " BLOCK_PREFIX "%ld\n", get_irn_node_nr(node));
+       be_emit_cstring("\tjnz ");
+       be_gas_emit_block_name(node);
+       be_emit_finish_line_gas(node);
 }
 
 static void emit_be_Return(const ir_node *node)
@@ -2075,7 +2050,7 @@ static int should_align_block(const ir_node *block)
                return 0;
 
        n_cfgpreds = get_Block_n_cfgpreds(block);
-       for(i = 0; i < n_cfgpreds; ++i) {
+       for (i = 0; i < n_cfgpreds; ++i) {
                const ir_node *pred      = get_Block_cfgpred_block(block, i);
                double         pred_freq = get_block_execfreq(exec_freq, pred);
 
@@ -2137,14 +2112,14 @@ static void ia32_emit_block_header(ir_node *block)
        }
 
        if (need_label) {
-               ia32_emit_block_name(block);
+               be_gas_emit_block_name(block);
                be_emit_char(':');
 
                be_emit_pad_comment();
                be_emit_cstring("   /* ");
        } else {
                be_emit_cstring("\t/* ");
-               ia32_emit_block_name(block);
+               be_gas_emit_block_name(block);
                be_emit_cstring(": ");
        }
 
@@ -2247,7 +2222,7 @@ void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
 
        ia32_register_emitters();
 
-       get_unique_label(pic_base_label, sizeof(pic_base_label), ".PIC_BASE");
+       get_unique_label(pic_base_label, sizeof(pic_base_label), "PIC_BASE");
 
        be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi));
        be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment);
@@ -2289,7 +2264,7 @@ void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
                        ia32_emit_exc_label(exc_list[i].exc_instr);
                        be_emit_char('\n');
                        be_emit_cstring("\t.long ");
-                       ia32_emit_block_name(exc_list[i].block);
+                       be_gas_emit_block_name(exc_list[i].block);
                        be_emit_char('\n');
                }
        }
@@ -2439,7 +2414,7 @@ static void bemit_entity(ir_entity *entity, bool entity_sign, int offset,
 static void bemit_jmp_destination(const ir_node *dest_block)
 {
        be_emit_cstring("\t.long ");
-       ia32_emit_block_name(dest_block);
+       be_gas_emit_block_name(dest_block);
        be_emit_cstring(" - . - 4\n");
        be_emit_write_line();
 }
@@ -2723,7 +2698,7 @@ static void bemit_copy(const ir_node *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))
+       if (in == out)
                return;
        /* copies of vf nodes aren't real... */
        if (arch_register_get_class(in) == &ia32_reg_classes[CLASS_ia32_vfp])