From 56fe3ca30e1343e4f232ca539726506440e23dd3 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 29 Apr 2020 10:56:49 +0100 Subject: [PATCH] aarch64: 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. As things stood, we'd get two sets of -Wpsabi warnings, one when trying to decide whether something was an SVE function, and another when actually processing the function definition or function call. The patch therefore makes aapcs_vfp_sub_candidate honour the CUMULATIVE_ARGS "silent_p" flag where applicable. This doesn't stop all duplicate warnings for parameters, and I suspect we'll get duplicate warnings for return values too, but it should be better than nothing. 2020-04-29 Richard Sandiford gcc/ * config/aarch64/aarch64.c (aarch64_function_arg_alignment): Add a comment explaining why we consider even zero-sized fields. (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. (aarch64_vfp_is_call_or_return_candidate): Add a parameter to say whether diagnostics should be suppressed. Update the calls to aapcs_vfp_sub_candidate and report a -Wpsabi warning for the [[no_unique_address]] case. (aarch64_return_in_msb): Update call accordingly, never silencing diagnostics. (aarch64_function_value): Likewise. (aarch64_return_in_memory_1): Likewise. (aarch64_init_cumulative_args): Likewise. (aarch64_gimplify_va_arg_expr): Likewise. (aarch64_pass_by_reference_1): Take a CUMULATIVE_ARGS pointer and use it to decide whether arch64_vfp_is_call_or_return_candidate should be silent. (aarch64_pass_by_reference): Update calls accordingly. (aarch64_vfp_is_call_candidate): Use the CUMULATIVE_ARGS argument to decide whether arch64_vfp_is_call_or_return_candidate should be silent. gcc/testsuite/ * g++.target/aarch64/no_unique_address_1.C: New test. * g++.target/aarch64/no_unique_address_2.C: Likewise. --- gcc/ChangeLog | 30 +++ gcc/config/aarch64/aarch64.c | 159 +++++++++----- gcc/testsuite/ChangeLog | 5 + .../g++.target/aarch64/no_unique_address_1.C | 206 ++++++++++++++++++ .../g++.target/aarch64/no_unique_address_2.C | 206 ++++++++++++++++++ 5 files changed, 553 insertions(+), 53 deletions(-) create mode 100644 gcc/testsuite/g++.target/aarch64/no_unique_address_1.C create mode 100644 gcc/testsuite/g++.target/aarch64/no_unique_address_2.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 93d509710b7..3a352f8bbd3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2020-04-29 Richard Sandiford + + * config/aarch64/aarch64.c (aarch64_function_arg_alignment): Add a + comment explaining why we consider even zero-sized fields. + (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. + (aarch64_vfp_is_call_or_return_candidate): Add a parameter to say + whether diagnostics should be suppressed. Update the calls to + aapcs_vfp_sub_candidate and report a -Wpsabi warning for the + [[no_unique_address]] case. + (aarch64_return_in_msb): Update call accordingly, never silencing + diagnostics. + (aarch64_function_value): Likewise. + (aarch64_return_in_memory_1): Likewise. + (aarch64_init_cumulative_args): Likewise. + (aarch64_gimplify_va_arg_expr): Likewise. + (aarch64_pass_by_reference_1): Take a CUMULATIVE_ARGS pointer and + use it to decide whether arch64_vfp_is_call_or_return_candidate + should be silent. + (aarch64_pass_by_reference): Update calls accordingly. + (aarch64_vfp_is_call_candidate): Use the CUMULATIVE_ARGS argument + to decide whether arch64_vfp_is_call_or_return_candidate should be + silent. + 2020-04-29 Haijian Zhang PR target/94820 diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 5316350a9da..e996fd12042 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -286,7 +286,7 @@ static bool aarch64_return_in_memory_1 (const_tree); static bool aarch64_vfp_is_call_or_return_candidate (machine_mode, const_tree, machine_mode *, int *, - bool *); + bool *, bool); static void aarch64_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED; static void aarch64_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED; static void aarch64_override_options_after_change (void); @@ -5369,7 +5369,8 @@ aarch64_function_ok_for_sibcall (tree, tree exp) passed in SVE registers. */ static bool -aarch64_pass_by_reference_1 (const function_arg_info &arg) +aarch64_pass_by_reference_1 (CUMULATIVE_ARGS *pcum, + const function_arg_info &arg) { HOST_WIDE_INT size; machine_mode dummymode; @@ -5393,8 +5394,8 @@ aarch64_pass_by_reference_1 (const function_arg_info &arg) /* Can this be a candidate to be passed in fp/simd register(s)? */ if (aarch64_vfp_is_call_or_return_candidate (arg.mode, arg.type, - &dummymode, &nregs, - NULL)) + &dummymode, &nregs, NULL, + !pcum || pcum->silent_p)) return false; /* Arguments which are variable sized or larger than 2 registers are @@ -5412,7 +5413,7 @@ aarch64_pass_by_reference (cumulative_args_t pcum_v, CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); if (!arg.type) - return aarch64_pass_by_reference_1 (arg); + return aarch64_pass_by_reference_1 (pcum, arg); pure_scalable_type_info pst_info; switch (pst_info.analyze (arg.type)) @@ -5431,12 +5432,12 @@ aarch64_pass_by_reference (cumulative_args_t pcum_v, || pcum->aapcs_nprn + pst_info.num_pr () > NUM_PR_ARG_REGS); case pure_scalable_type_info::DOESNT_MATTER: - gcc_assert (aarch64_pass_by_reference_1 (arg)); + gcc_assert (aarch64_pass_by_reference_1 (pcum, arg)); return true; case pure_scalable_type_info::NO_ABI_IDENTITY: case pure_scalable_type_info::ISNT_PST: - return aarch64_pass_by_reference_1 (arg); + return aarch64_pass_by_reference_1 (pcum, arg); } gcc_unreachable (); } @@ -5464,7 +5465,8 @@ aarch64_return_in_msb (const_tree valtype) is always passed/returned in the least significant bits of fp/simd register(s). */ if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (valtype), valtype, - &dummy_mode, &dummy_int, NULL)) + &dummy_mode, &dummy_int, NULL, + false)) return false; /* Likewise pure scalable types for SVE vector and predicate registers. */ @@ -5511,8 +5513,8 @@ aarch64_function_value (const_tree type, const_tree func, int count; machine_mode ag_mode; - if (aarch64_vfp_is_call_or_return_candidate (mode, type, - &ag_mode, &count, NULL)) + if (aarch64_vfp_is_call_or_return_candidate (mode, type, &ag_mode, &count, + NULL, false)) { gcc_assert (!sve_p); if (!aarch64_composite_type_p (type, mode)) @@ -5599,11 +5601,8 @@ aarch64_return_in_memory_1 (const_tree type) /* Simple scalar types always returned in registers. */ return false; - if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (type), - type, - &ag_mode, - &count, - NULL)) + if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (type), type, + &ag_mode, &count, NULL, false)) return false; /* Types larger than 2 registers returned in memory. */ @@ -5646,11 +5645,9 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, const_tree type, int *nregs) { CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); - return aarch64_vfp_is_call_or_return_candidate (mode, - type, + return aarch64_vfp_is_call_or_return_candidate (mode, type, &pcum->aapcs_vfp_rmode, - nregs, - NULL); + nregs, NULL, pcum->silent_p); } /* Given MODE and TYPE of a function argument, return the alignment in @@ -5684,6 +5681,19 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type, for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL) { + /* Note that we explicitly consider zero-sized fields here, + even though they don't map to AAPCS64 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". */ alignment = std::max (alignment, DECL_ALIGN (field)); if (DECL_BIT_FIELD_TYPE (field)) bitfield_alignment @@ -5976,7 +5986,7 @@ aarch64_init_cumulative_args (CUMULATIVE_ARGS *pcum, machine_mode mode ATTRIBUTE_UNUSED; /* To pass pointer as argument. */ int nregs ATTRIBUTE_UNUSED; /* Likewise. */ if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (type), type, - &mode, &nregs, NULL)) + &mode, &nregs, NULL, false)) aarch64_err_no_fpadvsimd (TYPE_MODE (type)); } @@ -16152,11 +16162,8 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, dw_align = false; adjust = 0; - if (aarch64_vfp_is_call_or_return_candidate (mode, - type, - &ag_mode, - &nregs, - &is_ha)) + if (aarch64_vfp_is_call_or_return_candidate (mode, type, &ag_mode, &nregs, + &is_ha, false)) { /* No frontends can create types with variable-sized modes, so we shouldn't be asked to pass or return them. */ @@ -16521,23 +16528,42 @@ aarch64_member_type_forces_blk (const_tree field_or_array, machine_mode mode) return default_member_type_forces_blk (field_or_array, mode); } +/* 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 PR94383 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; @@ -16614,7 +16640,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) @@ -16652,18 +16678,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 do contain padding, they have zero size and thus don't - contain any padding. */ - 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; @@ -16697,7 +16735,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; @@ -16796,14 +16834,20 @@ aarch64_composite_type_p (const_tree type, Upon successful return, *COUNT returns the number of needed registers, *BASE_MODE returns the mode of the individual register and when IS_HAF is not NULL, *IS_HA indicates whether or not the argument is a homogeneous - floating-point aggregate or a homogeneous short-vector aggregate. */ + floating-point aggregate or a homogeneous short-vector aggregate. + + SILENT_P is true if the function should refrain from reporting any + diagnostics. This should only be used if the caller is certain that + any ABI decisions would eventually come through this function with + SILENT_P set to false. */ static bool aarch64_vfp_is_call_or_return_candidate (machine_mode mode, const_tree type, machine_mode *base_mode, int *count, - bool *is_ha) + bool *is_ha, + bool silent_p) { if (is_ha != NULL) *is_ha = false; @@ -16824,24 +16868,33 @@ aarch64_vfp_is_call_or_return_candidate (machine_mode mode, } else if (type && composite_p) { - 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 <= HA_MAX_NUM_FLDS) { static unsigned last_reported_type_uid; unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type)); int alt; - if (warn_psabi - && avoided + if (!silent_p + && warn_psabi + && 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)); } if (is_ha != NULL) *is_ha = true; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c304ddcf2c7..701af0b1e72 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-04-29 Richard Sandiford + + * g++.target/aarch64/no_unique_address_1.C: New test. + * g++.target/aarch64/no_unique_address_2.C: Likewise. + 2020-04-29 Richard Sandiford * g++.target/arm/mve.exp: Restore the original dg-do-what-default diff --git a/gcc/testsuite/g++.target/aarch64/no_unique_address_1.C b/gcc/testsuite/g++.target/aarch64/no_unique_address_1.C new file mode 100644 index 00000000000..5fc68ea5d6d --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/no_unique_address_1.C @@ -0,0 +1,206 @@ +/* { dg-options "-std=c++11 -O -foptimize-sibling-calls -fpeephole2" } */ +/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */ + +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: +** ldr s0, \[x0\] +** b .* +*/ +T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of type 'A'} } */ + +/* +** _Z8caller_bR1B: +** ldr s0, \[x0\] +** b .* +*/ +T (B, b); int caller_b (B &b) { return callee_b (b); } /* { dg-bogus {argument of type 'B'} } */ + +/* +** _Z8caller_cR1C: +** ldr s0, \[x0\] +** b .* +*/ +T (C, c); int caller_c (C &c) { return callee_c (c); } /* { dg-bogus {argument of type 'C'} } */ + +/* +** _Z8caller_dR1D: +** ldr x0, \[x0\] +** b .* +*/ +T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument of type 'D'} } */ + +/* +** _Z8caller_eR1E: +** ldr x0, \[x0\] +** b .* +*/ +T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of type 'E'} } */ + +/* +** _Z8caller_fR1F: +** ldr s0, \[x0\] +** 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: +** ldr s0, \[x0\] +** 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: +** ldr x0, \[x0\] +** b .* +*/ +T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument of type 'H'} } */ + +/* +** _Z8caller_iR1I: +** ldr x0, \[x0\] +** b .* +*/ +T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type 'I'} } */ + +/* +** _Z8caller_jR1J: +** ldp s0, s1, \[x0\] +** 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: +** ldp s0, s1, \[x0\] +** 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: { target aarch64_little_endian } +** ( +** ldr w1, \[x0, 8\] +** ldr x0, \[x0\] +** | +** mov (x[0-9]+), x0 +** ldr x0, \[x0\] +** ldr w1, \[\1, 8\] +** ) +** b .* +*/ +T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of type 'L'} } */ + +/* +** _Z8caller_mR1M: { target aarch64_little_endian } +** ( +** ldr w1, \[x0, 8\] +** ldr x0, \[x0\] +** | +** mov (x[0-9]+), x0 +** ldr x0, \[x0\] +** ldr w1, \[\1, 8\] +** ) +** b .* +*/ +T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus {argument of type 'M'} } */ + +/* +** _Z8caller_nR1N: +** ldp s0, s1, \[x0\] +** b .* +*/ +T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument of type 'N'} } */ + +/* +** _Z8caller_oR1O: +** ldp s0, s1, \[x0\] +** b .* +*/ +T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument of type 'O'} } */ + +/* +** _Z8caller_pR1P: +** ldp s0, s1, \[x0\] +** ldp s2, s3, \[x0, 8\] +** b .* +*/ +T (P, p); int caller_p (P &p) { return callee_p (p); } /* { dg-bogus {argument of type 'P'} } */ + +/* +** _Z8caller_qR1Q: { target aarch64_little_endian } +** ldr w0, \[x0\] +** b .* +*/ +T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument of type 'Q'} } */ + +/* +** _Z8caller_rR1R: { target aarch64_little_endian } +** ldr w0, \[x0\] +** b .* +*/ +T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of type 'R'} } */ + +/* +** _Z8caller_sR1S: +** ldr s0, \[x0\] +** b .* +*/ +T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus {argument of type 'S'} } */ + +/* +** _Z8caller_tR1T: +** ldr s0, \[x0\] +** 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: +** ldp s0, s1, \[x0\] +** 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/aarch64/no_unique_address_2.C b/gcc/testsuite/g++.target/aarch64/no_unique_address_2.C new file mode 100644 index 00000000000..f0717133ccd --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/no_unique_address_2.C @@ -0,0 +1,206 @@ +/* { dg-options "-std=c++17 -O -foptimize-sibling-calls -fpeephole2" } */ +/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */ + +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: +** ldr s0, \[x0\] +** b .* +*/ +T (A, a); int caller_a (A &a) { return callee_a (a); } /* { dg-bogus {argument of type 'A'} } */ + +/* +** _Z8caller_bR1B: +** ldr s0, \[x0\] +** 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: +** ldr s0, \[x0\] +** 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: +** ldr x0, \[x0\] +** b .* +*/ +T (D, d); int caller_d (D &d) { return callee_d (d); } /* { dg-bogus {argument of type 'D'} } */ + +/* +** _Z8caller_eR1E: +** ldr x0, \[x0\] +** b .* +*/ +T (E, e); int caller_e (E &e) { return callee_e (e); } /* { dg-bogus {argument of type 'E'} } */ + +/* +** _Z8caller_fR1F: +** ldr s0, \[x0\] +** 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: +** ldr s0, \[x0\] +** 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: +** ldr x0, \[x0\] +** b .* +*/ +T (H, h); int caller_h (H &h) { return callee_h (h); } /* { dg-bogus {argument of type 'H'} } */ + +/* +** _Z8caller_iR1I: +** ldr x0, \[x0\] +** b .* +*/ +T (I, i); int caller_i (I &i) { return callee_i (i); } /* { dg-bogus {argument of type 'I'} } */ + +/* +** _Z8caller_jR1J: +** ldp s0, s1, \[x0\] +** 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: +** ldp s0, s1, \[x0\] +** 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: { target aarch64_little_endian } +** ( +** ldr w1, \[x0, 8\] +** ldr x0, \[x0\] +** | +** mov (x[0-9]+), x0 +** ldr x0, \[x0\] +** ldr w1, \[\1, 8\] +** ) +** b .* +*/ +T (L, l); int caller_l (L &l) { return callee_l (l); } /* { dg-bogus {argument of type 'L'} } */ + +/* +** _Z8caller_mR1M: { target aarch64_little_endian } +** ( +** ldr w1, \[x0, 8\] +** ldr x0, \[x0\] +** | +** mov (x[0-9]+), x0 +** ldr x0, \[x0\] +** ldr w1, \[\1, 8\] +** ) +** b .* +*/ +T (M, m); int caller_m (M &m) { return callee_m (m); } /* { dg-bogus {argument of type 'M'} } */ + +/* +** _Z8caller_nR1N: +** ldp s0, s1, \[x0\] +** b .* +*/ +T (N, n); int caller_n (N &n) { return callee_n (n); } /* { dg-bogus {argument of type 'N'} } */ + +/* +** _Z8caller_oR1O: +** ldp s0, s1, \[x0\] +** b .* +*/ +T (O, o); int caller_o (O &o) { return callee_o (o); } /* { dg-bogus {argument of type 'O'} } */ + +/* +** _Z8caller_pR1P: +** ldp s0, s1, \[x0\] +** ldp s2, s3, \[x0, 8\] +** 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: { target aarch64_little_endian } +** ldr w0, \[x0\] +** b .* +*/ +T (Q, q); int caller_q (Q &q) { return callee_q (q); } /* { dg-bogus {argument of type 'Q'} } */ + +/* +** _Z8caller_rR1R: { target aarch64_little_endian } +** ldr w0, \[x0\] +** b .* +*/ +T (R, r); int caller_r (R &r) { return callee_r (r); } /* { dg-bogus {argument of type 'R'} } */ + +/* +** _Z8caller_sR1S: +** ldr s0, \[x0\] +** b .* +*/ +T (Salias, s); int caller_s (Salias &s) { return callee_s (s); } /* { dg-bogus {argument of type 'S'} } */ + +/* +** _Z8caller_tR1T: +** ldr s0, \[x0\] +** 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: +** ldp s0, s1, \[x0\] +** 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 } */ -- 2.30.2