diff mbox series

[2/2] aarch64: Fix bit-field alignment in param passing [PR105549]

Message ID 20220617122100.2048938-2-christophe.lyon@arm.com
State New
Headers show
Series [1/2] aarch64: fix warning emission for ABI break since GCC 9.1 | expand

Commit Message

Christophe Lyon June 17, 2022, 12:21 p.m. UTC
While working on enabling DFP for AArch64, I noticed new failures in
gcc.dg/compat/struct-layout-1.exp (t028) which were not actually
caused by DFP types handling. These tests are generated during 'make
check' and enabling DFP made generation different (not sure if new
non-DFP tests are generated, or if existing ones are generated
differently, the tests in question are huge and difficult to compare).

Anyway, I reduced the problem to what I attach at the end of the new
gcc.target/aarch64/aapcs64/va_arg-17.c test and rewrote it in the same
scheme as other va_arg* AArch64 tests.  Richard Sandiford further
reduced this to a non-vararg function, added as a second testcase.

This is a tough case mixing bit-fields and alignment, where
aarch64_function_arg_alignment did not follow what its descriptive
comment says: we want to use the natural alignment of the bit-field
type only if the user didn't reduce the alignment for the bit-field
itself.

The fix would be very small, except that this introduces a new ABI
break, and we have to warn about that.  Since this actually fixes a
problem introduced in GCC 9.1, we keep the old computation to detect
when we now behave differently.

This patch adds two new tests (va_arg-17.c and
pr105549.c). va_arg-17.c contains the reduced offending testcase from
struct-layout-1.exp for reference.  We update some tests introduced by
the previous patch, where parameters with bit-fields and packed
attribute now emit a different warning.

We also take the opportunity to fix the comment above
aarch64_function_arg_alignment since the value of the abi_break
parameter was changed in a previous commit, no longer matching the
description.

2022-06-16  Christophe Lyon  <christophe.lyon@arm.com>

	gcc/
	PR target/105549
	* config/aarch64/aarch64.cc (aarch64_function_arg_alignment):
	Check DECL_PACKED for bitfield.
	(aarch64_layout_arg): Warn when parameter passing ABI changes.
	(aarch64_function_arg_boundary): Likewise.
	(aarch64_gimplify_va_arg_expr): Likewise.

	gcc/testsuite/
	PR target/105549
	* gcc.target/aarch64/bitfield-abi-warning-align16-O0.c: Update.
	* gcc.target/aarch64/bitfield-abi-warning-align16-O2.c: Update.
	* gcc.target/aarch64/aapcs64/va_arg-17.c: New test.
	* gcc.target/aarch64/pr105549.c: New test.
---
 gcc/config/aarch64/aarch64.cc                 |  87 ++++++++++++---
 .../gcc.target/aarch64/aapcs64/va_arg-17.c    | 105 ++++++++++++++++++
 .../aarch64/bitfield-abi-warning-align16-O0.c |  60 +++++-----
 .../aarch64/bitfield-abi-warning-align16-O2.c |  60 +++++-----
 gcc/testsuite/gcc.target/aarch64/pr105549.c   |  12 ++
 5 files changed, 249 insertions(+), 75 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/aapcs64/va_arg-17.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/pr105549.c
diff mbox series

