implement aggregate returns according to sparc ABI
[libfirm] / ir / be / TEMPLATE / bearch_TEMPLATE.c
index e0f6fdf..63acda2 100644 (file)
@@ -29,6 +29,7 @@
 #include "irprintf.h"
 #include "ircons.h"
 #include "irgmod.h"
+#include "lower_calls.h"
 
 #include "bitset.h"
 #include "debug.h"
@@ -42,6 +43,7 @@
 #include "../bemodule.h"
 #include "../begnuas.h"
 #include "../belistsched.h"
+#include "../bestack.h"
 
 #include "bearch_TEMPLATE_t.h"
 
@@ -114,7 +116,9 @@ static void TEMPLATE_prepare_graph(ir_graph *irg)
  */
 static void TEMPLATE_finish_irg(ir_graph *irg)
 {
-       (void) irg;
+       /* fix stack entity offsets */
+       be_abi_fix_stack_nodes(irg);
+       be_abi_fix_stack_bias(irg);
 }
 
 
@@ -124,12 +128,6 @@ static void TEMPLATE_before_ra(ir_graph *irg)
        /* Some stuff you need to do after scheduling but before register allocation */
 }
 
-static void TEMPLATE_after_ra(ir_graph *irg)
-{
-       (void) irg;
-       /* Some stuff you need to do immediatly after register allocation */
-}
-
 static void TEMPLATE_init_graph(ir_graph *irg)
 {
        (void) irg;
@@ -162,7 +160,7 @@ static TEMPLATE_isa_t TEMPLATE_isa_template = {
 static arch_env_t *TEMPLATE_init(FILE *outfile)
 {
        TEMPLATE_isa_t *isa = XMALLOC(TEMPLATE_isa_t);
-       memcpy(isa, &TEMPLATE_isa_template, sizeof(*isa));
+       *isa = TEMPLATE_isa_template;
 
        be_emit_init(outfile);
 
@@ -200,32 +198,16 @@ static const arch_register_class_t *TEMPLATE_get_reg_class_for_mode(const ir_mod
                return &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp];
 }
 
-
-
-typedef struct {
-       be_abi_call_flags_bits_t flags;
-       ir_graph                *irg;
-} TEMPLATE_abi_env_t;
-
-static void *TEMPLATE_abi_init(const be_abi_call_t *call, ir_graph *irg)
-{
-       TEMPLATE_abi_env_t *env = XMALLOC(TEMPLATE_abi_env_t);
-       be_abi_call_flags_t fl = be_abi_call_get_flags(call);
-       env->flags    = fl.bits;
-       env->irg      = irg;
-       return env;
-}
-
 /**
  * Get the between type for that call.
  * @param self The callback object.
  * @return The between type of for that call.
  */
-static ir_type *TEMPLATE_get_between_type(void *self)
+static ir_type *TEMPLATE_get_between_type(ir_graph *irg)
 {
        static ir_type *between_type = NULL;
        static ir_entity *old_bp_ent = NULL;
-       (void) self;
+       (void) irg;
 
        if (!between_type) {
                ir_entity *ret_addr_ent;
@@ -244,39 +226,8 @@ static ir_type *TEMPLATE_get_between_type(void *self)
        return between_type;
 }
 
-/**
- * Build the prolog, return the BASE POINTER register
- */
-static const arch_register_t *TEMPLATE_abi_prologue(void *self, ir_node **mem,
-                                                    pmap *reg_map, int *stack_bias)
-{
-       TEMPLATE_abi_env_t *env      = (TEMPLATE_abi_env_t*)self;
-       const arch_env_t   *arch_env = be_get_irg_arch_env(env->irg);
-       (void) reg_map;
-       (void) mem;
-       (void) stack_bias;
-
-       if (env->flags.try_omit_fp)
-               return arch_env->sp;
-       return arch_env->bp;
-}
-
-/* Build the epilog */
-static void TEMPLATE_abi_epilogue(void *self, ir_node *bl, ir_node **mem,
-                                  pmap *reg_map)
-{
-       (void) self;
-       (void) bl;
-       (void) mem;
-       (void) reg_map;
-}
-
 static const be_abi_callbacks_t TEMPLATE_abi_callbacks = {
-       TEMPLATE_abi_init,
-       free,
        TEMPLATE_get_between_type,
-       TEMPLATE_abi_prologue,
-       TEMPLATE_abi_epilogue,
 };
 
 /**
@@ -295,7 +246,6 @@ static void TEMPLATE_get_call_abi(const void *self, ir_type *method_type,
        (void) self;
 
        /* set abi flags for calls */
-       call_flags.bits.left_to_right         = 0;
        call_flags.bits.store_args_sequential = 1;
        call_flags.bits.try_omit_fp           = 1;
        call_flags.bits.fp_free               = 0;
@@ -337,16 +287,8 @@ static int TEMPLATE_get_reg_class_alignment(const arch_register_class_t *cls)
 
 static void TEMPLATE_lower_for_target(void)
 {
-       lower_params_t params = {
-               4,                                     /* def_ptr_alignment */
-               LF_COMPOUND_RETURN | LF_RETURN_HIDDEN, /* flags */
-               ADD_HIDDEN_ALWAYS_IN_FRONT,            /* hidden_params */
-               NULL,                                  /* find pointer type */
-               NULL,                                  /* ret_compound_in_regs */
-       };
-
        /* lower compound param handling */
-       lower_calls_with_compounds(&params);
+       lower_calls_with_compounds(LF_RETURN_HIDDEN);
 }
 
 static int TEMPLATE_is_mux_allowed(ir_node *sel, ir_node *mux_false,
@@ -367,9 +309,15 @@ static const backend_params *TEMPLATE_get_backend_params(void)
                0,     /* no inline assembly */
                0,     /* no support for Rotl nodes */
                0,     /* 0: little-endian, 1: big-endian */
+               1,     /* modulo shift efficient */
+               0,     /* non-modulo shift efficient */
                NULL,  /* architecture dependent settings, will be set later */
                TEMPLATE_is_mux_allowed,  /* parameter for if conversion */
+               32,    /* machine size - a 32bit CPU */
                NULL,  /* float arithmetic mode */
+               NULL,  /* long long type */
+               NULL,  /* unsigned long long type */
+               NULL,  /* long double type */
                0,     /* no trampoline support: size 0 */
                0,     /* no trampoline support: align 0 */
                NULL,  /* no trampoline support: no trampoline builder */
@@ -398,6 +346,50 @@ static int TEMPLATE_is_valid_clobber(const char *clobber)
        return 0;
 }
 
+/**
+ * Check if the given register is callee or caller save.
+ */
+static int TEMPLATE_register_saved_by(const arch_register_t *reg, int callee)
+{
+       if (callee) {
+               /* check for callee saved */
+               if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp]) {
+                       switch (reg->index) {
+                       case REG_GP_R7:
+                       case REG_GP_R8:
+                       case REG_GP_R9:
+                       case REG_GP_R10:
+                       case REG_GP_R11:
+                       case REG_GP_R12:
+                       case REG_GP_R13:
+                               return 1;
+                       default:
+                               return 0;
+                       }
+               }
+       } else {
+               /* check for caller saved */
+               if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp]) {
+                       switch (reg->index) {
+                       case REG_GP_R0:
+                       case REG_GP_R1:
+                       case REG_GP_R2:
+                       case REG_GP_R3:
+                       case REG_GP_R4:
+                       case REG_GP_R5:
+                       case REG_GP_R6:
+                               return 1;
+                       default:
+                               return 0;
+                       }
+               } else if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_fp]) {
+                       /* all FP registers are caller save */
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 const arch_isa_if_t TEMPLATE_isa_if = {
        TEMPLATE_init,
        TEMPLATE_lower_for_target,
@@ -417,12 +409,12 @@ const arch_isa_if_t TEMPLATE_isa_if = {
        NULL,   /* before_abi */
        TEMPLATE_prepare_graph,
        TEMPLATE_before_ra,
-       TEMPLATE_after_ra,
        TEMPLATE_finish_irg,
        TEMPLATE_emit_routine,
+       TEMPLATE_register_saved_by,
 };
 
-BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_TEMPLATE);
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_TEMPLATE)
 void be_init_arch_TEMPLATE(void)
 {
        be_register_isa_if("TEMPLATE", &TEMPLATE_isa_if);