diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index 5217dbdb2ac..6ebeee75d0a 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -716,6 +716,7 @@ static GTY(()) struct aarch64_simd_type_info aarch64_simd_types [] = {
 };
 #undef ENTRY
 
+static machine_mode aarch64_simd_tuple_modes[ARM_NEON_H_TYPES_LAST][3];
 static GTY(()) tree aarch64_simd_tuple_types[ARM_NEON_H_TYPES_LAST][3];
 
 static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE;
@@ -844,7 +845,7 @@ aarch64_lookup_simd_builtin_type (machine_mode mode,
 	return aarch64_simd_types[i].itype;
       if (aarch64_simd_tuple_types[i][0] != NULL_TREE)
 	for (int j = 0; j < 3; j++)
-	  if (TYPE_MODE (aarch64_simd_tuple_types[i][j]) == mode
+	  if (aarch64_simd_tuple_modes[i][j] == mode
 	      && aarch64_simd_types[i].q == q)
 	    return aarch64_simd_tuple_types[i][j];
     }
@@ -1297,8 +1298,10 @@ register_tuple_type (unsigned int num_vectors, unsigned int type_index)
     }
 
   unsigned int alignment
-	= (known_eq (GET_MODE_SIZE (type->mode), 16) ? 128 : 64);
-  gcc_assert (TYPE_MODE_RAW (array_type) == TYPE_MODE (array_type)
+    = known_eq (GET_MODE_SIZE (type->mode), 16) ? 128 : 64;
+  machine_mode tuple_mode = TYPE_MODE_RAW (array_type);
+  gcc_assert (VECTOR_MODE_P (tuple_mode)
+	      && TYPE_MODE (array_type) == tuple_mode
 	      && TYPE_ALIGN (array_type) == alignment);
 
   tree field = build_decl (input_location, FIELD_DECL,
@@ -1309,14 +1312,13 @@ register_tuple_type (unsigned int num_vectors, unsigned int type_index)
 						  make_array_slice (&field,
 								    1));
   gcc_assert (TYPE_MODE_RAW (t) == TYPE_MODE (t)
-	      && TYPE_ALIGN (t) == alignment);
-
-  if (num_vectors == 2)
-    aarch64_simd_tuple_types[type_index][0] = t;
-  else if (num_vectors == 3)
-    aarch64_simd_tuple_types[type_index][1] = t;
-  else if (num_vectors == 4)
-    aarch64_simd_tuple_types[type_index][2] = t;
+	      && (flag_pack_struct
+		  || maximum_field_alignment
+		  || (TYPE_MODE_RAW (t) == tuple_mode
+		      && TYPE_ALIGN (t) == alignment)));
+
+  aarch64_simd_tuple_modes[type_index][num_vectors - 2] = tuple_mode;
+  aarch64_simd_tuple_types[type_index][num_vectors - 2] = t;
 }
 
 static bool
@@ -1325,10 +1327,31 @@ aarch64_scalar_builtin_type_p (aarch64_simd_type t)
   return (t == Poly8_t || t == Poly16_t || t == Poly64_t || t == Poly128_t);
 }
 
