2020-04-28 Jakub Jelinek <ja...@redhat.com>
PR target/94707
* tree-core.h (tree_decl_common): Note decl_flag_0 used for
DECL_FIELD_ABI_IGNORED.
* tree.h (DECL_FIELD_ABI_IGNORED): Define.
* calls.h (cxx17_empty_base_field_p): Change into a temporary
macro, check DECL_FIELD_ABI_IGNORED flag with no "no_unique_address"
attribute.
* calls.c (cxx17_empty_base_field_p): Remove.
* tree-streamer-out.c (pack_ts_decl_common_value_fields): Handle
DECL_FIELD_ABI_IGNORED.
* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Likewise.
* lto-streamer-out.c (hash_tree): Likewise.
* config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Rename
cxx17_empty_base_seen to empty_base_seen, change type to int *,
adjust recursive calls, use DECL_FIELD_ABI_IGNORED instead of
cxx17_empty_base_field_p, if "no_unique_address" attribute is
present, propagate that to the caller too.
(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.
* config/rs6000/rs6000.c (rs6000_special_round_type_align,
darwin_rs6000_special_round_type_align): Skip DECL_FIELD_ABI_IGNORED
fields.
* class.c (build_base_field): Set DECL_FIELD_ABI_IGNORED on C++17 empty
base artificial FIELD_DECLs.
(layout_class_type): Set DECL_FIELD_ABI_IGNORED on empty class
field_poverlapping_p FIELD_DECLs.
* 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.
* g++.target/powerpc/pr94707-5.C: New test.
* g++.target/powerpc/pr94707-4.C: New test.
--- gcc/tree-core.h.jj 2020-04-08 18:15:36.936946772 +0200
+++ gcc/tree-core.h 2020-04-28 15:14:06.598814022 +0200
@@ -1709,7 +1709,8 @@ struct GTY(()) tree_decl_common {
unsigned lang_flag_8 : 1;
/* In VAR_DECL and PARM_DECL, this is DECL_REGISTER
- IN TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P. */
+ In TRANSLATION_UNIT_DECL, this is TRANSLATION_UNIT_WARN_EMPTY_P.
+ In FIELD_DECL, this is DECL_FIELD_ABI_IGNORED. */
unsigned decl_flag_0 : 1;
/* In FIELD_DECL, this is DECL_BIT_FIELD
In VAR_DECL and FUNCTION_DECL, this is DECL_EXTERNAL.
--- gcc/tree.h.jj 2020-04-08 18:15:36.939946727 +0200
+++ gcc/tree.h 2020-04-28 15:13:07.579695258 +0200
@@ -2750,6 +2750,13 @@ extern void decl_value_expr_insert (tree
/* In a FIELD_DECL, indicates this field should be bit-packed. */
#define DECL_PACKED(NODE) (FIELD_DECL_CHECK (NODE)->base.u.bits.packed_flag)
+/* In a FIELD_DECL, indicates this field should be ignored for ABI decisions
+ like passing/returning containing struct by value.
+ Set for C++17 empty base artificial FIELD_DECLs as well as
+ empty [[no_unique_address]] non-static data members. */
+#define DECL_FIELD_ABI_IGNORED(NODE) \
+ (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_0)
+
/* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
specially. */
#define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK
(NODE)->decl_common.decl_flag_1)
--- gcc/calls.h.jj 2020-04-27 14:31:09.123020831 +0200
+++ gcc/calls.h 2020-04-28 15:26:29.221724466 +0200
@@ -135,6 +135,9 @@ extern tree get_attr_nonstring_decl (tre
extern void maybe_warn_nonstring_arg (tree, tree);
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);
+/* FIXME: Remove after all backends are converted. */
+#define cxx17_empty_base_field_p(t) \
+ (DECL_FIELD_ABI_IGNORED (t) \
+ && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (t)))
#endif // GCC_CALLS_H
--- gcc/calls.c.jj 2020-04-27 14:31:09.117020922 +0200
+++ gcc/calls.c 2020-04-28 15:26:42.276529517 +0200
@@ -6261,23 +6261,5 @@ must_pass_va_arg_in_stack (tree type)
return targetm.calls.must_pass_in_stack (arg);
}
-/* Return true if FIELD is the C++17 empty base field that should
- be ignored for ABI calling convention decisions in order to
- maintain ABI compatibility between C++14 and earlier, which doesn't
- add this FIELD to classes with empty bases, and C++17 and later
- which does. */
-
-bool
-cxx17_empty_base_field_p (const_tree field)
-{
- return (TREE_CODE (field) == FIELD_DECL
- && DECL_ARTIFICIAL (field)
- && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
- && DECL_SIZE (field)
- && integer_zerop (DECL_SIZE (field))
- && TYPE_SIZE (TREE_TYPE (field))
- && !integer_zerop (TYPE_SIZE (TREE_TYPE (field))));
-}
-
/* Tell the garbage collector about GTY markers in this source file. */
#include "gt-calls.h"
--- gcc/tree-streamer-out.c.jj 2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-out.c 2020-04-28 15:24:40.062354539 +0200
@@ -217,6 +217,7 @@ pack_ts_decl_common_value_fields (struct
bp_pack_value (bp, DECL_PACKED (expr), 1);
bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
bp_pack_value (bp, DECL_PADDING_P (expr), 1);
+ bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1);
bp_pack_value (bp, expr->decl_common.off_align, 8);
}
--- gcc/tree-streamer-in.c.jj 2020-04-08 18:15:36.937946757 +0200
+++ gcc/tree-streamer-in.c 2020-04-28 15:24:22.511616625 +0200
@@ -256,6 +256,7 @@ unpack_ts_decl_common_value_fields (stru
DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_PADDING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
+ DECL_FIELD_ABI_IGNORED (expr) = (unsigned) bp_unpack_value (bp, 1);
expr->decl_common.off_align = bp_unpack_value (bp, 8);
}
--- gcc/lto-streamer-out.c.jj 2020-04-03 10:04:44.775971053 +0200
+++ gcc/lto-streamer-out.c 2020-04-28 15:23:51.361081794 +0200
@@ -1080,6 +1080,7 @@ hash_tree (struct streamer_tree_cache_d
hstate.add_flag (DECL_PACKED (t));
hstate.add_flag (DECL_NONADDRESSABLE_P (t));
hstate.add_flag (DECL_PADDING_P (t));
+ hstate.add_flag (DECL_FIELD_ABI_IGNORED (t));
hstate.add_int (DECL_OFFSET_ALIGN (t));
}
else if (code == VAR_DECL)
--- gcc/config/rs6000/rs6000-call.c.jj 2020-04-23 14:42:26.323839084 +0200
+++ gcc/config/rs6000/rs6000-call.c 2020-04-28 15:28:11.353199343 +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)
@@ -5638,14 +5638,18 @@ rs6000_aggregate_candidate (const_tree t
if (TREE_CODE (field) != FIELD_DECL)
continue;
- if (cxx17_empty_base_field_p (field))
+ if (DECL_FIELD_ABI_IGNORED (field))
{
- *cxx17_empty_base_seen = true;
+ if (lookup_attribute ("no_unique_address",
+ DECL_ATTRIBUTES (field)))
+ *empty_base_seen |= 2;
+ else
+ *empty_base_seen |= 1;
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 +5683,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 +5724,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 +5741,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/config/rs6000/rs6000.c.jj 2020-04-27 09:11:14.090608782 +0200
+++ gcc/config/rs6000/rs6000.c 2020-04-28 15:29:25.166097098 +0200
@@ -7204,7 +7204,9 @@ rs6000_special_round_type_align (tree ty
tree field = TYPE_FIELDS (type);
/* Skip all non field decls */
- while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+ while (field != NULL
+ && (TREE_CODE (field) != FIELD_DECL
+ || DECL_FIELD_ABI_IGNORED (field)))
field = DECL_CHAIN (field);
if (field != NULL && field != type)
@@ -7236,7 +7238,9 @@ darwin_rs6000_special_round_type_align (
do {
tree field = TYPE_FIELDS (type);
/* Skip all non field decls */
- while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+ while (field != NULL
+ && (TREE_CODE (field) != FIELD_DECL
+ || DECL_FIELD_ABI_IGNORED (field)))
field = DECL_CHAIN (field);
if (! field)
break;
--- gcc/cp/class.c.jj 2020-04-28 16:15:39.570540960 +0200
+++ gcc/cp/class.c 2020-04-28 16:35:18.423859735 +0200
@@ -4515,6 +4515,7 @@ build_base_field (record_layout_info rli
DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
+ DECL_FIELD_ABI_IGNORED (decl) = 1;
}
/* An empty virtual base causes a class to be non-empty
@@ -6522,7 +6523,10 @@ layout_class_type (tree t, tree *virtual
SET_DECL_MODE (field, TYPE_MODE (type));
}
else if (might_overlap && is_empty_class (type))
- layout_empty_base_or_field (rli, field, empty_base_offsets);
+ {
+ DECL_FIELD_ABI_IGNORED (field) = 1;
+ layout_empty_base_or_field (rli, field, empty_base_offsets);
+ }
else
layout_nonempty_base_or_field (rli, field, NULL_TREE,
empty_base_offsets);
--- 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)
--- gcc/testsuite/g++.target/powerpc/pr94707-5.C.jj 2020-04-28
16:33:53.431130852 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-5.C 2020-04-28
16:47:31.488901028 +0200
@@ -0,0 +1,35 @@
+// PR target/94707
+// { dg-do compile { target powerpc*-*-darwin* } }
+// { dg-require-effective-target ilp32 }
+// { dg-options "-std=c++14" }
+
+struct X { };
+struct Y { int : 0; };
+struct Z { int : 0; Y y; };
+struct U : public X { X q; };
+struct A { double a; };
+struct B : public X { double a; };
+struct C : public Y { double a; };
+struct D : public Z { double a; };
+struct E : public U { double a; };
+struct F { [[no_unique_address]] X x; double a; };
+struct G { [[no_unique_address]] Y y; double a; };
+struct H { [[no_unique_address]] Z z; double a; };
+struct I { [[no_unique_address]] U u; double a; };
+struct J { double a; [[no_unique_address]] X x; };
+struct K { double a; [[no_unique_address]] Y y; };
+struct L { double a; [[no_unique_address]] Z z; };
+struct M { double a; [[no_unique_address]] U u; };
+static_assert (__alignof__ (A) == 8, "");
+static_assert (__alignof__ (B) == 8, "");
+static_assert (__alignof__ (C) == 8, "");
+static_assert (__alignof__ (D) == 4, "");
+static_assert (__alignof__ (E) == 4, "");
+static_assert (__alignof__ (F) == 8, "");
+static_assert (__alignof__ (G) == 8, "");
+static_assert (__alignof__ (H) == 4, "");
+static_assert (__alignof__ (I) == 4, "");
+static_assert (__alignof__ (J) == 8, "");
+static_assert (__alignof__ (K) == 8, "");
+static_assert (__alignof__ (L) == 8, "");
+static_assert (__alignof__ (M) == 8, "");
--- gcc/testsuite/g++.target/powerpc/pr94707-6.C.jj 2020-04-28
16:33:53.431130852 +0200
+++ gcc/testsuite/g++.target/powerpc/pr94707-6.C 2020-04-28
16:47:54.056563731 +0200
@@ -0,0 +1,6 @@
+// PR target/94707
+// { dg-do compile { target powerpc*-*-darwin* } }
+// { dg-require-effective-target ilp32 }
+// { dg-options "-O2 -std=c++17" }
+
+#include "pr94707-5.C"
Jakub