#include "sparc_cconv.h"
#include "irmode.h"
+#include "irgwalk.h"
#include "typerep.h"
#include "xmalloc.h"
+#include "util.h"
#include "error.h"
+#include "gen_sparc_regalloc_if.h"
+
+static const unsigned ignore_regs[] = {
+ REG_G0,
+ /* reserved for sparc ABI: */
+ REG_G5,
+ REG_G6,
+ REG_G7,
+
+ REG_SP,
+ REG_O7,
+ REG_FRAME_POINTER,
+ REG_I7,
+
+ REG_FPFLAGS,
+ REG_FLAGS,
+ REG_Y,
+};
/**
* Maps an input register representing the i'th register input
*/
static const arch_register_t *map_i_to_o_reg(const arch_register_t *reg)
{
- unsigned idx = arch_register_get_index(reg);
+ unsigned idx = reg->global_index;
assert(REG_I0 <= idx && idx <= REG_I7);
idx += REG_O0 - REG_I0;
assert(REG_O0 <= idx && idx <= REG_O7);
- return &sparc_gp_regs[idx];
+ return &sparc_registers[idx];
+}
+
+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)
+ */
+ if ((is_Alloc(node) && get_Alloc_where(node) == stack_alloc)
+ || (is_Free(node) && get_Free_where(node) == stack_alloc)
+ || is_Call(node)) {
+ *can_omit_fp = false;
+ }
}
calling_convention_t *sparc_decide_calling_convention(ir_type *function_type,
- bool caller)
+ ir_graph *irg)
{
- int stack_offset = 0;
+ int stack_offset = 0;
+ int n_param_regs = ARRAY_SIZE(param_regs);
+ int 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_param_regs
- = sizeof(param_regs)/sizeof(param_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 float_regnum;
calling_convention_t *cconv;
+ 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);
+ }
+
/* determine how parameters are passed */
n_params = get_method_n_params(function_type);
regnum = 0;
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++];
- if (caller)
+ if (irg == NULL || omit_fp)
reg = map_i_to_o_reg(reg);
param->reg0 = reg;
} else {
+ param->type = param_type;
param->offset = stack_offset;
/* increase offset 4 bytes so everything is aligned */
stack_offset += bits > 32 ? bits/8 : 4;
if (regnum < n_param_regs) {
const arch_register_t *reg = param_regs[regnum++];
- if (caller)
+ if (irg == NULL || omit_fp)
reg = map_i_to_o_reg(reg);
param->reg1 = reg;
} else {
panic("Too many results for sparc backend");
} else {
const arch_register_t *reg = param_regs[regnum++];
- if (caller)
+ if (irg == NULL || omit_fp)
reg = map_i_to_o_reg(reg);
result->reg0 = reg;
}
cconv->parameters = params;
cconv->param_stack_size = stack_offset;
cconv->results = results;
+ cconv->omit_fp = omit_fp;
+
+ /* setup ignore register array */
+ 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_SPARC_REGISTERS);
+ rbitset_set_all(birg->allocatable_regs, N_SPARC_REGISTERS);
+ for (r = 0; r < n_ignores; ++r) {
+ rbitset_clear(birg->allocatable_regs, ignore_regs[r]);
+ }
+ }
return cconv;
}