arm: Fix parameter passing for [[no_unique_address]]
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 29 Apr 2020 10:51:03 +0000 (11:51 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Wed, 29 Apr 2020 10:51:03 +0000 (11:51 +0100)
This patch makes the ABI code ignore zero-sized [[no_unique_address]]
fields when deciding whether something is a HFA or HVA.

For the tests, I wanted an -march setting that was stable enough
to use check-function-bodies and also wanted to force -mfloat-abi=hard.
I couldn't see any existing way of doing both together, since most
arm-related effective-target keywords are agnostic about the choice
between -mfloat-abi=softfp and -mfloat-abi=hard.  I therefore added
a new effective-target keyword for this combination.

I used the arm_arch_* framework for the effective-target rather than
writing a new set of custom Tcl routines.  This has the nice property
of separating the "compile and assemble" cases from the "link and run"
cases.  I only need compilation to work for the new tests, so requiring
linking to work would be an unnecessary restriction.

However, including an ABI requirement is arguably stretching what the
list was originally intended to handle.  The name arm_arch_v8a_hard
doesn't fit very naturally with some of the NEON-based tests.
On the other hand, the naming convention isn't entirely consistent,
so any choice would be inconsistent with something.

2020-04-29  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* doc/sourcebuild.texi (arm_arch_v8a_hard_ok): Document new
effective-target keyword.
(arm_arch_v8a_hard_multilib): Likewise.
(arm_arch_v8a_hard): Document new dg-add-options keyword.
* config/arm/arm.c (arm_return_in_memory): Note that the APCS
code is deprecated and has not been updated to handle
DECL_FIELD_ABI_IGNORED.
(WARN_PSABI_EMPTY_CXX17_BASE): New constant.
(WARN_PSABI_NO_UNIQUE_ADDRESS): Likewise.
(aapcs_vfp_sub_candidate): Replace the boolean pointer parameter
avoid_cxx17_empty_base with a pointer to a bitmask.  Ignore fields
whose DECL_FIELD_ABI_IGNORED bit is set when determining whether
something actually is a HFA or HVA.  Record whether we see a
[[no_unique_address]] field that previous GCCs would not have
ignored in this way.
(aapcs_vfp_is_call_or_return_candidate): Update the calls to
aapcs_vfp_sub_candidate and report a -Wpsabi warning for the
[[no_unique_address]] case.  Use TYPE_MAIN_VARIANT in the
diagnostic messages.
(arm_needs_doubleword_align): Add a comment explaining why we
consider even zero-sized fields.

gcc/testsuite/
* lib/target-supports.exp: Add v8a_hard to the list of arm_arch_*
targets.
* g++.target/arm/no_unique_address_1.C: New test.
* g++.target/arm/no_unique_address_2.C: Likewise.

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/doc/sourcebuild.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.target/arm/no_unique_address_1.C [new file with mode: 0644]
gcc/testsuite/g++.target/arm/no_unique_address_2.C [new file with mode: 0644]
gcc/testsuite/lib/target-supports.exp

index 4b4eeef..7a04f1f 100644 (file)
@@ -1,3 +1,27 @@
+2020-04-29  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * doc/sourcebuild.texi (arm_arch_v8a_hard_ok): Document new
+       effective-target keyword.
+       (arm_arch_v8a_hard_multilib): Likewise.
+       (arm_arch_v8a_hard): Document new dg-add-options keyword.
+       * config/arm/arm.c (arm_return_in_memory): Note that the APCS
+       code is deprecated and has not been updated to handle
+       DECL_FIELD_ABI_IGNORED.
+       (WARN_PSABI_EMPTY_CXX17_BASE): New constant.
+       (WARN_PSABI_NO_UNIQUE_ADDRESS): Likewise.
+       (aapcs_vfp_sub_candidate): Replace the boolean pointer parameter
+       avoid_cxx17_empty_base with a pointer to a bitmask.  Ignore fields
+       whose DECL_FIELD_ABI_IGNORED bit is set when determining whether
+       something actually is a HFA or HVA.  Record whether we see a
+       [[no_unique_address]] field that previous GCCs would not have
+       ignored in this way.
+       (aapcs_vfp_is_call_or_return_candidate): Update the calls to
+       aapcs_vfp_sub_candidate and report a -Wpsabi warning for the
+       [[no_unique_address]] case.  Use TYPE_MAIN_VARIANT in the
+       diagnostic messages.
+       (arm_needs_doubleword_align): Add a comment explaining why we
+       consider even zero-sized fields.
+
 2020-04-29  Richard Biener  <rguenther@suse.de>
            Li Zekun  <lizekun1@huawei.com>
 
index 30a2a3a..dcaae7b 100644 (file)
@@ -5963,6 +5963,8 @@ arm_return_in_memory (const_tree type, const_tree fntype)
 
       /* Find the first field, ignoring non FIELD_DECL things which will
         have been created by C++.  */
+      /* NOTE: This code is deprecated and has not been updated to handle
+        DECL_FIELD_ABI_IGNORED.  */
       for (field = TYPE_FIELDS (type);
           field && TREE_CODE (field) != FIELD_DECL;
           field = DECL_CHAIN (field))
@@ -6135,23 +6137,42 @@ aapcs_vfp_cum_init (CUMULATIVE_ARGS *pcum  ATTRIBUTE_UNUSED,
   pcum->aapcs_vfp_reg_alloc = 0;
 }
 
+/* Bitmasks that indicate whether earlier versions of GCC would have
+   taken a different path through the ABI logic.  This should result in
+   a -Wpsabi warning if the earlier path led to a different ABI decision.
+
+   WARN_PSABI_EMPTY_CXX17_BASE
+      Indicates that the type includes an artificial empty C++17 base field
+      that, prior to GCC 10.1, would prevent the type from being treated as
+      a HFA or HVA.  See PR94711 for details.
+
+   WARN_PSABI_NO_UNIQUE_ADDRESS
+      Indicates that the type includes an empty [[no_unique_address]] field
+      that, prior to GCC 10.1, would prevent the type from being treated as
+      a HFA or HVA.  */
+const unsigned int WARN_PSABI_EMPTY_CXX17_BASE = 1U << 0;
+const unsigned int WARN_PSABI_NO_UNIQUE_ADDRESS = 1U << 1;
+
 /* Walk down the type tree of TYPE counting consecutive base elements.
    If *MODEP is VOIDmode, then set it to the first valid floating point
    type.  If a non-floating point type is found, or if a floating point
    type that doesn't match a non-VOIDmode *MODEP is found, then return -1,
    otherwise return the count in the sub-tree.
 
-   The AVOID_CXX17_EMPTY_BASE argument is to allow the caller to check whether
-   this function has changed its behavior after the fix for PR94384 -- this fix
-   is to avoid artificial fields in empty base classes.
-   When called with this argument as a NULL pointer this function does not
-   avoid the artificial fields -- this is useful to check whether the function
-   returns something different after the fix.
-   When called pointing at a value, this function avoids such artificial fields
-   and sets the value to TRUE when one of these fields has been set.  */
+   The WARN_PSABI_FLAGS argument allows the caller to check whether this
+   function has changed its behavior relative to earlier versions of GCC.
+   Normally the argument should be nonnull and point to a zero-initialized
+   variable.  The function then records whether the ABI decision might
+   be affected by a known fix to the ABI logic, setting the associated
+   WARN_PSABI_* bits if so.
+
+   When the argument is instead a null pointer, the function tries to
+   simulate the behavior of GCC before all such ABI fixes were made.
+   This is useful to check whether the function returns something
+   different after the ABI fixes.  */
 static int
 aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep,
-                        bool *avoid_cxx17_empty_base)
+                        unsigned int *warn_psabi_flags)
 {
   machine_mode mode;
   HOST_WIDE_INT size;
@@ -6224,7 +6245,7 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep,
          return -1;
 
        count = aapcs_vfp_sub_candidate (TREE_TYPE (type), modep,
-                                        avoid_cxx17_empty_base);
+                                        warn_psabi_flags);
        if (count == -1
            || !index
            || !TYPE_MAX_VALUE (index)
@@ -6262,20 +6283,30 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep,
            if (TREE_CODE (field) != FIELD_DECL)
              continue;
 
-           /* Ignore C++17 empty base fields, while their type indicates they
-              contain padding, this is only sometimes contributed to the derived
-              class.
-              When the padding is contributed to the derived class that's
-              caught by the general test for padding below.  */
-           if (cxx17_empty_base_field_p (field)
-               && avoid_cxx17_empty_base)
+           if (DECL_FIELD_ABI_IGNORED (field))
              {
-               *avoid_cxx17_empty_base = true;
-               continue;
+               /* See whether this is something that earlier versions of
+                  GCC failed to ignore.  */
+               unsigned int flag;
+               if (lookup_attribute ("no_unique_address",
+                                     DECL_ATTRIBUTES (field)))
+                 flag = WARN_PSABI_NO_UNIQUE_ADDRESS;
+               else if (cxx17_empty_base_field_p (field))
+                 flag = WARN_PSABI_EMPTY_CXX17_BASE;
+               else
+                 /* No compatibility problem.  */
+                 continue;
+
+               /* Simulate the old behavior when WARN_PSABI_FLAGS is null.  */
+               if (warn_psabi_flags)
+                 {
+                   *warn_psabi_flags |= flag;
+                   continue;
+                 }
              }
 
            sub_count = aapcs_vfp_sub_candidate (TREE_TYPE (field), modep,
-                                                avoid_cxx17_empty_base);
+                                                warn_psabi_flags);
            if (sub_count < 0)
              return -1;
            count += sub_count;
