Ping.
Thanks,
Kyrill

> On 17 Jun 2026, at 16:45, Kyrylo Tkachov <[email protected]> wrote:
> 
> From: Kyrylo Tkachov <[email protected]>
> 
> aarch64_function_arg_alignment returns the ABI alignment of an argument.
> For scalars and vectors this is the natural alignment of the type,
> ignoring any user-specified alignment.  The code obtains the natural
> alignment from the TYPE_MAIN_VARIANT, relying on the main variant having
> no user alignment.  PR108910 showed that this does not hold for pointers,
> and that case is handled explicitly.
> 
> PR124146 is another counterexample.  An attribute that affects type
> identity, such as may_alias, makes a type its own TYPE_MAIN_VARIANT, so
> the main variant retains the user alignment requested by the aligned
> attribute.  TYPE_MAIN_VARIANT therefore does not strip the alignment and
> the gcc_assert (!TYPE_USER_ALIGN (type)) fires.
> 
> In the testcase the may_alias+aligned type reaches the argument-passing
> code because foo is inlined into bar and forwprop propagates the value
> of that type directly into the recursive call to bar.
> 
> Fix it by ignoring user alignment explicitly: when the type still has
> user alignment, use the natural alignment of its mode, exactly as the
> !type path at the top of the function already does.  Behaviour is
> unchanged for the existing (non-user-aligned) cases, since the natural
> alignment of a scalar or vector equals its mode alignment.  This also
> gives the natural alignment when a may_alias typedef lowers the
> alignment of a 16-byte type, matching the AAPCS64 (and Clang).
> 
> Bootstrapped and tested on aarch64-none-linux-gnu.
> 
> Ok for trunk?
> Thanks,
> Kyrill
> 
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> 
> gcc/
> 
> PR target/124146
> * config/aarch64/aarch64.cc (aarch64_function_arg_alignment):
> Ignore user alignment left on a type's main variant; use the
> mode's natural alignment instead.
> 
> gcc/testsuite/
> 
> PR target/124146
> * gcc.target/aarch64/pr124146.c: New test.
> * gcc.target/aarch64/pr124146-2.c: New test.
> * gcc.target/aarch64/pr124146-3.c: New test.
> ---
> gcc/config/aarch64/aarch64.cc                 | 10 ++++-
> gcc/testsuite/gcc.target/aarch64/pr124146-2.c | 38 ++++++++++++++++
> gcc/testsuite/gcc.target/aarch64/pr124146-3.c | 45 +++++++++++++++++++
> gcc/testsuite/gcc.target/aarch64/pr124146.c   | 29 ++++++++++++
> 4 files changed, 121 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gcc.target/aarch64/pr124146-2.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/pr124146-3.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/pr124146.c
> 
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 42e56512c61..924dbcea0bd 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -7493,7 +7493,15 @@ aarch64_function_arg_alignment (machine_mode mode, 
> const_tree type,
>  *abi_break_gcc_14 = TYPE_ALIGN (type);
>  type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
> }
> -      gcc_assert (!TYPE_USER_ALIGN (type));
> +      /* Ignore any user-specified alignment: the AAPCS64 uses the
> + type's natural alignment for scalars and vectors.  We normally
> + strip user alignment by taking the TYPE_MAIN_VARIANT above, but
> + an attribute that affects type identity (such as may_alias) can
> + make a type its own main variant while still recording the user
> + alignment, so handle that case explicitly here (PR124146).  For
> + a scalar or vector the natural alignment is that of its mode.  */
> +      if (TYPE_USER_ALIGN (type))
> + return GET_MODE_ALIGNMENT (mode);
>       return TYPE_ALIGN (type);
>     }
> 
> diff --git a/gcc/testsuite/gcc.target/aarch64/pr124146-2.c 
> b/gcc/testsuite/gcc.target/aarch64/pr124146-2.c
> new file mode 100644
> index 00000000000..3dabdc59e02
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/pr124146-2.c
> @@ -0,0 +1,38 @@
> +/* PR target/124146 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +/* A type that combines an alignment attribute with an attribute that affects
> +   type identity (may_alias) is its own TYPE_MAIN_VARIANT and keeps
> +   TYPE_USER_ALIGN set.  aarch64_function_arg_alignment used to assert that
> +   the main variant had no user alignment, which ICEd for such types.  Verify
> +   that a wide range of them can be passed (alone and after another argument,
> +   over-aligned and under-aligned) and returned without an ICE.  */
> +
> +typedef int v4si __attribute__((__vector_size__ (16)));
> +
> +#define TEST(BASE, SUF) \
> +  typedef __attribute__((__aligned__, __may_alias__)) BASE big_##SUF; \
> +  typedef __attribute__((__aligned__ (8), __may_alias__)) BASE al8_##SUF; \
> +  void gbig_##SUF (big_##SUF); \
> +  void hbig_##SUF (int, big_##SUF); \
> +  void gal8_##SUF (al8_##SUF); \
> +  void hal8_##SUF (int, al8_##SUF); \
> +  void call_##SUF (big_##SUF a, al8_##SUF b) \
> +  { \
> +    gbig_##SUF (a); \
> +    hbig_##SUF (1, a); \
> +    gal8_##SUF (b); \
> +    hal8_##SUF (1, b); \
> +  } \
> +  big_##SUF ret_##SUF (big_##SUF a) { return a; }
> +
> +TEST (unsigned char, uc)
> +TEST (unsigned short, us)
> +TEST (unsigned int, ui)
> +TEST (unsigned long, ul)
> +TEST (long long, ll)
> +TEST (__int128, i128)
> +TEST (float, f)
> +TEST (double, d)
> +TEST (v4si, v)
> diff --git a/gcc/testsuite/gcc.target/aarch64/pr124146-3.c 
> b/gcc/testsuite/gcc.target/aarch64/pr124146-3.c
> new file mode 100644
> index 00000000000..f9ca9319d77
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/pr124146-3.c
> @@ -0,0 +1,45 @@
> +/* PR target/124146 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +/* The AAPCS64 passes scalars and vectors using their natural alignment,
> +   ignoring user alignment.  A 16-byte __int128 must therefore use its
> +   natural 16-byte alignment (so the C.8 rule rounds NGRN up to an even
> +   register), even when a may_alias typedef records a different user
> +   alignment.  These checks would have ICEd before the PR124146 fix.  */
> +
> +typedef __attribute__((__aligned__, __may_alias__)) __int128 ma_i128;
> +typedef __attribute__((__aligned__ (8), __may_alias__)) __int128 ma8_i128;
> +typedef __attribute__((__aligned__, __may_alias__)) unsigned long ma_ul;
> +
> +void consume_i128 (int, __int128);
> +void consume_ul (int, unsigned long);
> +
> +/* Over-aligned __int128: natural alignment 16 -> argument in x2/x3.
> +** pass_i128:
> +** mov x2, x0
> +** mov x3, x1
> +** mov w0, 5
> +** b consume_i128
> +*/
> +void pass_i128 (ma_i128 y) { consume_i128 (5, y); }
> +
> +/* Under-aligned (aligned(8)) __int128: natural alignment is still 16, so the
> +   argument must still land in x2/x3, not x1/x2.
> +** pass_i128_underaligned:
> +** mov x2, x0
> +** mov x3, x1
> +** mov w0, 5
> +** b consume_i128
> +*/
> +void pass_i128_underaligned (ma8_i128 y) { consume_i128 (5, y); }
> +
> +/* Over-aligned unsigned long: a single 8-byte register, alignment is
> +   irrelevant to placement -> argument in x1.
> +** pass_ul:
> +** mov x1, x0
> +** mov w0, 5
> +** b consume_ul
> +*/
> +void pass_ul (ma_ul y) { consume_ul (5, y); }
> diff --git a/gcc/testsuite/gcc.target/aarch64/pr124146.c 
> b/gcc/testsuite/gcc.target/aarch64/pr124146.c
> new file mode 100644
> index 00000000000..29142847ed4
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/pr124146.c
> @@ -0,0 +1,29 @@
> +/* PR target/124146 */
> +/* { dg-do compile } */
> +/* { dg-options "-O1" } */
> +
> +/* The may_alias attribute makes the typedef T its own TYPE_MAIN_VARIANT
> +   while still recording the user alignment from the aligned attribute.
> +   Taking the main variant in aarch64_function_arg_alignment therefore did
> +   not strip the user alignment, which used to trigger an assertion failure
> +   (ICE) when foo was inlined into bar and the value of type T was passed
> +   directly to bar.  */
> +
> +long a;
> +void *b;
> +char c;
> +
> +long
> +foo (void *p)
> +{
> +  typedef __attribute__((__aligned__)) __attribute__((__may_alias__)) 
> unsigned long T;
> +  a = *(T *) b;
> +  return a;
> +}
> +
> +void
> +bar (unsigned long x)
> +{
> +  long d = foo (&c);
> +  bar (d);
> +}
> -- 
> 2.50.1 (Apple Git-155)
> 

Reply via email to