aarch64: Fix arm_sve_vector_bits on typedefs [PR95105]
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 14 May 2020 11:20:32 +0000 (12:20 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 14 May 2020 11:20:32 +0000 (12:20 +0100)
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<typename T> struct s { T x; };
extern s<bar> 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  <richard.sandiford@arm.com>

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
gcc/config/aarch64/aarch64-sve-builtins.cc
gcc/testsuite/ChangeLog
gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c [new file with mode: 0644]

index e0a50f10e855e00fd36e63de0ac862930ca77305..125f7c7c389f8373d7e87a8b511a2049e14f970b 100644 (file)
@@ -1,3 +1,11 @@
+2020-05-14  Richard Sandiford  <richard.sandiford@arm.com>
+
+       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  <rguenther@suse.de>
 
        PR middle-end/95118
index 8511382351cae00dfcad2b03e8d12b8505c55b2b..bdb04e8170d645bf2deac1e9268eb179ef58ad70 100644 (file)
@@ -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;
 }
 
index ce278eda6b3f23e170d4a739a2093d08dfe25912..5163470c2456b56b715c20c64653e2788d38be1b 100644 (file)
@@ -1,3 +1,9 @@
+2020-05-14  Richard Sandiford  <richard.sandiford@arm.com>
+
+       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  <rguenther@suse.de>
 
        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 (file)
index 0000000..befd494
--- /dev/null
@@ -0,0 +1,122 @@
+/* { dg-options "-msve-vector-bits=256 -W -Wall" } */
+
+#include <arm_sve.h>
+
+#define N __ARM_FEATURE_SVE_BITS
+#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
+
+template<typename T> 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<fixed1> extern1_foo;
+extern foo<fixed1_alias> extern1_alias_foo;
+extern foo<fixed2> extern2_foo;
+
+extern const_fixed1 const_extern1;
+extern const_fixed1_alias const_extern1_alias;
+extern const_fixed2 const_extern2;
+
+extern foo<const_fixed1> const_extern1_foo;
+extern foo<const_fixed1_alias> const_extern1_alias_foo;
+extern foo<const_fixed2> 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 (file)
index 0000000..f302927
--- /dev/null
@@ -0,0 +1,101 @@
+/* { dg-options "-msve-vector-bits=256 -W -Wall" } */
+
+#include <arm_sve.h>
+
+#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);