X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_stackframe.c;h=fdadc757b6bc9e224f43acca329b1dddb05e5f00;hb=b009bb03a362a0a9584a1928d7b8b1aded6d6232;hp=e08043fa168666cefd498871c37e44835dc6313b;hpb=22eb6c0a72ad11e96469143d4764375f6d2c3ef9;p=libfirm diff --git a/ir/be/sparc/sparc_stackframe.c b/ir/be/sparc/sparc_stackframe.c index e08043fa1..fdadc757b 100644 --- a/ir/be/sparc/sparc_stackframe.c +++ b/ir/be/sparc/sparc_stackframe.c @@ -21,19 +21,20 @@ * @file * @brief Manage addressing into the stackframe * @author Matthias Braun - * @version $Id$ */ #include "config.h" +#include "beirg.h" +#include "error.h" #include "firm_types.h" #include "irnode_t.h" #include "bearch_sparc_t.h" #include "sparc_new_nodes.h" #include "sparc_cconv.h" #include "bitfiddle.h" -#include "../bearch.h" -#include "../benode.h" -#include "../besched.h" +#include "bearch.h" +#include "benode.h" +#include "besched.h" static void set_irn_sp_bias(ir_node *node, int new_bias) { @@ -48,11 +49,9 @@ static void set_irn_sp_bias(ir_node *node, int new_bias) } } -static void process_bias(ir_node *block, bool sp_relative, int bias, int free_bytes) +static void process_bias(ir_node *block, bool sp_relative, int bias, + int free_bytes) { - const ir_edge_t *edge; - ir_node *irn; - mark_Block_block_visited(block); /* process schedule */ @@ -64,10 +63,18 @@ static void process_bias(ir_node *block, bool sp_relative, int bias, int free_by if (entity != NULL) { int offset = get_entity_offset(entity); if (sp_relative) - offset -= bias; + offset += bias + SPARC_MIN_STACKSIZE; arch_set_frame_offset(irn, offset); } + /* The additional alignment bytes cannot be used + * anymore after alloca. */ + if (is_sparc_SubSP(irn)) { + free_bytes = 0; + } else if (is_sparc_AddSP(irn)) { + assert(free_bytes == 0); + } + irn_bias = arch_get_sp_bias(irn); if (irn_bias == 0) { /* do nothing */ @@ -80,7 +87,8 @@ static void process_bias(ir_node *block, bool sp_relative, int bias, int free_by irn_bias -= free_bytes; new_bias_unaligned = bias + irn_bias; - new_bias_aligned = round_up2(new_bias_unaligned, 8); + new_bias_aligned + = round_up2(new_bias_unaligned, SPARC_STACK_ALIGNMENT); free_bytes = new_bias_aligned - new_bias_unaligned; set_irn_sp_bias(irn, new_bias_aligned - bias); bias = new_bias_aligned; @@ -114,12 +122,66 @@ static void adjust_entity_offsets(ir_type *type, long offset) } } -static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv) +/** + * Perform some fixups for variadic functions. + * To make the rest of the frontend code easier to understand we add + * "dummy" parameters until the number of parameters transmitted in registers. + * (because otherwise the backend wouldn't store the value of the register + * parameters into memory for the VLA magic) + */ +bool sparc_variadic_fixups(ir_graph *irg, calling_convention_t *cconv) +{ + ir_entity *entity = get_irg_entity(irg); + ir_type *mtp = get_entity_type(entity); + if (get_method_variadicity(mtp) != variadicity_variadic) + return false; + + if (cconv->n_param_regs >= SPARC_N_PARAM_REGS) + return false; + + { + size_t n_params = get_method_n_params(mtp); + type_dbg_info *dbgi = get_type_dbg_info(mtp); + size_t n_ress = get_method_n_ress(mtp); + size_t new_n_params + = n_params + (SPARC_N_PARAM_REGS - cconv->n_param_regs); + ir_type *new_mtp = new_d_type_method(new_n_params, n_ress, dbgi); + ir_mode *gp_reg_mode = sparc_reg_classes[CLASS_sparc_gp].mode; + ir_type *gp_reg_type = get_type_for_mode(gp_reg_mode); + ir_type *frame_type = get_irg_frame_type(irg); + size_t i; + + for (i = 0; i < n_ress; ++i) { + ir_type *type = get_method_res_type(mtp, i); + set_method_res_type(new_mtp, i, type); + } + for (i = 0; i < n_params; ++i) { + ir_type *type = get_method_param_type(mtp, i); + set_method_param_type(new_mtp, i, type); + } + for ( ; i < new_n_params; ++i) { + set_method_param_type(new_mtp, i, gp_reg_type); + new_parameter_entity(frame_type, i, gp_reg_type); + } + + set_method_variadicity(new_mtp, get_method_variadicity(mtp)); + set_method_calling_convention(new_mtp, get_method_calling_convention(mtp)); + set_method_additional_properties(new_mtp, get_method_additional_properties(mtp)); + set_higher_type(new_mtp, mtp); + + set_entity_type(entity, new_mtp); + } + return true; +} + +static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv, + ir_type *between_type) { - ir_entity *entity = get_irg_entity(irg); - ir_type *mtp = get_entity_type(entity); - size_t n_params = get_method_n_params(mtp); - ir_entity **param_map = ALLOCANZ(ir_entity*, n_params); + ir_entity *va_start_entity = NULL; + const ir_entity *entity = get_irg_entity(irg); + const ir_type *mtp = get_entity_type(entity); + size_t n_params = get_method_n_params(mtp); + ir_entity **param_map = ALLOCANZ(ir_entity*, n_params); ir_type *frame_type = get_irg_frame_type(irg); size_t n_frame_members = get_compound_n_members(frame_type); @@ -132,36 +194,65 @@ static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv) for (f = n_frame_members; f > 0; ) { ir_entity *member = get_compound_member(frame_type, --f); size_t num; - const reg_or_stackslot_t *param; if (!is_parameter_entity(member)) continue; num = get_entity_parameter_number(member); + if (num == IR_VA_START_PARAMETER_NUMBER) { + if (va_start_entity != NULL) + panic("multiple va_start entities found (%+F,%+F)", + va_start_entity, member); + va_start_entity = member; + continue; + } assert(num < n_params); if (param_map[num] != NULL) panic("multiple entities for parameter %u in %+F found", f, irg); - param = &cconv->parameters[num]; - if (param->reg0 != NULL) - continue; - param_map[num] = member; /* move to new arg_type */ set_entity_owner(member, res); } + /* calculate offsets/create missing entities */ for (i = 0; i < n_params; ++i) { - reg_or_stackslot_t *param = &cconv->parameters[i]; - ir_entity *entity; - - if (param->reg0 != NULL) + reg_or_stackslot_t *param = &cconv->parameters[i]; + ir_entity *entity = param_map[i]; + + if (param->reg0 != NULL) { + /* use reserved spill space on between type */ + if (entity != NULL) { + long offset = SPARC_PARAMS_SPILL_OFFSET + i * SPARC_REGISTER_SIZE; + assert(i < SPARC_N_PARAM_REGS); + set_entity_owner(entity, between_type); + set_entity_offset(entity, offset); + } continue; - entity = param_map[i]; + } + if (entity == NULL) entity = new_parameter_entity(res, i, param->type); param->entity = entity; set_entity_offset(entity, param->offset); } + + if (va_start_entity != NULL) { + /* sparc_variadic_fixups() fiddled with our type, find out the + * original number of parameters */ + ir_type *non_lowered = get_higher_type(mtp); + size_t orig_n_params = get_method_n_params(non_lowered); + long offset; + assert(get_method_variadicity(mtp) == variadicity_variadic); + if (orig_n_params < n_params) { + assert(param_map[orig_n_params] != NULL); + offset = get_entity_offset(param_map[orig_n_params]); + set_entity_owner(va_start_entity, between_type); + set_entity_offset(va_start_entity, offset); + } else { + set_entity_owner(va_start_entity, res); + set_entity_offset(va_start_entity, cconv->param_stack_size); + } + } set_type_size_bytes(res, cconv->param_stack_size); return res; @@ -174,11 +265,15 @@ void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv) memset(layout, 0, sizeof(*layout)); between_type = new_type_class(new_id_from_str("sparc_between_type")); - set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE); + if (cconv->omit_fp) { + set_type_size_bytes(between_type, 0); + } else { + set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE); + } layout->frame_type = get_irg_frame_type(irg); layout->between_type = between_type; - layout->arg_type = compute_arg_type(irg, cconv); + layout->arg_type = compute_arg_type(irg, cconv, between_type); layout->initial_offset = 0; layout->initial_bias = 0; layout->sp_relative = cconv->omit_fp; @@ -192,7 +287,7 @@ void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv) /* Assign entity offsets, to all stack-related entities. * The offsets are relative to the begin of the stack frame. */ -static void process_frame_types(ir_graph *irg) +void sparc_adjust_stack_entity_offsets(ir_graph *irg) { be_stack_layout_t *layout = be_get_irg_stack_layout(irg); @@ -216,8 +311,27 @@ static void process_frame_types(ir_graph *irg) ir_type *between_type = layout->between_type; unsigned between_size = get_type_size_bytes(between_type); - ir_type *frame_type = get_irg_frame_type(irg); - unsigned frame_size = get_type_size_bytes(frame_type); + ir_type *frame_type = get_irg_frame_type(irg); + unsigned frame_size = get_type_size_bytes(frame_type); + unsigned frame_align = get_type_alignment_bytes(frame_type); + + /* There's the tricky case of the stackframe size not being a multiple + * of the alignment. There are 2 variants: + * + * - frame-pointer relative addressing: + * Increase frame_size in case it is not a multiple of the alignment as we + * address entities from the "top" with negative offsets + * - stack-pointer relative addressing: + * Stackframesize + SPARC_MIN_STACK_SIZE has to be aligned. Increase + * frame_size accordingly. + */ + if (!layout->sp_relative) { + frame_size = (frame_size + frame_align-1) & ~(frame_align-1); + } else { + unsigned misalign = (SPARC_MIN_STACKSIZE+frame_size) % frame_align; + frame_size += misalign; + } + set_type_size_bytes(frame_type, frame_size); ir_type *arg_type = layout->arg_type; @@ -228,12 +342,12 @@ static void process_frame_types(ir_graph *irg) void sparc_fix_stack_bias(ir_graph *irg) { - ir_node *start_block = get_irg_start_block(irg); + bool sp_relative = be_get_irg_stack_layout(irg)->sp_relative; - process_frame_types(irg); + ir_node *start_block = get_irg_start_block(irg); ir_reserve_resources(irg, IR_RESOURCE_BLOCK_VISITED); inc_irg_block_visited(irg); - process_bias(start_block, be_get_irg_stack_layout(irg)->sp_relative, 0, 0); + process_bias(start_block, sp_relative, 0, 0); ir_free_resources(irg, IR_RESOURCE_BLOCK_VISITED); }