fix a bug in constraint enforcement; improve phi handling and phi0 construction ...
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 2008d3a..feb7200 100644 (file)
 #include "irargs_t.h"
 #include "irprog_t.h"
 #include "iredges_t.h"
+#include "irtools.h"
 #include "execfreq.h"
 #include "error.h"
 #include "raw_bitset.h"
 #include "dbginfo.h"
+#include "lc_opts.h"
 
-#include "../besched_t.h"
+#include "../besched.h"
 #include "../benode_t.h"
 #include "../beabi.h"
 #include "../be_dbgout.h"
 #include "../beemitter.h"
 #include "../begnuas.h"
-#include "../beirg_t.h"
+#include "../beirg.h"
 #include "../be_dbgout.h"
 
 #include "ia32_emitter.h"
@@ -68,10 +70,10 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
 static const ia32_isa_t *isa;
 static ia32_code_gen_t  *cg;
-static int               do_pic;
 static char              pic_base_label[128];
 static ir_label_t        exc_label_id;
 static int               mark_spill_reload = 0;
+static int               do_pic;
 
 /** Return the next block in Block schedule */
 static ir_node *get_prev_block_sched(const ir_node *block)
@@ -102,6 +104,9 @@ static int block_needs_label(const ir_node *block)
        int need_label = 1;
        int  n_cfgpreds = get_Block_n_cfgpreds(block);
 
