From ff94a727febe4d155e1e807b57179df47f8fd489 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 10 Sep 2010 13:26:23 +0000 Subject: [PATCH] refactoring: split stackframe handling completely from beabi struct [r27992] --- ir/be/beabi.c | 376 +----------------------------------- ir/be/beabi.h | 14 -- ir/be/bechordal_main.c | 1 + ir/be/beinfo.c | 2 +- ir/be/beirg.h | 2 + ir/be/bemain.c | 1 + ir/be/beprefalloc.c | 1 + ir/be/bestack.c | 375 +++++++++++++++++++++++++++++++++++ ir/be/bestack.h | 48 +++++ ir/be/sparc/sparc_emitter.c | 1 + 10 files changed, 438 insertions(+), 383 deletions(-) create mode 100644 ir/be/bestack.c create mode 100644 ir/be/bestack.h diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 984df6b55..03a5baaf8 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -105,8 +105,6 @@ struct be_abi_irg_t { pset *ignore_regs; /**< Additional registers which shall be ignored. */ ir_node **calls; /**< flexible array containing all be_Call nodes */ - - arch_register_req_t *sp_req; }; static ir_heights_t *ir_heights; @@ -279,79 +277,6 @@ static void be_abi_call_free(be_abi_call_t *call) free(call); } -/* - _____ _ _ _ _ _ - | ___| __ __ _ _ __ ___ ___ | | | | __ _ _ __ __| | (_)_ __ __ _ - | |_ | '__/ _` | '_ ` _ \ / _ \ | |_| |/ _` | '_ \ / _` | | | '_ \ / _` | - | _|| | | (_| | | | | | | __/ | _ | (_| | | | | (_| | | | | | | (_| | - |_| |_| \__,_|_| |_| |_|\___| |_| |_|\__,_|_| |_|\__,_|_|_|_| |_|\__, | - |___/ - - Handling of the stack frame. It is composed of three types: - 1) The type of the arguments which are pushed on the stack. - 2) The "between type" which consists of stuff the call of the - function pushes on the stack (like the return address and - the old base pointer for ia32). - 3) The Firm frame type which consists of all local variables - and the spills. -*/ - -int be_get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent, - int bias) -{ - ir_type *t = get_entity_owner(ent); - int ofs = get_entity_offset(ent); - - int index; - - /* Find the type the entity is contained in. */ - for (index = 0; index < N_FRAME_TYPES; ++index) { - if (frame->order[index] == t) - break; - /* Add the size of all the types below the one of the entity to the entity's offset */ - ofs += get_type_size_bytes(frame->order[index]); - } - - /* correct the offset by the initial position of the frame pointer */ - ofs -= frame->initial_offset; - - /* correct the offset with the current bias. */ - ofs += bias; - - return ofs; -} - -/** - * Retrieve the entity with given offset from a frame type. - */ -static ir_entity *search_ent_with_offset(ir_type *t, int offset) -{ - int i, n; - - for (i = 0, n = get_compound_n_members(t); i < n; ++i) { - ir_entity *ent = get_compound_member(t, i); - if (get_entity_offset(ent) == offset) - return ent; - } - - return NULL; -} - -static int stack_frame_compute_initial_offset(be_stack_layout_t *frame) -{ - ir_type *base = frame->stack_dir < 0 ? frame->between_type : frame->frame_type; - ir_entity *ent = search_ent_with_offset(base, 0); - - if (ent == NULL) { - frame->initial_offset - = frame->stack_dir < 0 ? get_type_size_bytes(frame->frame_type) : get_type_size_bytes(frame->between_type); - } else { - frame->initial_offset = be_get_stack_entity_offset(frame, ent, 0); - } - - return frame->initial_offset; -} - /** * Initializes the frame layout from parts * @@ -2251,7 +2176,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg) { be_abi_irg_t *env = XMALLOCZ(be_abi_irg_t); ir_node *old_frame = get_irg_frame(irg); - struct obstack *obst = be_get_be_obst(irg); be_options_t *options = be_get_irg_options(irg); const arch_env_t *arch_env = be_get_irg_arch_env(irg); ir_entity *entity = get_irg_entity(irg); @@ -2259,32 +2183,8 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg) pmap_entry *ent; ir_node *dummy; - unsigned *limited_bitset; - arch_register_req_t *sp_req; - - be_omit_fp = options->omit_fp; - be_omit_leaf_fp = options->omit_leaf_fp; - - obstack_init(obst); env->ignore_regs = pset_new_ptr_default(); - env->keep_map = pmap_create(); - env->dce_survivor = new_survive_dce(); - - sp_req = OALLOCZ(obst, arch_register_req_t); - env->sp_req = sp_req; - - sp_req->type = arch_register_req_type_limited - | arch_register_req_type_produces_sp; - sp_req->cls = arch_register_get_class(arch_env->sp); - sp_req->width = 1; - - limited_bitset = rbitset_obstack_alloc(obst, sp_req->cls->n_regs); - rbitset_set(limited_bitset, arch_register_get_index(arch_env->sp)); - sp_req->limited = limited_bitset; - if (arch_env->sp->type & arch_register_type_ignore) { - sp_req->type |= arch_register_req_type_ignore; - } /* break here if backend provides a custom API. * Note: we shouldn't have to setup any be_abi_irg_t* stuff at all, @@ -2294,7 +2194,12 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg) if (arch_env->custom_abi) return env; - env->call = be_abi_call_new(arch_env->sp->reg_class); + be_omit_fp = options->omit_fp; + be_omit_leaf_fp = options->omit_leaf_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); env->init_sp = dummy = new_r_Dummy(irg, arch_env->sp->reg_class->mode); @@ -2348,7 +2253,8 @@ void be_abi_free(ir_graph *irg) if (env->call != NULL) be_abi_call_free(env->call); - free_survive_dce(env->dce_survivor); + if (env->dce_survivor != NULL) + free_survive_dce(env->dce_survivor); if (env->ignore_regs != NULL) del_pset(env->ignore_regs); if (env->regs != NULL) @@ -2388,272 +2294,6 @@ void be_abi_set_non_ignore_regs(be_abi_irg_t *abi, const arch_register_class_t * } } -/* - _____ _ ____ _ _ - | ___(_)_ __ / ___|| |_ __ _ ___| | __ - | |_ | \ \/ / \___ \| __/ _` |/ __| |/ / - | _| | |> < ___) | || (_| | (__| < - |_| |_/_/\_\ |____/ \__\__,_|\___|_|\_\ - -*/ - -typedef ir_node **node_array; - -typedef struct fix_stack_walker_env_t { - node_array sp_nodes; -} fix_stack_walker_env_t; - -/** - * Walker. Collect all stack modifying nodes. - */ -static void collect_stack_nodes_walker(ir_node *node, void *data) -{ - ir_node *insn = node; - fix_stack_walker_env_t *env = data; - const arch_register_req_t *req; - - if (is_Proj(node)) { - insn = get_Proj_pred(node); - } - - if (arch_irn_get_n_outs(insn) == 0) - return; - if (get_irn_mode(node) == mode_T) - return; - - req = arch_get_register_req_out(node); - if (! (req->type & arch_register_req_type_produces_sp)) - return; - - ARR_APP1(ir_node*, env->sp_nodes, node); -} - -void be_abi_fix_stack_nodes(ir_graph *irg) -{ - be_abi_irg_t *abi = be_get_irg_abi(irg); - be_lv_t *lv = be_get_irg_liveness(irg); - const arch_env_t *arch_env = be_get_irg_arch_env(irg); - be_ssa_construction_env_t senv; - int i, len; - ir_node **phis; - fix_stack_walker_env_t walker_env; - - walker_env.sp_nodes = NEW_ARR_F(ir_node*, 0); - - irg_walk_graph(irg, collect_stack_nodes_walker, NULL, &walker_env); - - /* 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; - } - - be_ssa_construction_init(&senv, irg); - 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); - } - - phis = be_ssa_construction_get_new_phis(&senv); - - /* set register requirements for stack phis */ - len = ARR_LEN(phis); - for (i = 0; i < len; ++i) { - ir_node *phi = phis[i]; - be_set_phi_reg_req(phi, abi->sp_req); - arch_set_irn_register(phi, arch_env->sp); - } - be_ssa_construction_destroy(&senv); - - DEL_ARR_F(walker_env.sp_nodes); -} - -/** - * Fix all stack accessing operations in the block bl. - * - * @param bl the block to process - * @param real_bias the bias value - * - * @return the bias at the end of this block - */ -static int process_stack_bias(ir_node *bl, int real_bias) -{ - int wanted_bias = real_bias; - ir_graph *irg = get_Block_irg(bl); - be_stack_layout_t *layout = be_get_irg_stack_layout(irg); - bool sp_relative = layout->sp_relative; - const arch_env_t *arch_env = be_get_irg_arch_env(irg); - ir_node *irn; - - sched_foreach(bl, irn) { - int ofs; - - /* - Check, if the node relates to an entity on the stack frame. - If so, set the true offset (including the bias) for that - node. - */ - ir_entity *ent = arch_get_frame_entity(irn); - if (ent != NULL) { - int bias = sp_relative ? real_bias : 0; - int offset = be_get_stack_entity_offset(layout, ent, bias); - arch_set_frame_offset(irn, offset); - DBG((dbg, LEVEL_2, "%F has offset %d (including bias %d)\n", - ent, offset, bias)); - } - - /* - * If the node modifies the stack pointer by a constant offset, - * record that in the bias. - */ - ofs = arch_get_sp_bias(irn); - - if (be_is_IncSP(irn)) { - /* fill in real stack frame size */ - if (ofs == BE_STACK_FRAME_SIZE_EXPAND) { - ir_type *frame_type = get_irg_frame_type(irg); - ofs = (int) get_type_size_bytes(frame_type); - be_set_IncSP_offset(irn, ofs); - } else if (ofs == BE_STACK_FRAME_SIZE_SHRINK) { - ir_type *frame_type = get_irg_frame_type(irg); - ofs = - (int)get_type_size_bytes(frame_type); - be_set_IncSP_offset(irn, ofs); - } else { - if (be_get_IncSP_align(irn)) { - /* patch IncSP to produce an aligned stack pointer */ - ir_type *between_type = layout->between_type; - int between_size = get_type_size_bytes(between_type); - int alignment = 1 << arch_env->stack_alignment; - int delta = (real_bias + ofs + between_size) & (alignment - 1); - assert(ofs >= 0); - if (delta > 0) { - be_set_IncSP_offset(irn, ofs + alignment - delta); - real_bias += alignment - delta; - } - } else { - /* adjust so real_bias corresponds with wanted_bias */ - int delta = wanted_bias - real_bias; - assert(delta <= 0); - if (delta != 0) { - be_set_IncSP_offset(irn, ofs + delta); - real_bias += delta; - } - } - } - } - - real_bias += ofs; - wanted_bias += ofs; - } - - assert(real_bias == wanted_bias); - return real_bias; -} - -/** - * A helper struct for the bias walker. - */ -struct bias_walk { - int start_block_bias; /**< The bias at the end of the start block. */ - int between_size; - ir_node *start_block; /**< The start block of the current graph. */ -}; - -/** - * Block-Walker: fix all stack offsets for all blocks - * except the start block - */ -static void stack_bias_walker(ir_node *bl, void *data) -{ - struct bias_walk *bw = data; - if (bl != bw->start_block) { - process_stack_bias(bl, bw->start_block_bias); - } -} - -/** - * Walker: finally lower all Sels of outer frame or parameter - * entities. - */ -static void lower_outer_frame_sels(ir_node *sel, void *ctx) -{ - ir_node *ptr; - ir_entity *ent; - ir_type *owner; - be_stack_layout_t *layout; - ir_graph *irg; - (void) ctx; - - if (! is_Sel(sel)) - return; - - ent = get_Sel_entity(sel); - owner = get_entity_owner(ent); - ptr = get_Sel_ptr(sel); - irg = get_irn_irg(sel); - layout = be_get_irg_stack_layout(irg); - - if (owner == layout->frame_type || owner == layout->arg_type) { - /* found access to outer frame or arguments */ - int offset = be_get_stack_entity_offset(layout, ent, 0); - - if (offset != 0) { - ir_node *bl = get_nodes_block(sel); - dbg_info *dbgi = get_irn_dbg_info(sel); - ir_mode *mode = get_irn_mode(sel); - ir_mode *mode_UInt = get_reference_mode_unsigned_eq(mode); - ir_node *cnst = new_r_Const_long(current_ir_graph, mode_UInt, offset); - - ptr = new_rd_Add(dbgi, bl, ptr, cnst, mode); - } - exchange(sel, ptr); - } -} - -void be_abi_fix_stack_bias(ir_graph *irg) -{ - be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg); - ir_type *frame_tp; - int i; - struct bias_walk bw; - - stack_frame_compute_initial_offset(stack_layout); - // stack_layout_dump(stdout, stack_layout); - - /* Determine the stack bias at the end of the start block. */ - bw.start_block_bias = process_stack_bias(get_irg_start_block(irg), - stack_layout->initial_bias); - bw.between_size = get_type_size_bytes(stack_layout->between_type); - - /* fix the bias is all other blocks */ - bw.start_block = get_irg_start_block(irg); - irg_block_walk_graph(irg, stack_bias_walker, NULL, &bw); - - /* fix now inner functions: these still have Sel node to outer - frame and parameter entities */ - frame_tp = get_irg_frame_type(irg); - for (i = get_class_n_members(frame_tp) - 1; i >= 0; --i) { - ir_entity *ent = get_class_member(frame_tp, i); - ir_graph *irg = get_entity_irg(ent); - - if (irg != NULL) { - irg_walk_graph(irg, NULL, lower_outer_frame_sels, NULL); - } - } -} - 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)); diff --git a/ir/be/beabi.h b/ir/be/beabi.h index 99f4acebd..595c3311c 100644 --- a/ir/be/beabi.h +++ b/ir/be/beabi.h @@ -183,22 +183,8 @@ ir_type *be_abi_call_get_method_type(const be_abi_call_t *call); be_abi_irg_t *be_abi_introduce(ir_graph *irg); -/** - * Fix the stack bias for all nodes accessing the stack frame using the - * stack pointer. - */ -void be_abi_fix_stack_bias(ir_graph *irg); void be_abi_free(ir_graph *irg); -int be_get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent, - int bias); - -/** - * Rewire all stack modifying nodes and their users to assure SSA property. - * @param env The abi - */ -void be_abi_fix_stack_nodes(ir_graph *irg); - /** * Put the registers which are forbidden specifically for this IRG in a bitset. */ diff --git a/ir/be/bechordal_main.c b/ir/be/bechordal_main.c index 07377fde3..7897c0144 100644 --- a/ir/be/bechordal_main.c +++ b/ir/be/bechordal_main.c @@ -71,6 +71,7 @@ #include "bera.h" #include "beirg.h" #include "bedump_minir.h" +#include "bestack.h" #include "bespillslots.h" #include "bespill.h" diff --git a/ir/be/beinfo.c b/ir/be/beinfo.c index dc4a52dbf..837d22394 100644 --- a/ir/be/beinfo.c +++ b/ir/be/beinfo.c @@ -43,7 +43,7 @@ void be_info_new_node(ir_node *node) backend_info_t *info; /* Projs need no be info, their tuple holds all information */ - if (is_Proj(node)) + if (is_Proj(node)) return; obst = be_get_be_obst(current_ir_graph); diff --git a/ir/be/beirg.h b/ir/be/beirg.h index 57f4af65c..881a42603 100644 --- a/ir/be/beirg.h +++ b/ir/be/beirg.h @@ -83,6 +83,8 @@ typedef struct be_irg_t { be_dom_front_info_t *dom_front; be_lv_t *lv; be_stack_layout_t stack_layout; + arch_register_req_t *sp_req; /**< requirements for stackpointer producing + nodes. */ struct obstack obst; /**< birg obstack (mainly used to keep register constraints which we can't keep in the irg obst, because it gets replace diff --git a/ir/be/bemain.c b/ir/be/bemain.c index 3f5dba5c0..7501c05b8 100644 --- a/ir/be/bemain.c +++ b/ir/be/bemain.c @@ -73,6 +73,7 @@ #include "beverify.h" #include "be_dbgout.h" #include "beirg.h" +#include "bestack.h" #define NEW_ID(s) new_id_from_chars(s, sizeof(s) - 1) diff --git a/ir/be/beprefalloc.c b/ir/be/beprefalloc.c index 1ab4e3cc9..834d93b38 100644 --- a/ir/be/beprefalloc.c +++ b/ir/be/beprefalloc.c @@ -72,6 +72,7 @@ #include "bespillutil.h" #include "beverify.h" #include "beutil.h" +#include "bestack.h" #define USE_FACTOR 1.0f #define DEF_FACTOR 1.0f diff --git a/ir/be/bestack.c b/ir/be/bestack.c new file mode 100644 index 000000000..d63e7dc61 --- /dev/null +++ b/ir/be/bestack.c @@ -0,0 +1,375 @@ +/* + * Copyright (C) 1995-2008 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. + * + * 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 + * @author Sebastian Hack, Matthias Braun + * @version $Id$ + * + * Handling of the stack frame. It is composed of three types: + * 1) The type of the arguments which are pushed on the stack. + * 2) The "between type" which consists of stuff the call of the + * function pushes on the stack (like the return address and + * the old base pointer for ia32). + * 3) The Firm frame type which consists of all local variables + * and the spills. + */ +#include "config.h" + +#include "bestack.h" +#include "beirg.h" +#include "besched.h" +#include "benode.h" +#include "bessaconstr.h" + +#include "ircons_t.h" +#include "irnode_t.h" +#include "irgwalk.h" +#include "irgmod.h" + +int be_get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent, + int bias) +{ + ir_type *t = get_entity_owner(ent); + int ofs = get_entity_offset(ent); + + int index; + + /* Find the type the entity is contained in. */ + for (index = 0; index < N_FRAME_TYPES; ++index) { + if (frame->order[index] == t) + break; + /* Add the size of all the types below the one of the entity to the entity's offset */ + ofs += get_type_size_bytes(frame->order[index]); + } + + /* correct the offset by the initial position of the frame pointer */ + ofs -= frame->initial_offset; + + /* correct the offset with the current bias. */ + ofs += bias; + + return ofs; +} + +/** + * Retrieve the entity with given offset from a frame type. + */ +static ir_entity *search_ent_with_offset(ir_type *t, int offset) +{ + int i, n; + + for (i = 0, n = get_compound_n_members(t); i < n; ++i) { + ir_entity *ent = get_compound_member(t, i); + if (get_entity_offset(ent) == offset) + return ent; + } + + return NULL; +} + +static int stack_frame_compute_initial_offset(be_stack_layout_t *frame) +{ + ir_type *base = frame->stack_dir < 0 ? frame->between_type : frame->frame_type; + ir_entity *ent = search_ent_with_offset(base, 0); + + if (ent == NULL) { + frame->initial_offset + = frame->stack_dir < 0 ? get_type_size_bytes(frame->frame_type) : get_type_size_bytes(frame->between_type); + } else { + frame->initial_offset = be_get_stack_entity_offset(frame, ent, 0); + } + + return frame->initial_offset; +} + +/** + * Walker: finally lower all Sels of outer frame or parameter + * entities. + */ +static void lower_outer_frame_sels(ir_node *sel, void *ctx) +{ + ir_node *ptr; + ir_entity *ent; + ir_type *owner; + be_stack_layout_t *layout; + ir_graph *irg; + (void) ctx; + + if (! is_Sel(sel)) + return; + + ent = get_Sel_entity(sel); + owner = get_entity_owner(ent); + ptr = get_Sel_ptr(sel); + irg = get_irn_irg(sel); + layout = be_get_irg_stack_layout(irg); + + if (owner == layout->frame_type || owner == layout->arg_type) { + /* found access to outer frame or arguments */ + int offset = be_get_stack_entity_offset(layout, ent, 0); + + if (offset != 0) { + ir_node *bl = get_nodes_block(sel); + dbg_info *dbgi = get_irn_dbg_info(sel); + ir_mode *mode = get_irn_mode(sel); + ir_mode *mode_UInt = get_reference_mode_unsigned_eq(mode); + ir_node *cnst = new_r_Const_long(current_ir_graph, mode_UInt, offset); + + ptr = new_rd_Add(dbgi, bl, ptr, cnst, mode); + } + exchange(sel, ptr); + } +} + +/** + * A helper struct for the bias walker. + */ +struct bias_walk { + int start_block_bias; /**< The bias at the end of the start block. */ + int between_size; + ir_node *start_block; /**< The start block of the current graph. */ +}; + +/** + * Fix all stack accessing operations in the block bl. + * + * @param bl the block to process + * @param real_bias the bias value + * + * @return the bias at the end of this block + */ +static int process_stack_bias(ir_node *bl, int real_bias) +{ + int wanted_bias = real_bias; + ir_graph *irg = get_Block_irg(bl); + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + bool sp_relative = layout->sp_relative; + const arch_env_t *arch_env = be_get_irg_arch_env(irg); + ir_node *irn; + + sched_foreach(bl, irn) { + int ofs; + + /* + Check, if the node relates to an entity on the stack frame. + If so, set the true offset (including the bias) for that + node. + */ + ir_entity *ent = arch_get_frame_entity(irn); + if (ent != NULL) { + int bias = sp_relative ? real_bias : 0; + int offset = be_get_stack_entity_offset(layout, ent, bias); + arch_set_frame_offset(irn, offset); + } + + /* + * If the node modifies the stack pointer by a constant offset, + * record that in the bias. + */ + ofs = arch_get_sp_bias(irn); + + if (be_is_IncSP(irn)) { + /* fill in real stack frame size */ + if (ofs == BE_STACK_FRAME_SIZE_EXPAND) { + ir_type *frame_type = get_irg_frame_type(irg); + ofs = (int) get_type_size_bytes(frame_type); + be_set_IncSP_offset(irn, ofs); + } else if (ofs == BE_STACK_FRAME_SIZE_SHRINK) { + ir_type *frame_type = get_irg_frame_type(irg); + ofs = - (int)get_type_size_bytes(frame_type); + be_set_IncSP_offset(irn, ofs); + } else { + if (be_get_IncSP_align(irn)) { + /* patch IncSP to produce an aligned stack pointer */ + ir_type *between_type = layout->between_type; + int between_size = get_type_size_bytes(between_type); + int alignment = 1 << arch_env->stack_alignment; + int delta = (real_bias + ofs + between_size) & (alignment - 1); + assert(ofs >= 0); + if (delta > 0) { + be_set_IncSP_offset(irn, ofs + alignment - delta); + real_bias += alignment - delta; + } + } else { + /* adjust so real_bias corresponds with wanted_bias */ + int delta = wanted_bias - real_bias; + assert(delta <= 0); + if (delta != 0) { + be_set_IncSP_offset(irn, ofs + delta); + real_bias += delta; + } + } + } + } + + real_bias += ofs; + wanted_bias += ofs; + } + + assert(real_bias == wanted_bias); + return real_bias; +} + +/** + * Block-Walker: fix all stack offsets for all blocks + * except the start block + */ +static void stack_bias_walker(ir_node *bl, void *data) +{ + struct bias_walk *bw = data; + if (bl != bw->start_block) { + process_stack_bias(bl, bw->start_block_bias); + } +} + +void be_abi_fix_stack_bias(ir_graph *irg) +{ + be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg); + ir_type *frame_tp; + int i; + struct bias_walk bw; + + stack_frame_compute_initial_offset(stack_layout); + + /* Determine the stack bias at the end of the start block. */ + bw.start_block_bias = process_stack_bias(get_irg_start_block(irg), + stack_layout->initial_bias); + bw.between_size = get_type_size_bytes(stack_layout->between_type); + + /* fix the bias is all other blocks */ + bw.start_block = get_irg_start_block(irg); + irg_block_walk_graph(irg, stack_bias_walker, NULL, &bw); + + /* fix now inner functions: these still have Sel node to outer + frame and parameter entities */ + frame_tp = get_irg_frame_type(irg); + for (i = get_class_n_members(frame_tp) - 1; i >= 0; --i) { + ir_entity *ent = get_class_member(frame_tp, i); + ir_graph *irg = get_entity_irg(ent); + + if (irg != NULL) { + irg_walk_graph(irg, NULL, lower_outer_frame_sels, NULL); + } + } +} + +typedef struct fix_stack_walker_env_t { + ir_node **sp_nodes; +} fix_stack_walker_env_t; + +/** + * Walker. Collect all stack modifying nodes. + */ +static void collect_stack_nodes_walker(ir_node *node, void *data) +{ + ir_node *insn = node; + fix_stack_walker_env_t *env = data; + const arch_register_req_t *req; + + if (is_Proj(node)) { + insn = get_Proj_pred(node); + } + + if (arch_irn_get_n_outs(insn) == 0) + return; + if (get_irn_mode(node) == mode_T) + return; + + req = arch_get_register_req_out(node); + if (! (req->type & arch_register_req_type_produces_sp)) + return; + + ARR_APP1(ir_node*, env->sp_nodes, node); +} + +void be_abi_fix_stack_nodes(ir_graph *irg) +{ + be_lv_t *lv = be_get_irg_liveness(irg); + const arch_env_t *arch_env = be_get_irg_arch_env(irg); + be_irg_t *birg = be_birg_from_irg(irg); + const arch_register_req_t *sp_req = birg->sp_req; + be_ssa_construction_env_t senv; + int i, len; + ir_node **phis; + fix_stack_walker_env_t walker_env; + + if (sp_req == NULL) { + struct obstack *obst = be_get_be_obst(irg); + arch_register_req_t *new_sp_req; + unsigned *limited_bitset; + + new_sp_req = OALLOCZ(obst, arch_register_req_t); + new_sp_req->type = arch_register_req_type_limited + | arch_register_req_type_produces_sp; + new_sp_req->cls = arch_register_get_class(arch_env->sp); + new_sp_req->width = 1; + + limited_bitset = rbitset_obstack_alloc(obst, new_sp_req->cls->n_regs); + rbitset_set(limited_bitset, arch_register_get_index(arch_env->sp)); + new_sp_req->limited = limited_bitset; + if (arch_env->sp->type & arch_register_type_ignore) { + new_sp_req->type |= arch_register_req_type_ignore; + } + + sp_req = new_sp_req; + birg->sp_req = new_sp_req; + } + + walker_env.sp_nodes = NEW_ARR_F(ir_node*, 0); + + irg_walk_graph(irg, collect_stack_nodes_walker, NULL, &walker_env); + + /* 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; + } + + be_ssa_construction_init(&senv, irg); + 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); + } + + phis = be_ssa_construction_get_new_phis(&senv); + + /* set register requirements for stack phis */ + len = ARR_LEN(phis); + for (i = 0; i < len; ++i) { + ir_node *phi = phis[i]; + be_set_phi_reg_req(phi, sp_req); + arch_set_irn_register(phi, arch_env->sp); + } + be_ssa_construction_destroy(&senv); + + DEL_ARR_F(walker_env.sp_nodes); +} diff --git a/ir/be/bestack.h b/ir/be/bestack.h new file mode 100644 index 000000000..cc74f80e7 --- /dev/null +++ b/ir/be/bestack.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 1995-2008 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. + * + * 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 Helper functions for handling offsets into stack frames/ + * activation records. + * @author Matthias Braun + * @version $Id$ + */ +#ifndef FIRM_BE_BESTACK_H +#define FIRM_BE_BESTACK_H + +#include "firm_types.h" +#include "be_types.h" + +/** + * Rewire all stack modifying nodes and their users to assure SSA property. + * @param env The abi + */ +void be_abi_fix_stack_nodes(ir_graph *irg); + +/** + * Fix the stack bias for all nodes accessing the stack frame using the + * stack pointer. + */ +void be_abi_fix_stack_bias(ir_graph *irg); + +int be_get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent, + int bias); + +#endif diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 427b89e16..5bbb0c4f6 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -47,6 +47,7 @@ #include "../begnuas.h" #include "../be_dbgout.h" #include "../benode.h" +#include "../bestack.h" #include "sparc_emitter.h" #include "gen_sparc_emitter.h" -- 2.20.1