===================================================================
@@ -1648,6 +1648,10 @@ extern enum reg_class rs6000_constraints
#define GP_ARG_RETURN GP_ARG_MIN_REG
#define FP_ARG_RETURN FP_ARG_MIN_REG
#define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2)
+#define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN \
+ : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
+#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \
+ : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
/* Flags for the call/call_value rtl operations set up by function_arg */
#define CALL_NORMAL 0x00000000 /* no special processing */
@@ -1667,8 +1671,10 @@ extern enum reg_class rs6000_constraints
On RS/6000, this is r3, fp1, and v2 (for AltiVec). */
#define FUNCTION_VALUE_REGNO_P(N) \
((N) == GP_ARG_RETURN \
- || ((N) == FP_ARG_RETURN && TARGET_HARD_FLOAT && TARGET_FPRS) \
- || ((N) == ALTIVEC_ARG_RETURN && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI))
+ || ((N) >= FP_ARG_RETURN && (N) <= FP_ARG_MAX_RETURN \
+ && TARGET_HARD_FLOAT && TARGET_FPRS) \
+ || ((N) >= ALTIVEC_ARG_RETURN && (N) <= ALTIVEC_ARG_MAX_RETURN \
+ && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI))
/* 1 if N is a possible register number for function argument passing.
On RS/6000, these are r3-r10 and fp1-fp13.
===================================================================
@@ -1449,6 +1449,9 @@ static const struct attribute_spec rs600
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
+#undef TARGET_RETURN_IN_MSB
+#define TARGET_RETURN_IN_MSB rs6000_return_in_msb
+
#undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
@@ -8725,6 +8728,16 @@ rs6000_return_in_memory (const_tree type
/* Otherwise fall through to more conventional ABI rules. */
}
+ /* The ELFv2 ABI returns homogeneous VFP aggregates in registers */
+ if (rs6000_discover_homogeneous_aggregate (TYPE_MODE (type), type,
+ NULL, NULL))
+ return false;
+
+ /* The ELFv2 ABI returns aggregates up to 16B in registers */
+ if (DEFAULT_ABI == ABI_ELFv2 && AGGREGATE_TYPE_P (type)
+ && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) <= 16)
+ return false;
+
if (AGGREGATE_TYPE_P (type)
&& (aix_struct_return
|| (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
@@ -8756,6 +8769,19 @@ rs6000_return_in_memory (const_tree type
return false;
}
+/* Specify whether values returned in registers should be at the most
+ significant end of a register. We want aggregates returned by
+ value to match the way aggregates are passed to functions. */
+
+static bool
+rs6000_return_in_msb (const_tree valtype)
+{
+ return (DEFAULT_ABI == ABI_ELFv2
+ && BYTES_BIG_ENDIAN
+ && AGGREGATE_TYPE_P (valtype)
+ && FUNCTION_ARG_PADDING (TYPE_MODE (valtype), valtype) == upward);
+}
+
#ifdef HAVE_AS_GNU_ATTRIBUTE
/* Return TRUE if a call to function FNDECL may be one that
potentially affects the function calling ABI of the object file. */
@@ -29897,6 +29923,8 @@ rs6000_function_value (const_tree valtyp
{
enum machine_mode mode;
unsigned int regno;
+ enum machine_mode elt_mode;
+ int n_elts;
/* Special handling for structs in darwin64. */
if (TARGET_MACHO
@@ -29916,6 +29944,36 @@ rs6000_function_value (const_tree valtyp
/* Otherwise fall through to standard ABI rules. */
}
+ /* The ELFv2 ABI returns homogeneous VFP aggregates in registers. */
+ if (rs6000_discover_homogeneous_aggregate (TYPE_MODE (valtype), valtype,
+ &elt_mode, &n_elts))
+ {
+ int first_reg, n_regs, i;
+ rtx par;
+
+ if (SCALAR_FLOAT_MODE_P (elt_mode))
+ {
+ /* _Decimal128 must use even/odd register pairs. */
+ first_reg = (elt_mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN;
+ n_regs = (GET_MODE_SIZE (elt_mode) + 7) >> 3;
+ }
+ else
+ {
+ first_reg = ALTIVEC_ARG_RETURN;
+ n_regs = 1;
+ }
+
+ par = gen_rtx_PARALLEL (TYPE_MODE (valtype), rtvec_alloc (n_elts));
+ for (i = 0; i < n_elts; i++)
+ {
+ rtx r = gen_rtx_REG (elt_mode, first_reg + i * n_regs);
+ rtx off = GEN_INT (i * GET_MODE_SIZE (elt_mode));
+ XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, r, off);
+ }
+
+ return par;
+ }
+
if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
{
/* Long long return value need be split in -mpowerpc64, 32bit ABI. */