[PATCH] arm: Fix parameter passing for [[no_unique_address]]

Kyrylo Tkachov Kyrylo.Tkachov@arm.com
Wed Apr 29 10:42:18 GMT 2020


Hi Richard,

> -----Original Message-----
> From: Richard Sandiford <richard.sandiford@arm.com>
> Sent: 29 April 2020 11:04
> To: gcc-patches@gcc.gnu.org
> Cc: nickc@redhat.com; Richard Earnshaw <Richard.Earnshaw@arm.com>;
> Ramana Radhakrishnan <Ramana.Radhakrishnan@arm.com>; Kyrylo
> Tkachov <Kyrylo.Tkachov@arm.com>
> Subject: [PATCH] arm: Fix parameter passing for [[no_unique_address]]
> 
> 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.
> 
> Like with the aarch64 patch, clang produces equivalent code for all
> tests except unions Q and R, which clang passes in s0 rather than r0.
> I think this is a clang bug, since the "x" field contains a single-byte
> FDT and so shouldn't be ignored.

Worth reporting it?

> 
> Tested on arm-linux-gnueabihf and armeb-eabi.  OK to install?

Ok.
Thanks,
Kyrill

> 
> Richard
> 
> 
> 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/config/arm/arm.c                          | 108 +++++++---
>  gcc/doc/sourcebuild.texi                      |  15 ++
>  .../g++.target/arm/no_unique_address_1.C      | 201 ++++++++++++++++++
>  .../g++.target/arm/no_unique_address_2.C      | 201 ++++++++++++++++++
>  gcc/testsuite/lib/target-supports.exp         |   1 +
>  5 files changed, 498 insertions(+), 28 deletions(-)
>  create mode 100644 gcc/testsuite/g++.target/arm/no_unique_address_1.C
>  create mode 100644 gcc/testsuite/g++.target/arm/no_unique_address_2.C
> 
> diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
> index b69612024be..d8da77d5ba4 100644
> --- a/gcc/doc/sourcebuild.texi
> +++ b/gcc/doc/sourcebuild.texi
> @@ -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}
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 30a2a3aeb0e..dcaae7bf7aa 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -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)
>        {
> diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-
> supports.exp
> index f416d5cafda..13761491e63 100644
> --- a/gcc/testsuite/lib/target-supports.exp
> +++ b/gcc/testsuite/lib/target-supports.exp
> @@ -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__
> 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
> index 00000000000..038aa00a499
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/arm/no_unique_address_1.C
> @@ -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
> index 00000000000..8be5de2539a
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/arm/no_unique_address_2.C
> @@ -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 } */


More information about the Gcc-patches mailing list