From: oltolm <[email protected]>
Commit 77b2eaf09c77bf2dddcb8c35ee8bc9cc99e2f93c attempted to fix
PR54412 by handling some over-aligned indirect argument and structure
return cases in calls.cc. During testing, that approach exposed a
regression and also made the fix larger than necessary.
Keep the fix centered on function.cc instead: add
assign_stack_local_aligned for stack slots whose requested alignment
exceeds MAX_SUPPORTED_STACK_ALIGNMENT, preserve over-alignment only on
targets that opt in, and let the target decide which type classes need
that treatment. On i386, use this for fixed-size AVX/AVX512 payload
types under TARGET_SEH.
gcc/ChangeLog:
PR target/54412
* gcc/target.def (overaligned_stack_slot_required): New hook.
(preserve_overaligned_stack_slot): New hook.
* gcc/function.cc (assign_stack_local_aligned): New helper.
(assign_stack_temp_for_type): Preserve over-alignment only when
targetm.calls.overaligned_stack_slot_required and
targetm.calls.preserve_overaligned_stack_slot return true.
(assign_parm_setup_block): Use assign_stack_local_aligned.
(assign_parm_setup_reg): Likewise preserve over-alignment only
for target-selected types on targets that opt in.
* gcc/config/i386/i386.cc (ix86_overaligned_fixed_size_type_p): New.
(ix86_overaligned_stack_slot_required): New.
(ix86_preserve_overaligned_stack_slot): New.
(TARGET_OVERALIGNED_STACK_SLOT_REQUIRED): Define for i386.
(TARGET_PRESERVE_OVERALIGNED_STACK_SLOT): Define for i386.
* gcc/calls.cc (initialize_argument_information): Restore the
regular temporary stack allocation path for by-reference arguments.
(expand_call): Restore the regular temporary stack allocation
path for structure return slots.
* gcc/doc/tm.texi.in: Document the new hooks.
* gcc/doc/tm.texi: Regenerate.
Signed-off-by: oltolm <[email protected]>
---
gcc/calls.cc | 72 ++++++++++++-----------------------------
gcc/config/i386/i386.cc | 40 +++++++++++++++++++++++
gcc/doc/tm.texi | 21 ++++++++----
gcc/doc/tm.texi.in | 2 ++
gcc/function.cc | 57 +++++++++++++++++++++-----------
gcc/target.def | 24 +++++++++-----
6 files changed, 131 insertions(+), 85 deletions(-)
diff --git a/gcc/calls.cc b/gcc/calls.cc
index ee885a60b58..d491a414611 100644
--- a/gcc/calls.cc
+++ b/gcc/calls.cc
@@ -159,8 +159,6 @@ static void compute_argument_addresses (struct arg_data *,
rtx, int);
static rtx rtx_for_function_call (tree, tree);
static void load_register_parameters (struct arg_data *, int, rtx *, int,
int, bool *);
-static rtx allocate_call_dynamic_stack_space (rtx, unsigned int, HOST_WIDE_INT,
- rtx *, poly_int64 *);
static int special_function_p (const_tree, int);
static bool check_sibcall_argument_overlap_1 (rtx);
static bool check_sibcall_argument_overlap (rtx_insn *, struct arg_data *,
@@ -213,28 +211,6 @@ mark_stack_region_used (poly_uint64 lower_bound,
poly_uint64 upper_bound)
stack_usage_watermark = MIN (stack_usage_watermark, const_lower);
}
-/* Allocate temporary call-related stack space with ALIGN alignment.
- Save the stack pointer on first use so the caller can restore it after
- the call sequence completes. */
-
-static rtx
-allocate_call_dynamic_stack_space (rtx size, unsigned int align,
- HOST_WIDE_INT known_size,
- rtx *old_stack_level,
- poly_int64 *old_pending_adj)
-{
- if (*old_stack_level == 0)
- {
- emit_stack_save (SAVE_BLOCK, old_stack_level);
- *old_pending_adj = pending_stack_adjust;
- pending_stack_adjust = 0;
- }
-
- /* We can pass TRUE as the 5th argument because we just saved the stack
- pointer and will restore it right after the call. */
- return allocate_dynamic_stack_space (size, align, align, known_size, true);
-}
-
/* Force FUNEXP into a form suitable for the address of a CALL,
and return that as an rtx. Also load the static chain register
if FNDECL is a nested function.
@@ -1505,23 +1481,30 @@ initialize_argument_information (int num_actuals
ATTRIBUTE_UNUSED,
if (!COMPLETE_TYPE_P (type)
|| TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
- || (targetm.calls.overaligned_stack_slot_required ()
- && TYPE_ALIGN (type) > MAX_SUPPORTED_STACK_ALIGNMENT)
|| (flag_stack_check == GENERIC_STACK_CHECK
&& compare_tree_int (TYPE_SIZE_UNIT (type),
STACK_CHECK_MAX_VAR_SIZE) > 0))
{
- /* Variable-sized or over-aligned by-reference arguments
cannot
- use a regular stack temp when the target can't guarantee
the
- requested alignment for stack slots. Allocate temporary
- space dynamically and restore the stack right after the
call. */
+ /* This is a variable-sized object. Make space on the stack
+ for it. */
rtx size_rtx = expr_size (args[i].tree_value);
- copy = allocate_call_dynamic_stack_space (size_rtx,
- TYPE_ALIGN (type),
- max_int_size_in_bytes (type),
- old_stack_level,
- old_pending_adj);
+ if (*old_stack_level == 0)
+ {
+ emit_stack_save (SAVE_BLOCK, old_stack_level);
+ *old_pending_adj = pending_stack_adjust;
+ pending_stack_adjust = 0;
+ }
+
+ /* We can pass TRUE as the 4th argument because we just
+ saved the stack pointer and will restore it right after
+ the call. */
+ copy = allocate_dynamic_stack_space (size_rtx,
+ TYPE_ALIGN (type),
+ TYPE_ALIGN (type),
+ max_int_size_in_bytes
+ (type),
+ true);
copy = gen_rtx_MEM (BLKmode, copy);
set_mem_attributes (copy, type, 1);
}
@@ -2928,23 +2911,8 @@ expand_call (tree exp, rtx target, int ignore)
/* For variable-sized objects, we must be called with a target
specified. If we were to allocate space on the stack here,
we would have no way of knowing when to free it. */
- if (targetm.calls.overaligned_stack_slot_required ()
- && TYPE_ALIGN (rettype) > MAX_SUPPORTED_STACK_ALIGNMENT)
- {
- unsigned HOST_WIDE_INT size;
-
- gcc_checking_assert (TREE_CODE (TYPE_SIZE_UNIT (rettype))
- == INTEGER_CST);
- size = tree_to_uhwi (TYPE_SIZE_UNIT (rettype));
- structure_value_addr = allocate_call_dynamic_stack_space (
- gen_int_mode (size, Pmode), TYPE_ALIGN (rettype), size,
- &old_stack_level, &old_pending_adj);
- }
- else
- {
- rtx d = assign_temp (rettype, 1, 1);
- structure_value_addr = XEXP (d, 0);
- }
+ rtx d = assign_temp (rettype, 1, 1);
+ structure_value_addr = XEXP (d, 0);
target = 0;
}
}
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index dd1f715b460..0d2fa554c5d 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -431,6 +431,7 @@ static bool ix86_function_value_regno_p (const unsigned
int);
static unsigned int ix86_function_arg_boundary (machine_mode,
const_tree);
static bool ix86_overaligned_stack_slot_required (void);
+static bool ix86_preserve_overaligned_stack_slot (tree);
static rtx ix86_static_chain (const_tree, bool);
static int ix86_function_regparm (const_tree, const_tree);
static void ix86_compute_frame_layout (void);
@@ -1634,12 +1635,49 @@ ix86_must_pass_in_stack (const function_arg_info &arg)
/* Implement TARGET_OVERALIGNED_STACK_SLOT_REQUIRED. */
+static bool
+ix86_overaligned_fixed_size_type_p (tree type)
+{
+ if (!type || !COMPLETE_TYPE_P (type)
+ || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
+ || TYPE_ALIGN (type) <= MAX_SUPPORTED_STACK_ALIGNMENT)
+ return false;
+
+ switch (TREE_CODE (type))
+ {
+ case VECTOR_TYPE:
+ return tree_to_uhwi (TYPE_SIZE_UNIT (type)) == 32
+ || tree_to_uhwi (TYPE_SIZE_UNIT (type)) == 64;
+
+ case ARRAY_TYPE:
+ return ix86_overaligned_fixed_size_type_p (TREE_TYPE (type));
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && ix86_overaligned_fixed_size_type_p (TREE_TYPE (field)))
+ return true;
+ return false;
+
+ default:
+ return false;
+ }
+}
+
static bool
ix86_overaligned_stack_slot_required (void)
{
return TARGET_SEH;
}
+static bool
+ix86_preserve_overaligned_stack_slot (tree type)
+{
+ return ix86_overaligned_fixed_size_type_p (type);
+}
+
/* It returns the size, in bytes, of the area reserved for arguments passed
in registers for the function represented by fndecl dependent to the used
abi format. */
@@ -28516,6 +28554,8 @@ static const scoped_attribute_specs *const
ix86_attribute_table[] =
#define TARGET_MUST_PASS_IN_STACK ix86_must_pass_in_stack
#undef TARGET_OVERALIGNED_STACK_SLOT_REQUIRED
#define TARGET_OVERALIGNED_STACK_SLOT_REQUIRED
ix86_overaligned_stack_slot_required
+#undef TARGET_PRESERVE_OVERALIGNED_STACK_SLOT
+#define TARGET_PRESERVE_OVERALIGNED_STACK_SLOT
ix86_preserve_overaligned_stack_slot
#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS ix86_allocate_stack_slots_for_args
#undef TARGET_FUNCTION_ARG_ADVANCE
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 04537aa3200..3676edcca17 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -4301,13 +4301,20 @@ documentation.
@end deftypefn
@deftypefn {Target Hook} bool TARGET_OVERALIGNED_STACK_SLOT_REQUIRED (void)
-This hook should return @code{true} when call-related stack slots whose
-requested alignment exceeds @code{MAX_SUPPORTED_STACK_ALIGNMENT} need special
-handling on the target. This covers stack slots created by call expansion
-(such as by-reference argument copies and hidden structure return storage) and
-incoming argument setup. When @code{true}, GCC may avoid normal fixed stack
-slots for such cases and use over-allocation plus dynamic address alignment
-instead.
+This hook should return @code{true} when stack slots whose requested
+alignment exceeds @code{MAX_SUPPORTED_STACK_ALIGNMENT} need special handling
+on the target. This covers slots created by call expansion (such as
+by-reference argument copies and hidden structure return storage), temporary
+stack slots, and incoming argument setup. When @code{true}, GCC may avoid
+normal fixed stack slots for such cases and use over-allocation plus dynamic
+address alignment instead.
+@end deftypefn
+
+@deftypefn {Target Hook} bool TARGET_PRESERVE_OVERALIGNED_STACK_SLOT (tree
@var{type})
+This hook should return @code{true} when a stack slot for @var{type} whose
+requested alignment exceeds @code{MAX_SUPPORTED_STACK_ALIGNMENT} should
+preserve that requested alignment instead of using the normal fixed stack slot
+handling.
@end deftypefn
@deftypefn {Target Hook} rtx TARGET_FUNCTION_INCOMING_ARG (cumulative_args_t
@var{ca}, const function_arg_info @var{&arg})
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index e31d7440b75..335ef9dfcf4 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -3360,6 +3360,8 @@ the stack.
@hook TARGET_OVERALIGNED_STACK_SLOT_REQUIRED
+@hook TARGET_PRESERVE_OVERALIGNED_STACK_SLOT
+
@hook TARGET_FUNCTION_INCOMING_ARG
@hook TARGET_USE_PSEUDO_PIC_REG
diff --git a/gcc/function.cc b/gcc/function.cc
index 84023070ad8..1a031d79d07 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -560,8 +560,7 @@ static rtx
assign_stack_local_aligned (machine_mode mode, poly_int64 size,
unsigned int align)
{
- if (targetm.calls.overaligned_stack_slot_required ()
- && align > MAX_SUPPORTED_STACK_ALIGNMENT)
+ if (align > MAX_SUPPORTED_STACK_ALIGNMENT)
{
if (!size.is_constant ())
return assign_stack_local (mode, size, MAX_SUPPORTED_STACK_ALIGNMENT);
@@ -908,21 +907,34 @@ assign_stack_temp_for_type (machine_mode mode, poly_int64
size, tree type)
p = ggc_alloc<temp_slot> ();
- /* We are passing an explicit alignment request to assign_stack_local.
- One side effect of that is assign_stack_local will not round SIZE
- to ensure the frame offset remains suitably aligned.
+ /* We are passing an explicit alignment request. One side effect of that
+ is that the allocator will not round SIZE to ensure the frame offset
+ remains suitably aligned.
So for requests which depended on the rounding of SIZE, we go ahead
and round it now. We also make sure ALIGNMENT is at least
- BIGGEST_ALIGNMENT. */
- gcc_assert (mode != BLKmode || align == BIGGEST_ALIGNMENT);
- p->slot = assign_stack_local_1 (mode,
- (mode == BLKmode
- ? aligned_upper_bound (size,
- (int) align
- / BITS_PER_UNIT)
- : size),
- align, 0);
+ BIGGEST_ALIGNMENT on the regular path below. */
+ bool preserve_alignment
+ = align > MAX_SUPPORTED_STACK_ALIGNMENT
+ && targetm.calls.overaligned_stack_slot_required ()
+ && targetm.calls.preserve_overaligned_stack_slot (type);
+
+ gcc_assert (preserve_alignment || mode != BLKmode
+ || align == BIGGEST_ALIGNMENT);
+
+ poly_int64 rounded_size
+ = (mode == BLKmode
+ ? aligned_upper_bound (size, (int) align / BITS_PER_UNIT)
+ : size);
+
+ if (preserve_alignment)
+ p->slot = assign_stack_local_aligned (mode, rounded_size, align);
+ else
+ p->slot = assign_stack_local_1 (mode, rounded_size, align, 0);
+
+ if (!preserve_alignment && align > MAX_SUPPORTED_STACK_ALIGNMENT
+ && targetm.calls.overaligned_stack_slot_required ())
+ align = MAX_SUPPORTED_STACK_ALIGNMENT;
p->align = align;
@@ -3385,10 +3397,19 @@ assign_parm_setup_reg (struct assign_parm_data_all
*all, tree parm,
int align = STACK_SLOT_ALIGNMENT (TREE_TYPE (parm),
TYPE_MODE (TREE_TYPE (parm)),
TYPE_ALIGN (TREE_TYPE (parm)));
- parmreg = assign_stack_local_aligned (TYPE_MODE (TREE_TYPE (parm)),
- GET_MODE_SIZE (
- TYPE_MODE (TREE_TYPE (parm))),
- align);
+ if (align > (int) MAX_SUPPORTED_STACK_ALIGNMENT
+ && targetm.calls.overaligned_stack_slot_required ()
+ && targetm.calls.preserve_overaligned_stack_slot (
+ TREE_TYPE (parm)))
+ parmreg = assign_stack_local_aligned (TYPE_MODE (TREE_TYPE (parm)),
+ GET_MODE_SIZE (TYPE_MODE (
+ TREE_TYPE (parm))),
+ align);
+ else
+ parmreg = assign_stack_local (TYPE_MODE (TREE_TYPE (parm)),
+ GET_MODE_SIZE (
+ TYPE_MODE (TREE_TYPE (parm))),
+ align);
set_mem_attributes (parmreg, parm, 1);
}
diff --git a/gcc/target.def b/gcc/target.def
index 0b7436b67a4..850279287f9 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -5213,16 +5213,25 @@ documentation.",
DEFHOOK
(overaligned_stack_slot_required,
- "This hook should return @code{true} when call-related stack slots whose\n\
-requested alignment exceeds @code{MAX_SUPPORTED_STACK_ALIGNMENT} need
special\n\
-handling on the target. This covers stack slots created by call expansion\n\
-(such as by-reference argument copies and hidden structure return storage)
and\n\
-incoming argument setup. When @code{true}, GCC may avoid normal fixed stack\n\
-slots for such cases and use over-allocation plus dynamic address alignment\n\
-instead.",
+ "This hook should return @code{true} when stack slots whose requested\n\
+alignment exceeds @code{MAX_SUPPORTED_STACK_ALIGNMENT} need special handling\n\
+on the target. This covers slots created by call expansion (such as\n\
+by-reference argument copies and hidden structure return storage), temporary\n\
+stack slots, and incoming argument setup. When @code{true}, GCC may avoid\n\
+normal fixed stack slots for such cases and use over-allocation plus dynamic\n\
+address alignment instead.",
bool, (void),
hook_bool_void_false)
+DEFHOOK
+(preserve_overaligned_stack_slot,
+ "This hook should return @code{true} when a stack slot for @var{type} whose\n\
+requested alignment exceeds @code{MAX_SUPPORTED_STACK_ALIGNMENT} should\n\
+preserve that requested alignment instead of using the normal fixed stack
slot\n\
+handling.",
+ bool, (tree type),
+ hook_bool_tree_false)
+
/* Return true if type TYPE, mode MODE, which is passed by reference,
should have the object copy generated by the callee rather than
the caller. It is never called for TYPE requiring constructors. */
@@ -7704,4 +7713,3 @@ The default value is NULL.",
/* Close the 'struct gcc_target' definition. */
HOOK_VECTOR_END (C90_EMPTY_HACK)
-
--
2.54.0.windows.1