X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbeabi.c;h=e10097a1e6ff709a9f9f42e8ded586e5026bb251;hb=a8e4a954b36da58bce5413b569532ef54b87abcd;hp=69723d803b8e1ff633fac5547249a458e40765a7;hpb=2adf84106c02caf097c2d6cf1764706bdc437bcc;p=libfirm diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 69723d803..e10097a1e 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -1,9 +1,27 @@ -/** - * ABI lowering. +/* + * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved. + * + * This file is part of libFirm. + * + * This file may be distributed and/or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation and appearing in the file LICENSE.GPL included in the + * packaging of this file. * - * @author Sebastian Hack - * @date 7.3.2005 - * @cvsid $Id$ + * Licensees holding valid libFirm Professional Edition licenses may use + * this file in accordance with the libFirm Commercial License. + * Agreement provided with the Software. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +/** + * @file + * @brief Backend ABI implementation. + * @author Sebastian Hack, Michael Beck + * @version $Id$ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -12,7 +30,6 @@ #include "obst.h" #include "offset.h" -#include "type.h" #include "irgopt.h" #include "irgraph_t.h" @@ -28,15 +45,16 @@ #include "pdeq.h" #include "irtools.h" #include "raw_bitset.h" +#include "error.h" #include "be.h" #include "beabi.h" -#include "bearch.h" +#include "bearch_t.h" #include "benode_t.h" #include "belive_t.h" #include "besched_t.h" -#include "beirg.h" -#include "beirgmod.h" +#include "beirg_t.h" +#include "bessaconstr.h" 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. */ @@ -46,9 +64,9 @@ typedef struct _be_abi_call_arg_t { int pos; const arch_register_t *reg; ir_entity *stack_ent; - unsigned alignment; - unsigned space_before; - unsigned space_after; + unsigned alignment; /**< stack alignment */ + unsigned space_before; /**< allocate space before */ + unsigned space_after; /**< allocate space after */ } be_abi_call_arg_t; struct _be_abi_call_t { @@ -70,15 +88,15 @@ struct _be_abi_irg_t { ir_type *method_type; /**< The type of the method of the IRG. */ ir_node *init_sp; /**< The node representing the stack pointer - at the start of the function. */ + at the start of the function. */ ir_node *start_barrier; /**< The barrier of the start block */ ir_node *reg_params; /**< The reg params node. */ pmap *regs; /**< A map of all callee-save and ignore regs to - their Projs to the RegParams node. */ + their Projs to the RegParams node. */ - int start_block_bias; /**< The stack bias at the end of the start block. */ + int start_block_bias; /**< The stack bias at the end of the start block. */ void *cb; /**< ABI Callback self pointer. */ @@ -776,6 +794,31 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i return curr_sp; } +/** + * Adjust the size of a node representing a stack alloc or free for the minimum stack alignment. + * + * @param alignment the minimum stack alignment + * @param size the node containing the non-aligned size + * @param irg the irg where new nodes are allocated on + * @param irg the block where new nodes are allocated on + * @param dbg debug info for new nodes + * + * @return a node representing the aligned size + */ +static ir_node *adjust_alloc_size(unsigned stack_alignment, ir_node *size, ir_graph *irg, ir_node *block, dbg_info *dbg) { + if (stack_alignment > 1) { + ir_mode *mode = get_irn_mode(size); + tarval *tv = new_tarval_from_long(stack_alignment-1, mode); + ir_node *mask = new_r_Const(irg, block, mode, tv); + + size = new_rd_Add(dbg, irg, block, size, mask, mode); + + tv = new_tarval_from_long(-(long)stack_alignment, mode); + mask = new_r_Const(irg, block, mode, tv); + size = new_rd_And(dbg, irg, block, size, mask, mode); + } + return size; +} /** * Adjust an alloca. * The alloca is transformed into a back end alloca node and connected to the stack nodes. @@ -787,13 +830,11 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp ir_node *alloc_mem; ir_node *alloc_res; ir_type *type; + dbg_info *dbg; const ir_edge_t *edge; - ir_node *new_alloc; - ir_node *size; - ir_node *addr; - ir_node *copy; - ir_node *ins[2]; + ir_node *new_alloc, *size, *addr, *copy, *ins[2]; + unsigned stack_alignment; if (get_Alloc_where(alloc) != stack_alloc) { assert(0); @@ -830,11 +871,13 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp return curr_sp; } + dbg = get_irn_dbg_info(alloc); + /* we might need to multiply the size with the element size */ if(type != get_unknown_type() && get_type_size_bytes(type) != 1) { tarval *tv = new_tarval_from_long(get_type_size_bytes(type), mode_Iu); - ir_node *cnst = new_rd_Const(NULL, irg, block, mode_Iu, tv); - ir_node *mul = new_rd_Mul(NULL, irg, block, get_Alloc_size(alloc), + ir_node *cnst = new_rd_Const(dbg, irg, block, mode_Iu, tv); + ir_node *mul = new_rd_Mul(dbg, irg, block, get_Alloc_size(alloc), cnst, mode_Iu); size = mul; } else { @@ -844,7 +887,13 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp /* The stack pointer will be modified in an unknown manner. We cannot omit it. */ env->call->flags.bits.try_omit_fp = 0; + + /* FIXME: size must be here round up for the stack alignment, but + this must be transmitted from the backend. */ + stack_alignment = 4; + size = adjust_alloc_size(stack_alignment, size, irg, block, dbg); new_alloc = be_new_AddSP(env->isa->sp, irg, block, curr_sp, size); + set_irn_dbg_info(new_alloc, dbg); if(alloc_mem != NULL) { ir_node *addsp_mem; @@ -852,8 +901,8 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp addsp_mem = new_r_Proj(irg, block, new_alloc, mode_M, pn_be_AddSP_M); - // We need to sync the output mem of the AddSP with the input mem - // edge into the alloc node + /* We need to sync the output mem of the AddSP with the input mem + edge into the alloc node. */ ins[0] = get_Alloc_mem(alloc); ins[1] = addsp_mem; sync = new_r_Sync(irg, block, 2, ins); @@ -894,6 +943,9 @@ static ir_node *adjust_free(be_abi_irg_t *env, ir_node *free, ir_node *curr_sp) ir_node *subsp, *mem, *res, *size, *sync; ir_type *type; ir_node *in[2]; + ir_mode *sp_mode; + unsigned stack_alignment; + dbg_info *dbg; if (get_Free_where(free) != stack_alloc) { assert(0); @@ -903,25 +955,33 @@ static ir_node *adjust_free(be_abi_irg_t *env, ir_node *free, ir_node *curr_sp) block = get_nodes_block(free); irg = get_irn_irg(block); type = get_Free_type(free); + sp_mode = env->isa->sp->reg_class->mode; + dbg = get_irn_dbg_info(free); /* we might need to multiply the size with the element size */ if(type != get_unknown_type() && get_type_size_bytes(type) != 1) { tarval *tv = new_tarval_from_long(get_type_size_bytes(type), mode_Iu); - ir_node *cnst = new_rd_Const(NULL, irg, block, mode_Iu, tv); - ir_node *mul = new_rd_Mul(NULL, irg, block, get_Free_size(free), + ir_node *cnst = new_rd_Const(dbg, irg, block, mode_Iu, tv); + ir_node *mul = new_rd_Mul(dbg, irg, block, get_Free_size(free), cnst, mode_Iu); size = mul; } else { size = get_Free_size(free); } + /* FIXME: size must be here round up for the stack alignment, but + this must be transmitted from the backend. */ + stack_alignment = 4; + size = adjust_alloc_size(stack_alignment, size, irg, block, dbg); + /* The stack pointer will be modified in an unknown manner. We cannot omit it. */ env->call->flags.bits.try_omit_fp = 0; subsp = be_new_SubSP(env->isa->sp, irg, block, curr_sp, size); + set_irn_dbg_info(subsp, dbg); mem = new_r_Proj(irg, block, subsp, mode_M, pn_be_SubSP_M); - res = new_r_Proj(irg, block, subsp, mode_P_data, pn_be_SubSP_res); + res = new_r_Proj(irg, block, subsp, sp_mode, pn_be_SubSP_res); /* we need to sync the memory */ in[0] = get_Free_mem(free); @@ -982,7 +1042,7 @@ static int dependent_on(ir_node *n1, ir_node *n2) return heights_reachable_in_block(ir_heights, n1, n2); } -static int cmp_call_dependecy(const void *c1, const void *c2) +static int cmp_call_dependency(const void *c1, const void *c2) { ir_node *n1 = *(ir_node **) c1; ir_node *n2 = *(ir_node **) c2; @@ -1051,7 +1111,7 @@ static void process_calls_in_block(ir_node *bl, void *data) nodes = obstack_finish(&env->obst); /* order the call nodes according to data dependency */ - qsort(nodes, n, sizeof(nodes[0]), cmp_call_dependecy); + qsort(nodes, n, sizeof(nodes[0]), cmp_call_dependency); for(i = n - 1; i >= 0; --i) { ir_node *irn = nodes[i]; @@ -1068,6 +1128,7 @@ static void process_calls_in_block(ir_node *bl, void *data) curr_sp = adjust_free(env, irn, curr_sp); break; default: + panic("invalid call"); break; } } @@ -1075,9 +1136,12 @@ static void process_calls_in_block(ir_node *bl, void *data) obstack_free(&env->obst, nodes); /* Keep the last stack state in the block by tying it to Keep node */ - nodes[0] = curr_sp; - keep = be_new_Keep(env->isa->sp->reg_class, get_irn_irg(bl), bl, 1, nodes); - pmap_insert(env->keep_map, bl, keep); + if(curr_sp != env->init_sp) { + nodes[0] = curr_sp; + keep = be_new_Keep(env->isa->sp->reg_class, get_irn_irg(bl), + bl, 1, nodes); + pmap_insert(env->keep_map, bl, keep); + } } set_irn_link(bl, curr_sp); @@ -1408,11 +1472,9 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, i */ stack = be_abi_reg_map_get(env->regs, isa->sp); if (keep) { - ir_node *bad = new_r_Bad(env->birg->irg); stack = get_irn_n(keep, 0); - set_nodes_block(keep, bad); - set_irn_n(keep, 0, bad); - // exchange(keep, new_r_Bad(env->birg->irg)); + be_kill_node(keep); + remove_End_keepalive(get_irg_end(env->birg->irg), keep); } /* Insert results for Return into the register map. */ @@ -1672,7 +1734,9 @@ static void modify_irg(be_abi_irg_t *env) ir_graph *irg = env->birg->irg; ir_node *bl = get_irg_start_block(irg); ir_node *end = get_irg_end_block(irg); - ir_node *mem = get_irg_initial_mem(irg); + ir_node *old_mem = get_irg_initial_mem(irg); + ir_node *new_mem_proj; + ir_node *mem; ir_type *method_type = get_entity_type(get_irg_entity(irg)); pset *dont_save = pset_new_ptr(8); @@ -1813,6 +1877,13 @@ static void modify_irg(be_abi_irg_t *env) } obstack_free(&env->obst, rm); + /* create a new initial memory proj */ + assert(is_Proj(old_mem)); + new_mem_proj = new_r_Proj(irg, get_nodes_block(old_mem), + new_r_Unknown(irg, mode_T), mode_M, + get_Proj_proj(old_mem)); + mem = new_mem_proj; + /* Generate the Prologue */ fp_reg = call->cb->prologue(env->cb, &mem, env->regs); @@ -1831,6 +1902,10 @@ static void modify_irg(be_abi_irg_t *env) set_irg_frame(irg, frame_pointer); pset_insert_ptr(env->ignore_regs, fp_reg); + /* rewire old mem users to new mem */ + set_Proj_pred(new_mem_proj, get_Proj_pred(old_mem)); + exchange(old_mem, mem); + set_irg_initial_mem(irg, mem); /* Now, introduce stack param nodes for all parameters passed on the stack */ @@ -1841,13 +1916,14 @@ static void modify_irg(be_abi_irg_t *env) if(arg_proj != NULL) { be_abi_call_arg_t *arg; ir_type *param_type; - int nr = get_Proj_proj(arg_proj); + int nr = get_Proj_proj(arg_proj); + ir_mode *mode; nr = MIN(nr, n_params); arg = get_call_arg(call, 0, nr); param_type = get_method_param_type(method_type, nr); - if(arg->in_reg) { + if (arg->in_reg) { repl = pmap_get(env->regs, (void *) arg->reg); } @@ -1860,14 +1936,21 @@ static void modify_irg(be_abi_irg_t *env) } /* The stack parameter is not primitive (it is a struct or array), - we thus will create a node representing the parameter's address - on the stack. */ + we thus will create a node representing the parameter's address + on the stack. */ else { repl = be_new_FrameAddr(sp->reg_class, irg, reg_params_bl, frame_pointer, arg->stack_ent); } } assert(repl != NULL); + + /* Beware: the mode of the register parameters is always the mode of the register class + which may be wrong. Add Conv's then. */ + mode = get_irn_mode(args[i]); + if (mode != get_irn_mode(repl)) { + repl = new_r_Conv(irg, get_irn_n(repl, -1), repl, mode); + } exchange(args[i], repl); } } @@ -1903,7 +1986,7 @@ void fix_call_state_inputs(be_abi_irg_t *env) { const arch_isa_t *isa = env->isa; int i, n, n_states; - const arch_register_t **stateregs = NEW_ARR_F(const arch_register_t*, 0); + arch_register_t **stateregs = NEW_ARR_F(arch_register_t*, 0); /* Collect caller save registers */ n = arch_isa_get_n_reg_class(isa); @@ -1913,7 +1996,7 @@ void fix_call_state_inputs(be_abi_irg_t *env) 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)) { - ARR_APP1(arch_register_t*, stateregs, reg); + ARR_APP1(arch_register_t*, stateregs, (arch_register_t *)reg); } } } @@ -2019,6 +2102,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) void be_abi_free(be_abi_irg_t *env) { + be_abi_call_free(env->call); free_survive_dce(env->dce_survivor); del_pset(env->ignore_regs); pmap_destroy(env->regs); @@ -2054,8 +2138,6 @@ typedef ir_node **node_array; typedef struct fix_stack_walker_env_t { node_array sp_nodes; - node_array *state_nodes; - const arch_register_t **state_regs; const arch_env_t *arch_env; } fix_stack_walker_env_t; @@ -2066,99 +2148,65 @@ static void collect_stack_nodes_walker(ir_node *node, void *data) { fix_stack_walker_env_t *env = data; - if (is_Block(node)) - return; - if (arch_irn_is(env->arch_env, node, modify_sp)) { assert(get_irn_mode(node) != mode_M && get_irn_mode(node) != mode_T); ARR_APP1(ir_node*, env->sp_nodes, node); } - - if(ARR_LEN(env->state_nodes) > 0) { - int i, n; - const arch_register_t *reg = arch_get_irn_register(env->arch_env, node); - - n = ARR_LEN(env->state_nodes); - for(i = 0; i < n; ++i) { - if(reg == env->state_regs[i]) { - ARR_APP1(ir_node*, env->state_nodes[i], node); - } - } - } } void be_abi_fix_stack_nodes(be_abi_irg_t *env) { - int i, n; + be_ssa_construction_env_t senv; + int i, len; ir_node **phis; be_irg_t *birg = env->birg; + be_lv_t *lv = be_get_birg_liveness(birg); fix_stack_walker_env_t walker_env; arch_isa_t *isa; walker_env.sp_nodes = NEW_ARR_F(ir_node*, 0); walker_env.arch_env = birg->main_env->arch_env; - walker_env.state_nodes = NEW_ARR_F(node_array, 0); - walker_env.state_regs = NEW_ARR_F(const arch_register_t*, 0); isa = walker_env.arch_env->isa; - /* collect all state registers */ - for(i = 0, n = arch_isa_get_n_reg_class(isa); i < n; ++i) { - const arch_register_class_t *cls = arch_isa_get_reg_class(isa, i); - int j, n_regs = cls->n_regs; + irg_walk_graph(birg->irg, collect_stack_nodes_walker, NULL, &walker_env); - for(j = 0; j < n_regs; ++j) { - const arch_register_t *reg = arch_register_for_index(cls, j); - if(arch_register_type_is(reg, state)) { - node_array arr = NEW_ARR_F(ir_node*, 0); - ARR_APP1(node_array, walker_env.state_nodes, arr); - ARR_APP1(const arch_register_t*, walker_env.state_regs, reg); - } - } + /* nothing to be done if we didn't find any node, in fact we mustn't + * continue, as for endless loops incsp might have had no users and is bad + * now. + */ + len = ARR_LEN(walker_env.sp_nodes); + if(len == 0) { + DEL_ARR_F(walker_env.sp_nodes); + return; } - irg_walk_graph(birg->irg, collect_stack_nodes_walker, NULL, &walker_env); + be_ssa_construction_init(&senv, birg); + be_ssa_construction_add_copies(&senv, walker_env.sp_nodes, + ARR_LEN(walker_env.sp_nodes)); + be_ssa_construction_fix_users_array(&senv, walker_env.sp_nodes, + ARR_LEN(walker_env.sp_nodes)); + + if(lv != NULL) { + len = ARR_LEN(walker_env.sp_nodes); + for(i = 0; i < len; ++i) { + be_liveness_update(lv, walker_env.sp_nodes[i]); + } + be_ssa_construction_update_liveness_phis(&senv, lv); + } - be_assure_dom_front(birg); - phis = be_ssa_construction( - be_get_birg_dom_front(birg), - be_get_birg_liveness(birg), - env->init_sp, - ARR_LEN(walker_env.sp_nodes), walker_env.sp_nodes, - NULL, 1); + phis = be_ssa_construction_get_new_phis(&senv); /* set register requirements for stack phis */ - for(i = 0; i < ARR_LEN(phis); ++i) { + len = ARR_LEN(phis); + for(i = 0; i < len; ++i) { ir_node *phi = phis[i]; be_set_phi_reg_req(walker_env.arch_env, phi, &env->sp_req); be_set_phi_flags(walker_env.arch_env, phi, arch_irn_flags_ignore | arch_irn_flags_modify_sp); arch_set_irn_register(walker_env.arch_env, phi, env->isa->sp); } + be_ssa_construction_destroy(&senv); - DEL_ARR_F(phis); DEL_ARR_F(walker_env.sp_nodes); - - n = ARR_LEN(walker_env.state_nodes); - for(i = 0; i < n; ++i) { - const arch_register_t *reg = walker_env.state_regs[i]; - node_array nodes = walker_env.state_nodes[i]; - ir_node *initial_value = be_abi_reg_map_get(env->regs, reg); - - phis = be_ssa_construction( - be_get_birg_dom_front(birg), - be_get_birg_liveness(birg), - initial_value, - ARR_LEN(nodes), nodes, - NULL, 1); - - /* set registers for the phis */ - for(i = 0; i < ARR_LEN(phis); ++i) { - ir_node *phi = phis[i]; - be_set_phi_flags(walker_env.arch_env, phi, arch_irn_flags_ignore); - arch_set_irn_register(walker_env.arch_env, phi, reg); - } - DEL_ARR_F(phis); - DEL_ARR_F(nodes); - } } static int process_stack_bias(be_abi_irg_t *env, ir_node *bl, int bias)