From 2c814af65ef9f146519cba657890a4fd93c5be38 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 14 May 2020 12:20:32 +0100 Subject: [PATCH] aarch64: Fix arm_sve_vector_bits on typedefs [PR95105] MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Compiling this testcase with -march=armv8.2-a+sve -msve-vector-bits=512: ---------------------------------------------------------- typedef __SVFloat32_t foo; typedef foo bar __attribute__((arm_sve_vector_bits(512))); template struct s { T x; }; extern s a; bar &b = a.x; ---------------------------------------------------------- gave the bogus error: cannot bind non-const lvalue reference of type ‘bar&’ to an rvalue of type ‘bar’ The testcase works if the attribute is applied directly to __SVFloat32_t instead of via foo. This shows a more general problem with the way that we were handling the arm_sve_vector_bits attribute: we started by building a distinct copy of the type to which the attribute was applied, instead of starting with its main variant. This new type then became its own main variant, meaning that the relationship between types that have the attribute could be different from the relationship between types that don't have the attribute. This patch instead copies the main variant of the original type and then reapplies all the differences. 2020-05-14 Richard Sandiford gcc/ PR target/95105 * config/aarch64/aarch64-sve-builtins.cc (handle_arm_sve_vector_bits_attribute): Create a copy of the original type's TYPE_MAIN_VARIANT, then reapply all the differences between the original type and its main variant. gcc/testsuite/ PR target/95105 * gcc.target/aarch64/sve/acle/general/attributes_8.c: New test. * g++.target/aarch64/sve/acle/general-c++/attributes_1.C: Likewise. --- gcc/ChangeLog | 8 ++ gcc/config/aarch64/aarch64-sve-builtins.cc | 35 +++-- gcc/testsuite/ChangeLog | 6 + .../sve/acle/general-c++/attributes_1.C | 122 ++++++++++++++++++ .../aarch64/sve/acle/general/attributes_8.c | 101 +++++++++++++++ 5 files changed, 262 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e0a50f10e85..125f7c7c389 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2020-05-14 Richard Sandiford + + PR target/95105 + * config/aarch64/aarch64-sve-builtins.cc + (handle_arm_sve_vector_bits_attribute): Create a copy of the + original type's TYPE_MAIN_VARIANT, then reapply all the differences + between the original type and its main variant. + 2020-05-14 Richard Biener PR middle-end/95118 diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index 8511382351c..bdb04e8170d 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -3676,24 +3676,39 @@ handle_arm_sve_vector_bits_attribute (tree *node, tree, tree args, int, svbool_t and its fixed-length variants. Using a type variant avoids that but means that we treat some ambiguous combinations as valid. */ + tree new_type; + tree base_type = TYPE_MAIN_VARIANT (type); if (lang_GNU_C () && VECTOR_BOOLEAN_TYPE_P (type)) - type = build_variant_type_copy (type); + new_type = build_variant_type_copy (base_type); else - type = build_distinct_type_copy (type); + new_type = build_distinct_type_copy (base_type); + + /* Allow the GNU vector extensions to be applied to vectors. + The extensions aren't yet defined for packed predicates, + so continue to treat them as abstract entities for now. */ + if (!VECTOR_BOOLEAN_TYPE_P (new_type)) + TYPE_INDIVISIBLE_P (new_type) = 0; /* The new type is a normal sized type; it doesn't have the same restrictions as sizeless types. */ - TYPE_ATTRIBUTES (type) + TYPE_ATTRIBUTES (new_type) = remove_attribute ("SVE sizeless type", - copy_list (TYPE_ATTRIBUTES (type))); + copy_list (TYPE_ATTRIBUTES (new_type))); - /* Allow the GNU vector extensions to be applied to vectors. - The extensions aren't yet defined for packed predicates, - so continue to treat them as abstract entities for now. */ - if (!VECTOR_BOOLEAN_TYPE_P (type)) - TYPE_INDIVISIBLE_P (type) = 0; + /* Apply the relevant attributes, qualifiers and alignment of TYPE, + if they differ from the original (sizeless) BASE_TYPE. */ + if (TYPE_ATTRIBUTES (base_type) != TYPE_ATTRIBUTES (type) + || TYPE_QUALS (base_type) != TYPE_QUALS (type)) + { + tree attrs = remove_attribute ("SVE sizeless type", + copy_list (TYPE_ATTRIBUTES (type))); + new_type = build_type_attribute_qual_variant (new_type, attrs, + TYPE_QUALS (type)); + } + if (TYPE_ALIGN (base_type) != TYPE_ALIGN (type)) + new_type = build_aligned_type (new_type, TYPE_ALIGN (type)); - *node = type; + *node = new_type; return NULL_TREE; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ce278eda6b3..5163470c245 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-05-14 Richard Sandiford + + PR target/95105 + * gcc.target/aarch64/sve/acle/general/attributes_8.c: New test. + * g++.target/aarch64/sve/acle/general-c++/attributes_1.C: Likewise. + 2020-05-14 Richard Biener PR testsuite/94703 diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C new file mode 100644 index 00000000000..befd494cd13 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C @@ -0,0 +1,122 @@ +/* { dg-options "-msve-vector-bits=256 -W -Wall" } */ + +#include + +#define N __ARM_FEATURE_SVE_BITS +#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N))) + +template struct foo { T var; }; + +typedef svint8_t var1; +typedef __SVInt8_t var2; + +typedef const var1 const_var1; +typedef const var2 const_var2; + +typedef svint8_t fixed1 FIXED_ATTR; +typedef svint8_t fixed1_alias FIXED_ATTR; +typedef __SVInt8_t fixed2 FIXED_ATTR; + +typedef const_var1 const_fixed1 FIXED_ATTR; +typedef const var1 const_fixed1_alias FIXED_ATTR; +typedef const_var2 const_fixed2 FIXED_ATTR; + +extern fixed1 extern1; +extern fixed1_alias extern1_alias; +extern fixed2 extern2; + +extern foo extern1_foo; +extern foo extern1_alias_foo; +extern foo extern2_foo; + +extern const_fixed1 const_extern1; +extern const_fixed1_alias const_extern1_alias; +extern const_fixed2 const_extern2; + +extern foo const_extern1_foo; +extern foo const_extern1_alias_foo; +extern foo const_extern2_foo; + +fixed1 &ref1a = extern1; +fixed1_alias &ref1b = extern1; +fixed2 &ref1c = extern1; + +fixed1 &ref2a = extern1_alias; +fixed1_alias &ref2b = extern1_alias; +fixed2 &ref2c = extern1_alias; + +fixed1 &ref3a = extern2; +fixed1_alias &ref3b = extern2; +fixed2 &ref3c = extern2; + +fixed1 &ref1a_foo = extern1_foo.var; +fixed1_alias &ref1b_foo = extern1_foo.var; +fixed2 &ref1c_foo = extern1_foo.var; + +fixed1 &ref2a_foo = extern1_alias_foo.var; +fixed1_alias &ref2b_foo = extern1_alias_foo.var; +fixed2 &ref2c_foo = extern1_alias_foo.var; + +fixed1 &ref3a_foo = extern2_foo.var; +fixed1_alias &ref3b_foo = extern2_foo.var; +fixed2 &ref3c_foo = extern2_foo.var; + +fixed1 &ref4a = const_extern1; // { dg-error {discards qualifiers} } +fixed1_alias &ref4b = const_extern1; // { dg-error {discards qualifiers} } +fixed2 &ref4c = const_extern1; // { dg-error {discards qualifiers} } + +fixed1 &ref4a_foo = const_extern1_foo.var; // { dg-error {discards qualifiers} } +fixed1_alias &ref4b_foo = const_extern1_foo.var; // { dg-error {discards qualifiers} } +fixed2 &ref4c_foo = const_extern1_foo.var; // { dg-error {discards qualifiers} } + +const fixed1 &ref5a = const_extern2; +const fixed1_alias &ref5b = const_extern2; +const fixed2 &ref5c = const_extern2; + +const_fixed1 &const_ref1a = extern1; +const_fixed1_alias &const_ref1b = extern1; +const_fixed2 &const_ref1c = extern1; + +const_fixed1 &const_ref2a = extern1_alias; +const_fixed1_alias &const_ref2b = extern1_alias; +const_fixed2 &const_ref2c = extern1_alias; + +const_fixed1 &const_ref3a = extern2; +const_fixed1_alias &const_ref3b = extern2; +const_fixed2 &const_ref3c = extern2; + +const_fixed1 &const_ref1a_foo = extern1_foo.var; +const_fixed1_alias &const_ref1b_foo = extern1_foo.var; +const_fixed2 &const_ref1c_foo = extern1_foo.var; + +const_fixed1 &const_ref2a_foo = extern1_alias_foo.var; +const_fixed1_alias &const_ref2b_foo = extern1_alias_foo.var; +const_fixed2 &const_ref2c_foo = extern1_alias_foo.var; + +const_fixed1 &const_ref3a_foo = extern2_foo.var; +const_fixed1_alias &const_ref3b_foo = extern2_foo.var; +const_fixed2 &const_ref3c_foo = extern2_foo.var; + +const_fixed1 &const_ref4a = const_extern1; +const_fixed1_alias &const_ref4b = const_extern1; +const_fixed2 &const_ref4c = const_extern1; + +const_fixed1 &const_ref5a = const_extern1_alias; +const_fixed1_alias &const_ref5b = const_extern1_alias; +const_fixed2 &const_ref5c = const_extern1_alias; + +const_fixed1 &const_ref6a = const_extern2; +const_fixed1_alias &const_ref6b = const_extern2; +const_fixed2 &const_ref6c = const_extern2; + +const_fixed1 &const_ref4a_foo = const_extern1_foo.var; +const_fixed1_alias &const_ref4b_foo = const_extern1_foo.var; +const_fixed2 &const_ref4c_foo = const_extern1_foo.var; + +const_fixed1 &const_ref5a_foo = const_extern1_alias_foo.var; +const_fixed1_alias &const_ref5b_foo = const_extern1_alias_foo.var; +const_fixed2 &const_ref5c_foo = const_extern1_alias_foo.var; + +const_fixed1 &const_ref6a_foo = const_extern2_foo.var; +const_fixed1_alias &const_ref6b_foo = const_extern2_foo.var; +const_fixed2 &const_ref6c_foo = const_extern2_foo.var; diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c new file mode 100644 index 00000000000..f302927c55b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c @@ -0,0 +1,101 @@ +/* { dg-options "-msve-vector-bits=256 -W -Wall" } */ + +#include + +#define N __ARM_FEATURE_SVE_BITS +#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N))) +#define ALIGNED_ATTR __attribute__((aligned(N / 8))) + +typedef svint8_t var1; +typedef __SVInt8_t var2; + +typedef const var1 const_var1; +typedef const var2 const_var2; + +typedef var1 aligned_var1 ALIGNED_ATTR; +typedef var2 aligned_var2 ALIGNED_ATTR; + +typedef var1 fixed1 FIXED_ATTR; +typedef var1 fixed1_alias FIXED_ATTR; +typedef var2 fixed2 FIXED_ATTR; + +typedef const_var1 const_fixed1 FIXED_ATTR; +typedef const var1 const_fixed1_alias FIXED_ATTR; +typedef const_var2 const_fixed2 FIXED_ATTR; + +typedef aligned_var1 aligned_fixed1 FIXED_ATTR; +typedef var1 aligned_fixed1_alias FIXED_ATTR ALIGNED_ATTR; +typedef aligned_var2 aligned_fixed2 FIXED_ATTR; + +extern fixed1 extern1; +extern fixed1_alias extern1_alias; +extern fixed2 extern2; + +extern const_fixed1 const_extern1; +extern const_fixed1_alias const_extern1_alias; +extern const_fixed2 const_extern2; + +fixed1 *ptr1a = &extern1; +fixed1_alias *ptr1b = &extern1; +fixed2 *ptr1c = &extern1; + +fixed1 *ptr2a = &extern1_alias; +fixed1_alias *ptr2b = &extern1_alias; +fixed2 *ptr2c = &extern1_alias; + +fixed1 *ptr3a = &extern2; +fixed1_alias *ptr3b = &extern2; +fixed2 *ptr3c = &extern2; + +fixed1 *ptr4a = &const_extern1; // { dg-error {invalid conversion} "c++" { target c++ } } + // { dg-warning {discards 'const' qualifier} "c" { target c } .-1 } +fixed1_alias *ptr4b = &const_extern1; // { dg-error {invalid conversion} "c++" { target c++ } } + // { dg-warning {discards 'const' qualifier} "c" { target c } .-1 } +fixed2 *ptr4c = &const_extern1; // { dg-error {invalid conversion} "c++" { target c++ } } + // { dg-warning {discards 'const' qualifier} "c" { target c } .-1 } + +const fixed1 *ptr5a = &const_extern2; +const fixed1_alias *ptr5b = &const_extern2; +const fixed2 *ptr5c = &const_extern2; + +const_fixed1 *const_ptr1a = &extern1; +const_fixed1_alias *const_ptr1b = &extern1; +const_fixed2 *const_ptr1c = &extern1; + +const_fixed1 *const_ptr2a = &extern1_alias; +const_fixed1_alias *const_ptr2b = &extern1_alias; +const_fixed2 *const_ptr2c = &extern1_alias; + +const_fixed1 *const_ptr3a = &extern2; +const_fixed1_alias *const_ptr3b = &extern2; +const_fixed2 *const_ptr3c = &extern2; + +const_fixed1 *const_ptr4a = &const_extern1; +const_fixed1_alias *const_ptr4b = &const_extern1; +const_fixed2 *const_ptr4c = &const_extern1; + +const_fixed1 *const_ptr5a = &const_extern1_alias; +const_fixed1_alias *const_ptr5b = &const_extern1_alias; +const_fixed2 *const_ptr5c = &const_extern1_alias; + +const_fixed1 *const_ptr6a = &const_extern2; +const_fixed1_alias *const_ptr6b = &const_extern2; +const_fixed2 *const_ptr6c = &const_extern2; + +struct normal1 { int x; fixed1 y; }; +struct normal1_alias { int x; fixed1_alias y; }; +struct normal2 { int x; fixed2 y; }; + +struct aligned1 { int x; aligned_fixed1 y; }; +struct aligned1_alias { int x; aligned_fixed1_alias y; }; +struct aligned2 { int x; aligned_fixed2 y; }; + +#define ASSERT(NAME, TEST) typedef int NAME[(TEST) ? 1 : -1] + +ASSERT (check_normal1, sizeof (struct normal1) == N / 8 + 16); +ASSERT (check_normal1_alias, sizeof (struct normal1_alias) == N / 8 + 16); +ASSERT (check_normal2, sizeof (struct normal2) == N / 8 + 16); + +ASSERT (check_aligned1, sizeof (struct aligned1) == N / 4); +ASSERT (check_aligned1_alias, sizeof (struct aligned1_alias) == N / 4); +ASSERT (check_aligned2, sizeof (struct aligned2) == N / 4); -- 2.30.2