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.
}
}
-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.
*/
}
}
-static void ia32_emit_entity(ir_entity *entity)
+static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
{
ident *id;
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);
+ }
}
/**
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) {
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) {
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('*');
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);
IA32_EMIT(LdTls);
IA32_EMIT(Minus64Bit);
IA32_EMIT(Jcc);
+ IA32_EMIT(GetEIP);
/* benode emitter */
BE_EMIT(Call);
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.
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;
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;
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(':');
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);