Patch

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 13984e3435b..e7a6288d7a7 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -7248,15 +7248,19 @@  aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode,
 /* Given MODE and TYPE of a function argument, return the alignment in
    bits.  The idea is to suppress any stronger alignment requested by
    the user and opt for the natural alignment (specified in AAPCS64 \S
-   4.1).  ABI_BREAK is set to true if the alignment was incorrectly
-   calculated in versions of GCC prior to GCC-9.  This is a helper
+   4.1).  ABI_BREAK is set to the old alignment if the alignment was
+   incorrectly calculated in versions of GCC prior to GCC-9.
+   ABI_BREAK_PACKED is set to the old alignment if it was incorrectly
+   calculated in versions between GCC-9 and GCC-13.  This is a helper
    function for local use only.  */
 
 static unsigned int
 aarch64_function_arg_alignment (machine_mode mode, const_tree type,
-				unsigned int *abi_break)
+				unsigned int *abi_break,
+				unsigned int *abi_break_packed)
 {
   *abi_break = 0;
+  *abi_break_packed = 0;
   if (!type)
     return GET_MODE_ALIGNMENT (mode);
 
@@ -7272,6 +7276,7 @@  aarch64_function_arg_alignment (machine_mode mode, const_tree type,
     return TYPE_ALIGN (TREE_TYPE (type));
 
   unsigned int alignment = 0;
+  unsigned int bitfield_alignment_with_packed = 0;
   unsigned int bitfield_alignment = 0;
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     if (TREE_CODE (field) == FIELD_DECL)
@@ -7290,12 +7295,32 @@  aarch64_function_arg_alignment (machine_mode mode, const_tree type,
 	   "s" contains only one Fundamental Data Type (the int field)
 	   but gains 8-byte alignment and size thanks to "e".  */
 	alignment = std::max (alignment, DECL_ALIGN (field));
+
 	if (DECL_BIT_FIELD_TYPE (field))
-	  bitfield_alignment
-	    = std::max (bitfield_alignment,
-			TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)));
+	  {
+	    /* Take the bit-field type's alignment into account only
+	       if the user didn't reduce this field's alignment with
+	       the packed attribute.  */
+	      if (!DECL_PACKED (field))
+		bitfield_alignment
+		  = std::max (bitfield_alignment,
+			      TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)));
+
+	      /* Compute the alignment even if the bit-field is
+		 packed, so that we can emit a warning in case the
+		 alignment changed between GCC versions.  */
+	      bitfield_alignment_with_packed
+		= std::max (bitfield_alignment_with_packed,
+			    TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)));
+	    }
       }
 
