===================================================================
@@ -158,6 +158,7 @@ extern tree altivec_resolve_overloaded_b
extern rtx rs6000_libcall_value (enum machine_mode);
extern rtx rs6000_va_arg (tree, tree);
extern int function_ok_for_sibcall (tree);
+extern int rs6000_reg_parm_stack_space (tree);
extern void rs6000_elf_declare_function_name (FILE *, const char *, tree);
extern bool rs6000_elf_in_small_data_p (const_tree);
#ifdef ARGS_SIZE_RTX
===================================================================
@@ -1527,10 +1527,6 @@ extern enum reg_class rs6000_constraints
#define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0 \
|| (flag_sanitize & SANITIZE_ADDRESS) != 0)
-/* Size of the outgoing register save area */
-#define RS6000_REG_SAVE \
- ((DEFAULT_ABI == ABI_V4 ? 0 : 32) << (TARGET_64BIT ? 1 : 0))
-
/* Size of the fixed area on the stack */
#define RS6000_SAVE_AREA \
((DEFAULT_ABI == ABI_V4 ? 8 : 24) << (TARGET_64BIT ? 1 : 0))
@@ -1588,7 +1584,7 @@ extern enum reg_class rs6000_constraints
/* Define this if stack space is still allocated for a parameter passed
in a register. The value is the number of bytes allocated to this
area. */
-#define REG_PARM_STACK_SPACE(FNDECL) RS6000_REG_SAVE
+#define REG_PARM_STACK_SPACE(FNDECL) rs6000_reg_parm_stack_space((FNDECL))
/* Define this if the above stack space is to be considered part of the
space allocated by the caller. */
===================================================================
@@ -10093,9 +10093,6 @@ rs6000_function_arg (cumulative_args_t c
if (TARGET_32BIT && TARGET_POWERPC64)
return rs6000_mixed_function_arg (mode, type, align_words);
- if (mode == BLKmode)
- mode = Pmode;
-
return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
}
else
@@ -10250,6 +10247,139 @@ rs6000_pass_by_reference (cumulative_arg
return 0;
}
+/* Process parameter of type TYPE after ARGS_SO_FAR parameters were
+ already processes. Return true if the parameter must be passed
+ (fully or partially) on the stack. */
+
+static bool
+rs6000_parm_needs_stack (cumulative_args_t args_so_far, tree type)
+{
+ enum machine_mode mode;
+ int unsignedp;
+ rtx entry_parm;
+
+ /* Catch errors. */
+ if (type == NULL || type == error_mark_node)
+ return true;
+
+ /* Handle types with no storage requirement. */
+ if (TYPE_MODE (type) == VOIDmode)
+ return false;
+
+ /* Handle complex types. */
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ return (rs6000_parm_needs_stack (args_so_far, TREE_TYPE (type))
+ || rs6000_parm_needs_stack (args_so_far, TREE_TYPE (type)));
+
+ /* Handle transparent aggregates. */
+ if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE)
+ && TYPE_TRANSPARENT_AGGR (type))
+ type = TREE_TYPE (first_field (type));
+
+ /* See if this arg was passed by invisible reference. */
+ if (pass_by_reference (get_cumulative_args (args_so_far),
+ TYPE_MODE (type), type, true))
+ type = build_pointer_type (type);
+
+ /* Find mode as it is passed by the ABI. */
+ unsignedp = TYPE_UNSIGNED (type);
+ mode = promote_mode (type, TYPE_MODE (type), &unsignedp);
+
+ /* If we must pass in stack, we need a stack. */
+ if (rs6000_must_pass_in_stack (mode, type))
+ return true;
+
+ /* If there is no incoming register, we need a stack. */
+ entry_parm = rs6000_function_arg (args_so_far, mode, type, true);
+ if (entry_parm == NULL)
+ return true;
+
+ /* Likewise if we need to pass both in registers and on the stack. */
+ if (GET_CODE (entry_parm) == PARALLEL
+ && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX)
+ return true;
+
+ /* Also true if we're partially in registers and partially not. */
+ if (rs6000_arg_partial_bytes (args_so_far, mode, type, true) != 0)
+ return true;
+
+ /* Update info on where next arg arrives in registers. */
+ rs6000_function_arg_advance (args_so_far, mode, type, true);
+ return false;
+}
+
+/* Return true if FUN has no prototype, has a variable argument
+ list, or passes any parameter in memory. */
+
+static bool
+rs6000_function_parms_need_stack (tree fun)
+{
+ function_args_iterator args_iter;
+ tree arg_type;
+ CUMULATIVE_ARGS args_so_far_v;
+ cumulative_args_t args_so_far;
+
+ if (!fun)
+ /* Must be a libcall, all of which only use reg parms. */
+ return false;
+ if (!TYPE_P (fun))
+ fun = TREE_TYPE (fun);
+
+ /* Varargs functions need the parameter save area. */
+ if (!prototype_p (fun) || stdarg_p (fun))
+ return true;
+
+ INIT_CUMULATIVE_INCOMING_ARGS (args_so_far_v, fun, NULL_RTX);
+ args_so_far = pack_cumulative_args (&args_so_far_v);
+
+ if (aggregate_value_p (TREE_TYPE (fun), fun))
+ {
+ tree type = build_pointer_type (TREE_TYPE (fun));
+ rs6000_parm_needs_stack (args_so_far, type);
+ }
+
+ FOREACH_FUNCTION_ARGS (fun, arg_type, args_iter)
+ if (rs6000_parm_needs_stack (args_so_far, arg_type))
+ return true;
+
+ return false;
+}
+
+/* Return the size of the REG_PARM_STACK_SPACE are for FUN. This is
+ usually a constant depending on the ABI. However, in the ELFv2 ABI
+ the register parameter area is optional when calling a function that
+ has a prototype is scope, has no variable argument list, and passes
+ all parameters in registers. */
+
+int
+rs6000_reg_parm_stack_space (tree fun)
+{
+ int reg_parm_stack_space;
+
+ switch (DEFAULT_ABI)
+ {
+ default:
+ reg_parm_stack_space = 0;
+ break;
+
+ case ABI_AIX:
+ case ABI_DARWIN:
+ reg_parm_stack_space = TARGET_64BIT ? 64 : 32;
+ break;
+
+ case ABI_ELFv2:
+ /* ??? Recomputing this every time is a bit expensive. Is there
+ a place to cache this information? */
+ if (rs6000_function_parms_need_stack (fun))
+ reg_parm_stack_space = TARGET_64BIT ? 64 : 32;
+ else
+ reg_parm_stack_space = 0;
+ break;
+ }
+
+ return reg_parm_stack_space;
+}
+
static void
rs6000_move_block_from_reg (int regno, rtx x, int nregs)
{