fix sparc stack offset, stack must be 8byte aligned on calls
authorMatthias Braun <matze@braunis.de>
Thu, 22 Jul 2010 19:07:46 +0000 (19:07 +0000)
committerMatthias Braun <matze@braunis.de>
Thu, 22 Jul 2010 19:07:46 +0000 (19:07 +0000)
[r27784]

ir/be/sparc/bearch_sparc.c
ir/be/sparc/bearch_sparc_t.h
ir/be/sparc/sparc_emitter.c

index 6ad5310..5dcba94 100644 (file)
 #include "sparc_transform.h"
 #include "sparc_emitter.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 112
-
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
 static arch_irn_class_t sparc_classify(const ir_node *irn)
@@ -113,10 +108,17 @@ static void sparc_set_frame_offset(ir_node *irn, int offset)
        }
 }
 
-static int sparc_get_sp_bias(const ir_node *irn)
+static int sparc_get_sp_bias(const ir_node *node)
 {
-       (void) irn;
-       return SPARC_MIN_STACKSIZE;
+       if (is_sparc_Save(node)) {
+               const sparc_save_attr_t *attr = get_sparc_save_attr_const(node);
+               /* Note we do not retport the change of the SPARC_MIN_STACKSIZE
+                * size, since we have additional magic in the emitter which
+                * calculates that! */
+               assert(attr->initial_stacksize >= SPARC_MIN_STACKSIZE);
+               return attr->initial_stacksize - SPARC_MIN_STACKSIZE;
+       }
+       return 0;
 }
 
 /* fill register allocator interface */
@@ -315,7 +317,7 @@ static sparc_isa_t sparc_isa_template = {
                &sparc_gp_regs[REG_FP],  /* base pointer register */
                &sparc_reg_classes[CLASS_sparc_gp],  /* link pointer register class */
                -1,                          /* stack direction */
-               1,                           /* power of two stack alignment for calls, 2^2 == 4 */
+               3,                           /* power of two stack alignment for calls, 2^2 == 4 */
                NULL,                        /* main environment */
                7,                           /* costs for a spill instruction */
                5,                           /* costs for a reload instruction */
@@ -493,7 +495,7 @@ static ir_type *sparc_get_between_type(void *self)
 
        if (between_type == NULL) {
                between_type = new_type_class(new_id_from_str("sparc_between_type"));
-               set_type_size_bytes(between_type, 0);
+               set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE);
        }
 
        return between_type;
@@ -526,7 +528,6 @@ static const arch_register_t *sparc_abi_prologue(void *self, ir_node **mem,
        (void) mem;
        (void) stack_bias;
 
-       *stack_bias -= SPARC_MIN_STACKSIZE;
        sp_proj = new_r_Proj(save, sp->reg_class->mode, pn_sparc_Save_stack);
        *mem    = new_r_Proj(save, mode_M, pn_sparc_Save_mem);
 
index 568f7a2..a3fd752 100644 (file)
@@ -59,4 +59,19 @@ struct sparc_transform_env_t {
 
 void sparc_finish_irg(sparc_code_gen_t *cg);
 
+/**
+ * Sparc ABI requires some space which is always available at the top of
+ * the stack. It contains:
+ * 16*4 bytes space for spilling the register window
+ * 1*4 byte   holding a pointer to space for agregate returns (the space is
+ *            always reserved, regardless wether we have an agregate return
+ *            or not)
+ * 6*4 bytes  Space for spilling parameters 0-5. For the cases when someone
+ *            takes the adress of a parameter. I guess this is also there so
+ *            the implementation of va_args gets easier -> We can simply store
+ *            param 0-5 in this spaces and then handle va_next by simply
+ *            incrementing the stack pointer
+ */
+#define SPARC_MIN_STACKSIZE 92
+
 #endif
index 54ceacd..42f948c 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.
  */
@@ -155,16 +148,27 @@ void sparc_emit_reg_or_imm(const ir_node *node, int pos)
        }
 }
 
+static bool is_stack_pointer_relative(const ir_node *node)
+{
+       const arch_register_t *sp = &sparc_gp_regs[REG_SP];
+       return (is_sparc_St(node) && get_in_reg(node, n_sparc_St_ptr) == sp)
+           || (is_sparc_Ld(node) && get_in_reg(node, n_sparc_Ld_ptr) == sp);
+}
+
 /**
  * emit SP offset
  */
 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("%+ld", attr->offset);
+       long                           offset = attr->offset;
+
+       /* bad hack: the real stack stuff is behind the always-there spill
+        * space for the register window and stack */
+       if (is_stack_pointer_relative(node))
+               offset += SPARC_MIN_STACKSIZE;
+       if (offset != 0) {
+               be_emit_irprintf("%+ld", offset);
        }
 }
 
@@ -326,7 +330,7 @@ static void emit_be_IncSP(const ir_node *irn)
  */
 static void emit_sparc_Save(const ir_node *irn)
 {
-       save_attr = get_sparc_save_attr_const(irn);
+       const sparc_save_attr_t *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);
@@ -570,7 +574,7 @@ static void emit_sparc_FrameAddr(const ir_node *irn)
                be_emit_cstring("\tadd ");
                sparc_emit_source_register(irn, 0);
                be_emit_cstring(", ");
-               be_emit_irprintf("%ld", attr->fp_offset + save_attr->initial_stacksize);
+               be_emit_irprintf("%ld", attr->fp_offset);
        } else {
                be_emit_cstring("\tsub ");
                sparc_emit_source_register(irn, 0);