> -----Original Message-----
> From: Richard Sandiford <richard.sandif...@arm.com>
> Sent: 10 July 2020 17:54
> To: gcc-patches@gcc.gnu.org
> Cc: ni...@redhat.com; Richard Earnshaw <richard.earns...@arm.com>;
> Ramana Radhakrishnan <ramana.radhakrish...@arm.com>; Kyrylo
> Tkachov <kyrylo.tkac...@arm.com>
> Subject: [PATCH] arm: Treat GNU and Advanced SIMD vectors as distinct
> [PR92789, PR95726]
> 
> This is an arm version of aarch64 patch r11-1741.  The approach
> is essentially identical, not much more than s/aarch64/arm/.
> 
> To recap, PR95726 is about template look-up for things like:
> 
>     foo<float vecf __attribute__((vector_size(16)))>
>     foo<float32x4_t>
> 
> The immediate cause of the problem is that the hash function usually
> returns different hashes for these types, yet the equality function
> thinks they are equal.  This then raises the question of how the types
> are supposed to be treated.
> 
> The answer we chose for AArch64 was that the GNU vector type should
> be treated as distinct from float32x4_t, but that each type should
> implicitly convert to the other.
> 
> This would mean that, as far as the PR is concerned, the hashing
> function is right to (sometimes) treat the types differently and
> the equality function is wrong to treat them as the same.
> 
> The most obvious way to enforce the type difference is to use a
> target-specific type attribute.  That on its own is enough to fix
> the PR.  The difficulty is deciding whether the knock-on effects
> are acceptable.
> 
> One obvious effect is that GCC then rejects:
> 
>     typedef float vecf __attribute__((vector_size(16)));
>     vecf x;
>     float32x4_t &z = x;
> 
> on the basis that the types are no longer reference-compatible.
> For AArch64 we took the approach that this was the correct behaviour.
> It is also consistent with current Clang.
> 
> A trickier question is whether:
> 
>     vecf x;
>     float32x4_t y;
>     … c ? x : y …
> 
> should be valid, and if so, what its type should be [PR92789].
> As explained in the comment in the testcase, GCC and Clang both
> accepted this, but GCC chose the “then” type while Clang chose
> the “else” type.  This can lead to different mangling for (probably
> artificial) corner cases, as seen for “sel1” and “sel2” in the
> testcase.
> 
> Adding the attribute makes GCC reject the conditional expression
> as ambiguous.  For AArch64 we took the approach that this too is
> the correct behaviour, for the reasons described in the testcase.
> However, it does seem to have the potential to break existing code.
> 
> Tested on arm-linux-gnueabihf.  OK for master?  The backport will
> involve an arm version of:
> 
>   https://gcc.gnu.org/pipermail/gcc-patches/2020-July/549614.html
> 

Ok. I'd like arm gcc to be consistent with aarch64 gcc for sure.
Thanks,
Kyrill

> Richard
> 
> 
> gcc/
>       PR target/92789
>       PR target/95726
>       * config/arm/arm.c (arm_attribute_table): Add
>       "Advanced SIMD type".
>       (arm_comp_type_attributes): Check that the "Advanced SIMD type"
>       attributes are equal.
>       * config/arm/arm-builtins.c: Include stringpool.h and
>       attribs.h.
>       (arm_mangle_builtin_vector_type): Use the mangling recorded
>       in the "Advanced SIMD type" attribute.
>       (arm_init_simd_builtin_types): Add an "Advanced SIMD type"
>       attribute to each Advanced SIMD type, using the mangled type
>       as the attribute's single argument.
> 
> gcc/testsuite/
>       PR target/92789
>       PR target/95726
>       * g++.target/arm/pr95726.C: New test.
> ---
>  gcc/config/arm/arm-builtins.c          | 35 ++++++++++--------
>  gcc/config/arm/arm.c                   | 10 ++++++
>  gcc/testsuite/g++.target/arm/pr95726.C | 49
> ++++++++++++++++++++++++++
>  3 files changed, 79 insertions(+), 15 deletions(-)
>  create mode 100644 gcc/testsuite/g++.target/arm/pr95726.C
> 
> 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 <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
> +//   _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} }

Reply via email to