X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbeabi.c;h=e01d3641cb945059c80386fa80677d8ea325d9be;hb=b151d11c50d89b9dffadfb63f7ccfd81ea8db44f;hp=567ac1fec66ce3285a8e94d7a981df2e4a99c93b;hpb=ce6161a7e42a48f7422b7babcc64d8ace18e2687;p=libfirm diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 567ac1fec..e01d3641c 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved. + * Copyright (C) 1995-2011 University of Karlsruhe. All right reserved. * * This file is part of libFirm. * @@ -55,6 +55,7 @@ #include "beirg.h" #include "bessaconstr.h" #include "bemodule.h" +#include "betranshlp.h" DEBUG_ONLY(static firm_dbg_module_t *dbg;) @@ -86,8 +87,6 @@ struct be_abi_call_t { * The ABI information for the current graph. */ struct be_abi_irg_t { - survive_dce_t *dce_survivor; - be_abi_call_t *call; /**< The ABI call information. */ ir_node *init_sp; /**< The node representing the stack pointer @@ -336,7 +335,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) const arch_env_t *arch_env = be_get_irg_arch_env(irg); ir_type *call_tp = get_Call_type(irn); ir_node *call_ptr = get_Call_ptr(irn); - int n_params = get_method_n_params(call_tp); + size_t n_params = get_method_n_params(call_tp); ir_node *curr_mem = get_Call_mem(irn); ir_node *bl = get_nodes_block(irn); int stack_size = 0; @@ -363,6 +362,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) int *reg_param_idxs; int *stack_param_idx; int i, n, destroy_all_regs; + size_t s; + size_t p; dbg_info *dbgi; /* Let the isa fill out the abi description for that call node. */ @@ -371,26 +372,26 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) /* Insert code to put the stack arguments on the stack. */ assert(get_Call_n_params(irn) == n_params); stack_param_idx = ALLOCAN(int, n_params); - for (i = 0; i < n_params; ++i) { - be_abi_call_arg_t *arg = get_call_arg(call, 0, i, 0); + for (p = 0; p < n_params; ++p) { + be_abi_call_arg_t *arg = get_call_arg(call, 0, p, 0); assert(arg); if (arg->on_stack) { - int arg_size = get_type_size_bytes(get_method_param_type(call_tp, i)); + int arg_size = get_type_size_bytes(get_method_param_type(call_tp, p)); stack_size += round_up2(arg->space_before, arg->alignment); stack_size += round_up2(arg_size, arg->alignment); stack_size += round_up2(arg->space_after, arg->alignment); - stack_param_idx[n_stack_params++] = i; + stack_param_idx[n_stack_params++] = p; } } /* Collect all arguments which are passed in registers. */ reg_param_idxs = ALLOCAN(int, n_params); - for (i = 0; i < n_params; ++i) { - be_abi_call_arg_t *arg = get_call_arg(call, 0, i, 0); + for (p = 0; p < n_params; ++p) { + be_abi_call_arg_t *arg = get_call_arg(call, 0, p, 0); if (arg && arg->in_reg) { - reg_param_idxs[n_reg_params++] = i; + reg_param_idxs[n_reg_params++] = p; } } @@ -526,15 +527,15 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) if (reg == arch_env->sp || reg == arch_env->bp) continue; - if (arch_register_type_is(reg, state)) { + if (reg->type & arch_register_type_state) { ARR_APP1(const arch_register_t*, destroyed_regs, reg); ARR_APP1(const arch_register_t*, states, reg); /* we're already in the destroyed set so no need for further * checking */ continue; } - if (destroy_all_regs || arch_register_type_is(reg, caller_save)) { - if (! arch_register_type_is(reg, ignore)) { + if (destroy_all_regs || (reg->type & arch_register_type_caller_save)) { + if (!(reg->type & arch_register_type_ignore)) { ARR_APP1(const arch_register_t*, destroyed_regs, reg); } } @@ -580,8 +581,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) } /* add state registers ins */ - for (i = 0; i < ARR_LEN(states); ++i) { - const arch_register_t *reg = states[i]; + for (s = 0; s < ARR_LEN(states); ++s) { + const arch_register_t *reg = states[s]; const arch_register_class_t *cls = arch_register_get_class(reg); #if 0 ir_node *regnode = be_abi_reg_map_get(env->regs, reg); @@ -644,8 +645,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) if (arg->in_reg) { /* remove register from destroyed regs */ - int j; - int n = ARR_LEN(destroyed_regs); + size_t j; + size_t n = ARR_LEN(destroyed_regs); for (j = 0; j < n; ++j) { if (destroyed_regs[j] == arg->reg) { destroyed_regs[j] = destroyed_regs[n-1]; @@ -697,6 +698,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) { ir_node **in, *keep; int i; + size_t d; int n = 0; int curr_res_proj = pn_be_Call_first_res + n_reg_results; int n_ins; @@ -708,8 +710,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) set_irn_link(curr_sp, (void*) sp); in[n++] = curr_sp; - for (i = 0; i < ARR_LEN(destroyed_regs); ++i) { - const arch_register_t *reg = destroyed_regs[i]; + for (d = 0; d < ARR_LEN(destroyed_regs); ++d) { + const arch_register_t *reg = destroyed_regs[d]; ir_node *proj = new_r_Proj(low_call, reg->reg_class->mode, curr_res_proj); /* memorize the register in the link field. we need afterwards to set the register class of the keep correctly. */ @@ -976,6 +978,7 @@ static int cmp_call_dependency(const void *c1, const void *c2) { ir_node *n1 = *(ir_node **) c1; ir_node *n2 = *(ir_node **) c2; + unsigned h1, h2; /* Classical qsort() comparison function behavior: @@ -990,7 +993,16 @@ static int cmp_call_dependency(const void *c1, const void *c2) return 1; /* The nodes have no depth order, but we need a total order because qsort() - * is not stable. */ + * is not stable. + * + * Additionally, we need to respect transitive dependencies. Consider a + * Call a depending on Call b and an independent Call c. + * We MUST NOT order c > a and b > c. */ + h1 = get_irn_height(ir_heights, n1); + h2 = get_irn_height(ir_heights, n2); + if (h1 < h2) return -1; + if (h1 > h2) return 1; + /* Same height, so use a random (but stable) order */ return get_irn_idx(n1) - get_irn_idx(n2); } @@ -1031,8 +1043,8 @@ static void link_ops_in_block_walker(ir_node *irn, void *data) * Block-walker: * Process all Call/Alloc/Free nodes inside a basic block. * Note that the link field of the block must contain a linked list of all - * Call nodes inside the Block. We first order this list according to data dependency - * and that connect the calls together. + * nodes inside the Block. We first order this list according to data dependency + * and that connect the nodes together. */ static void process_ops_in_block(ir_node *bl, void *data) { @@ -1193,14 +1205,14 @@ static int cmp_regs(const void *a, const void *b) if (p->reg->reg_class == q->reg->reg_class) return p->reg->index - q->reg->index; else - return p->reg->reg_class - q->reg->reg_class; + return p->reg->reg_class < q->reg->reg_class ? -1 : +1; } static void reg_map_to_arr(reg_node_map_t *res, pmap *reg_map) { pmap_entry *ent; - int n = pmap_count(reg_map); - int i = 0; + size_t n = pmap_count(reg_map); + size_t i = 0; foreach_pmap(reg_map, ent) { res[i].reg = (const arch_register_t*)ent->key; @@ -1211,76 +1223,14 @@ static void reg_map_to_arr(reg_node_map_t *res, pmap *reg_map) qsort(res, n, sizeof(res[0]), cmp_regs); } -/** - * Creates a barrier. - */ -static ir_node *create_barrier(ir_node *bl, ir_node **mem, pmap *regs, - int in_req) -{ - int n_regs = pmap_count(regs); - int n; - ir_node *irn; - ir_node **in; - reg_node_map_t *rm; - - in = ALLOCAN(ir_node*, n_regs+1); - rm = ALLOCAN(reg_node_map_t, n_regs); - reg_map_to_arr(rm, regs); - for (n = 0; n < n_regs; ++n) { - in[n] = rm[n].irn; - } - - if (mem) { - in[n++] = *mem; - } - - irn = be_new_Barrier(bl, n, in); - - for (n = 0; n < n_regs; ++n) { - ir_node *pred = rm[n].irn; - const arch_register_t *reg = rm[n].reg; - arch_register_req_type_t add_type = arch_register_req_type_none; - ir_node *proj; - const backend_info_t *info; - - /* stupid workaround for now... as not all nodes report register - * requirements. */ - info = be_get_info(skip_Proj(pred)); - if (info != NULL && info->out_infos != NULL) { - const arch_register_req_t *ireq = arch_get_register_req_out(pred); - if (ireq->type & arch_register_req_type_ignore) - add_type |= arch_register_req_type_ignore; - if (ireq->type & arch_register_req_type_produces_sp) - add_type |= arch_register_req_type_produces_sp; - } - - proj = new_r_Proj(irn, get_irn_mode(pred), n); - be_node_set_reg_class_in(irn, n, reg->reg_class); - if (in_req) { - be_set_constr_single_reg_in(irn, n, reg, - arch_register_req_type_none); - } - be_set_constr_single_reg_out(irn, n, reg, add_type); - arch_set_irn_register(proj, reg); - - pmap_insert(regs, (void *) reg, proj); - } - - if (mem) { - *mem = new_r_Proj(irn, mode_M, n); - } - - return irn; -} - /** * Creates a be_Return for a Return node. * - * @param @env the abi environment - * @param irn the Return node or NULL if there was none - * @param bl the block where the be_Retun should be placed - * @param mem the current memory - * @param n_res number of return results + * @param @env the abi environment + * @param irn the Return node or NULL if there was none + * @param bl the block where the be_Retun should be placed + * @param mem the current memory + * @param n_res number of return results */ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, ir_node *mem, int n_res) @@ -1291,7 +1241,7 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, dbg_info *dbgi; pmap *reg_map = pmap_create(); ir_node *keep = (ir_node*)pmap_get(env->keep_map, bl); - int in_max; + size_t in_max; ir_node *ret; int i, n; unsigned pop; @@ -1325,14 +1275,13 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, /* Add uses of the callee save registers. */ foreach_pmap(env->regs, ent) { const arch_register_t *reg = (const arch_register_t*)ent->key; - if (arch_register_type_is(reg, callee_save) || arch_register_type_is(reg, ignore)) + if (reg->type & (arch_register_type_callee_save | arch_register_type_ignore)) pmap_insert(reg_map, ent->key, ent->value); } be_abi_reg_map_set(reg_map, arch_env->sp, stack); /* Make the Epilogue node and call the arch's epilogue maker. */ - create_barrier(bl, &mem, reg_map, 1); call->cb->epilogue(env->cb, bl, &mem, reg_map); /* @@ -1379,13 +1328,14 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, /* we have to pop the shadow parameter in in case of struct returns */ pop = call->pop; ret = be_new_Return(dbgi, irg, bl, n_res, pop, n, in); + arch_irn_add_flags(ret, arch_irn_flags_epilog); /* Set the register classes of the return's parameter accordingly. */ for (i = 0; i < n; ++i) { if (regs[i] == NULL) continue; - be_node_set_reg_class_in(ret, i, regs[i]->reg_class); + be_set_constr_single_reg_in(ret, i, regs[i], arch_register_req_type_none); } /* Free the space of the Epilog's in array and the register <-> proj map. */ @@ -1608,25 +1558,13 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ir_graph *irg, */ static void fix_start_block(ir_graph *irg) { - ir_node *initial_X = get_irg_initial_exec(irg); - ir_node *start_block = get_irg_start_block(irg); - const ir_edge_t *edge; + ir_node *initial_X = get_irg_initial_exec(irg); + ir_node *start_block = get_irg_start_block(irg); + ir_node *jmp = new_r_Jmp(start_block); assert(is_Proj(initial_X)); - - foreach_out_edge(initial_X, edge) { - ir_node *block = get_edge_src_irn(edge); - - if (is_Anchor(block)) - continue; - if (block != start_block) { - ir_node *jmp = new_r_Jmp(start_block); - set_Block_cfgpred(block, get_edge_src_pos(edge), jmp); - set_irg_initial_exec(irg, jmp); - return; - } - } - panic("Initial exec has no follow block in %+F", irg); + exchange(initial_X, jmp); + set_irg_initial_exec(irg, new_r_Bad(irg)); } /** @@ -1734,8 +1672,6 @@ static void modify_irg(ir_graph *irg) DBG((dbg, LEVEL_1, "introducing abi on %+F\n", irg)); - /* Must fetch memory here, otherwise the start Barrier gets the wrong - * memory, which leads to loops in the DAG. */ old_mem = get_irg_initial_mem(irg); irp_reserve_resources(irp, IR_RESOURCE_ENTITY_LINK); @@ -1840,8 +1776,7 @@ static void modify_irg(ir_graph *irg) const arch_register_class_t *cls = &arch_env->register_classes[i]; for (j = 0; j < cls->n_regs; ++j) { const arch_register_t *reg = &cls->regs[j]; - if (arch_register_type_is(reg, callee_save) || - arch_register_type_is(reg, state)) { + if (reg->type & (arch_register_type_callee_save | arch_register_type_state)) { pmap_insert(env->regs, (void *) reg, NULL); } } @@ -1854,6 +1789,8 @@ static void modify_irg(ir_graph *irg) pmap_insert(env->regs, (void *) arch_env->bp, NULL); start_bl = get_irg_start_block(irg); env->start = be_new_Start(NULL, start_bl, pmap_count(env->regs) + 1); + arch_irn_add_flags(env->start, arch_irn_flags_prolog); + set_irg_start(irg, env->start); /* * make proj nodes for the callee save registers. @@ -1894,14 +1831,11 @@ static void modify_irg(ir_graph *irg) /* Generate the Prologue */ fp_reg = call->cb->prologue(env->cb, &mem, env->regs, &stack_layout->initial_bias); - /* do the stack allocation BEFORE the barrier, or spill code - might be added before it */ env->init_sp = be_abi_reg_map_get(env->regs, sp); env->init_sp = be_new_IncSP(sp, start_bl, env->init_sp, BE_STACK_FRAME_SIZE_EXPAND, 0); + arch_irn_add_flags(env->init_sp, arch_irn_flags_prolog); be_abi_reg_map_set(env->regs, sp, env->init_sp); - create_barrier(start_bl, &mem, env->regs, 0); - env->init_sp = be_abi_reg_map_get(env->regs, sp); arch_set_irn_register(env->init_sp, sp); @@ -2005,7 +1939,7 @@ static void fix_call_state_inputs(ir_graph *irg) const arch_register_class_t *cls = &arch_env->register_classes[i]; for (j = 0; j < cls->n_regs; ++j) { const arch_register_t *reg = arch_register_for_index(cls, j); - if (arch_register_type_is(reg, state)) { + if (reg->type & arch_register_type_state) { ARR_APP1(arch_register_t*, stateregs, (arch_register_t *)reg); } } @@ -2195,7 +2129,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg) struct obstack *obst = &birg->obst; unsigned r; - pmap_entry *ent; ir_node *dummy; /* determine allocatable registers */ @@ -2216,7 +2149,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg) be_omit_fp = options->omit_fp; - env->dce_survivor = new_survive_dce(); env->keep_map = pmap_create(); env->call = be_abi_call_new(arch_env->sp->reg_class); arch_env_get_call_abi(arch_env, method_type, env->call); @@ -2255,12 +2187,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg) exchange(dummy, env->init_sp); exchange(old_frame, get_irg_frame(irg)); - /* Make some important node pointers survive the dead node elimination. */ - survive_dce_register_irn(env->dce_survivor, &env->init_sp); - foreach_pmap(env->regs, ent) { - survive_dce_register_irn(env->dce_survivor, (ir_node **) &ent->value); - } - env->call->cb->done(env->cb); env->cb = NULL; return env; @@ -2272,8 +2198,6 @@ void be_abi_free(ir_graph *irg) if (env->call != NULL) be_abi_call_free(env->call); - if (env->dce_survivor != NULL) - free_survive_dce(env->dce_survivor); if (env->regs != NULL) pmap_destroy(env->regs); free(env); @@ -2281,6 +2205,28 @@ void be_abi_free(ir_graph *irg) be_set_irg_abi(irg, NULL); } +/** + * called after nodes have been transformed so some node references can be + * replaced with new nodes + */ +void be_abi_transform_fixup(ir_graph *irg) +{ + be_abi_irg_t *abi = be_get_irg_abi(irg); + pmap *new_regs; + pmap_entry *entry; + if (abi == NULL || abi->regs == NULL) + return; + + new_regs = pmap_create(); + foreach_pmap(abi->regs, entry) { + ir_node *value = (ir_node*)entry->value; + ir_node *transformed = be_transform_node(value); + pmap_insert(new_regs, entry->key, transformed); + } + pmap_destroy(abi->regs); + abi->regs = new_regs; +} + void be_put_allocatable_regs(const ir_graph *irg, const arch_register_class_t *cls, bitset_t *bs) { @@ -2323,14 +2269,14 @@ void be_set_allocatable_regs(const ir_graph *irg, ir_node *be_abi_get_callee_save_irn(be_abi_irg_t *abi, const arch_register_t *reg) { - assert(arch_register_type_is(reg, callee_save)); + assert(reg->type & arch_register_type_callee_save); assert(pmap_contains(abi->regs, (void *) reg)); return (ir_node*)pmap_get(abi->regs, (void *) reg); } ir_node *be_abi_get_ignore_irn(be_abi_irg_t *abi, const arch_register_t *reg) { - assert(arch_register_type_is(reg, ignore)); + assert(reg->type & arch_register_type_ignore); assert(pmap_contains(abi->regs, (void *) reg)); return (ir_node*)pmap_get(abi->regs, (void *) reg); }