share common phi code, fix missing phi input reqs
[libfirm] / ir / be / arm / arm_cconv.c
index 287a6dd..8ca715c 100644 (file)
@@ -21,7 +21,6 @@
  * @file
  * @brief   calling convention helpers
  * @author  Matthias Braun
- * @version $Id$
  */
 #include "config.h"
 
 #include "typerep.h"
 #include "xmalloc.h"
 #include "error.h"
+#include "util.h"
 
-calling_convention_t *arm_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_float_result_regs
-               = sizeof(float_result_regs)/sizeof(float_result_regs[0]);
-       int                   n_params;
-       int                   n_results;
-       int                   i;
-       int                   regnum;
-       int                   float_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 */
@@ -74,21 +99,22 @@ calling_convention_t *arm_decide_calling_convention(ir_type *function_type)
                /* 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;
-                               assert(get_mode_size_bits(mode) == 32);
+                               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;
@@ -101,18 +127,18 @@ calling_convention_t *arm_decide_calling_convention(ir_type *function_type)
 
                if (mode_is_float(result_mode)) {
                        if (float_regnum >= n_float_result_regs) {
-                               panic("Too many float results for arm backend");
+                               panic("Too many float results");
                        } else {
                                const arch_register_t *reg = float_result_regs[float_regnum++];
                                result->reg0 = reg;
                        }
                } else {
                        if (get_mode_size_bits(result_mode) > 32) {
-                               panic("Results with more than 32bits not supported by arm backend yet");
+                               panic("Results with more than 32bits not supported yet");
                        }
 
                        if (regnum >= n_result_regs) {
-                               panic("Too many results for arm backend");
+                               panic("Too many results");
                        } else {
                                const arch_register_t *reg = result_regs[regnum++];
                                result->reg0 = reg;
@@ -123,8 +149,24 @@ calling_convention_t *arm_decide_calling_convention(ir_type *function_type)
        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;
 }