+  /* Emit a warning if the alignment is different when taking the
+     'packed' attribute into account.  */
+  if (bitfield_alignment != bitfield_alignment_with_packed
+      && bitfield_alignment_with_packed > alignment)
+    *abi_break_packed = bitfield_alignment_with_packed;
+
   if (bitfield_alignment > alignment)
     {
       *abi_break = alignment;
@@ -7321,6 +7346,7 @@  aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
   bool allocate_ncrn, allocate_nvrn;
   HOST_WIDE_INT size;
   unsigned int abi_break;
+  unsigned int abi_break_packed;
 
   /* We need to do this once per argument.  */
   if (pcum->aapcs_arg_processed)
@@ -7457,15 +7483,24 @@  aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
 
       /* C.8 if the argument has an alignment of 16 then the NGRN is
 	 rounded up to the next even number.  */
-      alignment = aarch64_function_arg_alignment (mode, type, &abi_break);
-      if (ncrn % 2
+      alignment = aarch64_function_arg_alignment (mode, type, &abi_break,
+						  &abi_break_packed);
+      if (ncrn % 2)
+	{
+	  /* Emit a warning if the alignment changed when taking the
+	     'packed' attribute into account.  */
+	  if (abi_break_packed && warn_psabi && currently_expanding_gimple_stmt)
+	    inform (input_location, "parameter passing for argument of type "
+		    "%qT changed in GCC 13.1", type);
+
 	  /* The == 16 * BITS_PER_UNIT instead of >= 16 * BITS_PER_UNIT
 	     comparison is there because for > 16 * BITS_PER_UNIT
 	     alignment nregs should be > 2 and therefore it should be
 	     passed by reference rather than value.  */
-	  && (alignment
-	      == 16 * BITS_PER_UNIT))
+	  if (alignment
+	      == 16 * BITS_PER_UNIT)
 	{
+
 	  /* We want to emit a warning even if nregs == 1, because
 	     although we do not round ncrn up in this case, the callee
 	     has a different (broken) expectation.  */
@@ -7479,6 +7514,7 @@  aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
 	      gcc_assert (ncrn + nregs <= NUM_ARG_REGS);
 	    }
 	}
+	}
 
       /* If an argument with an SVE mode needs to be shifted up to the
 	 high part of the register, treat it as though it had an integer mode.
@@ -7530,7 +7566,14 @@  aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
 on_stack:
   pcum->aapcs_stack_words = size / UNITS_PER_WORD;
 
-  if (aarch64_function_arg_alignment (mode, type, &abi_break)
+  unsigned int alignment =
+    aarch64_function_arg_alignment (mode, type, &abi_break, &abi_break_packed);
+
+  if (abi_break_packed && warn_psabi && currently_expanding_gimple_stmt)
+    inform (input_location, "parameter passing for argument of type "
+	    "%qT changed in GCC 13.1", type);
+
+  if (alignment
       == 16 * BITS_PER_UNIT)
     {
       int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD);
@@ -7653,10 +7696,19 @@  static unsigned int
 aarch64_function_arg_boundary (machine_mode mode, const_tree type)
 {
   unsigned int abi_break;
+  unsigned int abi_break_packed;
   unsigned int alignment = aarch64_function_arg_alignment (mode, type,
-							   &abi_break);
+							   &abi_break,
+							   &abi_break_packed);
   alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY);
-  if (abi_break && warn_psabi)
+  if (abi_break_packed && warn_psabi)
+    {
+      abi_break_packed = MIN (MAX (abi_break_packed, PARM_BOUNDARY), STACK_BOUNDARY);
+      if (alignment != abi_break_packed)
+	inform (input_location, "parameter passing for argument of type "
+		"%qT changed in GCC 13.1", type);
+    }
+  else if (abi_break && warn_psabi)
     {
       abi_break = MIN (MAX (abi_break, PARM_BOUNDARY), STACK_BOUNDARY);
       if (alignment != abi_break)
@@ -19528,8 +19580,10 @@  aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   size = int_size_in_bytes (type);
 
   unsigned int abi_break;
+  unsigned int abi_break_packed;
   align
-    = aarch64_function_arg_alignment (mode, type, &abi_break) / BITS_PER_UNIT;
+    = aarch64_function_arg_alignment (mode, type, &abi_break, &abi_break_packed)
+    / BITS_PER_UNIT;
 
   dw_align = false;
   adjust = 0;
@@ -19572,7 +19626,10 @@  aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
       rsize = ROUND_UP (size, UNITS_PER_WORD);
       nregs = rsize / UNITS_PER_WORD;
 
-      if (align > 8)
+      if (align <= 8 && abi_break_packed && warn_psabi)
+	inform (input_location, "parameter passing for argument of type "
+		"%qT changed in GCC 13.1", type);
+      else if (align > 8)
 	{
 	  if (abi_break && warn_psabi)
 	    inform (input_location, "parameter passing for argument of type "
diff --git a/gcc/testsuite/gcc.target/aarch64/aapcs64/va_arg-17.c b/gcc/testsuite/gcc.target/aarch64/aapcs64/va_arg-17.c
new file mode 100644
index 00000000000..24895c3ab48
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/aapcs64/va_arg-17.c
@@ -0,0 +1,105 @@ 
+/* Test AAPCS64 layout and __builtin_va_arg.
+
+   This test covers a corner case where a composite type parameter fits in one
+   register: we do not need a double-word alignment when accessing it in the
+   va_arg stack area.  */
+
+/* { dg-do run { target aarch64*-*-* } } */
+
+#ifndef IN_FRAMEWORK
+#define AAPCS64_TEST_STDARG
+#define TESTFILE "va_arg-17.c"
+#include "type-def.h"
+
+enum E6 { e6_0, e6_1, e6_2, e6_3, e6_65533 = 65533, e6_65534, e6_65535 };
+typedef enum E6 Tal16E6 __attribute__((aligned (16)));
+typedef unsigned int Tuint;
+
+int fails;
+
+union S2844 {
+  Tuint a:((((10) - 1) & 31) + 1);
+  Tal16E6 __attribute__((aligned (2), packed)) b:31;
+  struct{}c[0];
+} ;
+union S2844 s2844;
+union S2844 a2844[5];
+
+#define HAS_DATA_INIT_FUNC
+void init_data ()
+{
+  memset (&s2844, '\0', sizeof (s2844));
+  memset (a2844, '\0', sizeof (a2844));
+  s2844.a = 799U;
+  a2844[2].a = 586U;
+}
+
+#include "abitest.h"
+#else
+  ARG       (int          , 1        , W0 , LAST_NAMED_ARG_ID)
+  DOTS
+  ANON_PROMOTED  (float   , 1.0f, double, 1.0, D0, 1)
+  ANON      (union S2844  , s2844    , X1 , 2)
+  ANON      (long long    , 2LL      , X2 , 3)
+  ANON      (union  S2844 , a2844[2] , X3 , 4)
+  LAST_ANON (union  S2844 , a2844[2] , X4 , 5)
+#endif
+
+#if 0
+  /* This test is derived from a case generated by struct-layout-1.exp:  */
+
+enum E6 { e6_0, e6_1, e6_2, e6_3, e6_65533 = 65533, e6_65534, e6_65535 };
+typedef enum E6 Tal16E6 __attribute__((aligned (16)));
+typedef unsigned int Tuint;
+
+int fails;
+
+union S2844 {
+  Tuint a:((((10) - 1) & 31) + 1);
+  Tal16E6 __attribute__((aligned (2), packed)) b:31;
+  struct{}c[0];
+} ;
+union S2844 s2844;
+union S2844 a2844[5];
+
+typedef __builtin_va_list __gnuc_va_list;
+typedef __gnuc_va_list va_list;
+
+void check2844va (int z, ...) {
+  union S2844 arg, *p;
+  va_list ap;
+
+  __builtin_va_start(ap,z);
+  if (__builtin_va_arg(ap,double) != 1.0)
+    printf ("fail %d.%d\n", 2844, 0), ++fails;
+
+  p = &s2844;
+  arg = __builtin_va_arg(ap,union S2844);  /* This would fail.  */
+  if (p->a != arg.a)
+    printf ("fail %d.%d\n", 2844, 1), ++fails;
+
+  if (__builtin_va_arg(ap,long long) != 3LL)
+    printf ("fail %d.%d\n", 2844, 2), ++fails;
+
+  p = &a2844[2];
+  arg = __builtin_va_arg(ap,union S2844);  /* This would fail.  */
+  if (p->a != arg.a)
+    printf ("fail %d.%d\n", 2844, 3), ++fails;
+
+  arg = __builtin_va_arg(ap,union S2844);  /* This would fail.  */
+  if (p->a != arg.a)
+    printf ("fail %d.%d\n", 2844, 4), ++fails;
+
+  __builtin_va_end(ap);
+}
+
+int main (void) {
+  int i, j;
+  memset (&s2844, '\0', sizeof (s2844));
+  memset (a2844, '\0', sizeof (a2844));
+  s2844.a = 799U;
+  a2844[2].a = 586U;
+  check2844va (1, 1.0, s2844, 2LL, a2844[2], a2844[2]);
+  exit (fails != 0);
+}
+#endif /* 0 */
diff --git a/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O0.c b/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O0.c
index 0a1f54acb2d..e52e1ae6d80 100644
--- a/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O0.c
+++ b/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O0.c
@@ -12,11 +12,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} "" { target *-*-* } 49 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} "" { target *-*-* } 50 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 53 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 54 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 55 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 56 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 57 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 53 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 54 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 55 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 56 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 57 } */
 
 /* Bitfield call argument in registers.  */
 /* { dg-note {parameter passing for argument of type 'struct S1' changed in GCC 9.1} ""  { target *-*-* } 60 } */
