- moved the imul mem,imm32 splitting into peephole optimizations
[libfirm] / ir / be / ia32 / ia32_emitter.c
index 4f3c794..21bd11a 100644 (file)
@@ -71,6 +71,8 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 static const arch_env_t *arch_env;
 static const ia32_isa_t *isa;
 static ia32_code_gen_t  *cg;
+static int               do_pic;
+static char              pic_base_label[128];
 
 /**
  * Returns the register at in position pos.
@@ -422,16 +424,6 @@ void ia32_emit_x87_binop(const ir_node *node) {
        }
 }
 
-void ia32_emit_am_or_dest_register(const ir_node *node,
-                                   int pos) {
-       if(get_ia32_op_type(node) == ia32_Normal) {
-               ia32_emit_dest_register(node, pos);
-       } else {
-               assert(get_ia32_op_type(node) == ia32_AddrModeD);
-               ia32_emit_am(node);
-       }
-}
-
 /**
  * Emits registers and/or address mode of a unary operation.
  */
@@ -456,7 +448,7 @@ void ia32_emit_unop(const ir_node *node, int pos) {
        }
 }
 
-static void ia32_emit_entity(ir_entity *entity)
+static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
 {
        ident *id;
 
@@ -464,13 +456,19 @@ static void ia32_emit_entity(ir_entity *entity)
        id = get_entity_ld_ident(entity);
        be_emit_ident(id);
 
-       if(get_entity_owner(entity) == get_tls_type()) {
+       if (get_entity_owner(entity) == get_tls_type()) {
                if (get_entity_visibility(entity) == visibility_external_allocated) {
                        be_emit_cstring("@INDNTPOFF");
                } else {
                        be_emit_cstring("@NTPOFF");
                }
        }
+
+       if (!no_pic_adjust && do_pic) {
+               /* TODO: only do this when necessary */
+               be_emit_char('-');
+               be_emit_string(pic_base_label);
+       }
 }
 
 /**
@@ -491,7 +489,7 @@ void ia32_emit_am(const ir_node *node) {
        if (ent != NULL) {
                if (is_ia32_am_sc_sign(node))
                        be_emit_char('-');
-               ia32_emit_entity(ent);
+               ia32_emit_entity(ent, 0);
        }
 
        if(offs != 0) {
@@ -1138,7 +1136,7 @@ static void emit_ia32_Immediate(const ir_node *node)
        if(attr->symconst != NULL) {
                if(attr->sc_sign)
                        be_emit_char('-');
-               ia32_emit_entity(attr->symconst);
+               ia32_emit_entity(attr->symconst, 0);
        }
        if(attr->symconst == NULL || attr->offset != 0) {
                if(attr->symconst != NULL) {
@@ -1532,7 +1530,7 @@ static void emit_be_Call(const ir_node *node)
 
        be_emit_cstring("\tcall ");
        if (ent) {
-               ia32_emit_entity(ent);
+               ia32_emit_entity(ent, 1);
        } else {
                const arch_register_t *reg = get_in_reg(node, be_pos_Call_ptr);
                be_emit_char('*');
@@ -1789,13 +1787,29 @@ zero_neg:
        emit_sbb( node, in_hi, out_hi);
 }
 
+static void emit_ia32_GetEIP(const ir_node *node)
+{
+       be_emit_cstring("\tcall ");
+       be_emit_string(pic_base_label);
+       be_emit_finish_line_gas(node);
+
+       be_emit_string(pic_base_label);
+       be_emit_cstring(":\n");
+       be_emit_write_line();
+
+       be_emit_cstring("\tpopl ");
+       ia32_emit_dest_register(node, 0);
+       be_emit_char('\n');
+       be_emit_write_line();
+}
+
 static void emit_be_Return(const ir_node *node)
 {
        unsigned pop;
        be_emit_cstring("\tret");
 
        pop = be_Return_get_pop(node);
-       if(pop > 0) {
+       if (pop > 0 || be_Return_get_emit_pop(node)) {
                be_emit_irprintf(" $%d", pop);
        }
        be_emit_finish_line_gas(node);
@@ -1852,6 +1866,7 @@ static void ia32_register_emitters(void) {
        IA32_EMIT(LdTls);
        IA32_EMIT(Minus64Bit);
        IA32_EMIT(Jcc);
+       IA32_EMIT(GetEIP);
 
        /* benode emitter */
        BE_EMIT(Call);
@@ -1918,12 +1933,12 @@ static void ia32_emit_alignment(unsigned align, unsigned skip)
 static void ia32_emit_align_label(void)
 {
        unsigned align        = ia32_cg_config.label_alignment;
-       unsigned maximum_skip = (1 << align) - 1;
+       unsigned maximum_skip = ia32_cg_config.label_alignment_max_skip;
        ia32_emit_alignment(align, maximum_skip);
 }
 
 /**
- * Test wether a block should be aligned.
+ * Test whether a block should be aligned.
  * For cpus in the P4/Athlon class it is useful to align jump labels to
  * 16 bytes. However we should only do that if the alignment nops before the
  * label aren't executed more often than we have jumps to the label.
@@ -1966,7 +1981,10 @@ static int should_align_block(ir_node *block, ir_node *prev)
        return jmp_freq > ia32_cg_config.label_alignment_factor;
 }
 
-static int can_omit_block_label(ir_node *cfgpred)
+/**
+ * Return non-zero, if a instruction in a fall-through.
+ */
+static int is_fallthrough(ir_node *cfgpred)
 {
        ir_node *pred;
 
@@ -1979,7 +1997,13 @@ static int can_omit_block_label(ir_node *cfgpred)
        return 1;
 }
 
-static void ia32_emit_block_header(ir_node *block, ir_node *prev)
+/**
+ * Emit the block header for a block.
+ *
+ * @param block       the block
+ * @param prev_block  the previous block
+ */
+static void ia32_emit_block_header(ir_node *block, ir_node *prev_block)
 {
        ir_graph     *irg = current_ir_graph;
        int           n_cfgpreds;
@@ -1996,16 +2020,38 @@ static void ia32_emit_block_header(ir_node *block, ir_node *prev)
                need_label = 0;
        } else if(n_cfgpreds == 1) {
                ir_node *cfgpred = get_Block_cfgpred(block, 0);
-               if(get_nodes_block(cfgpred) == prev && can_omit_block_label(cfgpred)) {
+               if(get_nodes_block(cfgpred) == prev_block && is_fallthrough(cfgpred)) {
                        need_label = 0;
                }
        }
 
-       if (should_align_block(block, prev)) {
-               ia32_emit_align_label();
+       if (ia32_cg_config.label_alignment > 0) {
+               /* align the current block if:
+                * a) if should be aligned due to its execution frequency
+                * b) there is no fall-through here
+                */
+               if (should_align_block(block, prev_block)) {
+                       ia32_emit_align_label();
+               } else {
+                       /* if the predecessor block has no fall-through,
+                          we can always align the label. */
+                       int i;
+                       ir_node *check_node = NULL;
+
+                       for (i = n_cfgpreds - 1; i >= 0; --i) {
+                               ir_node *cfg_pred = get_Block_cfgpred(block, i);
+
+                               if (get_nodes_block(skip_Proj(cfg_pred)) == prev_block) {
+                                       check_node = cfg_pred;
+                                       break;
+                               }
+                       }
+                       if (check_node == NULL || !is_fallthrough(check_node))
+                               ia32_emit_align_label();
+               }
        }
 
-       if(need_label) {
+       if (need_label) {
                ia32_emit_block_name(block);
                be_emit_char(':');
 
@@ -2090,9 +2136,12 @@ void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
        cg       = ia32_cg;
        isa      = (const ia32_isa_t*) cg->arch_env->isa;
        arch_env = cg->arch_env;
+       do_pic   = cg->birg->main_env->options->pic;
 
        ia32_register_emitters();
 
+       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);