On Thu, 27 Aug 2026, Oleg Tolmatcev wrote: > Targets that cannot realign the stack cap their stack alignment and rely > on the middle end to align over-aligned stack objects inside their slots. > 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. > > In several places the middle end does not do that alignment. 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). > There is an even bigger problem. Even with MEM_ALIGN and the slot's > alignment consistent, an escaped pointer loses the information about the > alignment cap: GCC assumes the object's natural alignment and uses an > aligned access on an under-aligned object, which faults on x86. > > aarch64 does not crash only because its loads and stores do not fault on > a misaligned address; the object is under-aligned there just the same. > > Add assign_stack_local_aligned, which preserves the requested alignment by > overallocating a slot and aligning an address inside it, and use it > wherever an object gets a stack slot of its own. This is what > assign_parm_setup_block already did for BLKmode parameters and what > expand_stack_vars does for locals. Such a slot has no fixed frame offset, > so it cannot be reused as a temp slot.
It seems to me that assign_stack_local itself guarantees alignment. Why does it (or rather assign_stack_local_1 with kind == ASLK_RECORD_PAD) not work? Richard. > Regtested on x86_64-pc-linux-gnu and, under QEMU, on > aarch64-unknown-linux-gnu, with no new failures. > > gcc/ChangeLog: > > PR target/54412 > * function.cc (assign_stack_local_aligned): New function, split > out of assign_parm_setup_block. > (assign_stack_temp_for_type): Compute the required alignment from > the type and the mode. Allocate an over-aligned temporary with > assign_stack_local_aligned and give it no temp_slot entry. Take > the resulting alignment from the allocated slot. > (assign_parm_setup_block): Use assign_stack_local_aligned. > (assign_parm_setup_reg): Likewise. > (assign_parm_setup_stack): Likewise. > > Signed-off-by: Oleg Tolmatcev <[email protected]> > --- > gcc/function.cc | 87 +++++++++++++++++++++++++++++++++++-------------- > 1 file changed, 63 insertions(+), 24 deletions(-) > > diff --git a/gcc/function.cc b/gcc/function.cc > index 9358787b26..0bc8e6da89 100644 > --- a/gcc/function.cc > +++ b/gcc/function.cc > @@ -551,6 +551,36 @@ assign_stack_local (machine_mode mode, poly_int64 size, > int align) > return assign_stack_local_1 (mode, size, align, ASLK_RECORD_PAD); > } > > +/* Like assign_stack_local, but preserve requested over-alignment by > + overallocating a BLKmode slot and aligning an address within it. */ > + > +static rtx > +assign_stack_local_aligned (machine_mode mode, poly_int64 size, > + unsigned int align) > +{ > + if (align > MAX_SUPPORTED_STACK_ALIGNMENT) > + { > + /* align_dynamic_address emits the alignment arithmetic into a pseudo. > */ > + gcc_assert (can_create_pseudo_p ()); > + > + /* The slot's base is aligned to MAX_SUPPORTED_STACK_ALIGNMENT, so > moving > + it to the next ALIGN boundary needs at most the difference between the > + two alignments. Keep the size polynomial for scalable modes. */ > + poly_int64 allocsize > + = size + ((align - MAX_SUPPORTED_STACK_ALIGNMENT) / BITS_PER_UNIT); > + rtx slot = assign_stack_local (BLKmode, allocsize, > + MAX_SUPPORTED_STACK_ALIGNMENT); > + rtx addr = align_dynamic_address (XEXP (slot, 0), align); > + mark_reg_pointer (addr, align); > + slot = gen_rtx_MEM (mode, addr); > + set_mem_align (slot, align); > + MEM_NOTRAP_P (slot) = 1; > + return slot; > + } > + > + return assign_stack_local (mode, size, align); > +} > + > /* In order to evaluate some expressions, such as function calls returning > structures in memory, we need to temporarily allocate stack locations. > We record each allocated temporary in the following structure. > @@ -801,6 +831,22 @@ assign_stack_temp_for_type (machine_mode mode, > poly_int64 size, tree type) > > gcc_assert (known_size_p (size)); > > + 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 inside an overallocated slot. BASE_OFFSET and FULL_SIZE > + cannot describe such a slot, so it gets no temp_slot entry: it is never > + reused or freed. */ > + if (required_align > MAX_SUPPORTED_STACK_ALIGNMENT) > + { > + slot = assign_stack_local_aligned (mode, size, required_align); > + align = MEM_ALIGN (slot); > + goto finalize_slot; > + } > + > align = get_stack_local_alignment (type, mode); > > /* Try to find an available, already-allocated temporary of the proper > @@ -892,7 +938,7 @@ assign_stack_temp_for_type (machine_mode mode, poly_int64 > size, tree type) > : size), > align, 0); > > - p->align = align; > + p->align = MEM_ALIGN (p->slot); > > /* The following slot size computation is necessary because we don't > know the actual size of the temporary slot until assign_stack_local > @@ -931,8 +977,11 @@ assign_stack_temp_for_type (machine_mode mode, > poly_int64 size, tree type) > insert_slot_to_list (p, pp); > insert_temp_slot_address (XEXP (p->slot, 0), p); > > + align = MEM_ALIGN (p->slot); > + > /* Create a new MEM rtx to avoid clobbering MEM flags of old slots. */ > slot = gen_rtx_MEM (mode, XEXP (p->slot, 0)); > +finalize_slot: > vec_safe_push (stack_slot_list, slot); > > /* If we know the alias set for the memory that will be used, use > @@ -2948,24 +2997,13 @@ 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_aligned (BLKmode, size_stored, DECL_ALIGN (parm)); > + int align = MEM_ALIGN (stack_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); > + set_mem_align (stack_parm, align); > } > > /* If a BLKmode arrives in registers, copy it to a stack slot. Handle > @@ -3366,11 +3404,13 @@ 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 (TYPE_MODE (TREE_TYPE (parm)), > - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parm))), > - align); > + parmreg = assign_stack_local_aligned (TYPE_MODE (TREE_TYPE (parm)), > + GET_MODE_SIZE ( > + TYPE_MODE (TREE_TYPE (parm))), > + align); > + align = MEM_ALIGN (parmreg); > set_mem_attributes (parmreg, parm, 1); > + set_mem_align (parmreg, align); > } > > /* We need to preserve an address based on VIRTUAL_STACK_VARS_REGNUM > for > @@ -3523,10 +3563,9 @@ assign_parm_setup_stack (struct assign_parm_data_all > *all, tree parm, > || targetm.slow_unaligned_access (GET_MODE (data->entry_parm), > align))) > align = GET_MODE_ALIGNMENT (GET_MODE (data->entry_parm)); > - data->stack_parm > - = assign_stack_local (GET_MODE (data->entry_parm), > - GET_MODE_SIZE (GET_MODE (data->entry_parm)), > - align); > + data->stack_parm = assign_stack_local_aligned ( > + GET_MODE (data->entry_parm), > + GET_MODE_SIZE (GET_MODE (data->entry_parm)), align); > align = MEM_ALIGN (data->stack_parm); > set_mem_attributes (data->stack_parm, parm, 1); > set_mem_align (data->stack_parm, align); > -- Richard Biener <[email protected]> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)
