#include "gen_sparc_regalloc_if.h"
#include "sparc_transform.h"
#include "sparc_emitter.h"
+#include "sparc_cconv.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
sparc_register_init();
sparc_create_opcodes(&sparc_irn_ops);
sparc_handle_intrinsics();
+ sparc_cconv_init();
return &isa->base;
}
#include "util.h"
#include "error.h"
#include "gen_sparc_regalloc_if.h"
+#include "bitfiddle.h"
static const unsigned ignore_regs[] = {
REG_G0,
&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 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 unsigned default_caller_saves[BITSET_SIZE_ELEMS(N_SPARC_REGISTERS)];
/**
* Maps an input register representing the i'th register input
}
}
+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)
{
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;
reg_or_stackslot_t *params;
reg_or_stackslot_t *results;
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);
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);
+
/* determine how parameters are passed */
n_params = get_method_n_params(function_type);
regnum = 0;
if (irg == NULL || omit_fp)
reg = map_i_to_o_reg(reg);
param->reg0 = reg;
+ param->req0 = reg->single_req;
param->reg_offset = regnum;
++regnum;
} else {
if (irg == NULL || omit_fp)
reg = map_i_to_o_reg(reg);
param->reg1 = reg;
- param->reg_offset = regnum;
+ param->req1 = reg->single_req;
++regnum;
} else {
ir_mode *regmode = param_regs[0]->reg_class->mode;
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) {
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;
}
}
}
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) {
{
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]->global_index);
+ }
+
+ 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;
+ }
+}
#include "firm_types.h"
#include "../be_types.h"
+#include "../benode.h"
#include "gen_sparc_regalloc_if.h"
/** information about a single parameter or result */
typedef struct reg_or_stackslot_t
{
- const arch_register_t *reg0; /**< if != NULL, the first register used for
- this parameter. */
- const arch_register_t *reg1; /**< if != NULL, the second register used. */
+ const arch_register_req_t *req0; /**< if != NULL, register requirements
+ for this parameter (or the first
+ part of it). */
+ const arch_register_req_t *req1; /**< if != NULL, register requirements
+ for the 2nd part of the parameter */
+ const arch_register_t *reg0;
+ const arch_register_t *reg1;
size_t reg_offset;
ir_type *type; /**< indicates that an entity of the specific
type is needed */
unsigned n_param_regs; /**< number of values passed in a
register */
reg_or_stackslot_t *results; /**< result info. */
+ unsigned n_reg_results;
+ unsigned *caller_saves; /**< bitset of caller save registers */
} calling_convention_t;
/**
*/
void sparc_free_calling_convention(calling_convention_t *cconv);
+void sparc_cconv_init(void);
+
#endif
static size_t start_params_offset;
static size_t start_callee_saves_offset;
-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 arch_register_t *const omit_fp_callee_saves[] = {
&sparc_registers[REG_L0],
&sparc_registers[REG_L1],
new_unop_fp_func new_func_double,
new_unop_fp_func new_func_quad)
{
- ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *op1 = get_binop_left(node);
- ir_node *new_op1 = be_transform_node(op1);
- dbg_info *dbgi = get_irn_dbg_info(node);
- unsigned bits = get_mode_size_bits(mode);
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *op = get_unop_op(node);
+ ir_node *new_op = be_transform_node(op);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ unsigned bits = get_mode_size_bits(mode);
switch (bits) {
case 32:
- return new_func_single(dbgi, block, new_op1, mode);
+ return new_func_single(dbgi, block, new_op, mode);
case 64:
- return new_func_double(dbgi, block, new_op1, mode);
+ return new_func_double(dbgi, block, new_op, mode);
case 128:
- return new_func_quad(dbgi, block, new_op1, mode);
+ return new_func_quad(dbgi, block, new_op, mode);
default:
break;
}
/* first output is memory */
start_mem_offset = o;
- arch_set_out_register_req(start, o++, arch_no_register_req);
+ arch_set_out_register_req(start, o, arch_no_register_req);
+ ++o;
+
/* the zero register */
start_g0_offset = o;
req = be_create_reg_req(obst, &sparc_registers[REG_G0],
ir_node *res_value = get_Return_res(node, i);
ir_node *new_res_value = be_transform_node(res_value);
const reg_or_stackslot_t *slot = ¤t_cconv->results[i];
- const arch_register_t *reg = slot->reg0;
- assert(slot->reg1 == NULL);
+ assert(slot->req1 == NULL);
in[p] = new_res_value;
- reqs[p] = reg->single_req;
+ reqs[p] = slot->req0;
++p;
}
/* callee saves */
dbg_info *dbgi = get_irn_dbg_info(node);
ir_type *type = get_Call_type(node);
size_t n_params = get_Call_n_params(node);
+ size_t n_ress = get_method_n_ress(type);
/* max inputs: memory, callee, register arguments */
ir_node **sync_ins = ALLOCAN(ir_node*, n_params);
struct obstack *obst = be_get_be_obst(irg);
int in_arity = 0;
int sync_arity = 0;
int n_caller_saves
- = sizeof(caller_saves)/sizeof(caller_saves[0]);
+ = rbitset_popcount(cconv->caller_saves, N_SPARC_REGISTERS);
ir_entity *entity = NULL;
ir_node *new_frame = get_stack_pointer_for(node);
ir_node *incsp;
int mem_pos;
ir_node *res;
size_t p;
+ size_t r;
int i;
int o;
int out_arity;
/* outputs:
* - memory
+ * - results
* - caller saves
*/
- out_arity = 1 + n_caller_saves;
+ out_arity = 1 + cconv->n_reg_results + n_caller_saves;
/* create call node */
if (entity != NULL) {
/* create output register reqs */
o = 0;
arch_set_out_register_req(res, o++, arch_no_register_req);
- for (i = 0; i < n_caller_saves; ++i) {
- const arch_register_t *reg = caller_saves[i];
+ /* add register requirements for the result regs */
+ for (r = 0; r < n_ress; ++r) {
+ const reg_or_stackslot_t *result_info = &cconv->results[r];
+ const arch_register_req_t *req = result_info->req0;
+ if (req != NULL) {
+ arch_set_out_register_req(res, o++, req);
+ }
+ assert(result_info->req1 == NULL);
+ }
+ for (i = 0; i < N_SPARC_REGISTERS; ++i) {
+ const arch_register_t *reg;
+ if (!rbitset_is_set(cconv->caller_saves, i))
+ continue;
+ reg = &sparc_registers[i];
arch_set_out_register_req(res, o++, reg->single_req);
}
assert(o == out_arity);
panic("Unexpected Call proj %ld\n", pn);
}
-/**
- * Finds number of output value of a mode_T node which is constrained to
- * a single specific register.
- */
-static int find_out_for_reg(ir_node *node, const arch_register_t *reg)
-{
- int n_outs = arch_irn_get_n_outs(node);
- int o;
-
- for (o = 0; o < n_outs; ++o) {
- const arch_register_req_t *req = arch_get_out_register_req(node, o);
- if (req == reg->single_req)
- return o;
- }
- return -1;
-}
-
static ir_node *gen_Proj_Proj_Call(ir_node *node)
{
long pn = get_Proj_proj(node);
ir_type *function_type = get_Call_type(call);
calling_convention_t *cconv
= sparc_decide_calling_convention(function_type, NULL);
- const reg_or_stackslot_t *res = &cconv->results[pn];
- const arch_register_t *reg = res->reg0;
- ir_mode *mode;
- int regn;
-
- assert(res->reg0 != NULL && res->reg1 == NULL);
- regn = find_out_for_reg(new_call, reg);
- if (regn < 0) {
- panic("Internal error in calling convention for return %+F", node);
- }
- mode = res->reg0->reg_class->mode;
+ const reg_or_stackslot_t *res = &cconv->results[pn];
+ ir_mode *mode;
+ long new_pn = 1 + res->reg_offset;
+ assert(res->req0 != NULL && res->req1 == NULL);
+ mode = res->req0->cls->mode;
sparc_free_calling_convention(cconv);
- return new_r_Proj(new_call, mode, regn);
+ return new_r_Proj(new_call, mode, new_pn);
}
/**