Commit 637450ac authored by Matthias Braun's avatar Matthias Braun
Browse files

perform custom abi construction in sparc as well to handle floatingpoint

[r27788]
parent 4ec0521f
......@@ -31,7 +31,7 @@
#include "xmalloc.h"
#include "error.h"
calling_convention_t *decide_calling_convention(ir_type *function_type)
calling_convention_t *arm_decide_calling_convention(ir_type *function_type)
{
int stack_offset = 0;
reg_or_stackslot_t *params;
......@@ -128,7 +128,7 @@ calling_convention_t *decide_calling_convention(ir_type *function_type)
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);
......
......@@ -102,11 +102,11 @@ typedef struct calling_convention_t
* Decides what goes to register or to stack and what stack offsets/
* datatypes are used.
*/
calling_convention_t *decide_calling_convention(ir_type *function_type);
calling_convention_t *arm_decide_calling_convention(ir_type *function_type);
/**
* free memory used by a calling_convention_t
*/
void free_calling_convention(calling_convention_t *cconv);
void arm_free_calling_convention(calling_convention_t *cconv);
#endif
......@@ -316,7 +316,6 @@ LinkMovPC => {
"\tarch_irn_add_flags(res, arch_irn_flags_modify_flags);",
emit => ". mov lr, pc\n".
". mov pc, %SO",
mode => "mode_T",
},
# mov lr, pc\n ldr pc, XXX -- This combination is used for calls to function
......@@ -330,7 +329,6 @@ LinkLdrPC => {
custominit => "arch_irn_add_flags(res, arch_irn_flags_modify_flags);",
emit => ". mov lr, pc\n".
". ldr pc, %SO",
mode => "mode_T",
},
Bl => {
......@@ -341,7 +339,6 @@ Bl => {
attr => "ir_entity *entity, int symconst_offset",
custominit => "arch_irn_add_flags(res, arch_irn_flags_modify_flags);",
emit => '. bl %SC',
mode => "mode_T",
},
# this node produces ALWAYS an empty (tempary) gp reg and cannot be CSE'd
......@@ -442,7 +439,7 @@ Str => {
op_flags => [ "labeled", "fragile" ],
state => "exc_pinned",
ins => [ "ptr", "val", "mem" ],
outs => [ "mem" ],
outs => [ "M" ],
reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] },
emit => '. str%SM %S1, [%S0, #%O]',
mode => "mode_M",
......
......@@ -1299,7 +1299,7 @@ static ir_node *gen_Proj_Proj_Call(ir_node *node)
ir_node *call = get_Proj_pred(get_Proj_pred(node));
ir_node *new_call = be_transform_node(call);
ir_type *function_type = get_Call_type(call);
calling_convention_t *cconv = decide_calling_convention(function_type);
calling_convention_t *cconv = arm_decide_calling_convention(function_type);
const reg_or_stackslot_t *res = &cconv->results[pn];
ir_mode *mode;
int regn;
......@@ -1312,7 +1312,7 @@ static ir_node *gen_Proj_Proj_Call(ir_node *node)
}
mode = res->reg0->reg_class->mode;
free_calling_convention(cconv);
arm_free_calling_convention(cconv);
return new_r_Proj(new_call, mode, regn);
}
......@@ -1616,7 +1616,7 @@ static ir_node *gen_Call(ir_node *node)
ir_node *new_mem = be_transform_node(mem);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_type *type = get_Call_type(node);
calling_convention_t *cconv = decide_calling_convention(type);
calling_convention_t *cconv = arm_decide_calling_convention(type);
int n_params = get_Call_n_params(node);
int n_param_regs = sizeof(param_regs)/sizeof(param_regs[0]);
/* max inputs: memory, callee, register arguments */
......@@ -1782,7 +1782,7 @@ static ir_node *gen_Call(ir_node *node)
/* copy pinned attribute */
set_irn_pinned(res, get_irn_pinned(node));
free_calling_convention(cconv);
arm_free_calling_convention(cconv);
return res;
}
......@@ -1941,7 +1941,7 @@ void arm_transform_graph(arm_code_gen_t *cg)
abihelper = be_abihelper_prepare(irg);
be_collect_stacknodes(abihelper);
assert(cconv == NULL);
cconv = decide_calling_convention(get_entity_type(entity));
cconv = arm_decide_calling_convention(get_entity_type(entity));
create_stacklayout(irg);
be_transform_graph(cg->irg, NULL);
......@@ -1949,7 +1949,7 @@ void arm_transform_graph(arm_code_gen_t *cg)
be_abihelper_finish(abihelper);
abihelper = NULL;
free_calling_convention(cconv);
arm_free_calling_convention(cconv);
cconv = NULL;
frame_type = get_irg_frame_type(irg);
......
......@@ -132,8 +132,8 @@ static void rsm_clear_regs(register_state_mapping_t *rsm,
}
}
static void rsm_add_reg(register_state_mapping_t *rsm,
const arch_register_t *reg, arch_irn_flags_t flags)
static int rsm_add_reg(register_state_mapping_t *rsm,
const arch_register_t *reg, arch_irn_flags_t flags)
{
int input_idx = ARR_LEN(rsm->regs);
int cls_idx = reg->reg_class->index;
......@@ -144,6 +144,12 @@ static void rsm_add_reg(register_state_mapping_t *rsm,
assert(rsm->reg_index_map[cls_idx][reg_idx] == -1);
rsm->reg_index_map[cls_idx][reg_idx] = input_idx;
ARR_APP1(reg_flag_t, rsm->regs, regflag);
if (rsm->value_map != NULL) {
ARR_APP1(ir_node*, rsm->value_map, NULL);
assert(ARR_LEN(rsm->value_map) == ARR_LEN(rsm->regs));
}
return input_idx;
}
......@@ -317,8 +323,8 @@ void be_epilog_begin(beabi_helper_env_t *env)
void be_epilog_add_reg(beabi_helper_env_t *env, const arch_register_t *reg,
arch_irn_flags_t flags, ir_node *value)
{
rsm_add_reg(&env->epilog, reg, flags);
ARR_APP1(ir_node*, env->epilog.value_map, value);
int index = rsm_add_reg(&env->epilog, reg, flags);
rsm_set_value(&env->epilog, index, value);
}
void be_epilog_set_reg_value(beabi_helper_env_t *env,
......@@ -379,7 +385,7 @@ ir_node *be_epilog_create_return(beabi_helper_env_t *env, dbg_info *dbgi,
static void add_missing_keep_walker(ir_node *node, void *data)
{
int n_outs, i;
unsigned found_projs = 0;
unsigned *found_projs;
const ir_edge_t *edge;
ir_mode *mode = get_irn_mode(node);
ir_node *last_keep;
......@@ -391,7 +397,7 @@ static void add_missing_keep_walker(ir_node *node, void *data)
if (n_outs <= 0)
return;
assert(n_outs < (int) sizeof(unsigned) * 8);
rbitset_alloca(found_projs, n_outs);
foreach_out_edge(node, edge) {
ir_node *succ = get_edge_src_irn(edge);
int pn;
......@@ -405,7 +411,7 @@ static void add_missing_keep_walker(ir_node *node, void *data)
pn = get_Proj_proj(succ);
assert(pn < n_outs);
found_projs |= 1 << pn;
rbitset_set(found_projs, pn);
}
......@@ -417,7 +423,7 @@ static void add_missing_keep_walker(ir_node *node, void *data)
const arch_register_req_t *req;
const arch_register_class_t *cls;
if (found_projs & (1 << i)) {
if (rbitset_is_set(found_projs, i)) {
continue;
}
......
......@@ -206,7 +206,9 @@ sub create_constructor {
} elsif($out_arity eq "dynamic") {
$out_arity = $ARITY_DYNAMIC;
}
if ($out_arity != 0 && $out_arity != 1 && !defined($known_mode)) {
$known_mode = "mode_T";
}
my $comment = $n->{"comment"};
if(!exists($n->{"comment"})) {
......
......@@ -48,7 +48,6 @@
#include "../belower.h"
#include "../besched.h"
#include "be.h"
#include "../beabi.h"
#include "../bemachine.h"
#include "../beilpsched.h"
#include "../bemodule.h"
......@@ -182,10 +181,9 @@ static void sparc_before_ra(void *self)
*/
static void transform_Reload(ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
ir_node *block = get_nodes_block(node);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *ptr = get_irg_frame(irg);
ir_node *ptr = get_irn_n(node, be_pos_Spill_frame);
ir_node *mem = get_irn_n(node, be_pos_Reload_mem);
ir_mode *mode = get_irn_mode(node);
ir_entity *entity = be_get_frame_entity(node);
......@@ -212,10 +210,9 @@ static void transform_Reload(ir_node *node)
*/
static void transform_Spill(ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
ir_node *block = get_nodes_block(node);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *ptr = get_irg_frame(irg);
ir_node *ptr = get_irn_n(node, be_pos_Spill_frame);
ir_node *mem = new_NoMem();
ir_node *val = get_irn_n(node, be_pos_Spill_val);
ir_mode *mode = get_irn_mode(val);
......@@ -313,16 +310,17 @@ static void *sparc_cg_init(ir_graph *irg)
const arch_isa_if_t sparc_isa_if;
static sparc_isa_t sparc_isa_template = {
{
&sparc_isa_if, /* isa interface implementation */
&sparc_gp_regs[REG_SP], /* stack pointer register */
&sparc_gp_regs[REG_FP], /* base pointer register */
&sparc_reg_classes[CLASS_sparc_gp], /* link pointer register class */
-1, /* stack direction */
3, /* power of two stack alignment for calls, 2^2 == 4 */
NULL, /* main environment */
7, /* costs for a spill instruction */
5, /* costs for a reload instruction */
false, /* no custom abi handling */
&sparc_isa_if, /* isa interface implementation */
&sparc_gp_regs[REG_SP], /* stack pointer register */
&sparc_gp_regs[REG_FRAME_POINTER], /* base pointer register */
&sparc_reg_classes[CLASS_sparc_gp], /* link pointer register class */
-1, /* stack direction */
3, /* power of two stack alignment
for calls */
NULL, /* main environment */
7, /* costs for a spill instruction */
5, /* costs for a reload instruction */
true, /* custom abi handling */
},
NULL /* current code generator */
};
......@@ -468,196 +466,6 @@ static const arch_register_class_t *sparc_get_reg_class_for_mode(const ir_mode *
return &sparc_reg_classes[CLASS_sparc_gp];
}
typedef struct {
be_abi_call_flags_bits_t flags;
ir_graph *irg;
} sparc_abi_env_t;
static void *sparc_abi_init(const be_abi_call_t *call, ir_graph *irg)
{
sparc_abi_env_t *env = XMALLOC(sparc_abi_env_t);
be_abi_call_flags_t fl = be_abi_call_get_flags(call);
env->flags = fl.bits;
env->irg = irg;
return env;
}
/**
* Get the between type for that call.
* @param self The callback object.
* @return The between type of for that call.
*/
static ir_type *sparc_get_between_type(void *self)
{
static ir_type *between_type = NULL;
(void) self;
if (between_type == NULL) {
between_type = new_type_class(new_id_from_str("sparc_between_type"));
set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE);
}
return between_type;
}
/**
* Build the prolog, return the BASE POINTER register
*/
static const arch_register_t *sparc_abi_prologue(void *self, ir_node **mem,
pmap *reg_map, int *stack_bias)
{
sparc_abi_env_t *env = self;
ir_node *block = get_irg_start_block(env->irg);
const arch_register_t *fp = &sparc_gp_regs[REG_FP];
const arch_register_t *sp = &sparc_gp_regs[REG_SP];
// sp
ir_node *sp_proj = be_abi_reg_map_get(reg_map, sp);
//ir_type *frame_type = get_irg_frame_type(env->irg);
//frame_alloc_area(frame_type, reserved_stack_size, 1, 1);
// alloc min required stack space
// TODO: the min stacksize depends on wether this is a leaf procedure or not
ir_node *save = new_bd_sparc_Save(NULL, block, sp_proj, *mem, SPARC_MIN_STACKSIZE);
(void) reg_map;
(void) mem;
(void) stack_bias;
sp_proj = new_r_Proj(save, sp->reg_class->mode, pn_sparc_Save_stack);
*mem = new_r_Proj(save, mode_M, pn_sparc_Save_mem);
arch_set_irn_register(sp_proj, sp);
be_abi_reg_map_set(reg_map, sp, sp_proj);
// we always have a framepointer
return fp;
}
/* Build the epilog */
static void sparc_abi_epilogue(void *self, ir_node *bl, ir_node **mem,
pmap *reg_map)
{
(void) self;
(void) bl;
(void) mem;
(void) reg_map;
}
static const be_abi_callbacks_t sparc_abi_callbacks = {
sparc_abi_init,
free,
sparc_get_between_type,
sparc_abi_prologue,
sparc_abi_epilogue,
};
static const arch_register_t *gp_param_out_regs[] = {
&sparc_gp_regs[REG_O0],
&sparc_gp_regs[REG_O1],
&sparc_gp_regs[REG_O2],
&sparc_gp_regs[REG_O3],
&sparc_gp_regs[REG_O4],
&sparc_gp_regs[REG_O5],
};
static const arch_register_t *gp_param_in_regs[] = {
&sparc_gp_regs[REG_I0],
&sparc_gp_regs[REG_I1],
&sparc_gp_regs[REG_I2],
&sparc_gp_regs[REG_I3],
&sparc_gp_regs[REG_I4],
&sparc_gp_regs[REG_I5],
};
/**
* get register for outgoing parameters 1-6
*/
static const arch_register_t *sparc_get_RegParamOut_reg(int n)
{
assert(n < 6 && n >=0 && "trying to get (out) register for param >= 6");
return gp_param_out_regs[n];
}
/**
* get register for incoming parameters 1-6
*/
static const arch_register_t *sparc_get_RegParamIn_reg(int n)
{
assert(n < 6 && n >=0 && "trying to get (in) register for param >= 6");
return gp_param_in_regs[n];
}
/**
* Get the ABI restrictions for procedure calls.
* @param self The this pointer.
* @param method_type The type of the method (procedure) in question.
* @param abi The abi object to be modified
*/
static void sparc_get_call_abi(const void *self, ir_type *method_type,
be_abi_call_t *abi)
{
ir_type *tp;
ir_mode *mode;
int i, n = get_method_n_params(method_type);
be_abi_call_flags_t call_flags;
(void) self;
/* set abi flags for calls */
call_flags.bits.left_to_right = 0;
call_flags.bits.store_args_sequential = 1;
call_flags.bits.try_omit_fp = 0;
call_flags.bits.fp_free = 0;
call_flags.bits.call_has_imm = 1;
/* set stack parameter passing style */
be_abi_call_set_flags(abi, call_flags, &sparc_abi_callbacks);
for (i = 0; i < n; i++) {
ir_type *type = get_method_param_type(method_type, i);
ir_mode *mode = get_type_mode(type);
if (mode_is_float(mode) || i >= 6) {
unsigned align = get_type_size_bytes(type);
be_abi_call_param_stack(abi, i, mode, align, 0, 0,
ABI_CONTEXT_BOTH);
continue;
}
/* pass integer params 0-5 via registers.
* On sparc we need to set the ABI context since register names of
* parameters change to i0-i5 if we are the callee */
be_abi_call_param_reg(abi, i, sparc_get_RegParamOut_reg(i),
ABI_CONTEXT_CALLER);
be_abi_call_param_reg(abi, i, sparc_get_RegParamIn_reg(i),
ABI_CONTEXT_CALLEE);
}
n = get_method_n_ress(method_type);
/* more than 1 result not supported */
assert(n <= 1);
for (i = 0; i < n; ++i) {
tp = get_method_res_type(method_type, i);
mode = get_type_mode(tp);
/* set return value register: return value is in i0 resp. f0 */
if (mode_is_float(mode)) {
be_abi_call_res_reg(abi, i, &sparc_fp_regs[REG_F0],
ABI_CONTEXT_BOTH);
} else {
be_abi_call_res_reg(abi, i, &sparc_gp_regs[REG_I0],
ABI_CONTEXT_CALLEE);
be_abi_call_res_reg(abi, i, &sparc_gp_regs[REG_O0],
ABI_CONTEXT_CALLER);
}
}
}
static int sparc_to_appear_in_schedule(void *block_env, const ir_node *irn)
{
(void) block_env;
......@@ -773,7 +581,7 @@ const arch_isa_if_t sparc_isa_if = {
sparc_get_n_reg_class,
sparc_get_reg_class,
sparc_get_reg_class_for_mode,
sparc_get_call_abi,
NULL,
sparc_get_code_generator_if,
sparc_get_list_sched_selector,
sparc_get_ilp_sched_selector,
......
/*
* Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation and appearing in the file LICENSE.GPL included in the
* packaging of this file.
*
* Licensees holding valid libFirm Professional Edition licenses may use
* this file in accordance with the libFirm Commercial License.
* Agreement provided with the Software.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*/
/**
* @file
* @brief calling convention helpers
* @author Matthias Braun
* @version $Id$
*/
#include "config.h"
#include "sparc_cconv.h"
#include "irmode.h"
#include "typerep.h"
#include "xmalloc.h"
#include "error.h"
static const arch_register_t *map_i_to_o_reg(const arch_register_t *reg)
{
unsigned idx = arch_register_get_index(reg);
assert(REG_I0 <= idx && idx <= REG_I7);
idx += REG_O0 - REG_I0;
assert(REG_O0 <= idx && idx <= REG_O7);
return &sparc_gp_regs[idx];
}
calling_convention_t *sparc_decide_calling_convention(ir_type *function_type,
bool caller)
{
int stack_offset = 0;
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 regnum;
int float_regnum;
calling_convention_t *cconv;
/* determine how parameters are passed */
n_params = get_method_n_params(function_type);
regnum = 0;
params = XMALLOCNZ(reg_or_stackslot_t, n_params);
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 = &params[i];
param->type = param_type;
if (regnum < n_param_regs) {
const arch_register_t *reg = param_regs[regnum++];
if (caller)
reg = map_i_to_o_reg(reg);
param->reg0 = reg;
} else {
param->offset = stack_offset;
/* increase offset 4 bytes so everything is aligned */
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 sparc backend");
if (regnum < n_param_regs) {
const arch_register_t *reg = param_regs[regnum++];
if (caller)
reg = map_i_to_o_reg(reg);
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);
stack_offset += 4;
}
}
}
/* determine how results are passed */
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 (mode_is_float(result_mode)) {
if (float_regnum >= 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;
}
} else {
if (get_mode_size_bits(result_mode) > 32) {
panic("Results with more than 32bits not supported by sparc backend yet");
}
if (regnum >= n_param_regs) {
panic("Too many results for sparc backend");
} else {
const arch_register_t *reg = param_regs[regnum++];
if (caller)
reg = map_i_to_o_reg(reg);
result->reg0 = reg;
}
}
}
cconv = XMALLOCZ(calling_convention_t);
cconv->parameters = params;
cconv->param_stack_size = stack_offset;
cconv->results = results;
return cconv;
}
void sparc_free_calling_convention(calling_convention_t *cconv)
{
free(cconv->parameters);
free(cconv->results);
free(cconv);
}
/*
* Copyright (C) 1995-2010 University of Karlsruhe. All right reserved.