Hi!
Ok, I've tried:
struct X { };
struct Y { int : 0; };
struct Z { int : 0; Y y; };
struct U : public X { X q; };
struct A { float a, b, c, d; };
struct B : public X { float a, b, c, d; };
struct C : public Y { float a, b, c, d; };
struct D : public Z { float a, b, c, d; };
struct E : public U { float a, b, c, d; };
struct F { [[no_unique_address]] X x; float a, b, c, d; };
struct G { [[no_unique_address]] Y y; float a, b, c, d; };
struct H { [[no_unique_address]] Z z; float a, b, c, d; };
struct I { [[no_unique_address]] U u; float a, b, c, d; };
struct J { float a, b; [[no_unique_address]] X x; float c, d; };
struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
struct M { float a, b; [[no_unique_address]] U u; float c, d; };
#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s (s);
return 0; }
T (A, a)
T (B, b)
T (C, c)
T (D, d)
T (E, e)
T (F, f)
T (G, g)
T (H, h)
T (I, i)
T (J, j)
T (K, k)
T (L, l)
T (M, m)
testcase on powerpc64-linux. Results:
G++ 9 -std=c++14 A, B, C passed in fprs, the rest in gprs
G++ 9 -std=c++17 A passed in fprs, the rest in gprs
current trunk -std=c++14 & 17 A, B, C passed in fprs, the rest in gprs
patched trunk -std=c++14 & 17 A, B, C, F, G, J, K passed in fprs, the
rest in gprs
clang++ [*] -std=c++14 & 17 A, B, C, F, G, J, K passed in fprs, the rest in gprs
[*] clang version 11.0.0 (g...@github.com:llvm/llvm-project.git
5c352e69e76a26e4eda075e20aa6a9bb7686042c)
Is that what we want? I think it matches the stated intent of P0840R2 or
what Jason/Jonathan said, and doing something different like e.g. not
treating C, G and K as homogenous because of the int : 0 in empty bases
or in zero sized [[no_unique_address] fields would be quite hard to
implement (because for C++14 the FIELD_DECL just isn't there).
I've included the above testcase as g++.target/powerpc/ testcases.
2020-04-28 Jakub Jelinek <ja...@redhat.com>
PR target/94707
* calls.h (no_unique_address_empty_field_p): Declare.
* calls.c (no_unique_address_empty_field_p): New function.
* rs6000-call.c (rs6000_aggregate_candidate): Rename
cxx17_empty_base_seen to empty_base_seen, change type to int *,
adjust recursive calls, ignore also no_unique_address_empty_field_p
fields and propagate that fact to caller.
(rs6000_discover_homogeneous_aggregate): Adjust
rs6000_aggregate_candidate caller, emit different diagnostics
when c++17 empty base fields are present and when empty
[[no_unique_address]] fields are present.
* g++.target/powerpc/pr94707-1.C: New test.
* g++.target/powerpc/pr94707-2.C: New test.
* g++.target/powerpc/pr94707-3.C: New test.
* g++.target/powerpc/pr94707-4.C: New test.
--- gcc/calls.h.jj 2020-04-27 14:31:09.123020831 +0200
+++ gcc/calls.h 2020-04-28 12:38:35.292851412 +0200
@@ -136,5 +136,6 @@ extern void maybe_warn_nonstring_arg (tr
extern bool get_size_range (tree, tree[2], bool = false);
extern rtx rtx_for_static_chain (const_tree, bool);
extern bool cxx17_empty_base_field_p (const_tree);
+extern bool no_unique_address_empty_field_p (const_tree);
#endif // GCC_CALLS_H
--- gcc/calls.c.jj 2020-04-27 14:31:09.117020922 +0200
+++ gcc/calls.c 2020-04-28 12:39:11.936308866 +0200
@@ -6279,5 +6279,24 @@ cxx17_empty_base_field_p (const_tree fie
&& !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
}
+/* Return true if FIELD is a non-static data member with empty
+ type and [[no_unique_address]] attribute that should be
+ ignored for ABI calling convention decisions, in order to make
+ struct S {};
+ struct T : S { float x; };
+ and
+ struct T2 : { [[no_unique_address]] S s; float x; };
+ ABI compatible. */
+
+bool
+no_unique_address_empty_field_p (const_tree field)
+{
+ return (TREE_CODE (field) == FIELD_DECL
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+ && DECL_SIZE (field)
+ && integer_zerop (DECL_SIZE (field))
+ && lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field)));
+}
+
/* Tell the garbage collector about GTY markers in this source file. */
#include "gt-calls.h"
--- gcc/config/rs6000/rs6000-call.c.jj 2020-04-23 14:42:26.323839084 +0200
+++ gcc/config/rs6000/rs6000-call.c 2020-04-28 12:43:28.277513460 +0200
@@ -5529,7 +5529,7 @@ const struct altivec_builtin_types altiv
static int
rs6000_aggregate_candidate (const_tree type, machine_mode *modep,
- bool *cxx17_empty_base_seen)
+ int *empty_base_seen)
{
machine_mode mode;
HOST_WIDE_INT size;
@@ -5600,7 +5600,7 @@ rs6000_aggregate_candidate (const_tree t
return -1;
count = rs6000_aggregate_candidate (TREE_TYPE (type), modep,
- cxx17_empty_base_seen);
+ empty_base_seen);
if (count == -1
|| !index
|| !TYPE_MAX_VALUE (index)
@@ -5640,12 +5640,18 @@ rs6000_aggregate_candidate (const_tree t
if (cxx17_empty_base_field_p (field))
{
- *cxx17_empty_base_seen = true;
+ *empty_base_seen |= 1;
+ continue;
+ }
+
+ if (no_unique_address_empty_field_p (field))
+ {
+ *empty_base_seen |= 2;
continue;
}
sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
- cxx17_empty_base_seen);
+ empty_base_seen);
if (sub_count < 0)
return -1;
count += sub_count;
@@ -5679,7 +5685,7 @@ rs6000_aggregate_candidate (const_tree t
continue;
sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep,
- cxx17_empty_base_seen);
+ empty_base_seen);
if (sub_count < 0)
return -1;
count = count > sub_count ? count : sub_count;
@@ -5720,9 +5726,9 @@ rs6000_discover_homogeneous_aggregate (m
&& AGGREGATE_TYPE_P (type))
{
machine_mode field_mode = VOIDmode;
- bool cxx17_empty_base_seen = false;
+ int empty_base_seen = false;
int field_count = rs6000_aggregate_candidate (type, &field_mode,
- &cxx17_empty_base_seen);
+ &empty_base_seen);
if (field_count > 0)
{
@@ -5737,16 +5743,22 @@ rs6000_discover_homogeneous_aggregate (m
*elt_mode = field_mode;
if (n_elts)
*n_elts = field_count;
- if (cxx17_empty_base_seen && warn_psabi)
+ if (empty_base_seen && warn_psabi)
{
static unsigned last_reported_type_uid;
unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
if (uid != last_reported_type_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);
+ if (empty_base_seen & 1)
+ 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);
+ else
+ inform (input_location,
+ "parameter passing for argument of type %qT "
+ "with %<[[no_unique_address]]%> members "
+ "changed in GCC 10.1", type);
last_reported_type_uid = uid;
}
}
--- gcc/testsuite/g++.target/powerpc/pr94707-1.C.jj 2020-04-28
13:26:01.417418105 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-1.C 2020-04-28
13:25:19.555046878 +0200
@@ -0,0 +1,34 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s
(s); return 0; }
+// { dg-message "parameter passing for argument of type 'F' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-1 }
+// { dg-message "parameter passing for argument of type 'G' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-2 }
+// { dg-message "parameter passing for argument of type 'J' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-3 }
+// { dg-message "parameter passing for argument of type 'K' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-4 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-2.C.jj 2020-04-28
13:26:04.782367567 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-2.C 2020-04-28
13:25:29.240901395 +0200
@@ -0,0 +1,30 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++14" }
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s
(s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
--- gcc/testsuite/g++.target/powerpc/pr94707-3.C.jj 2020-04-28
13:26:07.485326967 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-3.C 2020-04-28
13:25:40.206736691 +0200
@@ -0,0 +1,36 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// { dg-final { scan-assembler-times {(?n)^\s+lfs\s+(?:%f)?4,} 7 } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s
(s); return 0; }
+// { dg-message "parameter passing for argument of type 'B' when C\\+\\+17 is enabled changed
to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-1 }
+// { dg-message "parameter passing for argument of type 'C' when C\\+\\+17 is enabled changed
to match C\\+\\+14 in GCC 10.1" "" { target *-*-* } .-2 }
+// { dg-message "parameter passing for argument of type 'F' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-3 }
+// { dg-message "parameter passing for argument of type 'G' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-4 }
+// { dg-message "parameter passing for argument of type 'J' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-5 }
+// { dg-message "parameter passing for argument of type 'K' with
'\\\[\\\[no_unique_address\\\]\\\]' members changed in GCC 10.1" "" { target *-*-* }
.-6 }
+T (A, a)
+T (B, b)
+T (C, c)
+T (F, f)
+T (G, g)
+T (J, j)
+T (K, k)
--- gcc/testsuite/g++.target/powerpc/pr94707-4.C.jj 2020-04-28
13:26:10.257285341 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-4.C 2020-04-28
13:25:56.925485580 +0200
@@ -0,0 +1,30 @@
+// PR target/94707
+// { dg-do compile { target powerpc_elfv2 } }
+// { dg-options "-O2 -std=c++17" }
+// { dg-final { scan-assembler-not {(?n)^\s+lfs\s+(?:%f)?4,} } }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { float a, b, c, d; };
+struct B : public X { float a, b, c, d; };
+struct C : public Y { float a, b, c, d; };
+struct D : public Z { float a, b, c, d; };
+struct E : public U { float a, b, c, d; };
+struct F { [[no_unique_address]] X x; float a, b, c, d; };
+struct G { [[no_unique_address]] Y y; float a, b, c, d; };
+struct H { [[no_unique_address]] Z z; float a, b, c, d; };
+struct I { [[no_unique_address]] U u; float a, b, c, d; };
+struct J { float a, b; [[no_unique_address]] X x; float c, d; };
+struct K { float a, b; [[no_unique_address]] Y y; float c, d; };
+struct L { float a, b; [[no_unique_address]] Z z; float c, d; };
+struct M { float a, b; [[no_unique_address]] U u; float c, d; };
+#define T(S, s) extern S s; extern void foo##s (S); int bar##s () { foo##s
(s); return 0; }
+// { dg-bogus "parameter passing for argument of type" }
+T (D, d)
+T (E, e)
+T (H, h)
+T (I, i)
+T (L, l)
+T (M, m)
Jakub