+       if (has_Block_entity(block))
+               return 1;
+
        if (n_cfgpreds == 0) {
                need_label = 0;
        } else if (n_cfgpreds == 1) {
@@ -211,6 +216,9 @@ static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
  * |_|                                       |_|
  *************************************************************/
 
+/**
+ * Emit the name of the 8bit low register
+ */
 static void emit_8bit_register(const arch_register_t *reg)
 {
        const char *reg_name = arch_register_get_name(reg);
@@ -220,6 +228,18 @@ static void emit_8bit_register(const arch_register_t *reg)
        be_emit_char('l');
 }
 
+/**
+ * Emit the name of the 8bit high register
+ */
+static void emit_8bit_register_high(const arch_register_t *reg)
+{
+       const char *reg_name = arch_register_get_name(reg);
+
+       be_emit_char('%');
+       be_emit_char(reg_name[1]);
+       be_emit_char('h');
+}
+
 static void emit_16bit_register(const arch_register_t *reg)
 {
        const char *reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
@@ -228,6 +248,12 @@ static void emit_16bit_register(const arch_register_t *reg)
        be_emit_string(reg_name);
 }
 
+/**
+ * emit a register, possible shortened by a mode
+ *
+ * @param reg   the register
+ * @param mode  the mode of the register or NULL for full register
+ */
 static void emit_register(const arch_register_t *reg, const ir_mode *mode)
 {
        const char *reg_name;
@@ -256,11 +282,8 @@ void ia32_emit_source_register(const ir_node *node, int pos)
 
 static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
 {
-       ident *id;
-
        set_entity_backend_marked(entity, 1);
-       id = get_entity_ld_ident(entity);
-       be_emit_ident(id);
+       be_gas_emit_entity(entity);
 
        if (get_entity_owner(entity) == get_tls_type()) {
                if (get_entity_visibility(entity) == visibility_external_allocated) {
@@ -270,8 +293,7 @@ static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
                }
        }
 
-       if (!no_pic_adjust && do_pic) {
-               /* TODO: only do this when necessary */
+       if (do_pic && !no_pic_adjust) {
                be_emit_char('-');
                be_emit_string(pic_base_label);
        }
@@ -284,7 +306,7 @@ static void emit_ia32_Immediate_no_prefix(const ir_node *node)
        if (attr->symconst != NULL) {
                if (attr->sc_sign)
                        be_emit_char('-');
-               ia32_emit_entity(attr->symconst, 0);
+               ia32_emit_entity(attr->symconst, attr->no_pic_adjust);
        }
        if (attr->symconst == NULL || attr->offset != 0) {
                if (attr->symconst != NULL) {
@@ -304,7 +326,7 @@ static void emit_ia32_Immediate(const ir_node *node)
 void ia32_emit_8bit_source_register_or_immediate(const ir_node *node, int pos)
 {
        const arch_register_t *reg;
-       ir_node               *in = get_irn_n(node, pos);
+       const ir_node         *in = get_irn_n(node, pos);
        if (is_ia32_Immediate(in)) {
                emit_ia32_Immediate(in);
                return;
@@ -314,6 +336,25 @@ void ia32_emit_8bit_source_register_or_immediate(const ir_node *node, int pos)
        emit_8bit_register(reg);
 }
 
+void ia32_emit_8bit_high_source_register(const ir_node *node, int pos)
+{
+       const arch_register_t *reg = get_in_reg(node, pos);
+       emit_8bit_register_high(reg);
+}
+
+void ia32_emit_16bit_source_register_or_immediate(const ir_node *node, int pos)
+{
+       const arch_register_t *reg;
+       const ir_node         *in = get_irn_n(node, pos);
+       if (is_ia32_Immediate(in)) {
+               emit_ia32_Immediate(in);
+               return;
+       }
+
+       reg = get_in_reg(node, pos);
+       emit_16bit_register(reg);
+}
+
 void ia32_emit_dest_register(const ir_node *node, int pos)
 {
        const arch_register_t *reg  = get_out_reg(node, pos);
@@ -321,6 +362,13 @@ void ia32_emit_dest_register(const ir_node *node, int pos)
        emit_register(reg, NULL);
 }
 
+void ia32_emit_dest_register_size(const ir_node *node, int pos)
+{
+       const arch_register_t *reg  = get_out_reg(node, pos);
+
+       emit_register(reg, get_ia32_ls_mode(node));
+}
+
 void ia32_emit_8bit_dest_register(const ir_node *node, int pos)
 {
        const arch_register_t *reg  = get_out_reg(node, pos);
@@ -451,9 +499,9 @@ static ir_node *get_cfop_target_block(const ir_node *irn)
  */
 static void ia32_emit_block_name(const ir_node *block)
 {
-       if (has_Block_label(block)) {
-               be_emit_string(be_gas_block_label_prefix());
-               be_emit_irprintf("%lu", get_Block_label(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));
@@ -497,6 +545,9 @@ static const char *const cmp2condition_u[] = {
        NULL  /* always true */
 };
 
+/**
+ * Emit the suffix for a compare instruction.
+ */
 static void ia32_emit_cmp_suffix(int pnc)
 {
        const char *str;
@@ -520,6 +571,63 @@ typedef enum ia32_emit_mod_t {
        EMIT_LONG         = 1U << 2
 } ia32_emit_mod_t;
 
+/**
+ * Emits address mode.
+ */
+void ia32_emit_am(const ir_node *node)
+{
+       ir_entity *ent       = get_ia32_am_sc(node);
+       int        offs      = get_ia32_am_offs_int(node);
+       ir_node   *base      = get_irn_n(node, n_ia32_base);
+       int        has_base  = !is_ia32_NoReg_GP(base);
+       ir_node   *index     = get_irn_n(node, n_ia32_index);
+       int        has_index = !is_ia32_NoReg_GP(index);
+
+       /* just to be sure... */
+       assert(!is_ia32_use_frame(node) || get_ia32_frame_ent(node) != NULL);
+
+       /* emit offset */
+       if (ent != NULL) {
+               const ia32_attr_t *attr = get_ia32_attr_const(node);
+               if (is_ia32_am_sc_sign(node))
+                       be_emit_char('-');
+               ia32_emit_entity(ent, attr->data.am_sc_no_pic_adjust);
+       }
+
+       /* also handle special case if nothing is set */
+       if (offs != 0 || (ent == NULL && !has_base && !has_index)) {
+               if (ent != NULL) {
+                       be_emit_irprintf("%+d", offs);
+               } else {
+                       be_emit_irprintf("%d", offs);
+               }
+       }
+
+       if (has_base || has_index) {
+               be_emit_char('(');
+
+               /* emit base */
+               if (has_base) {
+                       const arch_register_t *reg = get_in_reg(node, n_ia32_base);
+                       emit_register(reg, NULL);
+               }
+
+               /* emit index + scale */
+               if (has_index) {
+                       const arch_register_t *reg = get_in_reg(node, n_ia32_index);
+                       int scale;
+                       be_emit_char(',');
+                       emit_register(reg, NULL);
+
+                       scale = get_ia32_am_scale(node);
+                       if (scale > 0) {
+                               be_emit_irprintf(",%d", 1 << scale);
+                       }
+               }
+               be_emit_char(')');
+       }
+}
+
 /**
  * fmt  parameter               output
  * ---- ----------------------  ---------------------------------------------
@@ -595,6 +703,7 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...)
                                        case 'M':
                                                if (mod & EMIT_ALTERNATE_AM)
                                                        be_emit_char('*');
+
                                                ia32_emit_am(node);
                                                break;
 
@@ -783,62 +892,6 @@ void ia32_emit_unop(const ir_node *node, int pos)
        ia32_emitf(node, fmt);
 }
 
-/**
- * Emits address mode.
- */
-void ia32_emit_am(const ir_node *node)
-{
-       ir_entity *ent       = get_ia32_am_sc(node);
-       int        offs      = get_ia32_am_offs_int(node);
-       ir_node   *base      = get_irn_n(node, n_ia32_base);
-       int        has_base  = !is_ia32_NoReg_GP(base);
-       ir_node   *index     = get_irn_n(node, n_ia32_index);
-       int        has_index = !is_ia32_NoReg_GP(index);
-
-       /* just to be sure... */
-       assert(!is_ia32_use_frame(node) || get_ia32_frame_ent(node) != NULL);
-
-       /* emit offset */
-       if (ent != NULL) {
-               if (is_ia32_am_sc_sign(node))
-                       be_emit_char('-');
-               ia32_emit_entity(ent, 0);
-       }
-
-       /* also handle special case if nothing is set */
-       if (offs != 0 || (ent == NULL && !has_base && !has_index)) {
-               if (ent != NULL) {
-                       be_emit_irprintf("%+d", offs);
-               } else {
-                       be_emit_irprintf("%d", offs);
-               }
-       }
-
-       if (has_base || has_index) {
-               be_emit_char('(');
-
-               /* emit base */
-               if (has_base) {
-                       const arch_register_t *reg = get_in_reg(node, n_ia32_base);
-                       emit_register(reg, NULL);
-               }
-
-               /* emit index + scale */
-               if (has_index) {
-                       const arch_register_t *reg = get_in_reg(node, n_ia32_index);
-                       int scale;
-                       be_emit_char(',');
-                       emit_register(reg, NULL);
-
-                       scale = get_ia32_am_scale(node);
-                       if (scale > 0) {
-                               be_emit_irprintf(",%d", 1 << scale);
-                       }
-               }
-               be_emit_char(')');
-       }
-}
-
 static void emit_ia32_IMul(const ir_node *node)
 {
        ir_node               *left    = get_irn_n(node, n_ia32_IMul_left);
@@ -2007,7 +2060,7 @@ static void ia32_emit_block_header(ir_node *block)
                }
        }
 
-       if (need_label || has_Block_label(block)) {
+       if (need_label) {
                ia32_emit_block_name(block);
                be_emit_char(':');