From 5c34afb830f4a9233b659c95a9f71643f8421f86 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Mon, 22 Aug 2011 16:11:58 +0200 Subject: [PATCH] sparc: support va_start --- ir/be/beabihelper.c | 19 ++++-- ir/be/sparc/bearch_sparc_t.h | 3 + ir/be/sparc/sparc_cconv.c | 2 +- ir/be/sparc/sparc_stackframe.c | 113 +++++++++++++++++++++++++++------ ir/be/sparc/sparc_transform.c | 56 +++++++++------- 5 files changed, 148 insertions(+), 45 deletions(-) diff --git a/ir/be/beabihelper.c b/ir/be/beabihelper.c index c5f95551f..7d3efb512 100644 --- a/ir/be/beabihelper.c +++ b/ir/be/beabihelper.c @@ -669,10 +669,9 @@ void be_free_stackorder(be_stackorder_t *env) free(env); } -void be_add_parameter_entity_stores(ir_graph *irg) +static void create_stores_for_type(ir_graph *irg, ir_type *type) { - ir_type *frame_type = get_irg_frame_type(irg); - size_t n = get_compound_n_members(frame_type); + size_t n = get_compound_n_members(type); ir_node *frame = get_irg_frame(irg); ir_node *initial_mem = get_irg_initial_mem(irg); ir_node *mem = initial_mem; @@ -684,7 +683,7 @@ void be_add_parameter_entity_stores(ir_graph *irg) /* all parameter entities left in the frame type require stores. * (The ones passed on the stack have been moved to the arg type) */ for (i = 0; i < n; ++i) { - ir_entity *entity = get_compound_member(frame_type, i); + ir_entity *entity = get_compound_member(type, i); ir_node *addr; size_t arg; if (!is_parameter_entity(entity)) @@ -727,3 +726,15 @@ void be_add_parameter_entity_stores(ir_graph *irg) set_Store_mem(first_store, initial_mem); } } + +void be_add_parameter_entity_stores(ir_graph *irg) +{ + ir_type *frame_type = get_irg_frame_type(irg); + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + ir_type *between_type = layout->between_type; + + create_stores_for_type(irg, frame_type); + if (between_type != NULL) { + create_stores_for_type(irg, between_type); + } +} diff --git a/ir/be/sparc/bearch_sparc_t.h b/ir/be/sparc/bearch_sparc_t.h index 4df7b506f..bc150f912 100644 --- a/ir/be/sparc/bearch_sparc_t.h +++ b/ir/be/sparc/bearch_sparc_t.h @@ -78,6 +78,8 @@ extern const arch_irn_ops_t sparc_irn_ops; #define SPARC_IMMEDIATE_MAX 4095 #define SPARC_MIN_STACKSIZE 92 #define SPARC_AGGREGATE_RETURN_OFFSET 64 +#define SPARC_PARAMS_SPILL_OFFSET 68 +#define SPARC_N_PARAM_REGS 6 static inline bool sparc_is_value_imm_encodeable(int32_t value) { @@ -90,6 +92,7 @@ void sparc_introduce_prolog_epilog(ir_graph *irg); void sparc_lower_64bit(void); +bool sparc_variadic_fixups(ir_graph *irg, calling_convention_t *cconv); void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv); void sparc_fix_stack_bias(ir_graph *irg); diff --git a/ir/be/sparc/sparc_cconv.c b/ir/be/sparc/sparc_cconv.c index 211699e8e..f1bc958dc 100644 --- a/ir/be/sparc/sparc_cconv.c +++ b/ir/be/sparc/sparc_cconv.c @@ -60,6 +60,7 @@ static const arch_register_t* const param_regs[] = { &sparc_registers[REG_I4], &sparc_registers[REG_I5], }; +COMPILETIME_ASSERT(ARRAY_SIZE(param_regs) == SPARC_N_PARAM_REGS, sparcparamregs) static const arch_register_t* const float_result_regs[] = { &sparc_registers[REG_F0], @@ -323,7 +324,6 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, struct obstack *obst = &birg->obst; size_t r; - assert(birg->allocatable_regs == NULL); birg->allocatable_regs = rbitset_obstack_alloc(obst, N_SPARC_REGISTERS); rbitset_set_all(birg->allocatable_regs, N_SPARC_REGISTERS); for (r = 0; r < n_ignores; ++r) { diff --git a/ir/be/sparc/sparc_stackframe.c b/ir/be/sparc/sparc_stackframe.c index e08043fa1..5d97933e3 100644 --- a/ir/be/sparc/sparc_stackframe.c +++ b/ir/be/sparc/sparc_stackframe.c @@ -48,7 +48,8 @@ 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; @@ -114,12 +115,59 @@ static void adjust_entity_offsets(ir_type *type, long offset) } } -static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv) +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); - size_t n_params = get_method_n_params(mtp); - ir_entity **param_map = ALLOCANZ(ir_entity*, n_params); + 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_lowered_type(mtp, new_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 *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 +180,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*4; + 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_associated_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; @@ -178,7 +255,7 @@ void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv) 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; @@ -228,7 +305,7 @@ 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); + ir_node *start_block = get_irg_start_block(irg); process_frame_types(irg); diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index 9f5785c44..67267c531 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -2061,16 +2061,13 @@ static ir_node *gen_Proj_Start(ir_node *node) static ir_node *gen_Proj_Proj_Start(ir_node *node) { - long pn = get_Proj_proj(node); - ir_node *block = get_nodes_block(node); - ir_graph *irg = get_irn_irg(node); - ir_node *new_block = be_transform_node(block); - ir_entity *entity = get_irg_entity(irg); - ir_type *method_type = get_entity_type(entity); - ir_type *param_type = get_method_param_type(method_type, pn); - ir_node *args = get_Proj_pred(node); - ir_node *start = get_Proj_pred(args); - ir_node *new_start = be_transform_node(start); + long pn = get_Proj_proj(node); + ir_node *block = get_nodes_block(node); + ir_graph *irg = get_irn_irg(node); + ir_node *new_block = be_transform_node(block); + ir_node *args = get_Proj_pred(node); + ir_node *start = get_Proj_pred(args); + ir_node *new_start = be_transform_node(start); const reg_or_stackslot_t *param; /* Proj->Proj->Start must be a method argument */ @@ -2080,22 +2077,32 @@ static ir_node *gen_Proj_Proj_Start(ir_node *node) if (param->reg0 != NULL) { /* argument transmitted in register */ - ir_mode *mode = get_type_mode(param_type); const arch_register_t *reg = param->reg0; ir_mode *reg_mode = reg->reg_class->mode; - long pn = param->reg_offset + start_params_offset; - ir_node *value = new_r_Proj(new_start, reg_mode, pn); + long new_pn = param->reg_offset + start_params_offset; + ir_node *value = new_r_Proj(new_start, reg_mode, new_pn); + bool is_float = false; + + { + ir_entity *entity = get_irg_entity(irg); + ir_type *method_type = get_entity_type(entity); + if (pn < (long)get_method_n_params(method_type)) { + ir_type *param_type = get_method_param_type(method_type, pn); + ir_mode *mode = get_type_mode(param_type); + is_float = mode_is_float(mode); + } + } - if (mode_is_float(mode)) { + if (is_float) { const arch_register_t *reg1 = param->reg1; ir_node *value1 = NULL; if (reg1 != NULL) { ir_mode *reg1_mode = reg1->reg_class->mode; - value1 = new_r_Proj(new_start, reg1_mode, pn+1); + value1 = new_r_Proj(new_start, reg1_mode, new_pn+1); } else if (param->entity != NULL) { - ir_node *fp = get_initial_fp(irg); - ir_node *mem = get_initial_mem(irg); + ir_node *fp = get_initial_fp(irg); + ir_node *mem = get_initial_mem(irg); ir_node *ld = new_bd_sparc_Ld_imm(NULL, new_block, fp, mem, mode_gp, param->entity, 0, true); @@ -2108,11 +2115,11 @@ static ir_node *gen_Proj_Proj_Start(ir_node *node) return value; } else { /* argument transmitted on stack */ - ir_node *mem = get_initial_mem(irg); - ir_mode *mode = get_type_mode(param->type); - ir_node *base = get_frame_base(irg); - ir_node *load; - ir_node *value; + ir_node *mem = get_initial_mem(irg); + ir_mode *mode = get_type_mode(param->type); + ir_node *base = get_frame_base(irg); + ir_node *load; + ir_node *value; if (mode_is_float(mode)) { load = create_ldf(NULL, new_block, base, mem, mode, @@ -2290,6 +2297,11 @@ void sparc_transform_graph(ir_graph *irg) stackorder = be_collect_stacknodes(irg); current_cconv = sparc_decide_calling_convention(get_entity_type(entity), irg); + if (sparc_variadic_fixups(irg, current_cconv)) { + sparc_free_calling_convention(current_cconv); + current_cconv + = sparc_decide_calling_convention(get_entity_type(entity), irg); + } sparc_create_stacklayout(irg, current_cconv); be_add_parameter_entity_stores(irg); -- 2.20.1