X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbeabi.c;h=ac788c4a4c20ebcd00d781a964dc26ad54fe431e;hb=34a3de54c5444d427c6b6a4a19cad9903a20da8e;hp=b6400df394c91457e93bcea16b70080902c1f79d;hpb=5c87c3af579d582a642d29d5f1be31c3421d2c65;p=libfirm diff --git a/ir/be/beabi.c b/ir/be/beabi.c index b6400df39..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; /* _ ____ ___ ____ _ _ _ _ @@ -410,9 +411,9 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) 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); @@ -425,7 +426,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) 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; @@ -443,7 +444,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) 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); @@ -451,7 +452,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) 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); @@ -512,7 +513,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) 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; /* @@ -684,7 +685,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) 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; @@ -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; @@ -1576,7 +1577,7 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ir_entity *value_ 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); @@ -1629,12 +1630,16 @@ 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); - 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 */ @@ -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); } @@ -2211,10 +2316,10 @@ static int process_stack_bias(be_abi_irg_t *env, ir_node *bl, int bias) 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); } }