-/*
-
- _____ _ ____ _ _
- | ___(_)_ __ / ___|| |_ __ _ ___| | __
- | |_ | \ \/ / \___ \| __/ _` |/ __| |/ /
- | _| | |> < ___) | || (_| | (__| <
- |_| |_/_/\_\ |____/ \__\__,_|\___|_|\_\
-
-*/
-
-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(be_abi_irg_t *env)
-{
- be_ssa_construction_env_t senv;
- int i, len;
- ir_node **phis;
- ir_graph *irg = env->irg;
- be_lv_t *lv = be_get_irg_liveness(irg);
- 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, env->sp_req);
- arch_set_irn_register(phi, env->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 env the abi environment
- * @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(be_abi_irg_t *env, ir_node *bl, int real_bias)
-{
- int omit_fp = env->call->flags.bits.try_omit_fp;
- ir_node *irn;
- int wanted_bias = real_bias;
-
- 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 = omit_fp ? real_bias : 0;
- int offset = get_stack_entity_offset(&env->frame, 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(env->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(env->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 = env->frame.between_type;
- int between_size = get_type_size_bytes(between_type);
- int alignment = 1 << env->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 {
- be_abi_irg_t *env; /**< The ABI irg environment. */
- 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(bw->env, 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)