@@ -24,11 +24,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} ""  { target *-*-* } 62 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} ""  { target *-*-* } 63 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 66 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 67 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 68 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 69 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 70 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 66 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 67 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 68 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 69 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 70 } */
 
 
 /* Bitfield parameter in stack.  */
@@ -37,11 +37,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} "" { target *-*-* } 76 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} "" { target *-*-* } 77 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 80 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 81 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 82 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 83 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 84 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 80 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 81 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 82 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 83 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 84 } */
 
 /* Bitfield call argument in stack.  */
 /* { dg-note {parameter passing for argument of type 'struct S1' changed in GCC 9.1} ""  { target *-*-* } 87 } */
@@ -49,11 +49,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} ""  { target *-*-* } 89 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} ""  { target *-*-* } 90 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 93 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 94 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 95 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 96 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 97 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 93 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 94 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 95 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 96 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 97 } */
 
 
 /* Bitfield parameter in stdarg.  */
@@ -62,11 +62,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} "" { target *-*-* } 103 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} "" { target *-*-* } 104 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 107 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 108 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 109 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 110 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 111 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 107 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 108 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 109 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 110 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 111 } */
 
 /* Bitfield call argument in stdarg.  */
 /* { dg-note {parameter passing for argument of type 'struct S1' changed in GCC 9.1} ""  { target *-*-* } 114 } */
