Targets that cannot realign the stack cap their stack alignment.  Win64 SEH
caps MAX_STACK_ALIGNMENT at 128 bits; aarch64 does not define
MAX_STACK_ALIGNMENT at all and is capped at STACK_BOUNDARY, also 128.
assign_stack_local silently ignored any alignment beyond that cap.

A 256-bit vector requires 32-byte alignment, its slot gets the capped 16
bytes, and MEM_ALIGN is set to 32 anyway.  x86 selects vmovaps from
MEM_ALIGN and faults on the under-aligned slot (PR54412,
MSYS2/MINGW-packages#1209).  Even with MEM_ALIGN consistent, an escaped
pointer carries only the alignment of the type, and the callee uses an
aligned access on the under-aligned object.  aarch64 does not crash only
because its loads and stores do not fault on a misaligned address.

Make assign_stack_local_1 honour an explicit alignment beyond the cap by
overallocating the slot and aligning an address inside it at run time, as
assign_parm_setup_block already did for BLKmode parameters and
expand_stack_vars does for locals.  Such a slot has no fixed frame offset, so
assign_stack_temp_for_type keeps an over-aligned temporary out of the temp
slot list, and caps the merely preferred alignment of other temporaries so
they can still be reused.

Callers that can do with less pass ASLK_REDUCE_ALIGN: LRA spill slots, which
are allocated after register allocation, and the sjlj function context, whose
alignment is a deliberate overestimate.

Regtested on x86_64-pc-linux-gnu and, under QEMU, on aarch64-unknown-linux-gnu,
with no new failures.

gcc/ChangeLog:

        PR target/54412
        * except.cc (sjlj_build_landing_pads): Pass ASLK_REDUCE_ALIGN.
        * function.cc (assign_stack_local_1): Honour a positive ALIGN beyond
        MAX_SUPPORTED_STACK_ALIGNMENT unless KIND has ASLK_REDUCE_ALIGN, by
        overallocating the slot and aligning its address at run time.
        (assign_stack_temp_for_type): Allocate a temporary whose required
        alignment exceeds MAX_SUPPORTED_STACK_ALIGNMENT without a temp_slot
        entry.  Cap the preferred alignment of other temporaries at
        MAX_SUPPORTED_STACK_ALIGNMENT and adjust the BLKmode assert.
        (assign_parm_setup_block): Let assign_stack_local align the slot.
        * lra-spills.cc (assign_mem_slot): Pass ASLK_REDUCE_ALIGN.

Signed-off-by: Oleg Tolmatcev <[email protected]>
---
 gcc/except.cc     | 12 ++++-----
 gcc/function.cc   | 68 +++++++++++++++++++++++++++++++++--------------
 gcc/lra-spills.cc |  5 ++--
 3 files changed, 57 insertions(+), 28 deletions(-)

diff --git a/gcc/except.cc b/gcc/except.cc
index 98876833ee..e3b8645733 100644
--- a/gcc/except.cc
+++ b/gcc/except.cc
@@ -1478,9 +1478,9 @@ sjlj_build_landing_pads (void)
                                        TYPE_MODE (sjlj_fc_type_node),
                                        TYPE_ALIGN (sjlj_fc_type_node));
       crtl->eh.sjlj_fc
-       = assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
-                             int_size_in_bytes (sjlj_fc_type_node),
-                             align);
+       = assign_stack_local_1 (TYPE_MODE (sjlj_fc_type_node),
+                               int_size_in_bytes (sjlj_fc_type_node),
+                               align, ASLK_RECORD_PAD | ASLK_REDUCE_ALIGN);
 
       sjlj_mark_call_sites ();
       sjlj_emit_function_enter (dispatch_label);
@@ -1496,9 +1496,9 @@ sjlj_build_landing_pads (void)
                                        TYPE_MODE (sjlj_fc_type_node),
                                        TYPE_ALIGN (sjlj_fc_type_node));
       crtl->eh.sjlj_fc
