X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_cconv.c;h=564c71fa88ae708d52cde13e8a3836689f433d76;hb=91f9fd8a65f0db8bcf956cfe54ac4cca394c45e8;hp=211699e8ed37c3da6276dc0a5facf4db9d72b564;hpb=22eb6c0a72ad11e96469143d4764375f6d2c3ef9;p=libfirm diff --git a/ir/be/sparc/sparc_cconv.c b/ir/be/sparc/sparc_cconv.c index 211699e8e..564c71fa8 100644 --- a/ir/be/sparc/sparc_cconv.c +++ b/ir/be/sparc/sparc_cconv.c @@ -21,10 +21,11 @@ * @file * @brief calling convention helpers * @author Matthias Braun - * @version $Id$ */ #include "config.h" +#include "be_t.h" +#include "beirg.h" #include "sparc_cconv.h" #include "irmode.h" #include "irgwalk.h" @@ -37,7 +38,9 @@ static const unsigned ignore_regs[] = { REG_G0, - /* reserved for sparc ABI: */ + /* used in case an address offset does not fit into an immediate: */ + REG_G4, + /* reserved for SPARC ABI: */ REG_G5, REG_G6, REG_G7, @@ -50,6 +53,8 @@ static const unsigned ignore_regs[] = { REG_FPFLAGS, REG_FLAGS, REG_Y, + + REG_F31, }; static const arch_register_t* const param_regs[] = { @@ -60,6 +65,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], @@ -74,52 +80,60 @@ static const arch_register_t* const float_result_regs[] = { static arch_register_req_t float_result_reqs_double[8]; static arch_register_req_t float_result_reqs_quad[8]; -static const arch_register_t *const caller_saves[] = { - &sparc_registers[REG_G1], - &sparc_registers[REG_G2], - &sparc_registers[REG_G3], - &sparc_registers[REG_G4], - &sparc_registers[REG_O0], - &sparc_registers[REG_O1], - &sparc_registers[REG_O2], - &sparc_registers[REG_O3], - &sparc_registers[REG_O4], - &sparc_registers[REG_O5], - &sparc_registers[REG_F0], - &sparc_registers[REG_F1], - &sparc_registers[REG_F2], - &sparc_registers[REG_F3], - &sparc_registers[REG_F4], - &sparc_registers[REG_F5], - &sparc_registers[REG_F6], - &sparc_registers[REG_F7], - &sparc_registers[REG_F8], - &sparc_registers[REG_F9], - &sparc_registers[REG_F10], - &sparc_registers[REG_F11], - &sparc_registers[REG_F12], - &sparc_registers[REG_F13], - &sparc_registers[REG_F14], - &sparc_registers[REG_F15], - &sparc_registers[REG_F16], - &sparc_registers[REG_F17], - &sparc_registers[REG_F18], - &sparc_registers[REG_F19], - &sparc_registers[REG_F20], - &sparc_registers[REG_F21], - &sparc_registers[REG_F22], - &sparc_registers[REG_F23], - &sparc_registers[REG_F24], - &sparc_registers[REG_F25], - &sparc_registers[REG_F26], - &sparc_registers[REG_F27], - &sparc_registers[REG_F28], - &sparc_registers[REG_F29], - &sparc_registers[REG_F30], - &sparc_registers[REG_F31], +static const unsigned caller_saves[] = { + REG_G1, + REG_G2, + REG_G3, + REG_O0, + REG_O1, + REG_O2, + REG_O3, + REG_O4, + REG_O5, + REG_F0, + REG_F1, + REG_F2, + REG_F3, + REG_F4, + REG_F5, + REG_F6, + REG_F7, + REG_F8, + REG_F9, + REG_F10, + REG_F11, + REG_F12, + REG_F13, + REG_F14, + REG_F15, + REG_F16, + REG_F17, + REG_F18, + REG_F19, + REG_F20, + REG_F21, + REG_F22, + REG_F23, + REG_F24, + REG_F25, + REG_F26, + REG_F27, + REG_F28, + REG_F29, + REG_F30, + REG_FLAGS, + REG_FPFLAGS, + REG_Y, }; static unsigned default_caller_saves[BITSET_SIZE_ELEMS(N_SPARC_REGISTERS)]; +static const unsigned returns_twice_saved[] = { + REG_SP, + REG_FRAME_POINTER, + REG_I7 +}; +static unsigned default_returns_twice_saves[BITSET_SIZE_ELEMS(N_SPARC_REGISTERS)]; + /** * Maps an input register representing the i'th register input * to the i'th register output. @@ -135,8 +149,6 @@ static const arch_register_t *map_i_to_o_reg(const arch_register_t *reg) static void check_omit_fp(ir_node *node, void *env) { - bool *can_omit_fp = (bool*) env; - /* omit-fp is not possible if: * - we have allocations on the stack * - we have calls (with the exception of tail-calls once we support them) @@ -144,6 +156,7 @@ static void check_omit_fp(ir_node *node, void *env) if ((is_Alloc(node) && get_Alloc_where(node) == stack_alloc) || (is_Free(node) && get_Free_where(node) == stack_alloc) || is_Call(node)) { + bool *can_omit_fp = (bool*) env; *can_omit_fp = false; } } @@ -159,50 +172,57 @@ static unsigned determine_n_float_regs(ir_mode *mode) case 128: return 4; default: - panic("sparc: Unexpected floatingpoint mode %+F", mode); + panic("Unexpected floatingpoint mode %+F", mode); } } calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, ir_graph *irg) { - unsigned stack_offset = 0; - unsigned n_param_regs_used = 0; - int n_param_regs = ARRAY_SIZE(param_regs); - unsigned n_float_result_regs = ARRAY_SIZE(float_result_regs); - bool omit_fp = false; - reg_or_stackslot_t *params; - reg_or_stackslot_t *results; - int n_params; - int n_results; - int i; - int regnum; - unsigned float_regnum; - unsigned n_reg_results = 0; - calling_convention_t *cconv; - unsigned *caller_saves; - + bool omit_fp = false; if (irg != NULL) { - const be_options_t *options = be_get_irg_options(irg); - omit_fp = options->omit_fp; - irg_walk_graph(irg, check_omit_fp, NULL, &omit_fp); + omit_fp = be_options.omit_fp; + /* our current vaarg handling needs the standard space to store the + * args 0-5 in it */ + if (get_method_variadicity(function_type) == variadicity_variadic) + omit_fp = false; + if (omit_fp == true) { + irg_walk_graph(irg, check_omit_fp, NULL, &omit_fp); + } } - caller_saves = rbitset_malloc(N_SPARC_REGISTERS); - rbitset_copy(caller_saves, default_caller_saves, N_SPARC_REGISTERS); + mtp_additional_properties mtp + = get_method_additional_properties(function_type); + unsigned *caller_saves = rbitset_malloc(N_SPARC_REGISTERS); + if (mtp & mtp_property_returns_twice) { + rbitset_copy(caller_saves, default_returns_twice_saves, + N_SPARC_REGISTERS); + } else { + rbitset_copy(caller_saves, default_caller_saves, N_SPARC_REGISTERS); + } /* determine how parameters are passed */ - n_params = get_method_n_params(function_type); - regnum = 0; - params = XMALLOCNZ(reg_or_stackslot_t, n_params); + int n_params = get_method_n_params(function_type); + int regnum = 0; + reg_or_stackslot_t *params = XMALLOCNZ(reg_or_stackslot_t, n_params); - for (i = 0; i < n_params; ++i) { + int n_param_regs = ARRAY_SIZE(param_regs); + unsigned stack_offset = 0; + for (int i = 0; i < n_params; ++i) { ir_type *param_type = get_method_param_type(function_type,i); - ir_mode *mode = get_type_mode(param_type); - int bits = get_mode_size_bits(mode); - reg_or_stackslot_t *param = ¶ms[i]; + ir_mode *mode; + int bits; + reg_or_stackslot_t *param; + + if (is_compound_type(param_type)) + panic("compound arguments not supported yet"); + + mode = get_type_mode(param_type); + bits = get_mode_size_bits(mode); + param = ¶ms[i]; - if (i == 0 && function_type->attr.ma.has_compound_ret_parameter) { + if (i == 0 && + (get_method_calling_convention(function_type) & cc_compound_ret)) { assert(mode_is_reference(mode) && bits == 32); /* special case, we have reserved space for this on the between * type */ @@ -222,15 +242,15 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, } else { param->type = param_type; param->offset = stack_offset; - /* increase offset 4 bytes so everything is aligned */ - stack_offset += bits > 32 ? bits/8 : 4; + /* increase offset by at least SPARC_REGISTER_SIZE bytes so everything is aligned */ + stack_offset += bits > 8 * SPARC_REGISTER_SIZE ? bits / 8 : SPARC_REGISTER_SIZE; continue; } /* we might need a 2nd 32bit component (for 64bit or double values) */ if (bits > 32) { if (bits > 64) - panic("only 32 and 64bit modes supported in sparc backend"); + panic("only 32 and 64bit modes supported"); if (regnum < n_param_regs) { const arch_register_t *reg = param_regs[regnum]; @@ -245,18 +265,20 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, param->type = type; param->offset = stack_offset; assert(get_mode_size_bits(regmode) == 32); - stack_offset += 4; + stack_offset += SPARC_REGISTER_SIZE; } } } - n_param_regs_used = regnum; + unsigned n_param_regs_used = regnum; /* determine how results are passed */ - n_results = get_method_n_ress(function_type); - regnum = 0; - float_regnum = 0; - results = XMALLOCNZ(reg_or_stackslot_t, n_results); - for (i = 0; i < n_results; ++i) { + int n_results = get_method_n_ress(function_type); + unsigned float_regnum = 0; + unsigned n_reg_results = 0; + unsigned n_float_result_regs = ARRAY_SIZE(float_result_regs); + reg_or_stackslot_t *results = XMALLOCNZ(reg_or_stackslot_t, n_results); + regnum = 0; + for (int i = 0; i < n_results; ++i) { ir_type *result_type = get_method_res_type(function_type, i); ir_mode *result_mode = get_type_mode(result_type); reg_or_stackslot_t *result = &results[i]; @@ -266,7 +288,7 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, unsigned next_reg = round_up2(float_regnum, n_regs); if (next_reg >= n_float_result_regs) { - panic("Too many float results for sparc backend"); + panic("Too many float results"); } else { const arch_register_t *reg = float_result_regs[next_reg]; rbitset_clear(caller_saves, reg->global_index); @@ -282,7 +304,7 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, rbitset_clear(caller_saves, reg->global_index+2); rbitset_clear(caller_saves, reg->global_index+3); } else { - panic("invalid number of registers in sparc float result"); + panic("invalid number of registers in result"); } float_regnum = next_reg + n_regs; @@ -290,11 +312,11 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, } } else { if (get_mode_size_bits(result_mode) > 32) { - panic("Results with more than 32bits not supported by sparc backend yet"); + panic("Results with more than 32bits not supported yet"); } if (regnum >= n_param_regs) { - panic("Too many results for sparc backend"); + panic("Too many results"); } else { const arch_register_t *reg = param_regs[regnum++]; if (irg == NULL || omit_fp) @@ -307,7 +329,7 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, } } - cconv = XMALLOCZ(calling_convention_t); + calling_convention_t *cconv = XMALLOCZ(calling_convention_t); cconv->parameters = params; cconv->param_stack_size = stack_offset; cconv->n_param_regs = n_param_regs_used; @@ -323,7 +345,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) { @@ -344,18 +365,25 @@ void sparc_free_calling_convention(calling_convention_t *cconv) void sparc_cconv_init(void) { - size_t i; - for (i = 0; i < ARRAY_SIZE(caller_saves); ++i) { - rbitset_set(default_caller_saves, caller_saves[i]->global_index); + for (size_t i = 0; i < ARRAY_SIZE(caller_saves); ++i) { + rbitset_set(default_caller_saves, caller_saves[i]); + } + + rbitset_set_all(default_returns_twice_saves, N_SPARC_REGISTERS); + for (size_t i = 0; i < ARRAY_SIZE(returns_twice_saved); ++i) { + rbitset_clear(default_returns_twice_saves, returns_twice_saved[i]); + } + for (size_t i = 0; i < ARRAY_SIZE(ignore_regs); ++i) { + rbitset_clear(default_returns_twice_saves, ignore_regs[i]); } - for (i = 0; i < ARRAY_SIZE(float_result_reqs_double); i += 2) { + for (size_t i = 0; i < ARRAY_SIZE(float_result_reqs_double); i += 2) { arch_register_req_t *req = &float_result_reqs_double[i]; *req = *float_result_regs[i]->single_req; req->type |= arch_register_req_type_aligned; req->width = 2; } - for (i = 0; i < ARRAY_SIZE(float_result_reqs_quad); i += 4) { + for (size_t i = 0; i < ARRAY_SIZE(float_result_reqs_quad); i += 4) { arch_register_req_t *req = &float_result_reqs_quad[i]; *req = *float_result_regs[i]->single_req; req->type |= arch_register_req_type_aligned;