From 8f4eae8e91e158a775828551f39a209e4e686b0d Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 11 Aug 2011 14:35:43 +0200 Subject: [PATCH] custom stack bias code for sparc --- ir/be/ia32/ia32_new_nodes.c | 2 +- ir/be/sparc/bearch_sparc.c | 6 +- ir/be/sparc/bearch_sparc_t.h | 4 + ir/be/sparc/sparc_cconv.h | 5 +- ir/be/sparc/sparc_finish.c | 45 +------ ir/be/sparc/sparc_stackframe.c | 237 +++++++++++++++++++++++++++++++++ ir/be/sparc/sparc_transform.c | 112 ++-------------- 7 files changed, 261 insertions(+), 150 deletions(-) create mode 100644 ir/be/sparc/sparc_stackframe.c diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index b9658e24e..def6e5f0d 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -190,7 +190,7 @@ static void ia32_dump_node(FILE *F, ir_node *n, dump_reason_t reason) } else if (is_ia32_CMovcc(n) || is_ia32_Setcc(n) || is_ia32_Jcc(n)) { ia32_attr_t *attr = get_ia32_attr(n); fprintf(F, "condition_code = 0x%X\n", (unsigned)get_ia32_condcode(n)); - fprintf(F, "ins_permuted = %u \n", attr->data.ins_permuted); + fprintf(F, "ins_permuted = %u\n", (unsigned)attr->data.ins_permuted); } else if (is_ia32_CopyB(n) || is_ia32_CopyB_i(n)) { fprintf(F, "size = %u\n", get_ia32_copyb_size(n)); diff --git a/ir/be/sparc/bearch_sparc.c b/ir/be/sparc/bearch_sparc.c index e5145e2eb..4a2424338 100644 --- a/ir/be/sparc/bearch_sparc.c +++ b/ir/be/sparc/bearch_sparc.c @@ -114,11 +114,7 @@ static int sparc_get_sp_bias(const ir_node *node) if (get_irn_arity(node) == 3) panic("no support for _reg variant yet"); - /* Note we do not report the change of the SPARC_MIN_STACKSIZE - * size, since we have additional magic in the emitter which - * calculates that! */ - assert(attr->immediate_value <= -SPARC_MIN_STACKSIZE); - return attr->immediate_value + SPARC_MIN_STACKSIZE; + return -attr->immediate_value; } else if (is_sparc_RestoreZero(node)) { return SP_BIAS_RESET; } diff --git a/ir/be/sparc/bearch_sparc_t.h b/ir/be/sparc/bearch_sparc_t.h index 6e69d804e..8c4ca2f62 100644 --- a/ir/be/sparc/bearch_sparc_t.h +++ b/ir/be/sparc/bearch_sparc_t.h @@ -32,6 +32,7 @@ typedef struct sparc_transform_env_t sparc_transform_env_t; typedef struct sparc_isa_t sparc_isa_t; +typedef struct calling_convention_t calling_convention_t; struct sparc_isa_t { arch_env_t base; /**< must be derived from arch_env_t */ @@ -80,4 +81,7 @@ void sparc_introduce_prolog_epilog(ir_graph *irg); void sparc_lower_64bit(void); +void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv); +void sparc_fix_stack_bias(ir_graph *irg); + #endif diff --git a/ir/be/sparc/sparc_cconv.h b/ir/be/sparc/sparc_cconv.h index 7be21cbc3..ac0d6f195 100644 --- a/ir/be/sparc/sparc_cconv.h +++ b/ir/be/sparc/sparc_cconv.h @@ -27,6 +27,7 @@ #define FIRM_BE_SPARC_SPARC_CCONV_H #include "firm_types.h" +#include "bearch_sparc_t.h" #include "../be_types.h" #include "../benode.h" #include "gen_sparc_regalloc_if.h" @@ -50,7 +51,7 @@ typedef struct reg_or_stackslot_t } reg_or_stackslot_t; /** The calling convention info for one call site. */ -typedef struct calling_convention_t +struct calling_convention_t { bool omit_fp; /**< do not use frame pointer (and no save/restore) */ @@ -61,7 +62,7 @@ typedef struct calling_convention_t reg_or_stackslot_t *results; /**< result info. */ unsigned n_reg_results; unsigned *caller_saves; /**< bitset of caller save registers */ -} calling_convention_t; +}; /** * Determine how function parameters and return values are passed. diff --git a/ir/be/sparc/sparc_finish.c b/ir/be/sparc/sparc_finish.c index f94f91685..39ecd47d0 100644 --- a/ir/be/sparc/sparc_finish.c +++ b/ir/be/sparc/sparc_finish.c @@ -131,26 +131,22 @@ void sparc_introduce_prolog_epilog(ir_graph *irg) schedpoint = sched_next(schedpoint); if (!layout->sp_relative) { - ir_node *incsp; ir_node *save = new_bd_sparc_Save_imm(NULL, block, sp, NULL, - -SPARC_MIN_STACKSIZE); + -SPARC_MIN_STACKSIZE-frame_size); arch_set_irn_register(save, sp_reg); sched_add_after(schedpoint, save); schedpoint = save; - incsp = be_new_IncSP(sp_reg, block, save, frame_size, 0); - edges_reroute(initial_sp, incsp); + edges_reroute(initial_sp, save); set_irn_n(save, n_sparc_Save_stack, initial_sp); - sched_add_after(schedpoint, incsp); - schedpoint = incsp; - /* we still need the IncSP even if noone is explicitely using the + /* we still need the Save even if noone is explicitely using the * value. (TODO: this isn't 100% correct yet, something at the end of - * the function should hold the IncSP, even if we use a restore + * the function should hold the Save, even if we use a restore * which just overrides it instead of using the value) */ - if (get_irn_n_edges(incsp) == 0) { - ir_node *in[] = { incsp }; + if (get_irn_n_edges(save) == 0) { + ir_node *in[] = { save }; ir_node *keep = be_new_Keep(block, 1, in); sched_add_after(schedpoint, keep); } @@ -254,11 +250,6 @@ static void finish_sparc_FrameAddr(ir_node *node) dbg_info *dbgi = get_irn_dbg_info(node); ir_node *block = get_nodes_block(node); int sign = 1; - bool sp_relative - = arch_get_irn_register(base) == &sparc_registers[REG_SP]; - if (sp_relative) { - offset += SPARC_MIN_STACKSIZE; - } if (offset < 0) { sign = -1; @@ -298,24 +289,6 @@ static void finish_sparc_FrameAddr(ir_node *node) attr->immediate_value = sign*offset; } -static void finish_sparc_LdSt(ir_node *node) -{ - sparc_load_store_attr_t *attr = get_sparc_load_store_attr(node); - if (attr->is_frame_entity) { - ir_node *base; - bool sp_relative; - if (is_sparc_Ld(node) || is_sparc_Ldf(node)) { - base = get_irn_n(node, n_sparc_Ld_ptr); - } else { - assert(is_sparc_St(node) || is_sparc_Stf(node)); - base = get_irn_n(node, n_sparc_St_ptr); - } - sp_relative = arch_get_irn_register(base) == &sparc_registers[REG_SP]; - if (sp_relative) - attr->base.immediate_value += SPARC_MIN_STACKSIZE; - } -} - static void peephole_be_IncSP(ir_node *node) { ir_node *pred; @@ -509,7 +482,7 @@ void sparc_finish(ir_graph *irg) /* fix stack entity offsets */ be_abi_fix_stack_nodes(irg); - be_abi_fix_stack_bias(irg); + sparc_fix_stack_bias(irg); /* perform peephole optimizations */ clear_irp_opcodes_generic_func(); @@ -521,12 +494,8 @@ void sparc_finish(ir_graph *irg) clear_irp_opcodes_generic_func(); register_peephole_optimisation(op_be_IncSP, finish_be_IncSP); register_peephole_optimisation(op_sparc_FrameAddr, finish_sparc_FrameAddr); - register_peephole_optimisation(op_sparc_Ld, finish_sparc_LdSt); - register_peephole_optimisation(op_sparc_Ldf, finish_sparc_LdSt); register_peephole_optimisation(op_sparc_Return, finish_sparc_Return); register_peephole_optimisation(op_sparc_Save, finish_sparc_Save); - register_peephole_optimisation(op_sparc_St, finish_sparc_LdSt); - register_peephole_optimisation(op_sparc_Stf, finish_sparc_LdSt); be_peephole_opt(irg); be_remove_dead_nodes_from_schedule(irg); diff --git a/ir/be/sparc/sparc_stackframe.c b/ir/be/sparc/sparc_stackframe.c new file mode 100644 index 000000000..22cd5fa84 --- /dev/null +++ b/ir/be/sparc/sparc_stackframe.c @@ -0,0 +1,237 @@ +/* + * Copyright (C) 1995-2010 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 + * @brief Manage addressing into the stackframe + * @author Matthias Braun + * @version $Id$ + */ +#include "config.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" + +static void set_irn_sp_bias(ir_node *node, int new_bias) +{ + if (be_is_IncSP(node)) { + be_set_IncSP_offset(node, new_bias); + } else if (is_sparc_Save(node)) { + sparc_attr_t *attr = get_sparc_attr(node); + attr->immediate_value = -new_bias; + } else if (is_sparc_Restore(node)) { + sparc_attr_t *attr = get_sparc_attr(node); + attr->immediate_value = new_bias; + } +} + +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 */ + sched_foreach(block, irn) { + int irn_bias; + + /* set bias to nodes with entities */ + ir_entity *entity = arch_get_frame_entity(irn); + if (entity != NULL) { + int offset = get_entity_offset(entity); + if (sp_relative) + offset -= bias; + arch_set_frame_offset(irn, offset); + } + + irn_bias = arch_get_sp_bias(irn); + if (irn_bias == 0) { + /* do nothing */ + } else if (irn_bias == SP_BIAS_RESET) { + bias = 0; + } else { + /* adjust values to respect stack alignment */ + int new_bias_unaligned; + int new_bias_aligned; + irn_bias -= free_bytes; + + new_bias_unaligned = bias + irn_bias; + new_bias_aligned = round_up2(new_bias_unaligned, 8); + free_bytes = new_bias_aligned - new_bias_unaligned; + set_irn_sp_bias(irn, new_bias_aligned - bias); + bias = new_bias_aligned; + } + } + +#ifndef NDEBUG + if (block == get_irg_end_block(get_irn_irg(block))) { + assert(bias == 0); + } +#endif + + /* continue at the successor blocks */ + foreach_block_succ(block, edge) { + ir_node *succ = get_edge_src_irn(edge); + if (Block_block_visited(succ)) + continue; + process_bias(succ, sp_relative, bias, free_bytes); + } +} + +static void adjust_entity_offsets(ir_type *type, long offset) +{ + size_t n_members = get_compound_n_members(type); + size_t i; + + for (i = 0; i < n_members; ++i) { + ir_entity *member = get_compound_member(type, i); + int member_offset = get_entity_offset(member); + set_entity_offset(member, member_offset + offset); + } +} + +static ir_type *compute_arg_type(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_type *frame_type = get_irg_frame_type(irg); + size_t n_frame_members = get_compound_n_members(frame_type); + size_t f; + size_t i; + + ir_type *res = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8))); + + /* search for existing value_param entities */ + 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); + 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); + } + + for (i = 0; i < n_params; ++i) { + reg_or_stackslot_t *param = &cconv->parameters[i]; + ir_entity *entity; + + if (param->reg0 != NULL) + 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); + } + set_type_size_bytes(res, cconv->param_stack_size); + + return res; +} + +void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv) +{ + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + ir_type *between_type; + 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); + + layout->frame_type = get_irg_frame_type(irg); + layout->between_type = between_type; + layout->arg_type = compute_arg_type(irg, cconv); + layout->initial_offset = 0; + layout->initial_bias = 0; + layout->sp_relative = cconv->omit_fp; + + assert(N_FRAME_TYPES == 3); + layout->order[0] = layout->frame_type; + layout->order[1] = layout->between_type; + layout->order[2] = layout->arg_type; +} + +/* 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) +{ + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + + /* initially the stackpointer points to the begin of our stackframe. + * Situation at the begin of our function: + * + * high address |----------------------------| + * | ... | + * arg-type | stackarg 1 | + * | stackarg 0 | + * |----------------------------| + * between type | 92-bytes utility+save area | + * stack pointer -> |----------------------------| + * | high end of stackframe | + * | ... | + * | low end of stackframe | + * |----------------------------| + */ + 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 *arg_type = layout->arg_type; + + adjust_entity_offsets(frame_type, -(long)frame_size); + /* no need to adjust between type, it's already at 0 */ + adjust_entity_offsets(arg_type, between_size); +} + +void sparc_fix_stack_bias(ir_graph *irg) +{ + ir_node *start_block = get_irg_start_block(irg); + + process_frame_types(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); + ir_free_resources(irg, IR_RESOURCE_BLOCK_VISITED); +} diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index 4178ed004..98084211b 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -1338,106 +1338,6 @@ static ir_node *gen_Unknown(ir_node *node) panic("Unexpected Unknown mode"); } -/** - * Produces the type which sits between the stack args and the locals on the - * stack. - */ -static ir_type *sparc_get_between_type(void) -{ - static ir_type *between_type = NULL; - static ir_type *between_type0 = NULL; - - if (current_cconv->omit_fp) { - if (between_type0 == NULL) { - between_type0 - = new_type_class(new_id_from_str("sparc_between_type")); - set_type_size_bytes(between_type0, 0); - } - return between_type0; - } - - if (between_type == NULL) { - between_type = new_type_class(new_id_from_str("sparc_between_type")); - set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE); - } - - return between_type; -} - -static ir_type *compute_arg_type(ir_graph *irg) -{ - 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_type *frame_type = get_irg_frame_type(irg); - size_t n_frame_members = get_compound_n_members(frame_type); - size_t f; - size_t i; - - ir_type *res = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8))); - - /* search for existing value_param entities */ - 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); - assert(num < n_params); - if (param_map[num] != NULL) - panic("multiple entities for parameter %u in %+F found", f, irg); - - param = ¤t_cconv->parameters[num]; - if (param->reg0 != NULL) - continue; - - param_map[num] = member; - /* move to new arg_type */ - set_entity_owner(member, res); - } - - for (i = 0; i < n_params; ++i) { - reg_or_stackslot_t *param = ¤t_cconv->parameters[i]; - ir_entity *entity; - - if (param->reg0 != NULL) - 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); - } - - return res; -} - -static void create_stacklayout(ir_graph *irg) -{ - be_stack_layout_t *layout = be_get_irg_stack_layout(irg); - - /* calling conventions must be decided by now */ - assert(current_cconv != NULL); - - memset(layout, 0, sizeof(*layout)); - - layout->frame_type = get_irg_frame_type(irg); - layout->between_type = sparc_get_between_type(); - layout->arg_type = compute_arg_type(irg); - layout->initial_offset = 0; - layout->initial_bias = 0; - layout->sp_relative = current_cconv->omit_fp; - - assert(N_FRAME_TYPES == 3); - layout->order[0] = layout->frame_type; - layout->order[1] = layout->between_type; - layout->order[2] = layout->arg_type; -} - /** * transform the start node to the prolog code */ @@ -1785,6 +1685,7 @@ static ir_node *gen_Call(ir_node *node) ir_mode *mode = get_type_mode(param_type); ir_node *new_values[2]; ir_node *str; + int offset; if (mode_is_float(mode) && param->reg0 != NULL) { unsigned size_bits = get_mode_size_bits(mode); @@ -1817,13 +1718,16 @@ static ir_node *gen_Call(ir_node *node) mode = mode_gp; } - /* create a parameter frame if necessary */ + /* we need to skip over our save area when constructing the call + * arguments on stack */ + offset = param->offset + SPARC_MIN_STACKSIZE; + if (mode_is_float(mode)) { str = create_stf(dbgi, new_block, new_value, incsp, new_mem, - mode, NULL, param->offset, true); + mode, NULL, offset, true); } else { str = new_bd_sparc_St_imm(dbgi, new_block, new_value, incsp, - new_mem, mode, NULL, param->offset, true); + new_mem, mode, NULL, offset, true); } set_irn_pinned(str, op_pin_state_floats); sync_ins[sync_arity++] = str; @@ -2357,7 +2261,7 @@ void sparc_transform_graph(ir_graph *irg) stackorder = be_collect_stacknodes(irg); current_cconv = sparc_decide_calling_convention(get_entity_type(entity), irg); - create_stacklayout(irg); + sparc_create_stacklayout(irg, current_cconv); be_add_parameter_entity_stores(irg); be_transform_graph(irg, NULL); -- 2.20.1