X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=ir%2Fbe%2Farm%2Farm_cconv.c;h=d225fdfe71a535aa0ddbf1a3e2b18a7e8f816ea1;hb=3dff5ea08f916551668dc18b449327a8a593bc9f;hp=e76bd42f71a4e411bd692965cb5438d8c60fa9e0;hpb=e086f5c2a79020ff404656713c348f8d30244b7c;p=libfirm diff --git a/ir/be/arm/arm_cconv.c b/ir/be/arm/arm_cconv.c index e76bd42f7..d225fdfe7 100644 --- a/ir/be/arm/arm_cconv.c +++ b/ir/be/arm/arm_cconv.c @@ -21,29 +21,58 @@ * @file * @brief calling convention helpers * @author Matthias Braun - * @version $Id$ */ #include "config.h" #include "arm_cconv.h" +#include "beirg.h" #include "irmode.h" #include "typerep.h" #include "xmalloc.h" #include "error.h" +#include "util.h" -calling_convention_t *decide_calling_convention(ir_type *function_type) +static const unsigned ignore_regs[] = { + REG_R12, + REG_SP, + REG_PC, + REG_FL, +}; + +static const arch_register_t* const param_regs[] = { + &arm_registers[REG_R0], + &arm_registers[REG_R1], + &arm_registers[REG_R2], + &arm_registers[REG_R3] +}; + +static const arch_register_t* const result_regs[] = { + &arm_registers[REG_R0], + &arm_registers[REG_R1], + &arm_registers[REG_R2], + &arm_registers[REG_R3] +}; + +static const arch_register_t* const float_result_regs[] = { + &arm_registers[REG_F0], + &arm_registers[REG_F1] +}; + +calling_convention_t *arm_decide_calling_convention(const ir_graph *irg, + ir_type *function_type) { - int stack_offset = 0; + unsigned stack_offset = 0; + unsigned n_param_regs_used = 0; reg_or_stackslot_t *params; reg_or_stackslot_t *results; - int n_param_regs - = sizeof(param_regs)/sizeof(param_regs[0]); - int n_result_regs - = sizeof(result_regs)/sizeof(result_regs[0]); - int n_params; - int n_results; - int i; - int regnum; + size_t const n_param_regs = ARRAY_SIZE(param_regs); + size_t const n_result_regs = ARRAY_SIZE(result_regs); + size_t const n_float_result_regs = ARRAY_SIZE(float_result_regs); + size_t n_params; + size_t n_results; + size_t i; + size_t regnum; + size_t float_regnum; calling_convention_t *cconv; /* determine how parameters are passed */ @@ -56,65 +85,93 @@ calling_convention_t *decide_calling_convention(ir_type *function_type) ir_mode *mode = get_type_mode(param_type); int bits = get_mode_size_bits(mode); reg_or_stackslot_t *param = ¶ms[i]; + param->type = param_type; if (regnum < n_param_regs) { const arch_register_t *reg = param_regs[regnum++]; param->reg0 = reg; } else { - param->type = param_type; param->offset = stack_offset; /* increase offset 4 bytes so everything is aligned */ - stack_offset += 4; + stack_offset += bits > 32 ? bits/8 : 4; 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 arm backend"); + panic("only 32 and 64bit modes supported"); if (regnum < n_param_regs) { const arch_register_t *reg = param_regs[regnum++]; param->reg1 = reg; } 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; + ir_mode *pmode = param_regs[0]->reg_class->mode; + ir_type *type = get_type_for_mode(pmode); + param->type = type; + param->offset = stack_offset; + assert(get_mode_size_bits(pmode) == 32); stack_offset += 4; } } } + n_param_regs_used = regnum; - n_results = get_method_n_ress(function_type); - regnum = 0; - results = XMALLOCNZ(reg_or_stackslot_t, n_results); + 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) { 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]; - if (get_mode_size_bits(result_mode) > 32) { - panic("Results with more than 32bits not supported by arm backend yet"); - } - - if (regnum >= n_result_regs) { - panic("Too many results for arm backend"); + if (mode_is_float(result_mode)) { + if (float_regnum >= n_float_result_regs) { + panic("Too many float results"); + } else { + const arch_register_t *reg = float_result_regs[float_regnum++]; + result->reg0 = reg; + } } else { - const arch_register_t *reg = result_regs[regnum++]; - result->reg0 = reg; + if (get_mode_size_bits(result_mode) > 32) { + panic("Results with more than 32bits not supported yet"); + } + + if (regnum >= n_result_regs) { + panic("Too many results"); + } else { + const arch_register_t *reg = result_regs[regnum++]; + result->reg0 = reg; + } } } cconv = XMALLOCZ(calling_convention_t); cconv->parameters = params; cconv->param_stack_size = stack_offset; + cconv->n_reg_params = n_param_regs_used; cconv->results = results; + /* setup allocatable registers */ + if (irg != NULL) { + be_irg_t *birg = be_birg_from_irg(irg); + size_t n_ignores = ARRAY_SIZE(ignore_regs); + struct obstack *obst = &birg->obst; + size_t r; + + assert(birg->allocatable_regs == NULL); + birg->allocatable_regs = rbitset_obstack_alloc(obst, N_ARM_REGISTERS); + rbitset_set_all(birg->allocatable_regs, N_ARM_REGISTERS); + for (r = 0; r < n_ignores; ++r) { + rbitset_clear(birg->allocatable_regs, ignore_regs[r]); + } + } + return cconv; } -void free_calling_convention(calling_convention_t *cconv) +void arm_free_calling_convention(calling_convention_t *cconv) { free(cconv->parameters); free(cconv->results);