Commit 932e9140 by Richard Sandiford

c++: Treat GNU and Advanced SIMD vectors as distinct [PR95726]

This is a release branch version of
r11-1741-g:31427b974ed7b7dd54e28fec595e731bf6eea8ba and
r11-2022-g:efe99cca78215e339ba79f0a900a896b4c0a3d36.

The trunk versions of the patch made GNU and Advanced SIMD vectors
distinct (but inter-convertible) in all cases.  However, the
traditional behaviour is that the types are distinct in template
arguments but not otherwise.

Following a suggestion from Jason, this patch puts the check
for different vector types under comparing_specializations.
In order to keep the backport as simple as possible, the patch
hard-codes the name of the attribute in the frontend rather than
adding a new branch-only target hook.

I didn't find a test that tripped the assert on the branch,
even with the --param in the PR, so instead I tested this by
forcing the hash function to only hash the tree code.  That made
the static assertion in the test fail without the patch but pass
with it.

This means that the tests pass for unmodified sources even
without the patch (unless you're very unlucky).

gcc/
	PR target/95726
	* config/aarch64/aarch64.c (aarch64_attribute_table): Add
	"Advanced SIMD type".
	* config/aarch64/aarch64-builtins.c: Include stringpool.h and
	attribs.h.
	(aarch64_init_simd_builtin_types): Add an "Advanced SIMD type"
	attribute to each Advanced SIMD type.
	* config/arm/arm.c (arm_attribute_table): Add "Advanced SIMD type".
	* config/arm/arm-builtins.c: Include stringpool.h and attribs.h.
	(arm_init_simd_builtin_types): Add an "Advanced SIMD type"
	attribute to each Advanced SIMD type.

gcc/cp/
	PR target/95726
	* typeck.c (structural_comptypes): When comparing template
	specializations, differentiate between vectors that have and
	do not have an "Advanced SIMD type" attribute.

gcc/testsuite/
	PR target/95726
	* g++.target/aarch64/pr95726.C: New test.
	* g++.target/arm/pr95726.C: Likewise.
parent 9a9e1ed8
......@@ -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
......@@ -802,10 +804,14 @@ 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);
TYPE_ATTRIBUTES (type)
= tree_cons (get_identifier ("Advanced SIMD type"),
NULL_TREE, TYPE_ATTRIBUTES (type));
aarch64_simd_types[i].itype = type;
}
tdecl = add_builtin_type (aarch64_simd_types[i].name,
......
......@@ -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", 0, 0, 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 }
......
......@@ -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
......@@ -1642,9 +1644,16 @@ 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);
TYPE_ATTRIBUTES (type)
= tree_cons (get_identifier ("Advanced SIMD type"),
NULL_TREE, TYPE_ATTRIBUTES (type));
arm_simd_types[i].itype = type;
}
tdecl = add_builtin_type (arm_simd_types[i].name,
arm_simd_types[i].itype);
......
......@@ -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", 0, 0, false, true, false, true, NULL, NULL },
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
......
......@@ -1429,6 +1429,48 @@ structural_comptypes (tree t1, tree t2, int strict)
|| maybe_ne (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
|| !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
/* This hack is specific to release branches and fixes PR95726 for
arm and aarch64 targets. The idea is to treat GNU and Advanced
SIMD types as distinct types for template specialization, but to
treat them as the same type for other purposes. For example:
typedef float vecf __attribute__((vector_size(16)));
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");
is supposed to be valid, and so "vecf" and "float32x4_t" should
be different for at least template specialization. However,
GCC 10 and earlier also allowed things like:
vecf x;
float32x4_t &z = x;
and:
vecf x;
float32x4_t y;
... c ? x : y ...
both of which require "vecf" and "float32x4_t" to be the same.
This was fixed in GCC 11+ by making the types distinct in all
contexts, making the reference binding and ?: expression above
invalid. However, it would be inappropriate to change the
semantics like that in release branches, so we do this instead.
The space in the attribute name prevents any clash with user-
specified attributes. */
if (comparing_specializations)
{
bool asimd1 = lookup_attribute ("Advanced SIMD type",
TYPE_ATTRIBUTES (t1));
bool asimd2 = lookup_attribute ("Advanced SIMD type",
TYPE_ATTRIBUTES (t2));
if (asimd1 != asimd2)
return false;
}
break;
case TYPE_PACK_EXPANSION:
......
#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 and earlier should continue to accept this, but the behavior
// changed in GCC 11.
vecf x;
float32x4_t y;
float32x4_t &z = x;
// 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; }
// GCC 10 and earlier should continue to accept this, but the behavior
// changed in GCC 11.
auto sel1(bool c, decltype(c ? x : y) d) { return d; }
auto sel2(bool c, decltype(c ? y : x) d) { return d; }
/* { dg-final { scan-assembler {_Z4sel1bRDv4_f} } } */
/* { dg-final { scan-assembler {_Z4sel2bR13__Float32x4_t} } } */
// { 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 and earlier should continue to accept this, but the behavior
// changed in GCC 11.
vecf x;
float32x4_t y;
float32x4_t &z = x;
// 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; }
// GCC 10 and earlier should continue to accept this, but the behavior
// changed in GCC 11.
auto sel1(bool c, decltype(c ? x : y) d) { return d; }
auto sel2(bool c, decltype(c ? y : x) d) { return d; }
/* { dg-final { scan-assembler {_Z4sel1bRDv4_f} } } */
/* { dg-final { scan-assembler {_Z4sel2bR19__simd128_float32_t} } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment