- various updates to sparc backend
authorHannes Rapp <rapp@ipd.info.uni-karlsruhe.de>
Tue, 13 Apr 2010 13:35:54 +0000 (13:35 +0000)
committerHannes Rapp <rapp@ipd.info.uni-karlsruhe.de>
Tue, 13 Apr 2010 13:35:54 +0000 (13:35 +0000)
- extende beabi so you can specify different registers at the call site
  and the beginning of a called function
- adapt all backends for API changes

[r27390]

18 files changed:
ir/be/TEMPLATE/bearch_TEMPLATE.c
ir/be/arm/bearch_arm.c
ir/be/beabi.c
ir/be/beabi.h
ir/be/bemodule.c
ir/be/ia32/bearch_ia32.c
ir/be/mips/bearch_mips.c
ir/be/ppc32/bearch_ppc32.c
ir/be/sparc/bearch_sparc.c
ir/be/sparc/bearch_sparc_t.h
ir/be/sparc/sparc_emitter.c
ir/be/sparc/sparc_map_regs.c
ir/be/sparc/sparc_map_regs.h
ir/be/sparc/sparc_new_nodes.c
ir/be/sparc/sparc_new_nodes.h
ir/be/sparc/sparc_nodes_attr.h
ir/be/sparc/sparc_spec.pl
ir/be/sparc/sparc_transform.c

index e4ba0d2..81b249a 100644 (file)
@@ -384,12 +384,12 @@ static void TEMPLATE_get_call_abi(const void *self, ir_type *method_type,
        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 */
@@ -399,7 +399,7 @@ static void TEMPLATE_get_call_abi(const void *self, ir_type *method_type,
                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);
        }
 }
 
index d06f8eb..d4cf7a1 100644 (file)
@@ -949,11 +949,11 @@ static void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call
                /* 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);
                }
        }
 
@@ -974,8 +974,8 @@ static void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call
 
                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;
 
@@ -984,7 +984,7 @@ static void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call
                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);
        }
 }
 
index f81292a..9568bd7 100644 (file)
@@ -63,6 +63,7 @@ typedef struct _be_abi_call_arg_t {
        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;
@@ -141,7 +142,7 @@ static int cmp_call_arg(const void *a, const void *b, size_t n)
 {
        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);
 }
 
 /**
@@ -150,8 +151,9 @@ static int cmp_call_arg(const void *a, const void *b, size_t n)
  * @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;
@@ -159,6 +161,7 @@ static be_abi_call_arg_t *get_call_arg(be_abi_call_t *call, int is_res, int pos)
        memset(&arg, 0, sizeof(arg));
        arg.is_res = is_res;
        arg.pos    = pos;
+       arg.callee = callee;
 
        hash = is_res * 128 + pos;
 
@@ -167,23 +170,18 @@ static be_abi_call_arg_t *get_call_arg(be_abi_call_t *call, int is_res, int 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. */
@@ -207,29 +205,49 @@ void be_abi_call_set_call_address_reg_class(be_abi_call_t *call, const arch_regi
 }
 
 
-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. */
@@ -379,16 +397,6 @@ static be_stack_layout_t *stack_frame_init(be_stack_layout_t *frame, ir_type *ar
        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;
-}
-
 /*
    ____      _ _
   / ___|__ _| | |___
@@ -456,7 +464,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        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));
@@ -472,7 +480,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        /* 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;
                }
@@ -519,7 +527,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
 
                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;
@@ -701,7 +709,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        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);
@@ -739,7 +747,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        /* 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,
@@ -749,7 +757,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        /* 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);
@@ -1226,7 +1234,7 @@ static ir_type *compute_arg_type(be_abi_irg_t *env, be_abi_call_t *call,
        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) {
@@ -1388,7 +1396,7 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
        /* 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);
        }
@@ -1424,7 +1432,7 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
        /* 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;
@@ -1583,7 +1591,7 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ent_pos_pair *val
        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));
@@ -1890,7 +1898,7 @@ static void modify_irg(be_abi_irg_t *env)
 
        /* 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]));
@@ -1995,7 +2003,7 @@ static void modify_irg(be_abi_irg_t *env)
                        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) {
index b307fe9..2c5dc82 100644 (file)
@@ -120,6 +120,16 @@ void be_abi_call_set_pop(be_abi_call_t *call, int pop);
  */
 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.
  *
