implement aggregate returns according to sparc ABI
authorMatthias Braun <matze@braunis.de>
Fri, 12 Aug 2011 11:30:22 +0000 (13:30 +0200)
committerMatthias Braun <matze@braunis.de>
Mon, 15 Aug 2011 12:01:44 +0000 (14:01 +0200)
ir/be/sparc/bearch_sparc_t.h
ir/be/sparc/sparc_cconv.c
ir/be/sparc/sparc_emitter.c
ir/be/sparc/sparc_nodes_attr.h
ir/be/sparc/sparc_spec.pl
ir/be/sparc/sparc_stackframe.c
ir/be/sparc/sparc_transform.c
ir/lower/lower_calls.c
ir/tr/type_t.h

index 8c4ca2f..da5e07e 100644 (file)
@@ -66,9 +66,10 @@ extern const arch_irn_ops_t sparc_irn_ops;
  *            param 0-5 in this spaces and then handle va_next by simply
  *            incrementing the stack pointer
  */
-#define SPARC_MIN_STACKSIZE 92
 #define SPARC_IMMEDIATE_MIN -4096
 #define SPARC_IMMEDIATE_MAX  4095
+#define SPARC_MIN_STACKSIZE 92
+#define SPARC_AGGREGATE_RETURN_OFFSET 64
 
 static inline bool sparc_is_value_imm_encodeable(int32_t value)
 {
index af2c09c..211699e 100644 (file)
@@ -202,6 +202,15 @@ calling_convention_t *sparc_decide_calling_convention(ir_type *function_type,
                int                 bits       = get_mode_size_bits(mode);
                reg_or_stackslot_t *param      = &params[i];
 
+               if (i == 0 && function_type->attr.ma.has_compound_ret_parameter) {
+                       assert(mode_is_reference(mode) && bits == 32);
+                       /* special case, we have reserved space for this on the between
+                        * type */
+                       param->type   = param_type;
+                       param->offset = -SPARC_MIN_STACKSIZE+SPARC_AGGREGATE_RETURN_OFFSET;
+                       continue;
+               }
+
                if (regnum < n_param_regs) {
                        const arch_register_t *reg = param_regs[regnum];
                        if (irg == NULL || omit_fp)
index d0a8507..045a385 100644 (file)
@@ -337,6 +337,10 @@ static bool emits_multiple_instructions(const ir_node *node)
        if (has_delay_slot(node))
                return true;
 
+       if (is_sparc_Call(node)) {
+               return arch_irn_get_flags(node) & sparc_arch_irn_flag_aggregate_return;
+       }
+
        return is_sparc_Mulh(node) || is_sparc_SDiv(node) || is_sparc_UDiv(node)
                || be_is_MemPerm(node) || be_is_Perm(node);
 }
@@ -531,6 +535,11 @@ static void emit_sparc_Call(const ir_node *node)
        be_emit_finish_line_gas(node);
 
        fill_delay_slot();
+
+       if (arch_irn_get_flags(node) & sparc_arch_irn_flag_aggregate_return) {
+               be_emit_cstring("\tunimp 8\n");
+               be_emit_write_line();
+       }
 }
 
 /**
@@ -621,6 +630,10 @@ static void emit_be_MemPerm(const ir_node *node)
 
 static void emit_sparc_Return(const ir_node *node)
 {
+       ir_graph  *irg    = get_irn_irg(node);
+       ir_entity *entity = get_irg_entity(irg);
+       ir_type   *type   = get_entity_type(entity);
+
        const char *destreg = "%o7";
 
        /* hack: we don't explicitely model register changes because of the
@@ -632,7 +645,11 @@ static void emit_sparc_Return(const ir_node *node)
        }
        be_emit_cstring("\tjmp ");
        be_emit_string(destreg);
-       be_emit_cstring("+8");
+       if (type->attr.ma.has_compound_ret_parameter) {
+               be_emit_cstring("+12");
+       } else {
+               be_emit_cstring("+8");
+       }
        be_emit_finish_line_gas(node);
        fill_delay_slot();
 }
index 4a44251..b1c0011 100644 (file)
@@ -46,6 +46,7 @@ enum sparc_arch_irn_flags_t {
        sparc_arch_irn_flag_modifies_fp_flags     = arch_irn_flags_backend << 1,
        sparc_arch_irn_flag_needs_64bit_spillslot = arch_irn_flags_backend << 2,
        sparc_arch_irn_flag_immediate_form        = arch_irn_flags_backend << 3,
+       sparc_arch_irn_flag_aggregate_return      = arch_irn_flags_backend << 4,
 };
 
 /**
index 502067a..4de1ed0 100644 (file)
@@ -518,14 +518,17 @@ Call => {
        out_arity => "variable",
        constructors => {
                imm => {
-                       attr       => "ir_entity *entity, int32_t offset",
-                       custominit => "\tsparc_set_attr_imm(res, entity, offset);",
+                       attr       => "ir_entity *entity, int32_t offset, bool aggregate_return",
+                       custominit => "\tsparc_set_attr_imm(res, entity, offset);".
+                                     "\tif (aggregate_return) arch_irn_add_flags(res, sparc_arch_irn_flag_aggregate_return);",
                        arity     => "variable",
                        out_arity => "variable",
                },
                reg => {
-                       arity     => "variable",
-                       out_arity => "variable",
+                       attr       => "bool aggregate_return",
+                       arity      => "variable",
+                       out_arity  => "variable",
+                       custominit => "\tif (aggregate_return) arch_irn_add_flags(res, sparc_arch_irn_flag_aggregate_return);",
                }
        },
 },
index 22cd5fa..e08043f 100644 (file)
@@ -199,17 +199,19 @@ static void process_frame_types(ir_graph *irg)
        /* initially the stackpointer points to the begin of our stackframe.
         * Situation at the begin of our function:
         *
-        *      high address |----------------------------|
-        *                   | ...                        |
-        *          arg-type | stackarg 1                 |
-        *                   | stackarg 0                 |
-        *                   |----------------------------|
-        *      between type | 92-bytes utility+save area |
-        *  stack pointer -> |----------------------------|
-        *                   | high end of stackframe     |
-        *                   |          ...               |
-        *                   | low end of stackframe      |
-        *                   |----------------------------|
+        *      high address |-----------------------------|
+        *                   |            ...              |
+        *          arg-type |         stackarg 1          |
+        *                   |         stackarg 0          |
+        *                   |-----------------------------|
+        *                   | space for storing regarg0-5 |
+        *      between type | pointer to aggregate return |
+        *                   |      16 words save are      |
+        *  stack pointer -> |-----------------------------|
+        *                   |    high end of stackframe   |
+        *                   |            ...              |
+        *                   |    low end of stackframe    |
+        *      low address  |-----------------------------|
         */
        ir_type *between_type = layout->between_type;
        unsigned between_size = get_type_size_bytes(between_type);
index 9808421..4a6c6ff 100644 (file)
@@ -1649,6 +1649,8 @@ static ir_node *gen_Call(ir_node *node)
                = rbitset_popcount(cconv->caller_saves, N_SPARC_REGISTERS);
        ir_entity       *entity       = NULL;
        ir_node         *new_frame    = get_stack_pointer_for(node);
+       bool             aggregate_return
+               = type->attr.ma.has_compound_ret_parameter;
        ir_node         *incsp;
        int              mem_pos;
        ir_node         *res;
@@ -1761,9 +1763,10 @@ static ir_node *gen_Call(ir_node *node)
        /* create call node */
        if (entity != NULL) {
                res = new_bd_sparc_Call_imm(dbgi, new_block, in_arity, in, out_arity,
-                                           entity, 0);
+                                           entity, 0, aggregate_return);
        } else {
-               res = new_bd_sparc_Call_reg(dbgi, new_block, in_arity, in, out_arity);
+               res = new_bd_sparc_Call_reg(dbgi, new_block, in_arity, in, out_arity,
+                                           aggregate_return);
        }
        arch_set_in_register_reqs(res, in_req);
 
index 2560b3f..fbb1e64 100644 (file)
@@ -147,6 +147,7 @@ static ir_type *lower_mtp(compound_call_lowering_flags flags, ir_type *mtp)
 
        /* create the new type */
        lowered = new_d_type_method(nn_params, nn_ress, get_type_dbg_info(mtp));
+       lowered->attr.ma.has_compound_ret_parameter = true;
 
        /* fill it */
        for (i = 0; i < nn_params; ++i)
index 3b7c3bd..660fb24 100644 (file)
@@ -27,6 +27,7 @@
 #ifndef FIRM_TR_TYPE_T_H
 #define FIRM_TR_TYPE_T_H
 
+#include <stdbool.h>
 #include "typerep.h"
 #include "tpop_t.h"
 #include "irgraph.h"
@@ -72,8 +73,9 @@ typedef struct {
        size_t       n_res;             /**< Number of results. */
        tp_ent_pair *res_type;          /**< Array of result type/value ir_entity pairs. */
        ir_variadicity variadicity;     /**< The variadicity of the method. */
-mtp_additional_properties additional_properties; /**< Set of additional method properties. */
+       mtp_additional_properties additional_properties; /**< Set of additional method properties. */
        unsigned irg_calling_conv;      /**< A set of calling convention flags. */
+       bool     has_compound_ret_parameter : 1; /**< first parameter compound return address */
 } mtd_attr;
 
 /** Union type attributes. */