#include "gimple-iterator.h"
#include "case-cfn-macros.h"
#include "emit-rtl.h"
+#include "stringpool.h"
+#include "attribs.h"
#define v8qi_UP E_V8QImode
#define v4hi_UP E_V4HImode
static const char *
aarch64_mangle_builtin_vector_type (const_tree type)
{
- int i;
- int nelts = sizeof (aarch64_simd_types) / sizeof (aarch64_simd_types[0]);
-
- for (i = 0; i < nelts; i++)
- if (aarch64_simd_types[i].mode == TYPE_MODE (type)
- && TYPE_NAME (type)
- && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && DECL_NAME (TYPE_NAME (type))
- && !strcmp
- (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
- aarch64_simd_types[i].name))
- return aarch64_simd_types[i].mangle;
+ tree attrs = TYPE_ATTRIBUTES (type);
+ if (tree attr = lookup_attribute ("Advanced SIMD type", attrs))
+ {
+ tree mangled_name = TREE_VALUE (TREE_VALUE (attr));
+ return IDENTIFIER_POINTER (mangled_name);
+ }
return NULL;
}
if (aarch64_simd_types[i].itype == NULL)
{
- aarch64_simd_types[i].itype
- = build_distinct_type_copy
- (build_vector_type (eltype, GET_MODE_NUNITS (mode)));
- SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
+ tree type = build_vector_type (eltype, GET_MODE_NUNITS (mode));
+ type = build_distinct_type_copy (type);
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+
+ tree mangled_name = get_identifier (aarch64_simd_types[i].mangle);
+ tree value = tree_cons (NULL_TREE, mangled_name, NULL_TREE);
+ TYPE_ATTRIBUTES (type)
+ = tree_cons (get_identifier ("Advanced SIMD type"), value,
+ TYPE_ATTRIBUTES (type));
+ aarch64_simd_types[i].itype = type;
}
tdecl = add_builtin_type (aarch64_simd_types[i].name,
{ "arm_sve_vector_bits", 1, 1, false, true, false, true,
aarch64_sve::handle_arm_sve_vector_bits_attribute,
NULL },
+ { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL },
{ "SVE type", 3, 3, false, true, false, true, NULL, NULL },
{ "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL },
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
static int
aarch64_comp_type_attributes (const_tree type1, const_tree type2)
{
- if (lookup_attribute ("aarch64_vector_pcs", TYPE_ATTRIBUTES (type1))
- != lookup_attribute ("aarch64_vector_pcs", TYPE_ATTRIBUTES (type2)))
+ auto check_attr = [&](const char *name) {
+ tree attr1 = lookup_attribute (name, TYPE_ATTRIBUTES (type1));
+ tree attr2 = lookup_attribute (name, TYPE_ATTRIBUTES (type2));
+ if (!attr1 && !attr2)
+ return true;
+
+ return attr1 && attr2 && attribute_value_equal (attr1, attr2);
+ };
+
+ if (!check_attr ("aarch64_vector_pcs"))
+ return 0;
+ if (!check_attr ("Advanced SIMD type"))
return 0;
return 1;
}
--- /dev/null
+#include <arm_neon.h>
+
+typedef float vecf __attribute__((vector_size(16)));
+
+// This assertion must hold: vecf and float32x4_t have distinct identities
+// and mangle differently, so they are not interchangeable.
+template<typename T> struct bar;
+template<> struct bar<vecf> { static const int x = 1; };
+template<> struct bar<float32x4_t> { static const int x = 2; };
+static_assert(bar<vecf>::x + bar<float32x4_t>::x == 3, "boo");
+
+// GCC 10.1 and earlier accepted this. However, the rule should be
+// that GNU vectors and Advanced SIMD vectors are distinct types but
+// that each one implicitly converts to the other. The types are not
+// reference-compatible.
+//
+// The behavior tested below is consistent with Clang.
+vecf x;
+float32x4_t y;
+float32x4_t &z = x; // { dg-error {cannot bind non-const lvalue reference} }
+
+// These assignment must be valid even in the strictest mode: vecf must
+// implicitly convert to float32x4_t and vice versa.
+void foo() { x = y; y = x; }
+
+// Previously GCC accepted this and took the type of "d" from the "then" arm.
+// It therefore mangled the functions as:
+//
+// _Z4sel1bRDv4_f
+// _Z4sel2bR13__Float32x4_t
+//
+// Clang currently also accepts it and takes the type of "d" from the
+// "else" arm. It therefore mangles the functions as follows, which is
+// inconsistent with the old GCC behavior:
+//
+// _Z4sel1b13__Float32x4_t
+// _Z4sel2bDv4_f
+//
+// Given that the types have distinct identities and that each one
+// implicitly converts to the other (see above), the expression ought
+// to be rejected as invalid. This is consistent (by analogy) with the
+// standard C++ handling of conditional expressions involving class types,
+// in cases where the "then" value implicitly converts to the "else" type
+// and the "else" value implicitly converts to the "then" type.
+auto sel1(bool c, decltype(c ? x : y) d) { return d; } // { dg-error {operands to '\?:' have different types} }
+auto sel2(bool c, decltype(c ? y : x) d) { return d; } // { dg-error {operands to '\?:' have different types} }