-       = assign_stack_local (TYPE_MODE (sjlj_fc_type_node),
-                             int_size_in_bytes (sjlj_fc_type_node),
-                             align);
+       = assign_stack_local_1 (TYPE_MODE (sjlj_fc_type_node),
+                               int_size_in_bytes (sjlj_fc_type_node),
+                               align, ASLK_RECORD_PAD | ASLK_REDUCE_ALIGN);
 
       sjlj_mark_call_sites ();
       sjlj_emit_function_enter (NULL);
diff --git a/gcc/function.cc b/gcc/function.cc
index 9358787b26..fbe341b96e 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -370,6 +370,10 @@ add_frame_space (poly_int64 start, poly_int64 end)
    -2 means use BITS_PER_UNIT,
    positive specifies alignment boundary in bits.
 
+   A positive ALIGN that exceeds MAX_SUPPORTED_STACK_ALIGNMENT is honoured
+   by overallocating the slot and aligning its address at run time, with
+   insns emitted at the current position, unless KIND has ASLK_REDUCE_ALIGN.
+
    KIND has ASLK_REDUCE_ALIGN bit set if it is OK to reduce
    alignment and ASLK_RECORD_PAD bit set if we should remember
    extra space we allocated for alignment purposes.  When we are
@@ -385,7 +389,7 @@ assign_stack_local_1 (machine_mode mode, poly_int64 size,
   rtx x, addr;
   poly_int64 bigend_correction = 0;
   poly_int64 slot_offset = 0, old_frame_offset;
-  unsigned int alignment, alignment_in_bits;
+  unsigned int alignment, alignment_in_bits, dynamic_align = 0;
 
   if (align == 0)
     {
@@ -404,9 +408,19 @@ assign_stack_local_1 (machine_mode mode, poly_int64 size,
 
   alignment_in_bits = alignment * BITS_PER_UNIT;
 
-  /* Ignore alignment if it exceeds MAX_SUPPORTED_STACK_ALIGNMENT.  */
+  /* The frame cannot be aligned beyond MAX_SUPPORTED_STACK_ALIGNMENT.  If more
+     is requested, pad the slot so that an over-aligned object still fits.  */
   if (alignment_in_bits > MAX_SUPPORTED_STACK_ALIGNMENT)
     {
+      if (align > 0 && !(kind & ASLK_REDUCE_ALIGN) && maybe_ne (size, 0))
+       {
+         gcc_assert (can_create_pseudo_p ());
+         dynamic_align = alignment_in_bits;
+         /* Pad from the alignment the frame base is guaranteed to have.  */
+         size += ((alignment_in_bits
+                   - REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM))
+                  / BITS_PER_UNIT);
+       }
       alignment_in_bits = MAX_SUPPORTED_STACK_ALIGNMENT;
       alignment = MAX_SUPPORTED_STACK_ALIGNMENT / BITS_PER_UNIT;
     }
@@ -506,7 +520,7 @@ assign_stack_local_1 (machine_mode mode, poly_int64 size,
  found_space:
   /* On a big-endian machine, if we are allocating more space than we will use,
      use the least significant bytes of those that are allocated.  */
-  if (mode != BLKmode)
+  if (mode != BLKmode && !dynamic_align)
     {
       /* The slot size can sometimes be smaller than the mode size;
         e.g. the rs6000 port allocates slots with a vector mode
@@ -531,6 +545,13 @@ assign_stack_local_1 (machine_mode mode, poly_int64 size,
                          (slot_offset + bigend_correction,
                           Pmode));
 
+  if (dynamic_align)
+    {
+      addr = align_dynamic_address (addr, dynamic_align);
+      mark_reg_pointer (addr, dynamic_align);
+      alignment_in_bits = dynamic_align;
+    }
+
   x = gen_rtx_MEM (mode, addr);
   set_mem_align (x, alignment_in_bits);
   MEM_NOTRAP_P (x) = 1;
@@ -801,7 +822,24 @@ assign_stack_temp_for_type (machine_mode mode, poly_int64 
size, tree type)
 
   gcc_assert (known_size_p (size));
 
-  align = get_stack_local_alignment (type, mode);
+  unsigned int required_align
+    = (mode == BLKmode ? BITS_PER_UNIT : GET_MODE_ALIGNMENT (mode));
+  if (type)
+    required_align = MAX (required_align, TYPE_ALIGN (type));
+
+  /* Alignment beyond what the frame can guarantee needs an address aligned
+     at run time, so such a temporary is never reused or freed.  */
+  if (required_align > MAX_SUPPORTED_STACK_ALIGNMENT)
+    {
+      slot = assign_stack_local_1 (mode, size, required_align, 0);
+      align = MEM_ALIGN (slot);
+      goto finalize_slot;
+    }
+
+  /* Cap the preferred alignment at MAX_SUPPORTED_STACK_ALIGNMENT so that the
+     slot can be reused like any other temporary.  */
+  align = MIN (get_stack_local_alignment (type, mode),
+              MAX_SUPPORTED_STACK_ALIGNMENT);
 
   /* Try to find an available, already-allocated temporary of the proper
      mode which meets the size and alignment requirements.  Choose the
@@ -883,7 +921,9 @@ assign_stack_temp_for_type (machine_mode mode, poly_int64 
size, tree type)
         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);
+      gcc_assert (mode != BLKmode
+                 || align == MIN (BIGGEST_ALIGNMENT,
+                                  MAX_SUPPORTED_STACK_ALIGNMENT));
       p->slot = assign_stack_local_1 (mode,
                                      (mode == BLKmode
                                       ? aligned_upper_bound (size,
@@ -935,6 +975,7 @@ assign_stack_temp_for_type (machine_mode mode, poly_int64 
size, tree type)
   slot = gen_rtx_MEM (mode, XEXP (p->slot, 0));
   vec_safe_push (stack_slot_list, slot);
 
+ finalize_slot:
   /* If we know the alias set for the memory that will be used, use
      it.  If there's no TYPE, then we don't know anything about the
      alias set for the memory.  */
@@ -2948,21 +2989,8 @@ assign_parm_setup_block (struct assign_parm_data_all 
*all,
           ? MAX (DECL_ALIGN (parm), BITS_PER_WORD) : DECL_ALIGN (parm));
 
       SET_DECL_ALIGN (parm, parm_align);
-      if (DECL_ALIGN (parm) > MAX_SUPPORTED_STACK_ALIGNMENT)
-       {
-         rtx allocsize = gen_int_mode (size_stored, Pmode);
-         get_dynamic_stack_size (&allocsize, 0, DECL_ALIGN (parm), NULL);
-         stack_parm = assign_stack_local (BLKmode, UINTVAL (allocsize),
-                                          MAX_SUPPORTED_STACK_ALIGNMENT);
-         rtx addr = align_dynamic_address (XEXP (stack_parm, 0),
-                                           DECL_ALIGN (parm));
-         mark_reg_pointer (addr, DECL_ALIGN (parm));
-         stack_parm = gen_rtx_MEM (GET_MODE (stack_parm), addr);
-         MEM_NOTRAP_P (stack_parm) = 1;
-       }
-      else
-       stack_parm = assign_stack_local (BLKmode, size_stored,
-                                        DECL_ALIGN (parm));
+      stack_parm = assign_stack_local (BLKmode, size_stored,
+                                      DECL_ALIGN (parm));
       if (known_eq (GET_MODE_SIZE (GET_MODE (entry_parm)), size))
        PUT_MODE (stack_parm, GET_MODE (entry_parm));
       set_mem_attributes (stack_parm, parm, 1);
diff --git a/gcc/lra-spills.cc b/gcc/lra-spills.cc
index 07801e39d5..f55839f50b 100644
--- a/gcc/lra-spills.cc
+++ b/gcc/lra-spills.cc
@@ -146,8 +146,9 @@ assign_mem_slot (int i)
   x = slots[slot_num].mem;
   if (!x)
     {
-      x = assign_stack_local (BLKmode, slots[slot_num].size,
-                             slots[slot_num].align);
+      x = assign_stack_local_1 (BLKmode, slots[slot_num].size,
+                               slots[slot_num].align,
+                               ASLK_RECORD_PAD | ASLK_REDUCE_ALIGN);
       slots[slot_num].mem = x;
     }
 
-- 
2.55.0.windows.5

Reply via email to