for (i = 0; i < n; i++) {
/* TODO: implement register parameter: */
/* reg = get reg for param i; */
- /* be_abi_call_param_reg(abi, i, reg); */
+ /* be_abi_call_param_reg(abi, i, reg, ABI_CONTEXT_BOTH); */
/* default: all parameters on stack */
tp = get_method_param_type(method_type, i);
mode = get_type_mode(tp);
- be_abi_call_param_stack(abi, i, mode, 4, 0, 0);
+ be_abi_call_param_stack(abi, i, mode, 4, 0, 0, ABI_CONTEXT_BOTH);
}
/* TODO: set correct return register */
mode = get_type_mode(tp);
be_abi_call_res_reg(abi, 0,
- mode_is_float(mode) ? &TEMPLATE_fp_regs[REG_F0] : &TEMPLATE_gp_regs[REG_R0]);
+ mode_is_float(mode) ? &TEMPLATE_fp_regs[REG_F0] : &TEMPLATE_gp_regs[REG_R0], ABI_CONTEXT_BOTH);
}
}
/* reg = get reg for param i; */
/* be_abi_call_param_reg(abi, i, reg); */
if (i < 4) {
- be_abi_call_param_reg(abi, i, arm_get_RegParam_reg(i));
+ be_abi_call_param_reg(abi, i, arm_get_RegParam_reg(i), ABI_CONTEXT_BOTH);
} else {
tp = get_method_param_type(method_type, i);
mode = get_type_mode(tp);
- be_abi_call_param_stack(abi, i, mode, 4, 0, 0);
+ be_abi_call_param_stack(abi, i, mode, 4, 0, 0, ABI_CONTEXT_BOTH);
}
}
assert(!mode_is_float(mode) && "mixed INT, FP results not supported");
- be_abi_call_res_reg(abi, 0, &arm_gp_regs[REG_R0]);
- be_abi_call_res_reg(abi, 1, &arm_gp_regs[REG_R1]);
+ be_abi_call_res_reg(abi, 0, &arm_gp_regs[REG_R0], ABI_CONTEXT_BOTH);
+ be_abi_call_res_reg(abi, 1, &arm_gp_regs[REG_R1], ABI_CONTEXT_BOTH);
} else if (n == 1) {
const arch_register_t *reg;
mode = get_type_mode(tp);
reg = mode_is_float(mode) ? &arm_fpa_regs[REG_F0] : &arm_gp_regs[REG_R0];
- be_abi_call_res_reg(abi, 0, reg);
+ be_abi_call_res_reg(abi, 0, reg, ABI_CONTEXT_BOTH);
}
}
unsigned is_res : 1; /**< 1: the call argument is a return value. 0: it's a call parameter. */
unsigned in_reg : 1; /**< 1: this argument is transmitted in registers. */
unsigned on_stack : 1; /**< 1: this argument is transmitted on the stack. */
+ unsigned callee : 1; /**< 1: someone called us. 0: We call another function */
int pos;
const arch_register_t *reg;
{
const be_abi_call_arg_t *p = a, *q = b;
(void) n;
- return !(p->is_res == q->is_res && p->pos == q->pos);
+ return !(p->is_res == q->is_res && p->pos == q->pos && p->callee == q->callee);
}
/**
* @param call the abi call
* @param is_res true for call results, false for call arguments
* @param pos position of the argument
+ * @param callee context type - if we are callee or caller
*/
-static be_abi_call_arg_t *get_call_arg(be_abi_call_t *call, int is_res, int pos)
+static be_abi_call_arg_t *get_call_arg(be_abi_call_t *call, int is_res, int pos, int callee)
{
be_abi_call_arg_t arg;
unsigned hash;
memset(&arg, 0, sizeof(arg));
arg.is_res = is_res;
arg.pos = pos;
+ arg.callee = callee;
hash = is_res * 128 + pos;
/**
* Set an ABI call object argument.
- *
- * @param call the abi call
- * @param is_res true for call results, false for call arguments
- * @param pos position of the argument
*/
-static be_abi_call_arg_t *create_call_arg(be_abi_call_t *call, int is_res, int pos)
+static void remember_call_arg(be_abi_call_arg_t *arg, be_abi_call_t *call, be_abi_context_t context)
{
- be_abi_call_arg_t arg;
- unsigned hash;
-
- memset(&arg, 0, sizeof(arg));
- arg.is_res = is_res;
- arg.pos = pos;
-
- hash = is_res * 128 + pos;
-
- return set_insert(call->params, &arg, sizeof(arg), hash);
+ unsigned hash = arg->is_res * 128 + arg->pos;
+ if (context & ABI_CONTEXT_CALLEE) {
+ arg->callee = 1;
+ set_insert(call->params, arg, sizeof(*arg), hash);
+ }
+ if (context & ABI_CONTEXT_CALLER) {
+ arg->callee = 0;
+ set_insert(call->params, arg, sizeof(*arg), hash);
+ }
}
/* Set the flags for a call. */
}
-void be_abi_call_param_stack(be_abi_call_t *call, int arg_pos, ir_mode *load_mode, unsigned alignment, unsigned space_before, unsigned space_after)
+void be_abi_call_param_stack(be_abi_call_t *call, int arg_pos,
+ ir_mode *load_mode, unsigned alignment,
+ unsigned space_before, unsigned space_after,
+ be_abi_context_t context)
{
- be_abi_call_arg_t *arg = create_call_arg(call, 0, arg_pos);
- arg->on_stack = 1;
- arg->load_mode = load_mode;
- arg->alignment = alignment;
- arg->space_before = space_before;
- arg->space_after = space_after;
+ be_abi_call_arg_t arg;
+ memset(&arg, 0, sizeof(arg));
assert(alignment > 0 && "Alignment must be greater than 0");
+ arg.on_stack = 1;
+ arg.load_mode = load_mode;
+ arg.alignment = alignment;
+ arg.space_before = space_before;
+ arg.space_after = space_after;
+ arg.is_res = 0;
+ arg.pos = arg_pos;
+
+ remember_call_arg(&arg, call, context);
}
-void be_abi_call_param_reg(be_abi_call_t *call, int arg_pos, const arch_register_t *reg)
+void be_abi_call_param_reg(be_abi_call_t *call, int arg_pos, const arch_register_t *reg, be_abi_context_t context)
{
- be_abi_call_arg_t *arg = create_call_arg(call, 0, arg_pos);
- arg->in_reg = 1;
- arg->reg = reg;
+ be_abi_call_arg_t arg;
+ memset(&arg, 0, sizeof(arg));
+
+ arg.in_reg = 1;
+ arg.reg = reg;
+ arg.is_res = 0;
+ arg.pos = arg_pos;
+
+ remember_call_arg(&arg, call, context);
}
-void be_abi_call_res_reg(be_abi_call_t *call, int arg_pos, const arch_register_t *reg)
+void be_abi_call_res_reg(be_abi_call_t *call, int arg_pos, const arch_register_t *reg, be_abi_context_t context)
{
- be_abi_call_arg_t *arg = create_call_arg(call, 1, arg_pos);
- arg->in_reg = 1;
- arg->reg = reg;
+ be_abi_call_arg_t arg;
+ memset(&arg, 0, sizeof(arg));
+
+ arg.in_reg = 1;
+ arg.reg = reg;
+ arg.is_res = 1;
+ arg.pos = arg_pos;
+
+ remember_call_arg(&arg, call, context);
}
/* Get the flags of a ABI call object. */
return frame;
}
-/**
- * Returns non-zero if the call argument at given position
- * is transfered on the stack.
- */
-static inline int is_on_stack(be_abi_call_t *call, int pos)
-{
- be_abi_call_arg_t *arg = get_call_arg(call, 0, pos);
- return arg && !arg->in_reg;
-}
-
/*
____ _ _
/ ___|__ _| | |___
assert(obstack_object_size(obst) == 0);
stack_param_idx = ALLOCAN(int, n_params);
for (i = 0; i < n_params; ++i) {
- be_abi_call_arg_t *arg = get_call_arg(call, 0, i);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, i, 0);
assert(arg);
if (arg->on_stack) {
int arg_size = get_type_size_bytes(get_method_param_type(call_tp, i));
/* Collect all arguments which are passed in registers. */
reg_param_idxs = ALLOCAN(int, n_params);
for (i = 0; i < n_params; ++i) {
- be_abi_call_arg_t *arg = get_call_arg(call, 0, i);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, i, 0);
if (arg && arg->in_reg) {
reg_param_idxs[n_reg_params++] = i;
}
for (i = 0; i < n_stack_params; ++i) {
int p = stack_param_idx[i];
- be_abi_call_arg_t *arg = get_call_arg(call, 0, p);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, p, 0);
ir_node *param = get_Call_param(irn, p);
ir_node *addr = curr_sp;
ir_node *mem = NULL;
for (i = 0; i < n_res; ++i) {
int pn;
ir_node *proj = res_projs[i];
- be_abi_call_arg_t *arg = get_call_arg(call, 1, i);
+ be_abi_call_arg_t *arg = get_call_arg(call, 1, i, 0);
/* returns values on stack not supported yet */
assert(arg->in_reg);
/* Set the register classes and constraints of the Call parameters. */
for (i = 0; i < n_reg_params; ++i) {
int index = reg_param_idxs[i];
- be_abi_call_arg_t *arg = get_call_arg(call, 0, index);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, index, 0);
assert(arg->reg != NULL);
be_set_constr_single_reg_in(low_call, be_pos_Call_first_arg + i,
/* Set the register constraints of the results. */
for (i = 0; i < n_res; ++i) {
ir_node *proj = res_projs[i];
- const be_abi_call_arg_t *arg = get_call_arg(call, 1, i);
+ const be_abi_call_arg_t *arg = get_call_arg(call, 1, i, 0);
int pn = get_Proj_proj(proj);
assert(arg->in_reg);
res = new_type_struct(id_mangle_u(id, new_id_from_chars("arg_type", 8)));
for (i = 0; i < n; ++i, curr += inc) {
ir_type *param_type = get_method_param_type(method_type, curr);
- be_abi_call_arg_t *arg = get_call_arg(call, 0, curr);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, curr, 1);
map[i] = NULL;
if (arg->on_stack) {
/* Insert results for Return into the register map. */
for (i = 0; i < n_res; ++i) {
ir_node *res = get_Return_res(irn, i);
- be_abi_call_arg_t *arg = get_call_arg(call, 1, i);
+ be_abi_call_arg_t *arg = get_call_arg(call, 1, i, 1);
assert(arg->in_reg && "return value must be passed in register");
pmap_insert(reg_map, (void *) arg->reg, res);
}
/* clear SP entry, since it has already been grown. */
pmap_insert(reg_map, (void *) arch_env->sp, NULL);
for (i = 0; i < n_res; ++i) {
- be_abi_call_arg_t *arg = get_call_arg(call, 1, i);
+ be_abi_call_arg_t *arg = get_call_arg(call, 1, i, 1);
in[n] = be_abi_reg_map_get(reg_map, arg->reg);
regs[n++] = arg->reg;
new_list = NULL;
for (i = 0; i < n; ++i) {
int pos = value_param_list[i].pos;
- be_abi_call_arg_t *arg = get_call_arg(call, 0, pos);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, pos, 1);
if (arg->in_reg) {
DBG((dbg, LEVEL_2, "\targ #%d need backing store\n", pos));
/* Count the register params and add them to the number of Projs for the RegParams node */
for (i = 0; i < n_params; ++i) {
- be_abi_call_arg_t *arg = get_call_arg(call, 0, i);
+ be_abi_call_arg_t *arg = get_call_arg(call, 0, i, 1);
if (arg->in_reg && args[i]) {
assert(arg->reg != sp && "cannot use stack pointer as parameter register");
assert(i == get_Proj_proj(args[i]));
ir_mode *mode;
nr = MIN(nr, n_params);
- arg = get_call_arg(call, 0, nr);
+ arg = get_call_arg(call, 0, nr, 1);
param_type = get_method_param_type(method_type, nr);
if (arg->in_reg) {
*/
void be_abi_call_set_call_address_reg_class(be_abi_call_t *call, const arch_register_class_t *cls);
+/**
+ * The ABI can change when we call a function vs. when we have
+ * been called.
+ */
+typedef enum {
+ ABI_CONTEXT_CALLEE = 1 << 0,
+ ABI_CONTEXT_CALLER = 1 << 1,
+ ABI_CONTEXT_BOTH = ABI_CONTEXT_CALLEE | ABI_CONTEXT_CALLER
+} be_abi_context_t;
+
/**
* Record the that ABI transmits call argument pos on the stack. Modifies the abi object.
*
* @param space_before size of allocated additional space before the parameter
* @param space_after size of allocated additional space after the parameter
*/
-void be_abi_call_param_stack(be_abi_call_t *call, int pos, ir_mode *load_mode, unsigned alignment, unsigned space_before, unsigned space_after);
+void be_abi_call_param_stack(be_abi_call_t *call, int pos, ir_mode *load_mode,
+ unsigned alignment, unsigned space_before,
+ unsigned space_after, be_abi_context_t context);
/**
* Record the that ABI transmits call argument pos in the given register.
* @param pos the parameter position
* @param reg the register used
*/
-void be_abi_call_param_reg(be_abi_call_t *call, int pos, const arch_register_t *reg);
+void be_abi_call_param_reg(be_abi_call_t *call, int pos,
+ const arch_register_t *reg,
+ be_abi_context_t context);
/**
* Record the that ABI transmits return value pos in the given register.
* @param pos the return value position
* @param reg the register used
*/
-void be_abi_call_res_reg(be_abi_call_t *call, int pos, const arch_register_t *reg);
+void be_abi_call_res_reg(be_abi_call_t *call, int pos,
+ const arch_register_t *reg,
+ be_abi_context_t context);
/**
* Get the flags of a ABI call object.
void be_init_arch_arm(void);
void be_init_arch_sparc(void);
void be_init_arch_sta(void);
+void be_init_arch_sparc(void);
void be_init_arch_TEMPLATE(void);
void be_init_ilpsched(void);
void be_init_copyilp(void);
reg = ia32_get_RegParam_reg(cc, regnum, mode);
}
if (reg != NULL) {
- be_abi_call_param_reg(abi, i, reg);
+ be_abi_call_param_reg(abi, i, reg, ABI_CONTEXT_BOTH);
++regnum;
} else {
/* Micro optimisation: if the mode is shorter than 4 bytes, load 4 bytes.
if (size < 4) load_mode = mode_Iu;
}
- be_abi_call_param_stack(abi, i, load_mode, 4, 0, 0);
+ be_abi_call_param_stack(abi, i, load_mode, 4, 0, 0, ABI_CONTEXT_BOTH);
}
}
assert(!mode_is_float(mode) && "mixed INT, FP results not supported");
- be_abi_call_res_reg(abi, 0, &ia32_gp_regs[REG_EAX]);
- be_abi_call_res_reg(abi, 1, &ia32_gp_regs[REG_EDX]);
+ be_abi_call_res_reg(abi, 0, &ia32_gp_regs[REG_EAX], ABI_CONTEXT_BOTH);
+ be_abi_call_res_reg(abi, 1, &ia32_gp_regs[REG_EDX], ABI_CONTEXT_BOTH);
}
else if (n == 1) {
const arch_register_t *reg;
reg = mode_is_float(mode) ? &ia32_vfp_regs[REG_VF0] : &ia32_gp_regs[REG_EAX];
- be_abi_call_res_reg(abi, 0, reg);
+ be_abi_call_res_reg(abi, 0, reg, ABI_CONTEXT_BOTH);
}
}
// first 4 params in $a0-$a3, the others on the stack
if (i < 4) {
reg = &mips_gp_regs[REG_A0 + i];
- be_abi_call_param_reg(abi, i, reg);
+ be_abi_call_param_reg(abi, i, reg, ABI_CONTEXT_BOTH);
} else {
/* default: all parameters on stack */
- be_abi_call_param_stack(abi, i, modes[i], 4, 0, 0);
+ be_abi_call_param_stack(abi, i, modes[i], 4, 0, 0, ABI_CONTEXT_BOTH);
}
}
ASSERT_NO_FLOAT(mode);
reg = &mips_gp_regs[REG_V0 + i];
- be_abi_call_res_reg(abi, i, reg);
+ be_abi_call_res_reg(abi, i, reg, ABI_CONTEXT_BOTH);
}
}
}
if (reg)
- be_abi_call_param_reg(abi, i, reg);
+ be_abi_call_param_reg(abi, i, reg, ABI_CONTEXT_BOTH);
else
{
- be_abi_call_param_stack(abi, i, mode, 4, stackoffs - lastoffs, 0);
+ be_abi_call_param_stack(abi, i, mode, 4, stackoffs - lastoffs, 0, ABI_CONTEXT_BOTH);
lastoffs = stackoffs+stackparamsize;
}
stackoffs += stackparamsize;
}
else
{
- be_abi_call_param_stack(abi, i, mode, 4, stackoffs - lastoffs, 0);
+ be_abi_call_param_stack(abi, i, mode, 4, stackoffs - lastoffs, 0, ABI_CONTEXT_BOTH);
stackoffs += (get_type_size_bytes(tp)+3) & -4;
lastoffs = stackoffs;
}
mode = get_type_mode(tp);
be_abi_call_res_reg(abi, 0,
- mode_is_float(mode) ? &ppc32_fp_regs[REG_F1] : &ppc32_gp_regs[REG_R3]);
+ mode_is_float(mode) ? &ppc32_fp_regs[REG_F1] : &ppc32_gp_regs[REG_R3], ABI_CONTEXT_BOTH);
}
}
#include "../beflags.h"
#include "bearch_sparc_t.h"
+#include "bearch_sparc.h"
#include "sparc_new_nodes.h"
#include "gen_sparc_regalloc_if.h"
static int sparc_get_sp_bias(const ir_node *irn)
{
(void) irn;
- return 0;
+ return SPARC_MIN_STACKSIZE;
}
/* fill register allocator interface */
-/**
- * Called immediatly before emit phase.
- */
-static void sparc_finish_irg(void *self)
-{
- sparc_code_gen_t *cg = self;
- ir_graph *irg = cg->irg;
-
- dump_ir_block_graph_sched(irg, "-sparc-finished");
-}
-
-
static ir_node *sparc_flags_remat(ir_node *node, ir_node *after)
{
ir_node *block;
NULL, /* spill hook */
sparc_before_ra, /* before register allocation hook */
sparc_after_ra, /* after register allocation hook */
- sparc_finish_irg,
+ NULL,
sparc_emit_and_done
};
return between_type;
}
+
/**
* Build the prolog, return the BASE POINTER register
*/
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);
+
(void) reg_map;
(void) mem;
(void) stack_bias;
- if (env->flags.try_omit_fp)
- return env->arch_env->sp;
+ // 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);
- //panic("framepointer not implemented yet");
- return env->arch_env->bp;
+ *stack_bias -= SPARC_MIN_STACKSIZE;
+ sp_proj = new_r_Proj(block, save, sp->reg_class->mode, pn_sparc_Save_stack);
+ *mem = new_r_Proj(block, 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 */
/* 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 = 1;
+ /* */
+ call_flags.bits.try_omit_fp = 0;
call_flags.bits.fp_free = 0;
call_flags.bits.call_has_imm = 1;
/* reg = get reg for param i; */
/* be_abi_call_param_reg(abi, i, reg); */
- /* pass args 0-5 via registers, remaining via stack */
+ /* pass outgoing params 0-5 via registers, remaining via stack */
+ /* on sparc we need to set the ABI context since register names of parameters change to i0-i5 if we are the callee */
if (i < 6) {
- be_abi_call_param_reg(abi, i, sparc_get_RegParam_reg(i));
+ 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);
} else {
tp = get_method_param_type(method_type, i);
mode = get_type_mode(tp);
- be_abi_call_param_stack(abi, i, mode, 4, 0, 0);
+ be_abi_call_param_stack(abi, i, mode, 4, 0, 0, ABI_CONTEXT_BOTH); /*< stack args have no special context >*/
}
}
- /* TODO: set correct return register */
- /* default: return value is in O0 resp. F0 */
+ /* set return value register: return value is in i0 resp. f0 */
if (get_method_n_ress(method_type) > 0) {
tp = get_method_res_type(method_type, 0);
mode = get_type_mode(tp);
be_abi_call_res_reg(abi, 0,
- mode_is_float(mode) ? &sparc_fp_regs[REG_F0] : &sparc_gp_regs[REG_O0]);
+ mode_is_float(mode) ? &sparc_fp_regs[REG_F0] : &sparc_gp_regs[REG_I0], ABI_CONTEXT_CALLEE); /*< return has no special context >*/
+
+ be_abi_call_res_reg(abi, 0,
+ mode_is_float(mode) ? &sparc_fp_regs[REG_F0] : &sparc_gp_regs[REG_O0], ABI_CONTEXT_CALLER); /*< return has no special context >*/
}
}
#include "../beemitter.h"
#include "set.h"
+// sparc ABI requires a min stacksize to
+// save registers in case of a trap etc.
+// by now we assume only non-leaf procedures: 92 + 4 (padding)
+#define SPARC_MIN_STACKSIZE 96
+
typedef struct sparc_transform_env_t sparc_transform_env_t;
typedef struct _sparc_isa_t sparc_isa_t;
ir_mode *mode; /**< The mode of the irn */
};
+void sparc_finish_irg(sparc_code_gen_t *cg);
+
#endif
#define SNPRINTF_BUF_LEN 128
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
+/**
+ * attribute of SAVE node which follows immediatelly after the START node
+ * we need this to correct all offsets since SPARC expects
+ * some reserved stack space after the stackpointer
+ */
+const sparc_save_attr_t *save_attr;
+
/**
* Returns the register at in position pos.
*/
{
// TODO: make sure it's a valid simm13 ?
const sparc_attr_t *attr = get_sparc_attr_const(node);
+
+ assert(!(attr->immediate_value < -4096 || attr->immediate_value > 4096));
+
be_emit_irprintf("%d", attr->immediate_value);
}
{
const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
assert(attr->base.is_load_store);
+
if (attr->offset > 0)
- be_emit_irprintf("+0x%X", attr->offset);
+ be_emit_irprintf("+%ld", attr->offset);
}
+
/**
* Emit load mode char
*/
{
int offs = -be_get_IncSP_offset(irn);
- if (offs != 0) {
- /* SPARC stack grows downwards */
- if (offs < 0) {
- be_emit_cstring("\tsub ");
- offs = -offs;
- } else {
- be_emit_cstring("\tadd ");
- }
+ if (offs == 0)
+ return;
- sparc_emit_source_register(irn, 0);
- be_emit_irprintf(", %d", offs);
- be_emit_cstring(", ");
- sparc_emit_dest_register(irn, 0);
- be_emit_finish_line_gas(irn);
+ /* SPARC stack grows downwards */
+ if (offs < 0) {
+ be_emit_cstring("\tsub ");
+ offs = -offs;
} else {
- // ignore IncSP(0)
- //be_emit_cstring("\t/* IncSP(0) skipped */");
-
-// be_emit_cstring("\t/* ");
-// be_emit_cstring("sub ");
-// offs = -offs;
-// sparc_emit_source_register(irn, 0);
-// be_emit_irprintf(", %d", offs);
-// be_emit_cstring(", ");
-// sparc_emit_dest_register(irn, 0);
-// be_emit_cstring(" ignored */ ");
-// be_emit_finish_line_gas(irn);
+ be_emit_cstring("\tadd ");
}
+ sparc_emit_source_register(irn, 0);
+ be_emit_irprintf(", %d", offs);
+ be_emit_cstring(", ");
+ sparc_emit_dest_register(irn, 0);
+ be_emit_finish_line_gas(irn);
+}
+/**
+ * emits code for save instruction
+ * and sets the current save_attr pointer
+ */
+static void emit_sparc_Save(const ir_node *irn)
+{
+ save_attr = get_sparc_save_attr_const(irn);
+ be_emit_cstring("\tsave ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_irprintf(", %d, ", -save_attr->initial_stacksize);
+ sparc_emit_dest_register(irn, 0);
+ be_emit_finish_line_gas(irn);
}
+/**
+ * emits code to load hi 22 bit of a constant
+ */
+static void emit_sparc_HiImm(const ir_node *irn)
+{
+ const sparc_attr_t *attr = get_sparc_attr_const(irn);
+ be_emit_cstring("\tsethi ");
+ be_emit_irprintf("%%hi(%d), ", attr->immediate_value);
+ sparc_emit_dest_register(irn, 0);
+ be_emit_finish_line_gas(irn);
+}
+
+/**
+ * emits code to load lo 10bits of a constant
+ */
+static void emit_sparc_LoImm(const ir_node *irn)
+{
+ const sparc_attr_t *attr = get_sparc_attr_const(irn);
+ be_emit_cstring("\tor ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_irprintf(", %%lo(%d), ", attr->immediate_value);
+ sparc_emit_dest_register(irn, 0);
+ be_emit_finish_line_gas(irn);
+}
+
+
/**
* Emits code for return node
*/
{
be_emit_cstring("\tret");
be_emit_finish_line_gas(irn);
+ be_emit_cstring("\trestore");
+ be_emit_finish_line_gas(irn);
}
/**
}
}
+/**
+ * TODO: check if this is correct
+ */
+static void emit_be_Perm(const ir_node *irn)
+{
+ be_emit_cstring("\txor ");
+ sparc_emit_source_register(irn, 1);
+ be_emit_cstring(", ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_cstring(", ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_finish_line_gas(NULL);
+
+ be_emit_cstring("\txor ");
+ sparc_emit_source_register(irn, 1);
+ be_emit_cstring(", ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_cstring(", ");
+ sparc_emit_source_register(irn, 1);
+ be_emit_finish_line_gas(NULL);
+
+ be_emit_cstring("\txor ");
+ sparc_emit_source_register(irn, 1);
+ be_emit_cstring(", ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_cstring(", ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_finish_line_gas(irn);
+}
+
/**
* Emit a SymConst.
*/
static void emit_sparc_SymConst(const ir_node *irn)
{
const sparc_symconst_attr_t *attr = get_sparc_symconst_attr_const(irn);
- //const char *entity_name = get_entity_ld_name(attr->entity);
ident *id_symconst = get_entity_ident(attr->entity);
const char *label = get_id_str(id_symconst);
be_emit_irprintf("\tsethi %%hi(%s), ", label);
sparc_emit_dest_register(irn, 0);
be_emit_cstring("\n ");
+
+ // TODO: could be combined with the following load/store instruction
be_emit_cstring("\tor ");
sparc_emit_dest_register(irn, 0);
be_emit_irprintf(", %%lo(%s), ", label);
static void emit_sparc_FrameAddr(const ir_node *irn)
{
const sparc_symconst_attr_t *attr = get_irn_generic_attr_const(irn);
- be_emit_cstring("\tadd ");
- sparc_emit_source_register(irn, 0);
- be_emit_cstring(", ");
- be_emit_irprintf("0x%X", attr->fp_offset);
+
+ // no need to fix offset as we are adressing via the framepointer
+ if (attr->fp_offset >= 0) {
+ be_emit_cstring("\tadd ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_cstring(", ");
+ be_emit_irprintf("%ld", attr->fp_offset + save_attr->initial_stacksize);
+ } else {
+ be_emit_cstring("\tsub ");
+ sparc_emit_source_register(irn, 0);
+ be_emit_cstring(", ");
+ be_emit_irprintf("%ld", -attr->fp_offset);
+ }
+
be_emit_cstring(", ");
sparc_emit_dest_register(irn, 0);
be_emit_finish_line_gas(irn);
proj_num = get_negated_pnc(proj_num, mode_Iu);
}
+
switch (proj_num) {
case pn_Cmp_Eq: suffix = "e"; break;
case pn_Cmp_Lt: suffix = "l"; break;
be_emit_cstring("\tba ");
sparc_emit_cfop_target(proj_false);
be_emit_finish_line_gas(proj_false);
- be_emit_cstring("\tnop\t\t/* TODO: use delay slot */");
- be_emit_write_line();
+ be_emit_cstring("\tnop\t\t/* TODO: use delay slot */\n");
+ be_emit_finish_line_gas(proj_false);
}
}
/**
- * emit Jmp (which actually is a branch always)
+ * emit Jmp (which actually is a branch always (ba) instruction)
*/
static void emit_sparc_Jmp(const ir_node *node)
{
if (get_irn_link(node) != next_block) {
be_emit_cstring("\tba ");
sparc_emit_cfop_target(node);
+ be_emit_finish_line_gas(node);
+ be_emit_cstring("\tnop\t\t/* TODO: use delay slot */\n");
} else {
be_emit_cstring("\t/* fallthrough to ");
sparc_emit_cfop_target(node);
be_emit_finish_line_gas(node);
}
+/**
+ * emit copy node
+ */
static void emit_be_Copy(const ir_node *irn)
{
ir_mode *mode = get_irn_mode(irn);
set_emitter(op_sparc_Branch, emit_sparc_Branch);
set_emitter(op_sparc_SymConst, emit_sparc_SymConst);
set_emitter(op_sparc_Jmp, emit_sparc_Jmp);
+ set_emitter(op_sparc_Save, emit_sparc_Save);
+
+ set_emitter(op_sparc_HiImm, emit_sparc_HiImm);
+ set_emitter(op_sparc_LoImm, emit_sparc_LoImm);
set_emitter(op_be_Copy, emit_be_Copy);
set_emitter(op_be_CopyKeep, emit_be_Copy);
+ set_emitter(op_be_Perm, emit_be_Perm);
+
/*
set_emitter(op_arm_B, emit_arm_B);
set_emitter(op_arm_CopyB, emit_arm_CopyB);
set_emitter(op_arm_LdTls, emit_arm_LdTls);
set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
set_emitter(op_be_MemPerm, emit_be_MemPerm);
- set_emitter(op_be_Perm, emit_be_Perm);
+
*/
/* no need to emit anything for the following nodes */
set_emitter(op_Phi, emit_nothing);
static void sparc_emit_func_prolog(ir_graph *irg)
{
ir_entity *ent = get_irg_entity(irg);
-
be_gas_emit_function_prolog(ent, 4);
- // TODO: fetch reg names via API func
- // TODO: move value to SPARC_MIN_STACKSIZE const
- be_emit_cstring("\tsave %sp, -64, %sp");
- be_emit_cstring("\t/* incr CWP and alloc min. required stack space */\n");
be_emit_write_line();
}
{
ir_entity *ent = get_irg_entity(irg);
const char *irg_name = get_entity_ld_name(ent);
-
- be_emit_cstring("\trestore");
- be_emit_cstring("\t/* decr CWP */\n");
+ be_emit_write_line();
be_emit_irprintf("\t.size %s, .-%s\n", irg_name, irg_name);
be_emit_cstring("# -- End ");
be_emit_string(irg_name);
#include "gen_sparc_regalloc_if.h"
-static const arch_register_t *gp_param_regs[] = {
+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_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
+ */
+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];
+}
-const arch_register_t *sparc_get_RegParam_reg(int n)
+/**
+ * get register for incoming parameters 1-6
+ */
+const arch_register_t *sparc_get_RegParamIn_reg(int n)
{
- assert(n < 6 && n >=0 && "trying to get register for param >= 6");
- return gp_param_regs[n];
+ assert(n < 6 && n >=0 && "trying to get (in) register for param >= 6");
+ return gp_param_in_regs[n];
}
#include "../bearch.h"
#include "sparc_nodes_attr.h"
-const arch_register_t *sparc_get_RegParam_reg(int n);
+const arch_register_t *sparc_get_RegParamIn_reg(int n);
+
+const arch_register_t *sparc_get_RegParamOut_reg(int n);
#endif
}
break;
+ case dump_node_info_txt:
+ arch_dump_reqs_and_registers(F, n);
+ break;
+
case dump_node_nodeattr_txt:
/* TODO: dump some attributes which should show up */
/* in node name in dump (e.g. consts or the like) */
+ fputs("\n", F);
- break;
+ if (is_sparc_FrameAddr(n)) {
+ const sparc_symconst_attr_t *attr = get_sparc_symconst_attr_const(n);
+ fprintf(F, "fp_offset: 0x%X\n", attr->fp_offset);
+ }
+
+ if (is_sparc_Load(n) || is_sparc_Store(n)) {
+ const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(n);
+ fprintf(F, "offset: 0x%lX\n", attr->offset);
+ fprintf(F, "is_frame_entity: %s\n", attr->is_frame_entity == true ? "true" : "false");
+ }
- case dump_node_info_txt:
- arch_dump_reqs_and_registers(F, n);
break;
+
+
}
return 0;
return (const sparc_jmp_switch_attr_t *)get_irn_generic_attr_const(node);
}
-
sparc_cmp_attr_t *get_sparc_cmp_attr(ir_node *node)
{
assert(is_sparc_irn(node) && "need sparc node to get attributes");
return (const sparc_cmp_attr_t *)get_irn_generic_attr_const(node);
}
+
+sparc_save_attr_t *get_sparc_save_attr(ir_node *node)
+{
+ assert(is_sparc_Save(node) && "need sparc Save node to get attributes");
+ return (sparc_save_attr_t *)get_irn_generic_attr_const(node);
+}
+
+const sparc_save_attr_t *get_sparc_save_attr_const(const ir_node *node)
+{
+ assert(is_sparc_Save(node) && "need sparc Save node to get attributes");
+ return (const sparc_save_attr_t *)get_irn_generic_attr_const(node);
+}
+
/**
* Returns the argument register requirements of a sparc node.
*/
attr->fp_offset = 0;
}
+static void init_sparc_save_attr(ir_node *res, int initial_stacksize)
+{
+ sparc_save_attr_t *attr = get_irn_generic_attr(res);
+ attr->initial_stacksize = initial_stacksize;
+}
+
/**
* copies sparc attributes of node
*/
|| attr_a->is_unsigned != attr_b->is_unsigned;
}
+static int cmp_attr_sparc_save(ir_node *a, ir_node *b)
+{
+ const sparc_save_attr_t *attr_a = get_sparc_save_attr_const(a);
+ const sparc_save_attr_t *attr_b = get_sparc_save_attr_const(b);
+
+ if (cmp_attr_sparc(a, b))
+ return 1;
+
+ return attr_a->initial_stacksize != attr_b->initial_stacksize;
+}
+
/* Include the generated constructor functions */
#include "gen_sparc_new_nodes.c.inl"
sparc_cmp_attr_t *get_sparc_cmp_attr(ir_node *node);
const sparc_cmp_attr_t *get_sparc_cmp_attr_const(const ir_node *node);
+sparc_save_attr_t *get_sparc_save_attr(ir_node *node);
+const sparc_save_attr_t *get_sparc_save_attr_const(const ir_node *node);
+
+
/**
* Returns the argument register requirements of an sparc node.
*/
};
+/**
+ * attribute for save instruction
+ */
+typedef struct sparc_save_attr_t sparc_save_attr_t;
+struct sparc_save_attr_t {
+ sparc_attr_t base; /**< generic attribute */
+ int initial_stacksize; /* the min. stack size required by the sparc ABI */
+};
+
/**
* attributes for load/store adressing modes
*/
{ name => "g4", realname => "g4", type => 1 },
{ name => "g5", realname => "g5", type => 4 }, # reserved by SPARC ABI
{ name => "g6", realname => "g6", type => 4 }, # reserved by SPARC ABI
- { name => "g7", realname => "g7", type => 2 }, # reserved by SPARC ABI
+ { name => "g7", realname => "g7", type => 4 }, # reserved by SPARC ABI
# window's out registers
- { name => "o0", realname => "o0", type => 1 }, # param 1 / return value from callee
- { name => "o1", realname => "o1", type => 1 }, # param 2
- { name => "o2", realname => "o2", type => 1 }, # param 3
- { name => "o3", realname => "o3", type => 1 }, # param 4
- { name => "o4", realname => "o4", type => 1 }, # param 5
- { name => "o5", realname => "o5", type => 1 }, # param 6
+ { name => "o0", realname => "o0", type => 0 }, # param 1 / return value from callee
+ { name => "o1", realname => "o1", type => 0 }, # param 2
+ { name => "o2", realname => "o2", type => 0 }, # param 3
+ { name => "o3", realname => "o3", type => 0 }, # param 4
+ { name => "o4", realname => "o4", type => 0 }, # param 5
+ { name => "o5", realname => "o5", type => 0 }, # param 6
{ name => "sp", realname => "sp", type => 4 }, # our stackpointer
- { name => "o7", realname => "o6", type => 1 }, # temp. value / address of CALL instr.
+ { name => "o7", realname => "o6", type => 4 }, # temp. value / address of CALL instr.
# window's local registers
- { name => "l0", realname => "l0", type => 2 },
- { name => "l1", realname => "l1", type => 2 },
- { name => "l2", realname => "l2", type => 2 },
- { name => "l3", realname => "l3", type => 2 },
- { name => "l4", realname => "l4", type => 2 },
- { name => "l5", realname => "l5", type => 2 },
- { name => "l6", realname => "l6", type => 2 },
- { name => "l7", realname => "l7", type => 2 },
+ { name => "l0", realname => "l0", type => 0 },
+ { name => "l1", realname => "l1", type => 0 },
+ { name => "l2", realname => "l2", type => 0 },
+ { name => "l3", realname => "l3", type => 0 },
+ { name => "l4", realname => "l4", type => 0 },
+ { name => "l5", realname => "l5", type => 0 },
+ { name => "l6", realname => "l6", type => 0 },
+ { name => "l7", realname => "l7", type => 0 },
# window's in registers
- { name => "i0", realname => "i0", type => 2 }, # incoming param1 / return value to caller
- { name => "i1", realname => "i1", type => 2 }, # param 2
- { name => "i2", realname => "i2", type => 2 }, # param 3
- { name => "i3", realname => "i3", type => 2 }, # param 4
- { name => "i4", realname => "i4", type => 2 }, # param 5
- { name => "i5", realname => "i5", type => 2 }, # param 6
- { name => "fp", realname => "i6", type => 4 }, # our framepointer
- { name => "i7", realname => "i7", type => 2 }, # return address - 8
+ { name => "i0", realname => "i0", type => 1 }, # incoming param1 / return value to caller
+ { name => "i1", realname => "i1", type => 1 }, # param 2
+ { name => "i2", realname => "i2", type => 1 }, # param 3
+ { name => "i3", realname => "i3", type => 1 }, # param 4
+ { name => "i4", realname => "i4", type => 1 }, # param 5
+ { name => "i5", realname => "i5", type => 1 }, # param 6
+ { name => "fp", realname => "fp", type => 4 }, # our framepointer
+ { name => "i7", realname => "i7", type => 4 }, # return address - 8
{ mode => $mode_gp }
],
flags => [
%init_attr = (
- sparc_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
- sparc_load_store_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
+ sparc_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
+ sparc_load_store_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_sparc_load_store_attributes(res, ls_mode, entity, entity_sign, offset, is_frame_entity);",
- sparc_symconst_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
- "\tinit_sparc_symconst_attributes(res, entity);",
- sparc_cmp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n",
- sparc_jmp_cond_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
- sparc_jmp_switch_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
+ sparc_symconst_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
+ "\tinit_sparc_symconst_attributes(res, entity);",
+ sparc_cmp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n",
+ sparc_jmp_cond_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
+ sparc_jmp_switch_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
+ sparc_save_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
);
%compare_attr = (
- sparc_attr_t => "cmp_attr_sparc",
- sparc_load_store_attr_t => "cmp_attr_sparc_load_store",
- sparc_symconst_attr_t => "cmp_attr_sparc_symconst",
- sparc_jmp_cond_attr_t => "cmp_attr_sparc_jmp_cond",
- sparc_jmp_switch_attr_t => "cmp_attr_sparc_jmp_switch",
- sparc_cmp_attr_t => "cmp_attr_sparc_cmp",
+ sparc_attr_t => "cmp_attr_sparc",
+ sparc_load_store_attr_t => "cmp_attr_sparc_load_store",
+ sparc_symconst_attr_t => "cmp_attr_sparc_symconst",
+ sparc_jmp_cond_attr_t => "cmp_attr_sparc_jmp_cond",
+ sparc_jmp_switch_attr_t => "cmp_attr_sparc_jmp_switch",
+ sparc_cmp_attr_t => "cmp_attr_sparc_cmp",
+ sparc_save_attr_t => "cmp_attr_sparc_save",
);
custominit => "sparc_set_attr_imm(res, immediate_value);" .
"\tinit_sparc_cmp_attr(res, ins_permuted, is_unsigned);",
reg_req => { in => [ "gp" ], out => [ "flags" ] },
- ins => [ "left" ],
+ ins => [ "left" ],
},
reg => {
- attr => "bool ins_permuted, bool is_unsigned",
+ attr => "bool ins_permuted, bool is_unsigned",
custominit => "init_sparc_cmp_attr(res, ins_permuted, is_unsigned);",
reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] },
ins => [ "left", "right" ],
reg_req => { in => [], out => [ "gp" ] },
},
reg => {
- # custominit => "set_sparc_attr_values(res, immediate_value);",
reg_req => { in => [ "gp" ], out => [ "gp" ] },
},
);
ins => [ "left" ],
},
reg => {
- # custominit => "set_sparc_attr_values(res, immediate_value);",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
ins => [ "left", "right" ],
},
reg_req => { in => [ "gp", "none" ], out => [ "gp", "none" ] },
attr_type => "sparc_load_store_attr_t",
attr => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity",
- emit => '. sethi %%hi(%S1), %D1'
+ emit => '. sethi %%hi(%S1), %D1',
+},
+
+HiImm => {
+ op_flags => "R",
+ comment => "construct LoadHi: Load(imm, mem) = sethi hi(imm) -> reg",
+ state => "exc_pinned",
+ outs => [ "res" ],
+ mode => $mode_gp,
+ reg_req => { in => [], out => [ "gp" ] },
+ #attr_type => "sparc_load_store_attr_t",
+ attr => "int immediate_value",
+ custominit => "sparc_set_attr_imm(res, immediate_value);",
+
+},
+
+LoImm => {
+ op_flags => "R",
+ comment => "construct LoadHi: Load(imm, mem) = sethi hi(imm) -> reg",
+ state => "exc_pinned",
+ ins => [ "hireg" ],
+ outs => [ "res" ],
+ mode => $mode_gp,
+ reg_req => { in => [ "gp" ], out => [ "gp" ] },
+ #attr_type => "sparc_load_store_attr_t",
+ attr => "int immediate_value",
+ custominit => "sparc_set_attr_imm(res, immediate_value);",
+
},
LoadLo => {
constructors => \%unop_operand_constructors,
},
+Save => {
+ comment => "function prolog instruction. autom. saves sp & shifts the register window. previous out regs become the new in regs",
+ reg_req => {
+ in => [ "sp", "none"],
+ out => [ "sp:I|S","none" ]
+ },
+ ins => [ "stack", "mem" ],
+ outs => [ "stack", "mem" ],
+ attr => "int initial_stacksize",
+ attr_type => "sparc_save_attr_t",
+ init_attr => "\tinit_sparc_save_attr(res, initial_stacksize);",
+},
+
AddSP => {
comment => "alloc stack space",
reg_req => { in => [ "sp", "gp", "none" ], out => [ "sp:I|S", "gp", "none" ] },
constructors => \%binop_operand_constructors,
},
-#Mul => {
-# op_flags => "C",
-# irn_flags => "R",
-# comment => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
-# reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
-# emit =>'. mul %S1, %S2, %D1'
-#},
+Xor => {
+ irn_flags => "R",
+ comment => "construct logical xor",
+ mode => $mode_gp,
+ reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
+ emit => '. xor %S1, %R2I, %D1',
+ constructors => \%binop_operand_constructors,
+},
+
+UMul => {
+ state => "exc_pinned",
+ comment => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
+ reg_req => { in => [ "gp", "gp" ], out => [ "gp", "flags" ] },
+ outs => [ "low", "high" ],
+ constructors => \%binop_operand_constructors,
+ emit =>'. umul %S1, %R2I, %D1'
+},
+
+Minus => {
+ irn_flags => "R",
+ mode => $mode_gp,
+ comment => "construct Minus: Minus(a) = -a",
+ #reg_req => { in => [ "gp" ], out => [ "in_r1" ] },
+ reg_req => { in => [ "gp" ], out => [ "gp" ] },
+ emit => ". sub %%g0, %S1, %D1"
+},
+
+Not => {
+ irn_flags => "R",
+ mode => $mode_gp,
+ comment => "construct Not: Not(a) = !a",
+ reg_req => { in => [ "gp" ], out => [ "gp" ] },
+ emit => '. xnor %S1, %%g0, %D1'
+},
#Mul_i => {
# irn_flags => "R",
{
ir_node *result;
- // TODO: find a better solution for this
+ // we need to load hi & lo separately
if (value < -4096 || value > 4095) {
- panic("FIXME: immediate value exceeds max. size of simm13 (13 bits signed)");
+ ir_node *hi = new_bd_sparc_HiImm(dbgi, block, (int) value);
+ result = new_bd_sparc_LoImm(dbgi, block, hi, value);
+ be_dep_on_frame(hi);
+ } else {
+ result = new_bd_sparc_Mov_imm(dbgi, block, (int) value);
+ be_dep_on_frame(result);
}
- result = new_bd_sparc_Mov_imm(dbgi, block, (int) value);
return result;
}
{
tarval *tv = get_Const_tarval(irn);
ir_mode *mode = get_tarval_mode(tv);
+ dbg_info *dbgi = get_irn_dbg_info(irn);
long value;
+
if (mode_is_reference(mode)) {
/* SPARC V8 is 32bit, so we can safely convert a reference tarval into Iu */
assert(get_mode_size_bits(mode) == get_mode_size_bits(mode_Iu));
tv = tarval_convert_to(tv, mode_Iu);
}
+
value = get_tarval_long(tv);
- return create_const_graph_value(get_irn_dbg_info(irn), block, value);
+ return create_const_graph_value(dbgi, block, value);
}
typedef ir_node* (*new_binop_imm_func) (dbg_info *dbgi, ir_node *block, ir_node *op1, int simm13);
/**
- * checks wether a node's value can be encoded as a immediate
- * TODO: pass a result pointer to fetch the encoded immediate
+ * checks if a node's value can be encoded as a immediate
*
*/
static bool is_imm_encodeable(const ir_node *node)
{
ir_mode *mode = get_irn_mode(node);
ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *op1 = get_Add_left(node);
- ir_node *op2 = get_Add_right(node);
dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *new_op1 = be_transform_node(op1);
- ir_node *new_op2 = be_transform_node(op2);
- (void) new_op1;
- (void) new_op2;
(void) block;
(void) dbgi;
{
ir_mode *mode = get_irn_mode(node);
ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *op1 = get_Add_left(node);
- ir_node *op2 = get_Add_right(node);
dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *new_op1 = be_transform_node(op1);
- ir_node *new_op2 = be_transform_node(op2);
- (void) new_op1;
- (void) new_op2;
(void) block;
(void) dbgi;
return new_store;
}
+/**
+ * Creates an sparc Mul.
+ *
+ * @return the created sparc Mul node
+ */
+static ir_node *gen_Mul(ir_node *node) {
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_mode *mode = get_irn_mode(node);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+
+ ir_node *mul;
+ ir_node *proj_res_low;
+
+ if (mode_is_float(mode))
+ panic("FP not supported yet");
+
+
+ assert(mode_is_data(mode));
+ mul = gen_helper_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, new_bd_sparc_UMul_reg, new_bd_sparc_UMul_imm);
+
+ // TODO: throws an error - check why
+ proj_res_low = new_rd_Proj(dbgi, block, mul, mode_Iu, pn_sparc_UMul_low);
+ return proj_res_low;
+
+ //return gen_helper_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, new_bd_sparc_Mul_reg, new_bd_sparc_Mul_imm);
+}
+/**
+ * transform abs node:
+ * mov a, b
+ * sra b, 31, b
+ * xor a, b
+ * sub a, b
+ *
+ * @return
+ */
+static ir_node *gen_Abs(ir_node *node) {
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_mode *mode = get_irn_mode(node);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *op = get_Abs_op(node);
+
+ ir_node *mov, *sra, *xor, *sub, *new_op;
+
+ if (mode_is_float(mode))
+ panic("FP not supported yet");
+
+ new_op = be_transform_node(op);
+
+ mov = new_bd_sparc_Mov_reg(dbgi, block, new_op);
+ sra = new_bd_sparc_ShiftRA_imm(dbgi, block, mov, 31);
+ xor = new_bd_sparc_Xor_reg(dbgi, block, new_op, sra);
+ sub = new_bd_sparc_Sub_reg(dbgi, block, sra, xor);
+
+ return sub;
+}
+
+/**
+ * Transforms a Not node.
+ *
+ * @return the created ARM Not node
+ */
+static ir_node *gen_Not(ir_node *node)
+{
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *op = get_Not_op(node);
+ ir_node *new_op = be_transform_node(op);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+
+ return new_bd_sparc_Not(dbgi, block, new_op);
+}
+
+static ir_node *gen_Shl(ir_node *node)
+{
+ return gen_helper_binop(node, MATCH_SIZE_NEUTRAL, new_bd_sparc_ShiftLL_reg, new_bd_sparc_ShiftLL_imm);
+}
+
+static ir_node *gen_Shr(ir_node *node)
+{
+ return gen_helper_binop(node, MATCH_SIZE_NEUTRAL, new_bd_sparc_ShiftLR_reg, new_bd_sparc_ShiftLR_imm);
+}
/****** TRANSFORM GENERAL BACKEND NODES ********/
+/**
+ * Transforms a Minus node.
+ *
+ */
+static ir_node *gen_Minus(ir_node *node)
+{
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *op = get_Minus_op(node);
+ ir_node *new_op = be_transform_node(op);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_mode *mode = get_irn_mode(node);
+
+ if (mode_is_float(mode)) {
+ panic("FP not implemented yet");
+ }
+
+ assert(mode_is_data(mode));
+ return new_bd_sparc_Minus(dbgi, block, new_op);
+}
+
/**
* Transforms a Const node.
*
is_unsigned = !mode_is_signed(cmp_mode);
/* compare with 0 can be done with Tst */
+ /*
if (is_Const(op2) && tarval_is_null(get_Const_tarval(op2))) {
new_op1 = be_transform_node(op1);
return new_bd_sparc_Tst(dbgi, block, new_op1, false,
return new_bd_sparc_Tst(dbgi, block, new_op2, true,
is_unsigned);
}
+ */
/* integer compare */
new_op1 = be_transform_node(op1);
}
}
+static ir_node *gen_Unknown(ir_node *node)
+{
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+
+ /* just produce a 0 */
+ ir_mode *mode = get_irn_mode(node);
+ if (mode_is_float(mode)) {
+ panic("FP not implemented");
+ be_dep_on_frame(node);
+ return node;
+ } else if (mode_needs_gp_reg(mode)) {
+ return create_const_graph_value(dbgi, new_block, 0);
+ }
+
+ panic("Unexpected Unknown mode");
+}
+
/**
* Transform some Phi nodes
*/
return be_duplicate_node(node);
}
+
/**
* transform a Jmp
*/
set_transformer(op_Conv, gen_Conv);
set_transformer(op_Jmp, gen_Jmp);
+ set_transformer(op_Mul, gen_Mul);
+ set_transformer(op_Abs, gen_Abs);
+ set_transformer(op_Shl, gen_Shl);
+ set_transformer(op_Shr, gen_Shr);
+
+ set_transformer(op_Minus, gen_Minus);
+ set_transformer(op_Not, gen_Not);
+
+ set_transformer(op_Unknown, gen_Unknown);
+
/* node list */
/*
- set_transformer(op_Abs, gen_Abs);
- set_transformer(op_Add, gen_Add);
set_transformer(op_And, gen_And);
- set_transformer(op_Const, gen_Const);
- set_transformer(op_Conv, gen_Conv);
set_transformer(op_CopyB, gen_CopyB);
set_transformer(op_Eor, gen_Eor);
- set_transformer(op_Jmp, gen_Jmp);
- set_transformer(op_Load, gen_Load);
- set_transformer(op_Minus, gen_Minus);
set_transformer(op_Mul, gen_Mul);
- set_transformer(op_Not, gen_Not);
set_transformer(op_Or, gen_Or);
set_transformer(op_Quot, gen_Quot);
set_transformer(op_Rotl, gen_Rotl);
- set_transformer(op_Shl, gen_Shl);
- set_transformer(op_Shr, gen_Shr);
set_transformer(op_Shrs, gen_Shrs);
- set_transformer(op_Store, gen_Store);
- set_transformer(op_Sub, gen_Sub);
- set_transformer(op_Unknown, gen_Unknown);
*/
set_transformer(op_ASM, bad_transform);