#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)
}
}
-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 */
&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 */
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;
(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);
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
#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.
*/
}
}
+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);
}
}
*/
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);
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);