X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbeabi.c;h=ac788c4a4c20ebcd00d781a964dc26ad54fe431e;hb=34a3de54c5444d427c6b6a4a19cad9903a20da8e;hp=598cc03f88c965a51b4fda36e11e9642c60dbb4d;hpb=e5b57877b6db678ba428e3cbc01cbcc0815922f9;p=libfirm diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 598cc03f8..ac788c4a4 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -1,5 +1,5 @@ /* - * 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. * @@ -115,6 +115,7 @@ static heights_t *ir_heights; /* 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; /* _ ____ ___ ____ _ _ _ _ @@ -1310,7 +1311,7 @@ static reg_node_map_t *reg_map_to_arr(struct obstack *obst, pmap *reg_map) 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++; @@ -1429,7 +1430,7 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, } /* 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); @@ -1469,7 +1470,7 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, } /* 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; @@ -1629,6 +1630,10 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ir_entity *value_ /* 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); unsigned align = get_type_alignment_bytes(tp); @@ -1643,6 +1648,8 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ir_entity *value_ offset += get_type_size_bytes(tp); } set_type_size_bytes(frame_tp, offset); + /* fix the layout again */ + set_type_state(frame_tp, layout_fixed); } } @@ -1937,7 +1944,9 @@ static void modify_irg(be_abi_irg_t *env) 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); } } @@ -1992,6 +2001,95 @@ void fix_call_state_inputs(be_abi_irg_t *env) } } +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])); @@ -2004,6 +2102,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) unsigned *limited_bitset; be_omit_fp = birg->main_env->options->omit_fp; + be_pic = birg->main_env->options->pic; obstack_init(&env->obst); @@ -2036,6 +2135,10 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) 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); @@ -2053,9 +2156,11 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) /* 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); @@ -2063,7 +2168,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) /* 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); }