@@ -130,7 +140,9 @@ void be_abi_call_set_call_address_reg_class(be_abi_call_t *call, const arch_regi
  * @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.
@@ -139,7 +151,9 @@ void be_abi_call_param_stack(be_abi_call_t *call, int pos, ir_mode *load_mode, u
  * @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.
@@ -148,7 +162,9 @@ void be_abi_call_param_reg(be_abi_call_t *call, int pos, const arch_register_t *
  * @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.
index b4369df..7eaa41e 100644 (file)
@@ -59,6 +59,7 @@ void be_init_arch_mips(void);
 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);
index cfa5f96..ba40fee 100644 (file)
@@ -1899,7 +1899,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type,
                        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.
@@ -1916,7 +1916,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type,
                                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);
                }
        }
 
@@ -1939,8 +1939,8 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type,
 
                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;
@@ -1951,7 +1951,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type,
 
                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);
        }
 }
 
index 37904da..df2a16f 100644 (file)
@@ -603,10 +603,10 @@ static void mips_get_call_abi(const void *self, ir_type *method_type,
                // 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);
                }
        }
 
@@ -621,7 +621,7 @@ static void mips_get_call_abi(const void *self, ir_type *method_type,
                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);
        }
 }
 
index 5d3c70d..adb00bd 100644 (file)
@@ -660,17 +660,17 @@ static void ppc32_get_call_abi(const void *self, ir_type *method_type, be_abi_ca
                        }
 
                        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;
                }
@@ -682,7 +682,7 @@ static void ppc32_get_call_abi(const void *self, ir_type *method_type, be_abi_ca
                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);
        }
 }
 
index 6ab6ada..fec1b04 100644 (file)
@@ -60,6 +60,7 @@
 #include "../beflags.h"
 
 #include "bearch_sparc_t.h"
+#include "bearch_sparc.h"
 
 #include "sparc_new_nodes.h"
 #include "gen_sparc_regalloc_if.h"
@@ -121,7 +122,7 @@ static void sparc_set_frame_offset(ir_node *irn, int offset)
 static int sparc_get_sp_bias(const ir_node *irn)
 {
        (void) irn;
-       return 0;
+       return SPARC_MIN_STACKSIZE;
 }
 
 /* fill register allocator interface */
@@ -158,18 +159,6 @@ static void sparc_prepare_graph(void *self)
 
 
 
-/**
- * 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;
@@ -302,7 +291,7 @@ static const arch_code_generator_if_t sparc_code_gen_if = {
        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
 };
 
@@ -459,6 +448,7 @@ static ir_type *sparc_get_between_type(void *self)
        return between_type;
 }
 
+
 /**
  * Build the prolog, return the BASE POINTER register
  */
@@ -466,15 +456,34 @@ 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);
+
        (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 */
@@ -513,7 +522,8 @@ static void sparc_get_call_abi(const void *self, ir_type *method_type,
        /* 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;
 
@@ -524,24 +534,28 @@ static void sparc_get_call_abi(const void *self, ir_type *method_type,
                /* 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 >*/
        }
 }
 
index 1c3add8..8240ef0 100644 (file)
 #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;
 
@@ -62,4 +67,6 @@ struct sparc_transform_env_t {
        ir_mode  *mode;     /**< The mode of the irn */
 };
 
+void sparc_finish_irg(sparc_code_gen_t *cg);
+
 #endif
index 3963946..40da546 100644 (file)
 #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.
  */
@@ -124,6 +131,9 @@ void sparc_emit_immediate(const ir_node *node)
 {
        // 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);
 }
 