@@ -74,8 +74,8 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} ""  { target *-*-* } 116 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} ""  { target *-*-* } 117 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 120 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 121 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 122 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 123 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 124 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 120 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 121 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 122 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 123 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 124 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O2.c b/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O2.c
index ce2e089588b..72bba44ba94 100644
--- a/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O2.c
+++ b/gcc/testsuite/gcc.target/aarch64/bitfield-abi-warning-align16-O2.c
@@ -17,11 +17,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} "" { target *-*-* } 49 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} "" { target *-*-* } 50 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 53 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 54 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 55 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 56 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 57 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 53 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 54 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 55 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 56 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 57 } */
 
 /* Bitfield call argument in registers.  */
 /* { dg-note {parameter passing for argument of type 'struct S1' changed in GCC 9.1} ""  { target *-*-* } 60 } */
@@ -29,11 +29,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} ""  { target *-*-* } 62 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} ""  { target *-*-* } 63 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 66 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 67 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 68 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 69 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 70 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 66 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 67 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 68 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 69 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 70 } */
 
 
 /* Bitfield parameter in stack.  */
@@ -42,11 +42,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} "" { target *-*-* } 76 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} "" { target *-*-* } 77 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 80 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 81 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 82 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 83 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 84 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 80 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 81 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 82 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 83 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 84 } */
 
 /* Bitfield call argument in stack.  */
 /* { dg-note {parameter passing for argument of type 'struct S1' changed in GCC 9.1} ""  { target *-*-* } 87 } */
@@ -54,11 +54,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} ""  { target *-*-* } 89 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} ""  { target *-*-* } 90 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 93 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 94 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 95 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 96 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 97 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 93 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 94 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 95 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 96 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 97 } */
 
 
 /* Bitfield parameter in stdarg.  */
@@ -67,11 +67,11 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} "" { target *-*-* } 103 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} "" { target *-*-* } 104 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 107 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 108 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 109 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 110 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 111 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 107 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 108 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 109 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 110 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 111 } */
 
 /* Bitfield call argument in stdarg.  */
 /* { dg-note {parameter passing for argument of type 'struct S1' changed in GCC 9.1} ""  { target *-*-* } 114 } */
@@ -79,8 +79,8 @@ 
 /* { dg-note {parameter passing for argument of type 'struct S4' changed in GCC 9.1} ""  { target *-*-* } 116 } */
 /* { dg-note {parameter passing for argument of type 'struct S8' changed in GCC 9.1} ""  { target *-*-* } 117 } */
 
-/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 9.1} "" { target *-*-* } 120 } */
-/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 9.1} "" { target *-*-* } 121 } */
-/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 9.1} "" { target *-*-* } 122 } */ 
-/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 9.1} "" { target *-*-* } 123 } */
-/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 9.1} "" { target *-*-* } 124 } */
+/* { dg-note {parameter passing for argument of type 'struct Sp' changed in GCC 13.1} "" { target *-*-* } 120 } */
+/* { dg-note {parameter passing for argument of type 'struct S1p' changed in GCC 13.1} "" { target *-*-* } 121 } */
+/* { dg-note {parameter passing for argument of type 'struct S2p' changed in GCC 13.1} "" { target *-*-* } 122 } */ 
+/* { dg-note {parameter passing for argument of type 'struct S4p' changed in GCC 13.1} "" { target *-*-* } 123 } */
+/* { dg-note {parameter passing for argument of type 'struct S8p' changed in GCC 13.1} "" { target *-*-* } 124 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/pr105549.c b/gcc/testsuite/gcc.target/aarch64/pr105549.c
new file mode 100644
index 00000000000..55a91ed6bc4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr105549.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* { dg-options "-save-temps" } */
+
+enum e { E1 };
+typedef enum e e __attribute__((aligned(16)));
+union u {
+    __attribute__((aligned(2), packed)) e a : 1;
+    int x[4];
+};
+union u g(int a, union u u2) { return u2; }
+
+/* { dg-final { scan-assembler "stp\tx1, x2, \\\[sp, 8\\\]" } } */