X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_cconv.c;h=132f704cef2e9c131b93d386fedce6c150f877ad;hb=52a818d61941174d4a7d39f37db43b1c7a7b984d;hp=7e7af839792cfe58f89f99c5efcfcab7031988f7;hpb=1a3b7d363474ab544c13093a2f0b578718d37c7a;p=libfirm diff --git a/ir/be/sparc/sparc_cconv.c b/ir/be/sparc/sparc_cconv.c index 7e7af8397..132f704ce 100644 --- a/ir/be/sparc/sparc_cconv.c +++ b/ir/be/sparc/sparc_cconv.c @@ -21,7 +21,6 @@ * @file * @brief calling convention helpers * @author Matthias Braun - * @version $Id$ */ #include "config.h" @@ -33,10 +32,13 @@ #include "util.h" #include "error.h" #include "gen_sparc_regalloc_if.h" +#include "bitfiddle.h" 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, @@ -51,6 +53,81 @@ static const unsigned ignore_regs[] = { REG_Y, }; +static const arch_register_t* const param_regs[] = { + &sparc_registers[REG_I0], + &sparc_registers[REG_I1], + &sparc_registers[REG_I2], + &sparc_registers[REG_I3], + &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], + &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], +}; +static arch_register_req_t float_result_reqs_double[8]; +static arch_register_req_t float_result_reqs_quad[8]; + +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_F31, +}; +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. @@ -79,26 +156,60 @@ static void check_omit_fp(ir_node *node, void *env) } } +static unsigned determine_n_float_regs(ir_mode *mode) +{ + unsigned bits = get_mode_size_bits(mode); + switch (bits) { + case 32: + return 1; + case 64: + return 2; + case 128: + return 4; + default: + panic("sparc: Unexpected floatingpoint mode %+F", mode); + } +} + calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, ir_graph *irg) { - int stack_offset = 0; + unsigned stack_offset = 0; + unsigned n_param_regs_used = 0; int n_param_regs = ARRAY_SIZE(param_regs); - int n_float_result_regs = ARRAY_SIZE(float_result_regs); + unsigned n_float_result_regs = ARRAY_SIZE(float_result_regs); bool omit_fp = false; + mtp_additional_properties mtp + = get_method_additional_properties(function_type); reg_or_stackslot_t *params; reg_or_stackslot_t *results; int n_params; int n_results; int i; int regnum; - int float_regnum; + unsigned float_regnum; + unsigned n_reg_results = 0; calling_convention_t *cconv; + unsigned *caller_saves; 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); + /* 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); + 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 */ @@ -108,20 +219,40 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, for (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("sparc: compound arguments not supported yet"); + + mode = get_type_mode(param_type); + bits = get_mode_size_bits(mode); + param = ¶ms[i]; + + 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 */ + param->type = param_type; + param->offset = -SPARC_MIN_STACKSIZE+SPARC_AGGREGATE_RETURN_OFFSET; + continue; + } if (regnum < n_param_regs) { - const arch_register_t *reg = param_regs[regnum++]; + const arch_register_t *reg = param_regs[regnum]; if (irg == NULL || omit_fp) reg = map_i_to_o_reg(reg); - param->reg0 = reg; + param->reg0 = reg; + param->req0 = reg->single_req; + param->reg_offset = regnum; + ++regnum; } 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; } @@ -131,20 +262,23 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, panic("only 32 and 64bit modes supported in sparc backend"); if (regnum < n_param_regs) { - const arch_register_t *reg = param_regs[regnum++]; + const arch_register_t *reg = param_regs[regnum]; if (irg == NULL || omit_fp) reg = map_i_to_o_reg(reg); - param->reg1 = reg; + param->reg1 = reg; + param->req1 = reg->single_req; + ++regnum; } else { - ir_mode *mode = param_regs[0]->reg_class->mode; - ir_type *type = get_type_for_mode(mode); - param->type = type; - param->offset = stack_offset; - assert(get_mode_size_bits(mode) == 32); - stack_offset += 4; + ir_mode *regmode = param_regs[0]->reg_class->mode; + ir_type *type = get_type_for_mode(regmode); + param->type = type; + param->offset = stack_offset; + assert(get_mode_size_bits(regmode) == 32); + stack_offset += SPARC_REGISTER_SIZE; } } } + n_param_regs_used = regnum; /* determine how results are passed */ n_results = get_method_n_ress(function_type); @@ -157,11 +291,31 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, reg_or_stackslot_t *result = &results[i]; if (mode_is_float(result_mode)) { - if (float_regnum >= n_float_result_regs) { + unsigned n_regs = determine_n_float_regs(result_mode); + unsigned next_reg = round_up2(float_regnum, n_regs); + + if (next_reg >= n_float_result_regs) { panic("Too many float results for sparc backend"); } else { - const arch_register_t *reg = float_result_regs[float_regnum++]; - result->reg0 = reg; + const arch_register_t *reg = float_result_regs[next_reg]; + rbitset_clear(caller_saves, reg->global_index); + result->reg_offset = i; + if (n_regs == 1) { + result->req0 = reg->single_req; + } else if (n_regs == 2) { + result->req0 = &float_result_reqs_double[next_reg]; + rbitset_clear(caller_saves, reg->global_index+1); + } else if (n_regs == 4) { + result->req0 = &float_result_reqs_quad[next_reg]; + rbitset_clear(caller_saves, reg->global_index+1); + 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"); + } + float_regnum = next_reg + n_regs; + + ++n_reg_results; } } else { if (get_mode_size_bits(result_mode) > 32) { @@ -174,7 +328,10 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, const arch_register_t *reg = param_regs[regnum++]; if (irg == NULL || omit_fp) reg = map_i_to_o_reg(reg); - result->reg0 = reg; + result->req0 = reg->single_req; + result->reg_offset = i; + rbitset_clear(caller_saves, reg->global_index); + ++n_reg_results; } } } @@ -182,8 +339,11 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type, cconv = XMALLOCZ(calling_convention_t); cconv->parameters = params; cconv->param_stack_size = stack_offset; + cconv->n_param_regs = n_param_regs_used; cconv->results = results; cconv->omit_fp = omit_fp; + cconv->caller_saves = caller_saves; + cconv->n_reg_results = n_reg_results; /* setup ignore register array */ if (irg != NULL) { @@ -192,7 +352,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) { @@ -207,5 +366,35 @@ void sparc_free_calling_convention(calling_convention_t *cconv) { free(cconv->parameters); free(cconv->results); + free(cconv->caller_saves); free(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]); + } + + rbitset_set_all(default_returns_twice_saves, N_SPARC_REGISTERS); + for (i = 0; i < ARRAY_SIZE(returns_twice_saved); ++i) { + rbitset_clear(default_returns_twice_saves, returns_twice_saved[i]); + } + for (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) { + 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) { + arch_register_req_t *req = &float_result_reqs_quad[i]; + *req = *float_result_regs[i]->single_req; + req->type |= arch_register_req_type_aligned; + req->width = 4; + } +}