Commit ff94a727 authored by Matthias Braun's avatar Matthias Braun
Browse files

refactoring: split stackframe handling completely from beabi struct

[r27992]
parent 688d1be8
......@@ -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));
......
......@@ -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.
*/
......
......@@ -71,6 +71,7 @@
#include "bera.h"
#include "beirg.h"
#include "bedump_minir.h"
#include "bestack.h"
#include "bespillslots.h"
#include "bespill.h"
......
......@@ -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);
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......
/*
* 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);