+/* Enable AARCH64_FL_* flags EXTRA_FLAGS on top of the base Advanced SIMD
+   set.  */
+aarch64_simd_switcher::aarch64_simd_switcher (unsigned int extra_flags)
+  : m_old_isa_flags (aarch64_isa_flags),
+    m_old_general_regs_only (TARGET_GENERAL_REGS_ONLY)
+{
+  /* Changing the ISA flags should be enough here.  We shouldn't need to
+     pay the compile-time cost of a full target switch.  */
+  aarch64_isa_flags = AARCH64_FL_FP | AARCH64_FL_SIMD | extra_flags;
+  global_options.x_target_flags &= ~MASK_GENERAL_REGS_ONLY;
+}
+
+aarch64_simd_switcher::~aarch64_simd_switcher ()
+{
+  if (m_old_general_regs_only)
+    global_options.x_target_flags |= MASK_GENERAL_REGS_ONLY;
+  aarch64_isa_flags = m_old_isa_flags;
+}
+
 /* Implement #pragma GCC aarch64 "arm_neon.h".  */
 void
 handle_arm_neon_h (void)
 {
+  aarch64_simd_switcher simd;
+
   /* Register the AdvSIMD vector tuple types.  */
   for (unsigned int i = 0; i < ARM_NEON_H_TYPES_LAST; i++)
     for (unsigned int count = 2; count <= 4; ++count)
@@ -1703,8 +1726,10 @@ aarch64_general_init_builtins (void)
 
   aarch64_init_bf16_types ();
 
-  if (TARGET_SIMD)
+  {
+    aarch64_simd_switcher simd;
     aarch64_init_simd_builtins ();
+  }
 
   aarch64_init_crc32_builtins ();
   aarch64_init_builtin_rsqrt ();
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 46bade28ed6..c6f13ee836c 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -746,6 +746,19 @@ const unsigned int AARCH64_BUILTIN_SHIFT = 1;
 /* Mask that selects the aarch64_builtin_class part of a function code.  */
 const unsigned int AARCH64_BUILTIN_CLASS = (1 << AARCH64_BUILTIN_SHIFT) - 1;
 
+/* RAII class for enabling enough features to define built-in types
+   and implement the arm_neon.h pragma.  */
+class aarch64_simd_switcher
+{
+public:
+  aarch64_simd_switcher (unsigned int extra_flags = 0);
+  ~aarch64_simd_switcher ();
+
+private:
+  unsigned long m_old_isa_flags;
+  bool m_old_general_regs_only;
+};
+
 void aarch64_post_cfi_startproc (void);
 poly_int64 aarch64_initial_elimination_offset (unsigned, unsigned);
 int aarch64_get_condition_code (rtx);
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc
index 5d1348afa88..9d78b270e47 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
@@ -871,20 +871,14 @@ registered_function_hasher::equal (value_type value, const compare_type &key)
 }
 
 sve_switcher::sve_switcher ()
