/*
- * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
/* Flag: if set, try to omit the frame pointer if called by the backend */
static int be_omit_fp = 1;
+static int be_pic = 0;
/*
_ ____ ___ ____ _ _ _ _
ir_graph *irg = env->birg->irg;
const arch_env_t *arch_env = env->birg->main_env->arch_env;
const arch_isa_t *isa = arch_env->isa;
- ir_type *mt = get_Call_type(irn);
+ ir_type *call_tp = get_Call_type(irn);
ir_node *call_ptr = get_Call_ptr(irn);
- int n_params = get_method_n_params(mt);
+ int n_params = get_method_n_params(call_tp);
ir_node *curr_mem = get_Call_mem(irn);
ir_node *bl = get_nodes_block(irn);
pset *results = pset_new_ptr(8);
ir_mode *mach_mode = sp->reg_class->mode;
struct obstack *obst = &env->obst;
int no_alloc = call->flags.bits.frame_is_setup_on_call;
- int n_res = get_method_n_ress(mt);
+ int n_res = get_method_n_ress(call_tp);
ir_node *res_proj = NULL;
int n_reg_params = 0;
int i, n;
/* Let the isa fill out the abi description for that call node. */
- arch_isa_get_call_abi(isa, mt, call);
+ arch_isa_get_call_abi(isa, call_tp, call);
/* Insert code to put the stack arguments on the stack. */
assert(get_Call_n_params(irn) == n_params);
be_abi_call_arg_t *arg = get_call_arg(call, 0, i);
assert(arg);
if (arg->on_stack) {
- int arg_size = get_type_size_bytes(get_method_param_type(mt, i));
+ int arg_size = get_type_size_bytes(get_method_param_type(call_tp, i));
stack_size += round_up2(arg->space_before, arg->alignment);
stack_size += round_up2(arg_size, arg->alignment);
ir_node *param = get_Call_param(irn, p);
ir_node *addr = curr_sp;
ir_node *mem = NULL;
- ir_type *param_type = get_method_param_type(mt, p);
+ ir_type *param_type = get_method_param_type(call_tp, p);
int param_size = get_type_size_bytes(param_type) + arg->space_after;
/*
pn = i + pn_be_Call_first_res;
if(proj == NULL) {
- ir_type *res_type = get_method_res_type(mt, i);
+ ir_type *res_type = get_method_res_type(call_tp, i);
ir_mode *mode = get_type_mode(res_type);
proj = new_r_Proj(irg, bl, low_call, mode, pn);
res_projs[i] = proj;
int i = 0;
reg_node_map_t *res = obstack_alloc(obst, n * sizeof(res[0]));
- pmap_foreach(reg_map, ent) {
+ foreach_pmap(reg_map, ent) {
res[i].reg = ent->key;
res[i].irn = ent->value;
i++;
}
/* Add uses of the callee save registers. */
- pmap_foreach(env->regs, ent) {
+ foreach_pmap(env->regs, ent) {
const arch_register_t *reg = ent->key;
if(arch_register_type_is(reg, callee_save) || arch_register_type_is(reg, ignore))
pmap_insert(reg_map, ent->key, ent->value);
}
/* grow the rest of the stuff. */
- pmap_foreach(reg_map, ent) {
+ foreach_pmap(reg_map, ent) {
if(ent->value) {
in[n] = ent->value;
regs[n++] = ent->key;
ir_node *frame, *imem, *nmem, *store, *mem, *args, *args_bl;
const ir_edge_t *edge;
optimization_state_t state;
- int offset;
+ unsigned offset;
foreach_block_succ(start_bl, edge) {
ir_node *succ = get_edge_src_irn(edge);
/* move all entities to the frame type */
frame_tp = get_irg_frame_type(irg);
offset = get_type_size_bytes(frame_tp);
+
+ /* we will add new entities: set the layout to undefined */
+ assert(get_type_state(frame_tp) == layout_fixed);
+ set_type_state(frame_tp, layout_undefined);
for (ent = new_list; ent; ent = get_entity_link(ent)) {
- ir_type *tp = get_entity_type(ent);
- int align = get_type_alignment_bytes(tp);
+ ir_type *tp = get_entity_type(ent);
+ unsigned align = get_type_alignment_bytes(tp);
offset += align - 1;
- offset &= -align;
+ offset &= ~(align - 1);
set_entity_owner(ent, frame_tp);
add_class_member(frame_tp, ent);
/* must be automatic to set a fixed layout */
offset += get_type_size_bytes(tp);
}
set_type_size_bytes(frame_tp, offset);
+ /* fix the layout again */
+ set_type_state(frame_tp, layout_fixed);
}
}
ir_node *irn = get_Block_cfgpred(end, i);
if (is_Return(irn)) {
- ir_node *ret = create_be_return(env, irn, get_nodes_block(irn), get_Return_mem(irn), get_Return_n_ress(irn));
+ ir_node *blk = get_nodes_block(irn);
+ ir_node *mem = get_Return_mem(irn);
+ ir_node *ret = create_be_return(env, irn, blk, mem, get_Return_n_ress(irn));
exchange(irn, ret);
}
}
}
}
+static ir_entity *create_trampoline(be_main_env_t *be, ir_entity *method)
+{
+ ir_type *type = get_entity_type(method);
+ ident *old_id = get_entity_ld_ident(method);
+ ident *id = mangle3("L", old_id, "$stub");
+ ir_type *parent = be->pic_trampolines_type;
+ ir_entity *ent = new_entity(parent, old_id, type);
+ set_entity_ld_ident(ent, id);
+ set_entity_visibility(ent, visibility_local);
+ set_entity_variability(ent, variability_uninitialized);
+
+ return ent;
+}
+
+static int can_address_relative(ir_entity *entity)
+{
+ return get_entity_variability(entity) == variability_initialized
+ || get_entity_visibility(entity) == visibility_local;
+}
+
+/** patches SymConsts to work in position independent code */
+static void fix_pic_symconsts(ir_node *node, void *data)
+{
+ ir_graph *irg;
+ ir_node *pic_base;
+ ir_node *add;
+ ir_node *block;
+ ir_node *unknown;
+ ir_mode *mode;
+ ir_node *load;
+ ir_node *load_res;
+ be_abi_irg_t *env = data;
+ int arity, i;
+ be_main_env_t *be = env->birg->main_env;
+
+ arity = get_irn_arity(node);
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ ir_entity *entity;
+ if (!is_SymConst(pred))
+ continue;
+
+ entity = get_SymConst_entity(pred);
+ block = get_nodes_block(pred);
+ irg = get_irn_irg(pred);
+
+ /* calls can jump to relative addresses, so we can directly jump to
+ the (relatively) known call address or the trampoline */
+ if (is_Call(node) && i == 1) {
+ dbg_info *dbgi;
+ ir_entity *trampoline;
+ ir_node *trampoline_const;
+
+ if (can_address_relative(entity))
+ continue;
+
+ dbgi = get_irn_dbg_info(pred);
+ trampoline = create_trampoline(be, entity);
+ trampoline_const = new_rd_SymConst_addr_ent(dbgi, irg, mode_P_code, trampoline, NULL);
+ set_irn_n(node, i, trampoline_const);
+ continue;
+ }
+
+ /* everything else is accessed relative to EIP */
+ mode = get_irn_mode(pred);
+ unknown = new_r_Unknown(irg, mode);
+ pic_base = arch_code_generator_get_pic_base(env->birg->cg);
+ add = new_r_Add(irg, block, pic_base, pred, mode);
+
+ /* make sure the walker doesn't visit this add again */
+ mark_irn_visited(add);
+
+ /* all ok now for locally constructed stuff */
+ if (can_address_relative(entity)) {
+ set_irn_n(node, i, add);
+ continue;
+ }
+
+ /* we need an extra indirection for global data outside our current
+ module. The loads are always safe and can therefore float
+ and need no memory input */
+ load = new_r_Load(irg, block, new_NoMem(), add, mode);
+ load_res = new_r_Proj(irg, block, load, mode, pn_Load_res);
+ set_irn_pinned(load, op_pin_state_floats);
+
+ set_irn_n(node, i, load_res);
+ }
+}
+
be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
{
be_abi_irg_t *env = xmalloc(sizeof(env[0]));
unsigned *limited_bitset;
be_omit_fp = birg->main_env->options->omit_fp;
+ be_pic = birg->main_env->options->pic;
obstack_init(&env->obst);
env->calls = NEW_ARR_F(ir_node*, 0);
+ if (be_pic) {
+ irg_walk_graph(irg, fix_pic_symconsts, NULL, env);
+ }
+
/* Lower all call nodes in the IRG. */
process_calls(env);
/* We don't need the keep map anymore. */
pmap_destroy(env->keep_map);
+ env->keep_map = NULL;
/* calls array is not needed anymore */
DEL_ARR_F(env->calls);
+ env->calls = NULL;
/* reroute the stack origin of the calls to the true stack origin. */
exchange(dummy, env->init_sp);
/* Make some important node pointers survive the dead node elimination. */
survive_dce_register_irn(env->dce_survivor, &env->init_sp);
- pmap_foreach(env->regs, ent) {
+ foreach_pmap(env->regs, ent) {
survive_dce_register_irn(env->dce_survivor, (ir_node **) &ent->value);
}
if(be_is_IncSP(irn)) {
if(ofs == BE_STACK_FRAME_SIZE_EXPAND) {
- ofs = get_type_size_bytes(get_irg_frame_type(env->birg->irg));
+ ofs = (int)get_type_size_bytes(get_irg_frame_type(env->birg->irg));
be_set_IncSP_offset(irn, ofs);
} else if(ofs == BE_STACK_FRAME_SIZE_SHRINK) {
- ofs = - get_type_size_bytes(get_irg_frame_type(env->birg->irg));
+ ofs = - (int)get_type_size_bytes(get_irg_frame_type(env->birg->irg));
be_set_IncSP_offset(irn, ofs);
}
}