X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbeabi.c;h=f48a543731ab0c5f746084db3b316c9ae3eead08;hb=55347641865ec720b29519a97d7e9c2ed0d2af03;hp=9adfeddddc7f7d5acb3ed7e04202968941c3b639;hpb=46ab1cb2d5064a6846b000ac5c853c32132ccf9f;p=libfirm diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 9adfedddd..f48a54373 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -24,6 +24,10 @@ #include "irgwalk.h" #include "irprintf_t.h" #include "irgopt.h" +#include "irbitset.h" +#include "height.h" +#include "pdeq.h" +#include "irtools.h" #include "be.h" #include "beabi.h" @@ -32,9 +36,6 @@ #include "belive_t.h" #include "besched_t.h" -#define MAX(x, y) ((x) > (y) ? (x) : (y)) -#define MIN(x, y) ((x) < (y) ? (x) : (y)) - typedef struct _be_abi_call_arg_t { unsigned is_res : 1; /**< 1: the call argument is a return value. 0: it's a call parameter. */ unsigned in_reg : 1; /**< 1: this argument is transmitted in registers. */ @@ -114,6 +115,7 @@ struct _be_abi_irg_t { /* Forward, since be need it in be_abi_introduce(). */ static const arch_irn_ops_if_t abi_irn_ops; static const arch_irn_handler_t abi_irn_handler; +static heights_t *ir_heights; /* Flag: if set, try to omit the frame pointer if called by the backend */ int be_omit_fp = 1; @@ -216,7 +218,7 @@ be_abi_call_flags_t be_abi_call_get_flags(const be_abi_call_t *call) * * @return the new ABI call object */ -static be_abi_call_t *be_abi_call_new() +static be_abi_call_t *be_abi_call_new(void) { be_abi_call_t *call = xmalloc(sizeof(call[0])); call->flags.val = 0; @@ -353,29 +355,6 @@ static void stack_layout_dump(FILE *file, be_stack_layout_t *frame) } } -/** - * Walker: Replaces Sels of frame type and - * value param type entities by FrameAddress. - */ -static void lower_frame_sels_walker(ir_node *irn, void *data) -{ - if (is_Sel(irn)) { - be_abi_irg_t *env = data; - ir_graph *irg = current_ir_graph; - ir_node *frame = get_irg_frame(irg); - ir_node *ptr = get_Sel_ptr(irn); - - if (ptr == frame || ptr == get_irg_value_param_base(irg)) { - entity *ent = get_Sel_entity(irn); - ir_node *bl = get_nodes_block(irn); - ir_node *nw; - - nw = be_new_FrameAddr(env->isa->sp->reg_class, irg, bl, frame, ent); - exchange(irn, nw); - } - } -} - /** * Returns non-zero if the call argument at given position * is transfered on the stack. @@ -640,6 +619,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) */ be_node_set_reg_class(low_call, be_pos_Call_ptr, sp->reg_class); + DBG((env->dbg, LEVEL_3, "\tcreated backend call %+F\n", low_call)); + /* Set the register classes and constraints of the Call parameters. */ for(i = 0; i < n_low_args; ++i) { int index = low_args[i]; @@ -765,44 +746,49 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp env->call->flags.bits.try_omit_fp = 0; new_alloc = be_new_AddSP(env->isa->sp, irg, bl, curr_sp, get_Alloc_size(alloc)); - exchange(alloc_res, env->isa->stack_dir < 0 ? new_alloc : curr_sp); + exchange(alloc, env->isa->stack_dir < 0 ? new_alloc : curr_sp); if(alloc_mem != NULL) exchange(alloc_mem, new_r_NoMem(irg)); - curr_sp = new_alloc; + /* fix projnum of alloca res */ + set_Proj_proj(alloc_res, 1); + + curr_sp = alloc_res; } return curr_sp; } +/* the following function is replaced by the usage of the heights module */ +#if 0 /** * Walker for dependent_on(). * This function searches a node tgt recursively from a given node * but is restricted to the given block. * @return 1 if tgt was reachable from curr, 0 if not. */ -static int check_dependence(ir_node *curr, ir_node *tgt, ir_node *bl, unsigned long visited_nr) +static int check_dependence(ir_node *curr, ir_node *tgt, ir_node *bl) { int n, i; - if(get_irn_visited(curr) >= visited_nr) - return 0; - - set_irn_visited(curr, visited_nr); - if(get_nodes_block(curr) != bl) + if (get_nodes_block(curr) != bl) return 0; - if(curr == tgt) + if (curr == tgt) return 1; - for(i = 0, n = get_irn_arity(curr); i < n; ++i) { - if(check_dependence(get_irn_n(curr, i), tgt, bl, visited_nr)) - return 1; + /* Phi functions stop the recursion inside a basic block */ + if (! is_Phi(curr)) { + for(i = 0, n = get_irn_arity(curr); i < n; ++i) { + if (check_dependence(get_irn_n(curr, i), tgt, bl)) + return 1; + } } return 0; } +#endif /* if 0 */ /** * Check if a node is somehow data dependent on another one. @@ -814,12 +800,11 @@ static int check_dependence(ir_node *curr, ir_node *tgt, ir_node *bl, unsigned l static int dependent_on(ir_node *n1, ir_node *n2) { ir_node *bl = get_nodes_block(n1); - ir_graph *irg = get_irn_irg(bl); - long vis_nr = get_irg_visited(irg) + 1; assert(bl == get_nodes_block(n2)); - set_irg_visited(irg, vis_nr); - return check_dependence(n1, n2, bl, vis_nr); + + return heights_reachable_in_block(ir_heights, n1, n2); + //return check_dependence(n1, n2, bl); } static int cmp_call_dependecy(const void *c1, const void *c2) @@ -833,7 +818,13 @@ static int cmp_call_dependecy(const void *c1, const void *c2) 1 if second is "smaller" that first -1 if first is "smaller" that second */ - return n1 == n2 ? 0 : (dependent_on(n1, n2) ? -1 : 1); + if (dependent_on(n1, n2)) + return -1; + + if (dependent_on(n2, n1)) + return 1; + + return 0; } /** @@ -841,12 +832,13 @@ static int cmp_call_dependecy(const void *c1, const void *c2) */ static void link_calls_in_block_walker(ir_node *irn, void *data) { - if(is_Call(irn)) { + if(is_Call(irn) || (get_irn_opcode(irn) == iro_Alloc && get_Alloc_where(irn) == stack_alloc)) { be_abi_irg_t *env = data; ir_node *bl = get_nodes_block(irn); void *save = get_irn_link(bl); - env->call->flags.bits.irg_is_leaf = 0; + if (is_Call(irn)) + env->call->flags.bits.irg_is_leaf = 0; set_irn_link(irn, save); set_irn_link(bl, irn); @@ -884,6 +876,7 @@ static void process_calls_in_block(ir_node *bl, void *data) for(i = n - 1; i >= 0; --i) { ir_node *irn = nodes[i]; + DBG((env->dbg, LEVEL_3, "\tprocessing call %+F\n", irn)); switch(get_irn_opcode(irn)) { case iro_Call: curr_sp = adjust_call(env, irn, curr_sp); @@ -916,7 +909,10 @@ static void process_calls(be_abi_irg_t *env) env->call->flags.bits.irg_is_leaf = 1; irg_walk_graph(irg, firm_clear_link, link_calls_in_block_walker, env); + + ir_heights = heights_new(env->birg->irg); irg_block_walk_graph(irg, NULL, process_calls_in_block, env); + heights_free(ir_heights); } static void collect_return_walker(ir_node *irn, void *data) @@ -1276,7 +1272,6 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, i /* clear SP entry, since it has already been grown. */ pmap_insert(reg_map, (void *) isa->sp, NULL); for(i = 0; i < n_res; ++i) { - ir_node *res = get_Return_res(irn, i); be_abi_call_arg_t *arg = get_call_arg(call, 1, i); in[n] = be_abi_reg_map_get(reg_map, arg->reg); @@ -1309,6 +1304,149 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, i return ret; } +typedef struct lower_frame_sels_env_t { + be_abi_irg_t *env; + entity *value_param_list; /**< the list of all value param antities */ +} lower_frame_sels_env_t; + +/** + * Walker: Replaces Sels of frame type and + * value param type entities by FrameAddress. + */ +static void lower_frame_sels_walker(ir_node *irn, void *data) +{ + lower_frame_sels_env_t *ctx = data; + + if (is_Sel(irn)) { + ir_graph *irg = current_ir_graph; + ir_node *frame = get_irg_frame(irg); + ir_node *param_base = get_irg_value_param_base(irg); + ir_node *ptr = get_Sel_ptr(irn); + + if (ptr == frame || ptr == param_base) { + be_abi_irg_t *env = ctx->env; + entity *ent = get_Sel_entity(irn); + ir_node *bl = get_nodes_block(irn); + ir_node *nw; + + nw = be_new_FrameAddr(env->isa->sp->reg_class, irg, bl, frame, ent); + exchange(irn, nw); + + if (ptr == param_base) { + set_entity_link(ent, ctx->value_param_list); + ctx->value_param_list = ent; + } + } + } +} + +/** + * Check if a value parameter is transmitted as a register. + * This might happen if the address of an parameter is taken which is + * transmitted in registers. + * + * Note that on some architectures this case must be handled specially + * because the place of the backing store is determined by their ABI. + * + * In the default case we move the entity to the frame type and create + * a backing store into the first block. + */ +static void fix_address_of_parameter_access(be_abi_irg_t *env, entity *value_param_list) { + be_abi_call_t *call = env->call; + ir_graph *irg = env->birg->irg; + entity *ent, *next_ent, *new_list; + ir_type *frame_tp; + DEBUG_ONLY(firm_dbg_module_t *dbg = env->dbg;) + + new_list = NULL; + for (ent = value_param_list; ent; ent = next_ent) { + int i = get_struct_member_index(get_entity_owner(ent), ent); + be_abi_call_arg_t *arg = get_call_arg(call, 0, i); + + next_ent = get_entity_link(ent); + if (arg->in_reg) { + DBG((dbg, LEVEL_2, "\targ #%d need backing store\n", i)); + set_entity_link(ent, new_list); + new_list = ent; + } + } + if (new_list) { + /* ok, change the graph */ + ir_node *start_bl = get_irg_start_block(irg); + ir_node *first_bl = NULL; + ir_node *frame, *imem, *nmem, *store, *mem, *args, *args_bl; + const ir_edge_t *edge; + optimization_state_t state; + int offset; + + foreach_block_succ(start_bl, edge) { + ir_node *succ = get_edge_src_irn(edge); + if (start_bl != succ) { + first_bl = succ; + break; + } + } + assert(first_bl); + /* we had already removed critical edges, so the following + assertion should be always true. */ + assert(get_Block_n_cfgpreds(first_bl) == 1); + + /* now create backing stores */ + frame = get_irg_frame(irg); + imem = get_irg_initial_mem(irg); + + save_optimization_state(&state); + set_optimize(0); + nmem = new_r_Proj(irg, first_bl, get_irg_start(irg), mode_M, pn_Start_M); + restore_optimization_state(&state); + + /* reroute all edges to the new memory source */ + edges_reroute(imem, nmem, irg); + + store = NULL; + mem = imem; + args = get_irg_args(irg); + args_bl = get_nodes_block(args); + for (ent = new_list; ent; ent = get_entity_link(ent)) { + int i = get_struct_member_index(get_entity_owner(ent), ent); + ir_type *tp = get_entity_type(ent); + ir_mode *mode = get_type_mode(tp); + ir_node *addr; + + /* address for the backing store */ + addr = be_new_FrameAddr(env->isa->sp->reg_class, irg, first_bl, frame, ent); + + if (store) + mem = new_r_Proj(irg, first_bl, store, mode_M, pn_Store_M); + + /* the backing store itself */ + store = new_r_Store(irg, first_bl, mem, addr, + new_r_Proj(irg, args_bl, args, mode, i)); + } + /* the new memory Proj gets the last Proj from store */ + set_Proj_pred(nmem, store); + set_Proj_proj(nmem, pn_Store_M); + + /* move all entities to the frame type */ + frame_tp = get_irg_frame_type(irg); + offset = get_type_size_bytes(frame_tp); + for (ent = new_list; ent; ent = get_entity_link(ent)) { + ir_type *tp = get_entity_type(ent); + int align = get_type_alignment_bytes(tp); + + offset += align - 1; + offset &= -align; + set_entity_owner(ent, frame_tp); + add_class_member(frame_tp, ent); + /* must be automatic to set a fixed layout */ + set_entity_allocation(ent, allocation_automatic); + set_entity_offset_bytes(ent, offset); + offset += get_type_size_bytes(tp); + } + set_type_size_bytes(frame_tp, offset); + } +} + /** * Modify the irg itself and the frame type. */ @@ -1324,8 +1462,8 @@ static void modify_irg(be_abi_irg_t *env) ir_node *mem = get_irg_initial_mem(irg); ir_type *method_type = get_entity_type(get_irg_entity(irg)); pset *dont_save = pset_new_ptr(8); - int n_params = get_method_n_params(method_type); + int n_params; int i, j, n; reg_node_map_t *rm; @@ -1337,6 +1475,7 @@ static void modify_irg(be_abi_irg_t *env) ir_node *arg_tuple; const ir_edge_t *edge; ir_type *arg_type, *bet_type; + lower_frame_sels_env_t ctx; bitset_t *used_proj_nr; DEBUG_ONLY(firm_dbg_module_t *dbg = env->dbg;) @@ -1344,15 +1483,30 @@ static void modify_irg(be_abi_irg_t *env) DBG((dbg, LEVEL_1, "introducing abi on %+F\n", irg)); /* Convert the Sel nodes in the irg to frame load/store/addr nodes. */ - irg_walk_graph(irg, lower_frame_sels_walker, NULL, env); + ctx.env = env; + ctx.value_param_list = NULL; + irg_walk_graph(irg, lower_frame_sels_walker, NULL, &ctx); env->frame = obstack_alloc(&env->obst, sizeof(env->frame[0])); env->regs = pmap_create(); used_proj_nr = bitset_alloca(1024); + n_params = get_method_n_params(method_type); args = obstack_alloc(&env->obst, n_params * sizeof(args[0])); memset(args, 0, n_params * sizeof(args[0])); + /* Check if a value parameter is transmitted as a register. + * This might happen if the address of an parameter is taken which is + * transmitted in registers. + * + * Note that on some architectures this case must be handled specially + * because the place of the backing store is determined by their ABI. + * + * In the default case we move the entity to the frame type and create + * a backing store into the first block. + */ + fix_address_of_parameter_access(env, ctx.value_param_list); + /* Fill the argument vector */ arg_tuple = get_irg_args(irg); foreach_out_edge(arg_tuple, edge) { @@ -1576,7 +1730,6 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) arch_env_push_irn_handler(env->birg->main_env->arch_env, &env->irn_handler); env->call->cb->done(env->cb); - be_liveness(irg); return env; } @@ -1627,7 +1780,7 @@ static void collect_stack_nodes_walker(ir_node *irn, void *data) pset_insert_ptr(info->nodes, irn); } -void be_abi_fix_stack_nodes(be_abi_irg_t *env) +void be_abi_fix_stack_nodes(be_abi_irg_t *env, be_lv_t *lv) { dom_front_info_t *df; pset *stack_nodes = pset_new_ptr(16); @@ -1640,12 +1793,9 @@ void be_abi_fix_stack_nodes(be_abi_irg_t *env) df = be_compute_dominance_frontiers(env->birg->irg); irg_walk_graph(env->birg->irg, collect_stack_nodes_walker, NULL, &info); pset_insert_ptr(stack_nodes, env->init_sp); - be_ssa_constr_set_phis(df, stack_nodes, env->stack_phis); + be_ssa_constr_set_phis(df, lv, stack_nodes, env->stack_phis); del_pset(stack_nodes); - /* Liveness could have changed due to Phi nodes. */ - be_liveness(env->birg->irg); - /* free these dominance frontiers */ be_free_dominance_frontiers(df); }