diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c index 95213cd70c8..e87a4559c36 100644 --- a/gcc/config/aarch64/aarch64-builtins.c +++ b/gcc/config/aarch64/aarch64-builtins.c @@ -43,6 +43,8 @@ #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 @@ -639,18 +641,12 @@ aarch64_mangle_builtin_scalar_type (const_tree type) 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; } @@ -802,10 +798,16 @@ aarch64_init_simd_builtin_types (void) 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, diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index f3551a73d87..57988f9330b 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1429,6 +1429,7 @@ static const struct attribute_spec aarch64_attribute_table[] = { "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 } @@ -22721,8 +22722,18 @@ aarch64_simd_clone_usable (struct cgraph_node *node) 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; } diff --git a/gcc/testsuite/g++.target/aarch64/pr95726.C b/gcc/testsuite/g++.target/aarch64/pr95726.C new file mode 100644 index 00000000000..ddd69b8b0da --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/pr95726.C @@ -0,0 +1,46 @@ +#include + +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 struct bar; +template<> struct bar { static const int x = 1; }; +template<> struct bar { static const int x = 2; }; +static_assert(bar::x + bar::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} }