X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_emitter.c;h=21bd11ad5868f8dcd7dfe93b7532ee47b34ca415;hb=7c4e33eb7648d9e1cc7efcffc8682a2f27a570a3;hp=4f3c794cca639d1600a2c12f659910c680a9ecd0;hpb=379fd05b0fb269dd9b9105810de1ce565b18e446;p=libfirm diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 4f3c794cc..21bd11ad5 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -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);