diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c index f64742e6447..33e8015b140 100644 --- a/gcc/config/arm/arm-builtins.c +++ b/gcc/config/arm/arm-builtins.c @@ -43,6 +43,8 @@ #include "sbitmap.h" #include "stringpool.h" #include "arm-builtins.h" +#include "stringpool.h" +#include "attribs.h" #define SIMD_MAX_BUILTIN_ARGS 7 @@ -1457,18 +1459,12 @@ arm_mangle_builtin_scalar_type (const_tree type) static const char * arm_mangle_builtin_vector_type (const_tree type) { - int i; - int nelts = sizeof (arm_simd_types) / sizeof (arm_simd_types[0]); - - for (i = 0; i < nelts; i++) - if (arm_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))), - arm_simd_types[i].name)) - return arm_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; } @@ -1642,9 +1638,18 @@ arm_init_simd_builtin_types (void) if (eltype == NULL) continue; if (arm_simd_types[i].itype == NULL) - arm_simd_types[i].itype = - build_distinct_type_copy - (build_vector_type (eltype, GET_MODE_NUNITS (mode))); + { + 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 (arm_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)); + arm_simd_types[i].itype = type; + } tdecl = add_builtin_type (arm_simd_types[i].name, arm_simd_types[i].itype); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index ea0ac01e68c..4ed717309ff 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -382,6 +382,7 @@ static const struct attribute_spec arm_attribute_table[] = arm_handle_cmse_nonsecure_entry, NULL }, { "cmse_nonsecure_call", 0, 0, true, false, false, true, arm_handle_cmse_nonsecure_call, NULL }, + { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -7539,6 +7540,15 @@ arm_comp_type_attributes (const_tree type1, const_tree type2) { int l1, l2, s1, s2; + tree attrs1 = lookup_attribute ("Advanced SIMD type", + TYPE_ATTRIBUTES (type1)); + tree attrs2 = lookup_attribute ("Advanced SIMD type", + TYPE_ATTRIBUTES (type2)); + if (bool (attrs1) != bool (attrs2)) + return 0; + if (attrs1 && !attribute_value_equal (attrs1, attrs2)) + return 0; + /* Check for mismatch of non-default calling convention. */ if (TREE_CODE (type1) != FUNCTION_TYPE) return 1; diff --git a/gcc/testsuite/g++.target/arm/pr95726.C b/gcc/testsuite/g++.target/arm/pr95726.C new file mode 100644 index 00000000000..5f7dbf11ddc --- /dev/null +++ b/gcc/testsuite/g++.target/arm/pr95726.C @@ -0,0 +1,49 @@ +// { dg-require-effective-target arm_neon_ok } +// { dg-add-options arm_neon } + +#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 +// _Z4sel2bR19__simd128_float32_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: +// +// _Z4sel1b19__simd128_float32_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} }