-  : m_old_isa_flags (aarch64_isa_flags)
+  : aarch64_simd_switcher (AARCH64_FL_F16 | AARCH64_FL_SVE)
 {
   /* Changing the ISA flags and have_regs_of_mode should be enough here.
      We shouldn't need to pay the compile-time cost of a full target
      switch.  */
-  aarch64_isa_flags = (AARCH64_FL_FP | AARCH64_FL_SIMD | AARCH64_FL_F16
-		       | AARCH64_FL_SVE);
-
   m_old_maximum_field_alignment = maximum_field_alignment;
   maximum_field_alignment = 0;
 
-  m_old_general_regs_only = TARGET_GENERAL_REGS_ONLY;
-  global_options.x_target_flags &= ~MASK_GENERAL_REGS_ONLY;
-
   memcpy (m_old_have_regs_of_mode, have_regs_of_mode,
 	  sizeof (have_regs_of_mode));
   for (int i = 0; i < NUM_MACHINE_MODES; ++i)
@@ -896,9 +890,6 @@ sve_switcher::~sve_switcher ()
 {
   memcpy (have_regs_of_mode, m_old_have_regs_of_mode,
 	  sizeof (have_regs_of_mode));
-  if (m_old_general_regs_only)
-    global_options.x_target_flags |= MASK_GENERAL_REGS_ONLY;
-  aarch64_isa_flags = m_old_isa_flags;
   maximum_field_alignment = m_old_maximum_field_alignment;
 }
 
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.h b/gcc/config/aarch64/aarch64-sve-builtins.h
index 48cae9a97a4..24594d58497 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.h
+++ b/gcc/config/aarch64/aarch64-sve-builtins.h
@@ -651,16 +651,14 @@ public:
 
 /* RAII class for enabling enough SVE features to define the built-in
    types and implement the arm_sve.h pragma.  */
-class sve_switcher
+class sve_switcher : public aarch64_simd_switcher
 {
 public:
   sve_switcher ();
   ~sve_switcher ();
 
 private:
-  unsigned long m_old_isa_flags;
   unsigned int m_old_maximum_field_alignment;
-  bool m_old_general_regs_only;
   bool m_old_have_regs_of_mode[MAX_MACHINE_MODE];
 };
 
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-1.C b/gcc/testsuite/g++.target/aarch64/pr103147-1.C
new file mode 100644
index 00000000000..4264c17f89a
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-1.C
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct" } */
+
+#include <arm_neon.h>
+
+static_assert(alignof(int32x2_t) == 8, "int32x2_t alignment");
+static_assert(alignof(int32x4_t) == 16, "int32x4_t alignment");
+static_assert(alignof(int32x2x2_t) == 1, "int32x2x2_t alignment");
+static_assert(alignof(int32x4x2_t) == 1, "int32x4x2_t alignment");
+static_assert(alignof(int32x2x3_t) == 1, "int32x2x3_t alignment");
+static_assert(alignof(int32x4x3_t) == 1, "int32x4x3_t alignment");
+static_assert(alignof(int32x2x4_t) == 1, "int32x2x4_t alignment");
+static_assert(alignof(int32x4x4_t) == 1, "int32x4x4_t alignment");
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-10.C b/gcc/testsuite/g++.target/aarch64/pr103147-10.C
new file mode 100644
index 00000000000..914fdf9c692
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-10.C
@@ -0,0 +1,88 @@
+/* { dg-options "-O2 -fpack-struct -mstrict-align" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#include <arm_neon.h>
+
+extern "C" {
+
+/*
+** ld2:
+**	...
+**	ld2	.*
+**	...
+** (
+**	strb	.*
+** |
+**	bl	memcpy
+** )
+**	...
+*/
+void
+ld2 (int32x4x2_t *a, int32_t *b)
+{
+  *a = vld2q_s32 (b);
+}
+
+/*
+** ld3:
+**	...
+**	ld3	.*
+**	...
+** (
+**	strb	.*
+** |
+**	bl	memcpy
+** )
+**	...
+*/
+void
+ld3 (int32x4x3_t *a, int32_t *b)
+{
+  *a = vld3q_s32 (b);
+}
+
+/*
+** ld4:
+**	...
+**	ld4	.*
+**	...
+** (
+**	strb	.*
+** |
+**	bl	memcpy
+** )
+**	...
+*/
+void
+ld4 (int32x4x4_t *a, int32_t *b)
+{
+  *a = vld4q_s32 (b);
+}
+
+/*
+** ret:
+**	...
+**	ldp	q0, q1, \[x0\]
+**	ldr	q2, \[x0, #?32\]
+**	...
+*/
+int32x4x3_t
+ret (int32x4_t *ptr)
+{
+  return (int32x4x3_t) { ptr[0], ptr[1], ptr[2] };
+}
+
+/*
+** arg:
+**	...
+**	stp	d0, d1, \[x0\]
+**	...
+*/
+void
+arg (int32x2x2_t arg, int32x2_t *ptr)
+{
+  ptr[0] = arg.val[0];
+  ptr[1] = arg.val[1];
+}
+
+}
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-2.C b/gcc/testsuite/g++.target/aarch64/pr103147-2.C
new file mode 100644
index 00000000000..565f2d237b3
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-2.C
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=1" } */
+
+#include <arm_neon.h>
+
+static_assert(alignof(int32x2_t) == 8, "int32x2_t alignment");
+static_assert(alignof(int32x4_t) == 16, "int32x4_t alignment");
+static_assert(alignof(int32x2x2_t) == 1, "int32x2x2_t alignment");
+static_assert(alignof(int32x4x2_t) == 1, "int32x4x2_t alignment");
+static_assert(alignof(int32x2x3_t) == 1, "int32x2x3_t alignment");
+static_assert(alignof(int32x4x3_t) == 1, "int32x4x3_t alignment");
+static_assert(alignof(int32x2x4_t) == 1, "int32x2x4_t alignment");
+static_assert(alignof(int32x4x4_t) == 1, "int32x4x4_t alignment");
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-3.C b/gcc/testsuite/g++.target/aarch64/pr103147-3.C
new file mode 100644
index 00000000000..579ca3770d8
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-3.C
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=2" } */
+
+#include <arm_neon.h>
+
+static_assert(alignof(int32x2_t) == 8, "int32x2_t alignment");
+static_assert(alignof(int32x4_t) == 16, "int32x4_t alignment");
+static_assert(alignof(int32x2x2_t) == 2, "int32x2x2_t alignment");
+static_assert(alignof(int32x4x2_t) == 2, "int32x4x2_t alignment");
+static_assert(alignof(int32x2x3_t) == 2, "int32x2x3_t alignment");
+static_assert(alignof(int32x4x3_t) == 2, "int32x4x3_t alignment");
+static_assert(alignof(int32x2x4_t) == 2, "int32x2x4_t alignment");
+static_assert(alignof(int32x4x4_t) == 2, "int32x4x4_t alignment");
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-4.C b/gcc/testsuite/g++.target/aarch64/pr103147-4.C
new file mode 100644
index 00000000000..752a47cd061
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-4.C
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=8" } */
+
+#include <arm_neon.h>
+
+static_assert(alignof(int32x2_t) == 8, "int32x2_t alignment");
+static_assert(alignof(int32x4_t) == 16, "int32x4_t alignment");
+static_assert(alignof(int32x2x2_t) == 8, "int32x2x2_t alignment");
+static_assert(alignof(int32x4x2_t) == 8, "int32x4x2_t alignment");
+static_assert(alignof(int32x2x3_t) == 8, "int32x2x3_t alignment");
+static_assert(alignof(int32x4x3_t) == 8, "int32x4x3_t alignment");
+static_assert(alignof(int32x2x4_t) == 8, "int32x2x4_t alignment");
+static_assert(alignof(int32x4x4_t) == 8, "int32x4x4_t alignment");
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-5.C b/gcc/testsuite/g++.target/aarch64/pr103147-5.C
new file mode 100644
index 00000000000..fbcdfd45e9e
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-5.C
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=16" } */
+
+#include <arm_neon.h>
+
+static_assert(alignof(int32x2_t) == 8, "int32x2_t alignment");
+static_assert(alignof(int32x4_t) == 16, "int32x4_t alignment");
+static_assert(alignof(int32x2x2_t) == 8, "int32x2x2_t alignment");
+static_assert(alignof(int32x4x2_t) == 16, "int32x4x2_t alignment");
+static_assert(alignof(int32x2x3_t) == 8, "int32x2x3_t alignment");
+static_assert(alignof(int32x4x3_t) == 16, "int32x4x3_t alignment");
+static_assert(alignof(int32x2x4_t) == 8, "int32x2x4_t alignment");
+static_assert(alignof(int32x4x4_t) == 16, "int32x4x4_t alignment");
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-6.C b/gcc/testsuite/g++.target/aarch64/pr103147-6.C
new file mode 100644
index 00000000000..15a606f976c
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-6.C
@@ -0,0 +1,3 @@
+/* { dg-options "-mgeneral-regs-only" } */
+
+#include <arm_neon.h>
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-7.C b/gcc/testsuite/g++.target/aarch64/pr103147-7.C
new file mode 100644
index 00000000000..40a7e4d6ffc
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-7.C
@@ -0,0 +1,3 @@
+/* { dg-options "-fpack-struct" } */
+
+#pragma GCC aarch64 "arm_neon.h"
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-8.C b/gcc/testsuite/g++.target/aarch64/pr103147-8.C
new file mode 100644
index 00000000000..65459945c70
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-8.C
@@ -0,0 +1,3 @@
+/* { dg-options "-mgeneral-regs-only" } */
+
+#pragma GCC aarch64 "arm_neon.h"
diff --git a/gcc/testsuite/g++.target/aarch64/pr103147-9.C b/gcc/testsuite/g++.target/aarch64/pr103147-9.C
new file mode 100644
index 00000000000..2d60c7dda60
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr103147-9.C
@@ -0,0 +1,10 @@
+/* { dg-options "-mgeneral-regs-only" } */
+/* { dg-excess-errors "arm_neon.h" } */
+
+#include <arm_neon.h>
+
+int32x4x4_t
+test (int32_t *ptr) /* { dg-error "-mgeneral-regs-only" } */
+{
+  return vld4q_s32 (ptr);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-1.c b/gcc/testsuite/gcc.target/aarch64/pr103147-1.c
new file mode 100644
index 00000000000..7b1f6414099
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-1.c
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct" } */
+
+#include <arm_neon.h>
+
+int assert1[__alignof__(int32x2_t) == 8 ? 1 : -1];
+int assert2[__alignof__(int32x4_t) == 16 ? 1 : -1];
+int assert3[__alignof__(int32x2x2_t) == 1 ? 1 : -1];
+int assert4[__alignof__(int32x4x2_t) == 1 ? 1 : -1];
+int assert5[__alignof__(int32x2x3_t) == 1 ? 1 : -1];
+int assert6[__alignof__(int32x4x3_t) == 1 ? 1 : -1];
+int assert7[__alignof__(int32x2x4_t) == 1 ? 1 : -1];
+int assert8[__alignof__(int32x4x4_t) == 1 ? 1 : -1];
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-10.c b/gcc/testsuite/gcc.target/aarch64/pr103147-10.c
new file mode 100644
index 00000000000..b2c34e4155d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-10.c
@@ -0,0 +1,84 @@
+/* { dg-options "-O2 -fpack-struct -mstrict-align" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#include <arm_neon.h>
+
+/*
+** ld2:
+**	...
+**	ld2	.*
+**	...
+** (
+**	strb	.*
+** |
+**	bl	memcpy
+** )
+**	...
+*/
+void
+ld2 (int32x4x2_t *a, int32_t *b)
+{
+  *a = vld2q_s32 (b);
+}
+
+/*
+** ld3:
+**	...
+**	ld3	.*
+**	...
+** (
+**	strb	.*
+** |
+**	bl	memcpy
+** )
+**	...
+*/
+void
+ld3 (int32x4x3_t *a, int32_t *b)
+{
+  *a = vld3q_s32 (b);
+}
+
+/*
+** ld4:
+**	...
+**	ld4	.*
+**	...
+** (
+**	strb	.*
+** |
+**	bl	memcpy
+** )
+**	...
+*/
+void
+ld4 (int32x4x4_t *a, int32_t *b)
+{
+  *a = vld4q_s32 (b);
+}
+
+/*
+** ret:
+**	...
+**	ldp	q0, q1, \[x0\]
+**	ldr	q2, \[x0, #?32\]
+**	...
+*/
+int32x4x3_t
+ret (int32x4_t *ptr)
+{
+  return (int32x4x3_t) { ptr[0], ptr[1], ptr[2] };
+}
+
+/*
+** arg:
+**	...
+**	stp	d0, d1, \[x0\]
+**	...
+*/
+void
+arg (int32x2x2_t arg, int32x2_t *ptr)
+{
+  ptr[0] = arg.val[0];
+  ptr[1] = arg.val[1];
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-2.c b/gcc/testsuite/gcc.target/aarch64/pr103147-2.c
new file mode 100644
index 00000000000..a6775f3e399
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-2.c
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=1" } */
+
+#include <arm_neon.h>
+
+int assert1[__alignof__(int32x2_t) == 8 ? 1 : -1];
+int assert2[__alignof__(int32x4_t) == 16 ? 1 : -1];
+int assert3[__alignof__(int32x2x2_t) == 1 ? 1 : -1];
+int assert4[__alignof__(int32x4x2_t) == 1 ? 1 : -1];
+int assert5[__alignof__(int32x2x3_t) == 1 ? 1 : -1];
+int assert6[__alignof__(int32x4x3_t) == 1 ? 1 : -1];
+int assert7[__alignof__(int32x2x4_t) == 1 ? 1 : -1];
+int assert8[__alignof__(int32x4x4_t) == 1 ? 1 : -1];
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-3.c b/gcc/testsuite/gcc.target/aarch64/pr103147-3.c
new file mode 100644
index 00000000000..ff76e25dc55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-3.c
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=2" } */
+
+#include <arm_neon.h>
+
+int assert1[__alignof__(int32x2_t) == 8 ? 1 : -1];
+int assert2[__alignof__(int32x4_t) == 16 ? 1 : -1];
+int assert3[__alignof__(int32x2x2_t) == 2 ? 1 : -1];
+int assert4[__alignof__(int32x4x2_t) == 2 ? 1 : -1];
+int assert5[__alignof__(int32x2x3_t) == 2 ? 1 : -1];
+int assert6[__alignof__(int32x4x3_t) == 2 ? 1 : -1];
+int assert7[__alignof__(int32x2x4_t) == 2 ? 1 : -1];
+int assert8[__alignof__(int32x4x4_t) == 2 ? 1 : -1];
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-4.c b/gcc/testsuite/gcc.target/aarch64/pr103147-4.c
new file mode 100644
index 00000000000..93331cf8c0a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-4.c
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=8" } */
+
+#include <arm_neon.h>
+
+int assert1[__alignof__(int32x2_t) == 8 ? 1 : -1];
+int assert2[__alignof__(int32x4_t) == 16 ? 1 : -1];
+int assert3[__alignof__(int32x2x2_t) == 8 ? 1 : -1];
+int assert4[__alignof__(int32x4x2_t) == 8 ? 1 : -1];
+int assert5[__alignof__(int32x2x3_t) == 8 ? 1 : -1];
+int assert6[__alignof__(int32x4x3_t) == 8 ? 1 : -1];
+int assert7[__alignof__(int32x2x4_t) == 8 ? 1 : -1];
+int assert8[__alignof__(int32x4x4_t) == 8 ? 1 : -1];
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-5.c b/gcc/testsuite/gcc.target/aarch64/pr103147-5.c
new file mode 100644
index 00000000000..a534bcb7c3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-5.c
@@ -0,0 +1,12 @@
+/* { dg-options "-fpack-struct=16" } */
+
+#include <arm_neon.h>
+
+int assert1[__alignof__(int32x2_t) == 8 ? 1 : -1];
+int assert2[__alignof__(int32x4_t) == 16 ? 1 : -1];
+int assert3[__alignof__(int32x2x2_t) == 8 ? 1 : -1];
+int assert4[__alignof__(int32x4x2_t) == 16 ? 1 : -1];
+int assert5[__alignof__(int32x2x3_t) == 8 ? 1 : -1];
+int assert6[__alignof__(int32x4x3_t) == 16 ? 1 : -1];
+int assert7[__alignof__(int32x2x4_t) == 8 ? 1 : -1];
+int assert8[__alignof__(int32x4x4_t) == 16 ? 1 : -1];
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-6.c b/gcc/testsuite/gcc.target/aarch64/pr103147-6.c
new file mode 100644
index 00000000000..15a606f976c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-6.c
@@ -0,0 +1,3 @@
+/* { dg-options "-mgeneral-regs-only" } */
+
+#include <arm_neon.h>
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-7.c b/gcc/testsuite/gcc.target/aarch64/pr103147-7.c
new file mode 100644
index 00000000000..40a7e4d6ffc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-7.c
@@ -0,0 +1,3 @@
+/* { dg-options "-fpack-struct" } */
+
+#pragma GCC aarch64 "arm_neon.h"
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-8.c b/gcc/testsuite/gcc.target/aarch64/pr103147-8.c
new file mode 100644
index 00000000000..65459945c70
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-8.c
@@ -0,0 +1,3 @@
+/* { dg-options "-mgeneral-regs-only" } */
+
+#pragma GCC aarch64 "arm_neon.h"
diff --git a/gcc/testsuite/gcc.target/aarch64/pr103147-9.c b/gcc/testsuite/gcc.target/aarch64/pr103147-9.c
new file mode 100644
index 00000000000..2d60c7dda60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr103147-9.c
@@ -0,0 +1,10 @@
+/* { dg-options "-mgeneral-regs-only" } */
+/* { dg-excess-errors "arm_neon.h" } */
+
+#include <arm_neon.h>
+
+int32x4x4_t
+test (int32_t *ptr) /* { dg-error "-mgeneral-regs-only" } */
+{
+  return vld4q_s32 (ptr);
+}
