Commit 816e7e07 authored by Matthias Braun's avatar Matthias Braun
Browse files

- add support for stack alignment on calls

- fix pic trampolines not being generated twice

[r19205]
parent 5e7c369c
......@@ -373,6 +373,7 @@ static TEMPLATE_isa_t TEMPLATE_isa_template = {
&TEMPLATE_general_purpose_regs[REG_SP], /* stack pointer register */
&TEMPLATE_general_purpose_regs[REG_BP], /* base pointer register */
-1, /* stack direction */
1, /* stack alignment for calls */
NULL, /* main environment */
7, /* costs for a spill instruction */
5, /* costs for a reload instruction */
......
......@@ -769,6 +769,7 @@ static arm_isa_t arm_isa_template = {
&arm_gp_regs[REG_SP], /* stack pointer */
&arm_gp_regs[REG_R11], /* base pointer */
-1, /* stack direction */
1, /* stack alignment for calls */
NULL, /* main environment */
7, /* spill costs */
5, /* reload costs */
......@@ -972,7 +973,7 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m
// TODO: Activate Omit fp in epilogue
if (env->flags.try_omit_fp) {
curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK);
curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK, 0);
add_irn_dep(curr_sp, *mem);
curr_lr = be_new_CopyKeep_single(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr, curr_sp, get_irn_mode(curr_lr));
......
......@@ -31,6 +31,7 @@
#include "debug.h"
#include "bitset.h"
#include "timing.h"
#include "pmap.h"
#include "be.h"
#include "bearch.h"
......@@ -84,7 +85,9 @@ struct be_main_env_t {
arch_code_generator_t *cg;
arch_irn_handler_t *phi_handler;
const char *cup_name;
pmap *ent_trampoline_map;
ir_type *pic_trampolines_type;
pmap *ent_pic_symbol_map;
ir_type *pic_symbols_type;
};
......
......@@ -108,7 +108,7 @@ struct _be_abi_irg_t {
arch_register_req_t sp_req;
arch_register_req_t sp_cls_req;
DEBUG_ONLY(firm_dbg_module_t *dbg;) /**< The debugging module. */
DEBUG_ONLY(firm_dbg_module_t *dbg;) /**< The debugging module. */
};
static heights_t *ir_heights;
......@@ -271,7 +271,8 @@ static void be_abi_call_free(be_abi_call_t *call)
and the spills.
*/
static int get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent, int bias)
static int 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);
......@@ -427,6 +428,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
struct obstack *obst = &env->obst;
int no_alloc = call->flags.bits.frame_is_setup_on_call;
int n_res = get_method_n_ress(call_tp);
int do_seq = call->flags.bits.store_args_sequential && !no_alloc;
ir_node *res_proj = NULL;
int n_reg_params = 0;
......@@ -473,10 +475,22 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
}
reg_param_idxs = obstack_finish(obst);
/*
* If the stack is decreasing and we do not want to store sequentially,
* or someone else allocated the call frame
* we allocate as much space on the stack all parameters need, by
* moving the stack pointer along the stack's direction.
*
* Note: we also have to do this for stack_size == 0, because we may have
* to adjust stack alignment for the call.
*/
if (stack_dir < 0 && !do_seq && !no_alloc) {
curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, stack_size, 1);
}
/* If there are some parameters which shall be passed on the stack. */
if (n_stack_params > 0) {
int curr_ofs = 0;
int do_seq = call->flags.bits.store_args_sequential && !no_alloc;
/*
* Reverse list of stack parameters if call arguments are from left to right.
......@@ -492,16 +506,6 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
}
}
/*
* If the stack is decreasing and we do not want to store sequentially,
* or someone else allocated the call frame
* we allocate as much space on the stack all parameters need, by
* moving the stack pointer along the stack's direction.
*/
if (stack_dir < 0 && !do_seq && !no_alloc) {
curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, stack_size);
}
curr_mem = get_Call_mem(irn);
if (! do_seq) {
obstack_ptr_grow(obst, curr_mem);
......@@ -523,7 +527,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
*/
if (do_seq) {
curr_ofs = 0;
addr = curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, param_size + arg->space_before);
addr = curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, param_size + arg->space_before, 0);
add_irn_dep(curr_sp, curr_mem);
}
else {
......@@ -805,11 +809,10 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
mem_proj = new_r_Proj(irg, bl, low_call, mode_M, pn_be_Call_M_regular);
keep_alive(mem_proj);
}
/* Clean up the stack frame if we allocated it */
if (! no_alloc) {
curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, -stack_size);
}
}
/* Clean up the stack frame or revert alignment fixes if we allocated it */
if (! no_alloc) {
curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, -stack_size, 0);
}
be_abi_call_free(call);
......@@ -836,6 +839,7 @@ 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) {
assert(is_po2(stack_alignment));
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);
......@@ -918,9 +922,7 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp
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;
stack_alignment = env->isa->stack_alignment;
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);
......@@ -989,10 +991,8 @@ static ir_node *adjust_free(be_abi_irg_t *env, ir_node *free, ir_node *curr_sp)
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);
stack_alignment = env->isa->stack_alignment;
size = adjust_alloc_size(stack_alignment, size, irg, block, dbg);
/* The stack pointer will be modified in an unknown manner.
We cannot omit it. */
......@@ -1864,7 +1864,7 @@ static void modify_irg(be_abi_irg_t *env)
/* do the stack allocation BEFORE the barrier, or spill code
might be added before it */
env->init_sp = be_abi_reg_map_get(env->regs, sp);
env->init_sp = be_new_IncSP(sp, irg, bl, env->init_sp, BE_STACK_FRAME_SIZE_EXPAND);
env->init_sp = be_new_IncSP(sp, irg, bl, env->init_sp, BE_STACK_FRAME_SIZE_EXPAND, 0);
be_abi_reg_map_set(env->regs, sp, env->init_sp);
create_barrier(env, bl, &mem, env->regs, 0);
......@@ -2015,6 +2015,17 @@ static ir_entity *create_trampoline(be_main_env_t *be, ir_entity *method)
return ent;
}
static ir_entity *get_trampoline(be_main_env_t *env, ir_entity *method)
{
ir_entity *result = pmap_get(env->ent_trampoline_map, method);
if (result == NULL) {
result = create_trampoline(env, method);
pmap_insert(env->ent_trampoline_map, method, result);
}
return result;
}
static int can_address_relative(ir_entity *entity)
{
return get_entity_variability(entity) == variability_initialized
......@@ -2058,7 +2069,7 @@ static void fix_pic_symconsts(ir_node *node, void *data)
continue;
dbgi = get_irn_dbg_info(pred);
trampoline = create_trampoline(be, entity);
trampoline = get_trampoline(be, entity);
trampoline_const = new_rd_SymConst_addr_ent(dbgi, irg, mode_P_code, trampoline, NULL);
set_irn_n(node, i, trampoline_const);
continue;
......@@ -2286,11 +2297,12 @@ void be_abi_fix_stack_nodes(be_abi_irg_t *env)
DEL_ARR_F(walker_env.sp_nodes);
}
static int process_stack_bias(be_abi_irg_t *env, ir_node *bl, int bias)
static int process_stack_bias(be_abi_irg_t *env, ir_node *bl, int real_bias)
{
const arch_env_t *arch_env = env->birg->main_env->arch_env;
int omit_fp = env->call->flags.bits.try_omit_fp;
ir_node *irn;
int omit_fp = env->call->flags.bits.try_omit_fp;
ir_node *irn;
int wanted_bias = real_bias;
sched_foreach(bl, irn) {
int ofs;
......@@ -2302,34 +2314,59 @@ static int process_stack_bias(be_abi_irg_t *env, ir_node *bl, int bias)
*/
ir_entity *ent = arch_get_frame_entity(arch_env, irn);
if(ent) {
int bias = omit_fp ? real_bias : 0;
int offset = get_stack_entity_offset(env->frame, ent, bias);
arch_set_frame_offset(arch_env, irn, offset);
DBG((env->dbg, LEVEL_2, "%F has offset %d (including bias %d)\n", ent, offset, bias));
DBG((env->dbg, LEVEL_2, "%F has offset %d (including bias %d)\n",
ent, offset, bias));
}
if(omit_fp || be_is_IncSP(irn)) {
/*
* If the node modifies the stack pointer by a constant offset,
* record that in the bias.
*/
ofs = arch_get_sp_bias(arch_env, irn);
if(be_is_IncSP(irn)) {
if(ofs == BE_STACK_FRAME_SIZE_EXPAND) {
ofs = (int)get_type_size_bytes(get_irg_frame_type(env->birg->irg));
be_set_IncSP_offset(irn, ofs);
} else if(ofs == BE_STACK_FRAME_SIZE_SHRINK) {
ofs = - (int)get_type_size_bytes(get_irg_frame_type(env->birg->irg));
be_set_IncSP_offset(irn, ofs);
/*
* If the node modifies the stack pointer by a constant offset,
* record that in the bias.
*/
ofs = arch_get_sp_bias(arch_env, 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->birg->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->birg->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 = env->isa->stack_alignment;
int delta = (real_bias + ofs + between_size) % env->isa->stack_alignment;
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;
}
}
}
if(omit_fp)
bias += ofs;
}
real_bias += ofs;
wanted_bias += ofs;
}
return bias;
assert(real_bias == wanted_bias);
return real_bias;
}
/**
......@@ -2337,8 +2374,9 @@ static int process_stack_bias(be_abi_irg_t *env, ir_node *bl, int bias)
*/
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. */
ir_node *start_block; /**< The start block of the current graph. */
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. */
};
/**
......@@ -2362,6 +2400,7 @@ void be_abi_fix_stack_bias(be_abi_irg_t *env)
/* Determine the stack bias at the end of the start block. */
bw.start_block_bias = process_stack_bias(env, get_irg_start_block(irg), 0);
bw.between_size = get_type_size_bytes(env->frame->between_type);
/* fix the bias is all other blocks */
bw.env = env;
......
......@@ -409,10 +409,11 @@ struct arch_isa_t {
const arch_isa_if_t *impl;
const arch_register_t *sp; /** The stack pointer register. */
const arch_register_t *bp; /** The base pointer register. */
const int stack_dir; /** -1 for decreasing, 1 for increasing. */
int stack_dir; /** -1 for decreasing, 1 for increasing. */
int stack_alignment; /** stack alignment */
const be_main_env_t *main_env; /** the be main environment */
const int spill_cost; /** cost for a be_Spill node */
const int reload_cost; /** cost for a be_Reload node */
int spill_cost; /** cost for a be_Spill node */
int reload_cost; /** cost for a be_Reload node */
};
#define arch_isa_stack_dir(isa) ((isa)->stack_dir)
......
......@@ -251,8 +251,10 @@ static be_main_env_t *be_init_env(be_main_env_t *env, FILE *file_handle)
obstack_init(&env->obst);
env->arch_env = obstack_alloc(&env->obst, sizeof(env->arch_env[0]));
env->options = &be_options;
env->ent_trampoline_map = pmap_create();
env->pic_trampolines_type
= new_type_class(new_id_from_str("$PIC_TRAMPOLINE_TYPE"));
env->ent_pic_symbol_map = pmap_create();
env->pic_symbols_type
= new_type_struct(new_id_from_str("$PIC_SYMBOLS_TYPE"));
......@@ -286,6 +288,8 @@ static void be_done_env(be_main_env_t *env)
be_phi_handler_free(env->phi_handler);
obstack_free(&env->obst, NULL);
pmap_destroy(env->ent_trampoline_map);
pmap_destroy(env->ent_pic_symbol_map);
free_type(env->pic_trampolines_type);
free_type(env->pic_symbols_type);
}
......
......@@ -73,8 +73,8 @@ typedef struct {
typedef struct {
const arch_register_t *reg;
be_req_t req;
be_req_t in_req;
be_req_t req;
be_req_t in_req;
} be_reg_data_t;
/** The generic be nodes attribute type. */
......@@ -92,28 +92,30 @@ typedef struct {
/** The be_IncSP attribute type. */
typedef struct {
be_node_attr_t node_attr; /**< base attributes of every be node. */
int offset; /**< The offset by which the stack shall be expanded/shrinked. */
int offset; /**< The offset by which the stack shall be expanded/shrinked. */
int align; /**< wether stack should be aligned after the
IncSP */
} be_incsp_attr_t;
/** The be_Frame attribute type. */
typedef struct {
be_node_attr_t node_attr; /**< base attributes of every be node. */
ir_entity *ent;
int offset;
be_node_attr_t node_attr; /**< base attributes of every be node. */
ir_entity *ent;
int offset;
} be_frame_attr_t;
/** The be_Call attribute type. */
typedef struct {
be_node_attr_t node_attr; /**< base attributes of every be node. */
ir_entity *ent; /**< The called entity if this is a static call. */
unsigned pop;
ir_type *call_tp; /**< The call type, copied from the original Call node. */
be_node_attr_t node_attr; /**< base attributes of every be node. */
ir_entity *ent; /**< The called entity if this is a static call. */
unsigned pop;
ir_type *call_tp; /**< The call type, copied from the original Call node. */
} be_call_attr_t;
typedef struct {
be_node_attr_t node_attr; /**< base attributes of every be node. */
ir_entity **in_entities;
ir_entity **out_entities;
be_node_attr_t node_attr; /**< base attributes of every be node. */
ir_entity **in_entities;
ir_entity **out_entities;
} be_memperm_attr_t;
ir_op *op_be_Spill;
......@@ -722,16 +724,19 @@ int be_Return_append_node(ir_node *ret, ir_node *node)
return pos;
}
ir_node *be_new_IncSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_node *old_sp, int offset)
ir_node *be_new_IncSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl,
ir_node *old_sp, int offset, int align)
{
be_incsp_attr_t *a;
ir_node *irn;
ir_node *in[1];
in[0] = old_sp;
irn = new_ir_node(NULL, irg, bl, op_be_IncSP, sp->reg_class->mode, sizeof(in) / sizeof(in[0]), in);
irn = new_ir_node(NULL, irg, bl, op_be_IncSP, sp->reg_class->mode,
sizeof(in) / sizeof(in[0]), in);
a = init_node_attr(irn, 1);
a->offset = offset;
a->align = align;
be_node_set_flags(irn, -1, arch_irn_flags_ignore | arch_irn_flags_modify_sp);
......@@ -1110,6 +1115,13 @@ int be_get_IncSP_offset(const ir_node *irn)
return a->offset;
}
int be_get_IncSP_align(const ir_node *irn)
{
const be_incsp_attr_t *a = get_irn_attr_const(irn);
assert(be_is_IncSP(irn));
return a->align;
}
ir_node *be_spill(const arch_env_t *arch_env, ir_node *block, ir_node *irn)
{
ir_graph *irg = get_irn_irg(block);
......
......@@ -259,7 +259,8 @@ ir_node *be_new_SubSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_
* @return A new stack pointer increment/decrement node.
* @note This node sets a register constraint to the @p sp register on its output.
*/
ir_node *be_new_IncSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_node *old_sp, int offset);
ir_node *be_new_IncSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl,
ir_node *old_sp, int offset, int align);
/** Returns the previous node that computes the stack pointer. */
ir_node *be_get_IncSP_pred(ir_node *incsp);
......@@ -277,6 +278,7 @@ void be_set_IncSP_offset(ir_node *irn, int offset);
/** Gets the offset from a IncSP node. */
int be_get_IncSP_offset(const ir_node *irn);
int be_get_IncSP_align(const ir_node *irn);
/** Gets the call entity or NULL if this is no static call. */
ir_entity *be_Call_get_entity(const ir_node *call);
......
......@@ -377,22 +377,23 @@ static void ia32_set_frame_entity(const void *self, ir_node *irn, ir_entity *ent
set_ia32_frame_ent(irn, ent);
}
static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) {
static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias)
{
const ia32_irn_ops_t *ops = self;
if (get_ia32_frame_ent(irn)) {
if (is_ia32_Pop(irn)) {
int omit_fp = be_abi_omit_fp(ops->cg->birg->abi);
if (omit_fp) {
/* Pop nodes modify the stack pointer before calculating the destination
* address, so fix this here
*/
bias -= 4;
}
}
if (get_ia32_frame_ent(irn) == NULL)
return;
add_ia32_am_offs_int(irn, bias);
if (is_ia32_Pop(irn)) {
int omit_fp = be_abi_omit_fp(ops->cg->birg->abi);
if (omit_fp) {
/* Pop nodes modify the stack pointer before calculating the
* destination address, so fix this here
*/
bias -= 4;
}
}
add_ia32_am_offs_int(irn, bias);
}
static int ia32_get_sp_bias(const void *self, const ir_node *node)
......@@ -496,7 +497,7 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_
if (env->flags.try_omit_fp) {
/* simply remove the stack frame here */
curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK);
curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK, 0);
add_irn_dep(curr_sp, *mem);
} else {
const ia32_isa_t *isa = (ia32_isa_t *)env->isa;
......@@ -1632,6 +1633,7 @@ static ia32_isa_t ia32_isa_template = {
&ia32_gp_regs[REG_ESP], /* stack pointer register */
&ia32_gp_regs[REG_EBP], /* base pointer register */
-1, /* stack direction */
16, /* stack alignment */
NULL, /* main environment */
7, /* costs for a spill instruction */
5, /* costs for a reload instruction */
......@@ -2127,6 +2129,8 @@ static lc_opt_enum_int_var_t gas_var = {
static const lc_opt_table_entry_t ia32_options[] = {
LC_OPT_ENT_ENUM_INT("gasmode", "set the GAS compatibility mode", &gas_var),
LC_OPT_ENT_INT("stackalign", "set stack alignment for calls",
&ia32_isa_template.arch_isa.stack_alignment),
LC_OPT_LAST
};
......
......@@ -606,6 +606,7 @@ static mips_isa_t mips_isa_template = {
&mips_gp_regs[REG_SP],
&mips_gp_regs[REG_FP],
-1, /* stack direction */
1, /* stack alignment for calls */
NULL, /* main environment */
7, /* spill costs */
5, /* reload costs */
......
......@@ -649,6 +649,7 @@ static ppc32_isa_t ppc32_isa_template = {
&ppc32_gp_regs[REG_R1], /* stack pointer */
&ppc32_gp_regs[REG_R31], /* base pointer */
-1, /* stack is decreasing */
1, /* call stack alignment */
NULL, /* main environment */
7, /* spill costs */
5, /* reload costs */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment