* 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)
{
int bits = get_mode_size_bits(mode);
reg_or_stackslot_t *param = ¶ms[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)
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);
}
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();
+ }
}
/**
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
}
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();
}
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,
};
/**
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);",
}
},
},
/* 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);
= 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;
/* 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);
/* 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)
#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"
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. */