@@ -164,10 +174,12 @@ void sparc_emit_offset(const ir_node *node)
 {
        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
  */
@@ -244,38 +256,64 @@ static void emit_be_IncSP(const ir_node *irn)
 {
        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
  */
@@ -283,6 +321,8 @@ static void emit_be_Return(const ir_node *irn)
 {
        be_emit_cstring("\tret");
        be_emit_finish_line_gas(irn);
+       be_emit_cstring("\trestore");
+       be_emit_finish_line_gas(irn);
 }
 
 /**
@@ -307,13 +347,42 @@ static void emit_be_Call(const ir_node *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);
 
@@ -323,6 +392,8 @@ static void emit_sparc_SymConst(const ir_node *irn)
        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);
@@ -337,10 +408,20 @@ static void emit_sparc_SymConst(const ir_node *irn)
 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);
@@ -397,6 +478,7 @@ static void emit_sparc_Branch(const ir_node *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;
@@ -426,13 +508,13 @@ static void emit_sparc_Branch(const ir_node *irn)
                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)
 {
@@ -446,6 +528,8 @@ 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);
@@ -454,6 +538,9 @@ static void emit_sparc_Jmp(const ir_node *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);
@@ -521,10 +608,16 @@ static void sparc_register_emitters(void)
     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);
@@ -533,7 +626,7 @@ static void sparc_register_emitters(void)
     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);
@@ -588,12 +681,7 @@ static void sparc_gen_block(ir_node *block, void *data)
 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();
 }
 
@@ -604,9 +692,7 @@ static void sparc_emit_func_epilog(ir_graph *irg)
 {
        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);
index e3ef011..1004854 100644 (file)
@@ -33,7 +33,7 @@
 #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],
@@ -42,9 +42,29 @@ static const arch_register_t *gp_param_regs[] = {
        &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];
 }
index ce01217..26a050b 100644 (file)
@@ -32,6 +32,8 @@
 #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
index e2e380b..dc92b50 100644 (file)
@@ -71,16 +71,30 @@ static int sparc_dump_node(ir_node *n, FILE *F, dump_reason_t reason)
                        }
                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;
@@ -199,7 +213,6 @@ const sparc_jmp_switch_attr_t *get_sparc_jmp_switch_attr_const(const ir_node *no
        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");
@@ -212,6 +225,19 @@ const sparc_cmp_attr_t *get_sparc_cmp_attr_const(const ir_node *node)
        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.
  */
@@ -291,6 +317,12 @@ static void init_sparc_symconst_attributes(ir_node *res, ir_entity *entity)
        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
  */
@@ -387,5 +419,16 @@ static int cmp_attr_sparc_cmp(ir_node *a, ir_node *b)
                        || 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"
index 569dfc5..6661575 100644 (file)
@@ -59,6 +59,10 @@ const sparc_jmp_switch_attr_t *get_sparc_jmp_switch_attr_const(const ir_node *no
 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.
  */
index 3f91a96..fe266ab 100644 (file)
@@ -41,6 +41,15 @@ struct sparc_attr_t
 };
 
 
+/**
+ * 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
  */
index aeefcfe..d917122 100644 (file)
@@ -114,37 +114,37 @@ $mode_fp      = "mode_D";
                { 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 => [
@@ -240,24 +240,26 @@ $default_copy_attr = "sparc_copy_attr";
 
 
 %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",
 );
 
 
@@ -271,10 +273,10 @@ my %cmp_operand_constructors = (
         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" ],
@@ -288,7 +290,6 @@ my %unop_operand_constructors = (
         reg_req    => { in => [], out => [ "gp" ] },
     },
     reg => {
-               # custominit => "set_sparc_attr_values(res, immediate_value);",
         reg_req    => { in => [ "gp" ], out => [ "gp" ] },
     },
 );
@@ -301,7 +302,6 @@ my %binop_operand_constructors = (
         ins        => [ "left" ],
     },
     reg => {
-               # custominit => "set_sparc_attr_values(res, immediate_value);",
         reg_req    => { in => [ "gp", "gp" ], out => [ "gp" ] },
         ins        => [ "left", "right" ],
     },
@@ -362,7 +362,34 @@ LoadHi => {
   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 => {
@@ -399,6 +426,19 @@ Mov => {
   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" ] },
@@ -527,13 +567,40 @@ Or => {
   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",
index c050cbc..7ddd323 100644 (file)
@@ -70,12 +70,16 @@ static ir_node *create_const_graph_value(dbg_info *dbgi, ir_node *block,
 {
        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;
 }
 
@@ -89,15 +93,18 @@ static ir_node *create_const_graph(ir_node *irn, ir_node *block)
 {
        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);
 }
 
 
@@ -111,8 +118,7 @@ typedef ir_node* (*new_binop_reg_func) (dbg_info *dbgi, ir_node *block, ir_node
 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)
@@ -177,14 +183,8 @@ static ir_node *gen_Add(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;
 
@@ -205,14 +205,8 @@ static ir_node *gen_Sub(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;
 
@@ -278,10 +272,110 @@ static ir_node *gen_Store(ir_node *node)
        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.
  *
@@ -484,6 +578,7 @@ static ir_node *gen_Cmp(ir_node *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,
@@ -495,6 +590,7 @@ static ir_node *gen_Cmp(ir_node *node)
                return new_bd_sparc_Tst(dbgi, block, new_op2, true,
                                          is_unsigned);
        }
+       */
 
        /* integer compare */
        new_op1 = be_transform_node(op1);
@@ -616,6 +712,25 @@ static ir_node *gen_Conv(ir_node *node)
        }
 }
 
+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
  */
@@ -798,6 +913,7 @@ static ir_node *gen_Proj(ir_node *node)
     return be_duplicate_node(node);
 }
 
+
 /**
  * transform a Jmp
  */
@@ -855,29 +971,26 @@ void sparc_register_transformers(void)
        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);