X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbeabi.c;h=2e7aad197f00066c237006129a7a89d0080f5e98;hb=44fdfafcf4d8940cbdc92266b091f18c62832d3a;hp=880a3c3b8f322fc87333835cedacdb583502404f;hpb=20aba3a7411997af46617a102d91cf05b2ebd8cb;p=libfirm diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 880a3c3b8..2e7aad197 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -44,6 +44,7 @@ #include "irtools.h" #include "raw_bitset.h" #include "error.h" +#include "pset_new.h" #include "be.h" #include "beabi.h" @@ -427,9 +428,6 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) 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); - pset *caller_save = pset_new_ptr(8); - pset *states = pset_new_ptr(2); int stack_size = 0; int stack_dir = arch_env_stack_dir(arch_env); const arch_register_t *sp = arch_env_sp(arch_env); @@ -445,6 +443,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) int n_stack_params = 0; int n_ins; + pset_new_t destroyed_regs, states; + pset_new_iterator_t iter; ir_node *low_call; ir_node **in; ir_node **res_projs; @@ -453,10 +453,12 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) const ir_edge_t *edge; int *reg_param_idxs; int *stack_param_idx; - int i; - int n; + int i, n, destroy_all_regs; dbg_info *dbgi; + pset_new_init(&destroyed_regs); + pset_new_init(&states); + /* Let the isa fill out the abi description for that call node. */ arch_env_get_call_abi(arch_env, call_tp, call); @@ -562,7 +564,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) if (is_atomic_type(param_type)) { ir_node *store; ir_node *mem_input = do_seq ? curr_mem : new_NoMem(); - store = new_rd_Store(dbgi, irg, bl, mem_input, addr, param); + store = new_rd_Store(dbgi, irg, bl, mem_input, addr, param, 0); mem = new_r_Proj(irg, bl, store, mode_M, pn_Store_M); } @@ -596,24 +598,45 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) obstack_free(obst, in); } - /* Collect caller save registers */ + /* check for the return_twice property */ + destroy_all_regs = 0; + if (is_SymConst_addr_ent(call_ptr)) { + ir_entity *ent = get_SymConst_entity(call_ptr); + + if (get_entity_additional_properties(ent) & mtp_property_returns_twice) + destroy_all_regs = 1; + } else { + ir_type *call_tp = get_Call_type(irn); + + if (get_method_additional_properties(call_tp) & mtp_property_returns_twice) + destroy_all_regs = 1; + } + + /* Put caller save into the destroyed set and state registers in the states set */ for (i = 0, n = arch_env_get_n_reg_class(arch_env); i < n; ++i) { unsigned j; const arch_register_class_t *cls = arch_env_get_reg_class(arch_env, 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, caller_save)) { - pset_insert_ptr(caller_save, (void *) reg); + + if (destroy_all_regs || arch_register_type_is(reg, caller_save)) { + if (! arch_register_type_is(reg, ignore)) + pset_new_insert(&destroyed_regs, (void *) reg); } if (arch_register_type_is(reg, state)) { - pset_insert_ptr(caller_save, (void*) reg); - pset_insert_ptr(states, (void*) reg); + pset_new_insert(&destroyed_regs, (void*) reg); + pset_new_insert(&states, (void*) reg); } } } - /* search the greatest result proj number */ + if (destroy_all_regs) { + /* even if destroyed all is specified, neither SP nor FP are destroyed (else bad things will happen) */ + pset_new_remove(&destroyed_regs, arch_env->sp); + pset_new_remove(&destroyed_regs, arch_env->bp); + } + /* search the largest result proj number */ res_projs = ALLOCANZ(ir_node*, n_res); foreach_out_edge(irn, edge) { @@ -647,7 +670,9 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) for (i = 0; i < n_reg_params; ++i) { obstack_ptr_grow(obst, get_Call_param(irn, reg_param_idxs[i])); } - foreach_pset(states, reg) { + + /* add state registers ins */ + foreach_pset_new(&states, reg, iter) { const arch_register_class_t *cls = arch_register_get_class(reg); #if 0 ir_node *regnode = be_abi_reg_map_get(env->regs, reg); @@ -656,23 +681,26 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) ir_node *regnode = new_rd_Unknown(irg, arch_register_class_mode(cls)); obstack_ptr_grow(obst, regnode); } - n_ins = n_reg_params + pset_count(states); + n_ins = n_reg_params + pset_new_size(&states); in = obstack_finish(obst); + /* ins collected, build the call */ if (env->call->flags.bits.call_has_imm && is_SymConst(call_ptr)) { /* direct call */ low_call = be_new_Call(dbgi, irg, bl, curr_mem, curr_sp, curr_sp, - n_reg_results + pn_be_Call_first_res + pset_count(caller_save), + n_reg_results + pn_be_Call_first_res + pset_new_size(&destroyed_regs), n_ins, in, get_Call_type(irn)); be_Call_set_entity(low_call, get_SymConst_entity(call_ptr)); } else { /* indirect call */ low_call = be_new_Call(dbgi, irg, bl, curr_mem, curr_sp, call_ptr, - n_reg_results + pn_be_Call_first_res + pset_count(caller_save), + n_reg_results + pn_be_Call_first_res + pset_new_size(&destroyed_regs), n_ins, in, get_Call_type(irn)); } be_Call_set_pop(low_call, call->pop); + + /* put the call into the list of all calls for later processing */ ARR_APP1(ir_node *, env->calls, low_call); /* create new stack pointer */ @@ -682,6 +710,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) arch_register_req_type_ignore | arch_register_req_type_produces_sp); arch_set_irn_register(curr_sp, sp); + /* now handle results */ for (i = 0; i < n_res; ++i) { int pn; ir_node *proj = res_projs[i]; @@ -708,7 +737,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) } if (arg->in_reg) { - pset_remove_ptr(caller_save, arg->reg); + pset_new_remove(&destroyed_regs, arg->reg); } } @@ -750,22 +779,21 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) /* Make additional projs for the caller save registers and the Keep node which keeps them alive. */ - if (1 || pset_count(caller_save) + n_reg_results > 0) { + { const arch_register_t *reg; ir_node **in, *keep; int i; int n = 0; - int curr_res_proj - = pn_be_Call_first_res + n_reg_results; + int curr_res_proj = pn_be_Call_first_res + n_reg_results; + pset_new_iterator_t iter; /* also keep the stack pointer */ ++n; set_irn_link(curr_sp, (void*) sp); obstack_ptr_grow(obst, curr_sp); - for (reg = pset_first(caller_save); reg; reg = pset_next(caller_save), ++n) { - ir_node *proj = new_r_Proj(irg, bl, low_call, reg->reg_class->mode, - curr_res_proj); + foreach_pset_new(&destroyed_regs, reg, iter) { + ir_node *proj = new_r_Proj(irg, bl, 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. */ be_set_constr_single_reg_out(low_call, curr_res_proj, reg, 0); @@ -773,7 +801,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) set_irn_link(proj, (void*) reg); obstack_ptr_grow(obst, proj); - curr_res_proj++; + ++curr_res_proj; + ++n; } for (i = 0; i < n_reg_results; ++i) { @@ -821,9 +850,9 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) be_abi_call_free(call); obstack_free(obst, stack_param_idx); - del_pset(results); - del_pset(states); - del_pset(caller_save); + + pset_new_destroy(&states); + pset_new_destroy(&destroyed_regs); return curr_sp; } @@ -851,11 +880,11 @@ static ir_node *adjust_alloc_size(unsigned stack_alignment, ir_node *size, mode = get_irn_mode(size); tv = new_tarval_from_long(stack_alignment-1, mode); - mask = new_r_Const(irg, mode, tv); + mask = new_r_Const(irg, 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, mode, tv); + mask = new_r_Const(irg, tv); size = new_rd_And(dbg, irg, block, size, mask, mode); } return size; @@ -917,7 +946,7 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp ir_mode *mode = get_irn_mode(size); tarval *tv = new_tarval_from_long(get_type_size_bytes(type), mode); - ir_node *cnst = new_rd_Const(dbg, irg, mode, tv); + ir_node *cnst = new_rd_Const(dbg, irg, tv); size = new_rd_Mul(dbg, irg, block, size, cnst, mode); } @@ -983,7 +1012,7 @@ static ir_node *adjust_free(be_abi_irg_t *env, ir_node *free, ir_node *curr_sp) /* we might need to multiply the size with the element size */ if (type != firm_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(dbg, irg, mode_Iu, tv); + ir_node *cnst = new_rd_Const(dbg, irg, tv); ir_node *mul = new_rd_Mul(dbg, irg, block, get_Free_size(free), cnst, mode_Iu); size = mul; @@ -1173,7 +1202,7 @@ static void process_ops_in_block(ir_node *bl, void *data) } set_irn_link(bl, curr_sp); -} /* process_calls_in_block */ +} /* process_ops_in_block */ /** * Adjust all call nodes in the graph to the ABI conventions. @@ -1587,7 +1616,7 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ir_entity *value_ /* the backing store itself */ store = new_r_Store(irg, first_bl, mem, addr, - new_r_Proj(irg, args_bl, args, mode, i)); + new_r_Proj(irg, args_bl, args, mode, i), 0); } /* the new memory Proj gets the last Proj from store */ set_Proj_pred(nmem, store); @@ -1619,38 +1648,32 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ir_entity *value_ } } -#if 1 /** * The start block has no jump, instead it has an initial exec Proj. * The backend wants to handle all blocks the same way, so we replace * the out cfg edge with a real jump. */ -static void fix_start_block(ir_node *block, void *env) { - int *done = env; - int i; - ir_node *start_block; - 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; - /* we processed the start block, return */ - if (*done) - return; + assert(is_Proj(initial_X)); - irg = get_irn_irg(block); - start_block = get_irg_start_block(irg); + foreach_out_edge(initial_X, edge) { + ir_node *block = get_edge_src_irn(edge); - for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) { - ir_node *pred = get_Block_cfgpred(block, i); - ir_node *pred_block = get_nodes_block(pred); + if (is_Anchor(block)) + continue; + if (block != start_block) { + ir_node *jmp = new_r_Jmp(irg, start_block); - /* ok, we are in the block, having start as cfg predecessor */ - if (pred_block == start_block) { - ir_node *jump = new_r_Jmp(irg, pred_block); - set_Block_cfgpred(block, i, jump); - *done = 1; + set_Block_cfgpred(block, get_edge_src_pos(edge), jmp); + return; } } + panic("Initial exec has no follow block"); } -#endif /** * Modify the irg itself and the frame type. @@ -1867,8 +1890,7 @@ static void modify_irg(be_abi_irg_t *env) ir_mode *mode = get_type_mode(param_type); ir_mode *load_mode = arg->load_mode; - ir_node *load = new_r_Load(irg, reg_params_bl, new_NoMem(), addr, load_mode); - set_irn_pinned(load, op_pin_state_floats); + ir_node *load = new_r_Load(irg, reg_params_bl, new_NoMem(), addr, load_mode, cons_floats); repl = new_r_Proj(irg, reg_params_bl, load, load_mode, pn_Load_res); if (mode != load_mode) { @@ -1917,8 +1939,7 @@ static void modify_irg(be_abi_irg_t *env) obstack_free(&env->obst, args); /* handle start block here (place a jump in the block) */ - i = 0; - irg_block_walk_graph(irg, fix_start_block, NULL, &i); + fix_start_block(irg); } /** Fix the state inputs of calls that still hang on unknowns */ @@ -2104,9 +2125,8 @@ static void fix_pic_symconsts(ir_node *node, void *data) /* 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 = new_r_Load(irg, block, new_NoMem(), add, mode, cons_floats); 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); }