@@ -6309,7 +6340,7 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep,
              continue;
 
            sub_count = aapcs_vfp_sub_candidate (TREE_TYPE (field), modep,
-                                                avoid_cxx17_empty_base);
+                                                warn_psabi_flags);
            if (sub_count < 0)
              return -1;
            count = count > sub_count ? count : sub_count;
@@ -6371,24 +6402,32 @@ aapcs_vfp_is_call_or_return_candidate (enum arm_pcs pcs_variant,
      out from the mode.  */
   if (type)
     {
-      bool avoided = false;
-      int ag_count = aapcs_vfp_sub_candidate (type, &new_mode, &avoided);
+      unsigned int warn_psabi_flags = 0;
+      int ag_count = aapcs_vfp_sub_candidate (type, &new_mode,
+                                             &warn_psabi_flags);
       if (ag_count > 0 && ag_count <= 4)
        {
          static unsigned last_reported_type_uid;
          unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
          int alt;
          if (warn_psabi
-             && avoided
+             && warn_psabi_flags
              && uid != last_reported_type_uid
              && ((alt = aapcs_vfp_sub_candidate (type, &new_mode, NULL))
                  != ag_count))
            {
              gcc_assert (alt == -1);
              last_reported_type_uid = uid;
-             inform (input_location, "parameter passing for argument of type "
-                     "%qT when C++17 is enabled changed to match C++14 "
-                     "in GCC 10.1", type);
+             /* Use TYPE_MAIN_VARIANT to strip any redundant const
+                qualification.  */
+             if (warn_psabi_flags & WARN_PSABI_NO_UNIQUE_ADDRESS)
+               inform (input_location, "parameter passing for argument of "
+                       "type %qT with %<[[no_unique_address]]%> members "
+                       "changed in GCC 10.1", TYPE_MAIN_VARIANT (type));
+             else if (warn_psabi_flags & WARN_PSABI_EMPTY_CXX17_BASE)
+               inform (input_location, "parameter passing for argument of "
+                       "type %qT when C++17 is enabled changed to match "
+                       "C++14 in GCC 10.1", TYPE_MAIN_VARIANT (type));
            }
          *count = ag_count;
        }
@@ -6933,7 +6972,20 @@ arm_needs_doubleword_align (machine_mode mode, const_tree type)
 
   int ret = 0;
   int ret2 = 0;
-  /* Record/aggregate types: Use greatest member alignment of any member.  */
+  /* Record/aggregate types: Use greatest member alignment of any member.
+
+     Note that we explicitly consider zero-sized fields here, even though
+     they don't map to AAPCS machine types.  For example, in:
+
+        struct __attribute__((aligned(8))) empty {};
+
+        struct s {
+          [[no_unique_address]] empty e;
+          int x;
+        };
+
+     "s" contains only one Fundamental Data Type (the int field)
+     but gains 8-byte alignment and size thanks to "e".  */
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     if (DECL_ALIGN (field) > PARM_BOUNDARY)
       {
index b696120..d8da77d 100644 (file)
@@ -1829,6 +1829,16 @@ Some multilibs may be incompatible with these options.
 ARM target supports @code{-mfpu=vfp3 -mfloat-abi=softfp}.
 Some multilibs may be incompatible with these options.
 
+@item arm_arch_v8a_hard_ok
+The compiler is targeting @code{arm*-*-*} and can compile and assemble code
+using the options @code{-march=armv8-a -mfpu=neon-fp-armv8 -mfloat-abi=hard}.
+This is not enough to guarantee that linking works.
+
+@item arm_arch_v8a_hard_multilib
+The compiler is targeting @code{arm*-*-*} and can build programs using
+the options @code{-march=armv8-a -mfpu=neon-fp-armv8 -mfloat-abi=hard}.
+The target can also run the resulting binaries.
+
 @item arm_v8_vfp_ok
 ARM target supports @code{-mfpu=fp-armv8 -mfloat-abi=softfp}.
 Some multilibs may be incompatible with these options.
@@ -2586,6 +2596,11 @@ the @ref{arm_neon_fp16_ok,,arm_neon_fp16_ok effective target keyword}.
 arm vfp3 floating point support; see
 the @ref{arm_vfp3_ok,,arm_vfp3_ok effective target keyword}.
 
+@item arm_arch_v8a_hard
+Add options for ARMv8-A and the hard-float variant of the AAPCS,
+if this is supported by the compiler; see the
+@ref{arm_arch_v8a_hard_ok,,arm_arch_v8a_hard_ok} effective target keyword.
+
 @item arm_v8_1a_neon
 Add options for ARMv8.1-A with Adv.SIMD support, if this is supported
 by the target; see the @ref{arm_v8_1a_neon_ok,,arm_v8_1a_neon_ok}
index 3810ea3..b4d1ee2 100644 (file)
@@ -1,3 +1,10 @@
+2020-04-29  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * lib/target-supports.exp: Add v8a_hard to the list of arm_arch_*
+       targets.
+       * g++.target/arm/no_unique_address_1.C: New test.
+       * g++.target/arm/no_unique_address_2.C: Likewise.
+
 2020-04-29  Richard Biener  <rguenther@suse.de>
            Li Zekun  <lizekun1@huawei.com>
 
diff --git a/gcc/testsuite/g++.target/arm/no_unique_address_1.C b/gcc/testsuite/g++.target/arm/no_unique_address_1.C
new file mode 100644 (file)
index 0000000..038aa00
--- /dev/null
@@ -0,0 +1,201 @@
+/* { dg-require-effective-target arm_arch_v8a_hard_ok } */
+/* { dg-options "-std=c++11 -O -foptimize-sibling-calls" } */
+/* { dg-add-options arm_arch_v8a_hard } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct W : public X { X q; };
+
+struct A { float a; };
+
+struct B : public X { float a; };
+struct C : public Y { float a; };
+struct D : public Z { float a; };
+struct E : public W { float a; };
+
+struct F { [[no_unique_address]] X x; float a; };
+struct G { [[no_unique_address]] Y y; float a; };
+struct H { [[no_unique_address]] Z z; float a; };
+struct I { [[no_unique_address]] W w; float a; };
+
+struct J { float a; [[no_unique_address]] X x; float b; };
+struct K { float a; [[no_unique_address]] Y y; float b; };
+struct L { float a; [[no_unique_address]] Z z; float b; };
+struct M { float a; [[no_unique_address]] W w; float b; };
+
+struct N : public A { float b; };
+struct O { [[no_unique_address]] A a; float b; };
+
+struct P : public Y { int : 0; float a, b, c, d; };
+
+union Q { X x; float a; };
+union R { [[no_unique_address]] X x; float a; };
+
+union S { A a; float b; };
+union T { F f; float b; };
+union U { N n; O o; };
+
+typedef S Salias;
+typedef T Talias;
+typedef U Ualias;
+
+#define T(S, s) extern int callee_##s (S)
+
+/*
+** _Z8caller_aR1A:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of type 'A'} } */
+
+/*
+** _Z8caller_bR1B:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (B, b); int caller_b (B &b) { return callee_b (b); } /* { dg-bogus {argument of type 'B'} } */
+
+/*
+** _Z8caller_cR1C:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (C, c); int caller_c (C &c) { return callee_c (c); } /* { dg-bogus {argument of type 'C'} } */
+
+/*
+** _Z8caller_dR1D:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument of type 'D'} } */
+
+/*
+** _Z8caller_eR1E:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of type 'E'} } */
+
+/*
+** _Z8caller_fR1F:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (F, f); int caller_f (F &f) { return callee_f (f); } /* { dg-message {parameter passing for argument of type 'F' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_gR1G:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (G, g); int caller_g (G &g) { return callee_g (g); } /* { dg-message {parameter passing for argument of type 'G' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_hR1H:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument of type 'H'} } */
+
+/*
+** _Z8caller_iR1I:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type 'I'} } */
+
+/*
+** _Z8caller_jR1J:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (J, j); int caller_j (J &j) { return callee_j (j); } /* { dg-message {parameter passing for argument of type 'J' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_kR1K:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (K, k); int caller_k (K &k) { return callee_k (k); } /* { dg-message {parameter passing for argument of type 'K' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_lR1L:
+**     ldm     r0, {r0, r1, r2}
+**     b       .*
+*/
+T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of type 'L'} } */
+
+/*
+** _Z8caller_mR1M:
+**     ldm     r0, {r0, r1, r2}
+**     b       .*
+*/
+T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus {argument of type 'M'} } */
+
+/*
+** _Z8caller_nR1N:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument of type 'N'} } */
+
+/*
+** _Z8caller_oR1O:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument of type 'O'} } */
+
+/*
+** _Z8caller_pR1P:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     vldr.32 s2, \[r0, #8\]
+**     vldr.32 s3, \[r0, #12\]
+**     b       .*
+*/
+T (P, p); int caller_p (P &p) { return callee_p (p); } /* { dg-bogus {argument of type 'P'} } */
+
+/*
+** _Z8caller_qR1Q:
+**     ldr     r0, \[r0\]
+**     b       .*
+*/
+T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument of type 'Q'} } */
+
+/*
+** _Z8caller_rR1R:
+**     ldr     r0, \[r0\]
+**     b       .*
+*/
+T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of type 'R'} } */
+
+/*
+** _Z8caller_sR1S:
+**     vldr.32 s0, \[r0\]      @ int
+**     b       .*
+*/
+T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus {argument of type 'S'} } */
+
+/*
+** _Z8caller_tR1T:
+**     vldr.32 s0, \[r0\]      @ int
+**     b       .*
+*/
+T (Talias, t); int caller_t (Talias &t) { return callee_t (t); } /* { dg-message {parameter passing for argument of type 'T' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_uR1U:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (Ualias, u); int caller_u (Ualias &u) { return callee_u (u); } /* { dg-bogus {argument of type 'U'} } */
+
+/* { dg-bogus {argument of type 'const} "should not be printed as const" { target *-*-*} 0 } */
diff --git a/gcc/testsuite/g++.target/arm/no_unique_address_2.C b/gcc/testsuite/g++.target/arm/no_unique_address_2.C
new file mode 100644 (file)
index 0000000..8be5de2
--- /dev/null
@@ -0,0 +1,201 @@
+/* { dg-require-effective-target arm_arch_v8a_hard_ok } */
+/* { dg-options "-std=c++17 -O -foptimize-sibling-calls" } */
+/* { dg-add-options arm_arch_v8a_hard } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct W : public X { X q; };
+
+struct A { float a; };
+
+struct B : public X { float a; };
+struct C : public Y { float a; };
+struct D : public Z { float a; };
+struct E : public W { float a; };
+
+struct F { [[no_unique_address]] X x; float a; };
+struct G { [[no_unique_address]] Y y; float a; };
+struct H { [[no_unique_address]] Z z; float a; };
+struct I { [[no_unique_address]] W w; float a; };
+
+struct J { float a; [[no_unique_address]] X x; float b; };
+struct K { float a; [[no_unique_address]] Y y; float b; };
+struct L { float a; [[no_unique_address]] Z z; float b; };
+struct M { float a; [[no_unique_address]] W w; float b; };
+
+struct N : public A { float b; };
+struct O { [[no_unique_address]] A a; float b; };
+
+struct P : public Y { int : 0; float a, b, c, d; };
+
+union Q { X x; float a; };
+union R { [[no_unique_address]] X x; float a; };
+
+union S { A a; float b; };
+union T { F f; float b; };
+union U { N n; O o; };
+
+typedef S Salias;
+typedef T Talias;
+typedef U Ualias;
+
+#define T(S, s) extern int callee_##s (S)
+
+/*
+** _Z8caller_aR1A:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of type 'A'} } */
+
+/*
+** _Z8caller_bR1B:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (B, b); int caller_b (B &b) { return callee_b (b); } /* { dg-message {parameter passing for argument of type 'B' when C\+\+17 is enabled changed to match C\+\+14 in GCC 10.1} } */
+
+/*
+** _Z8caller_cR1C:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (C, c); int caller_c (C &c) { return callee_c (c); } /* { dg-message {parameter passing for argument of type 'C' when C\+\+17 is enabled changed to match C\+\+14 in GCC 10.1} } */
+
+/*
+** _Z8caller_dR1D:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument of type 'D'} } */
+
+/*
+** _Z8caller_eR1E:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of type 'E'} } */
+
+/*
+** _Z8caller_fR1F:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (F, f); int caller_f (F &f) { return callee_f (f); } /* { dg-message {parameter passing for argument of type 'F' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_gR1G:
+**     vldr.32 s0, \[r0\]
+**     b       .*
+*/
+T (G, g); int caller_g (G &g) { return callee_g (g); } /* { dg-message {parameter passing for argument of type 'G' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_hR1H:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument of type 'H'} } */
+
+/*
+** _Z8caller_iR1I:
+**     ldm     r0, {r0, r1}
+**     b       .*
+*/
+T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type 'I'} } */
+
+/*
+** _Z8caller_jR1J:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (J, j); int caller_j (J &j) { return callee_j (j); } /* { dg-message {parameter passing for argument of type 'J' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_kR1K:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (K, k); int caller_k (K &k) { return callee_k (k); } /* { dg-message {parameter passing for argument of type 'K' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_lR1L:
+**     ldm     r0, {r0, r1, r2}
+**     b       .*
+*/
+T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of type 'L'} } */
+
+/*
+** _Z8caller_mR1M:
+**     ldm     r0, {r0, r1, r2}
+**     b       .*
+*/
+T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus {argument of type 'M'} } */
+
+/*
+** _Z8caller_nR1N:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument of type 'N'} } */
+
+/*
+** _Z8caller_oR1O:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument of type 'O'} } */
+
+/*
+** _Z8caller_pR1P:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     vldr.32 s2, \[r0, #8\]
+**     vldr.32 s3, \[r0, #12\]
+**     b       .*
+*/
+T (P, p); int caller_p (P &p) { return callee_p (p); } /* { dg-message {parameter passing for argument of type 'P' when C\+\+17 is enabled changed to match C\+\+14 in GCC 10.1} } */
+
+/*
+** _Z8caller_qR1Q:
+**     ldr     r0, \[r0\]
+**     b       .*
+*/
+T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument of type 'Q'} } */
+
+/*
+** _Z8caller_rR1R:
+**     ldr     r0, \[r0\]
+**     b       .*
+*/
+T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of type 'R'} } */
+
+/*
+** _Z8caller_sR1S:
+**     vldr.32 s0, \[r0\]      @ int
+**     b       .*
+*/
+T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus {argument of type 'S'} } */
+
+/*
+** _Z8caller_tR1T:
+**     vldr.32 s0, \[r0\]      @ int
+**     b       .*
+*/
+T (Talias, t); int caller_t (Talias &t) { return callee_t (t); } /* { dg-message {parameter passing for argument of type 'T' with '\[\[no_unique_address\]\]' members changed in GCC 10.1} } */
+
+/*
+** _Z8caller_uR1U:
+**     vldr.32 s0, \[r0\]
+**     vldr.32 s1, \[r0, #4\]
+**     b       .*
+*/
+T (Ualias, u); int caller_u (Ualias &u) { return callee_u (u); } /* { dg-bogus {argument of type 'U'} } */
+
+/* { dg-bogus {argument of type 'const} "should not be printed as const" { target *-*-*} 0 } */
index f416d5c..1376149 100644 (file)
@@ -4443,6 +4443,7 @@ foreach { armfunc armflag armdefs } {
        v7ve "-march=armv7ve -marm"
                "__ARM_ARCH_7A__ && __ARM_FEATURE_IDIV"
        v8a "-march=armv8-a" __ARM_ARCH_8A__
+       v8a_hard "-march=armv8-a -mfpu=neon-fp-armv8 -mfloat-abi=hard" __ARM_ARCH_8A__
        v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
        v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
        v8r "-march=armv8-r" __ARM_ARCH_8R__