return cp_build_qualified_type (t, quals);
}
+/* Merge the attributes of type OTHER_TYPE into the attributes of type TYPE
+ and return a variant of TYPE with the merged attributes. */
+
+static tree
+merge_type_attributes_from (tree type, tree other_type)
+{
+ tree attrs = targetm.merge_type_attributes (type, other_type);
+ attrs = restrict_type_identity_attributes_to (attrs, TYPE_ATTRIBUTES (type));
+ return cp_build_type_attribute_variant (type, attrs);
+}
+
/* Return the common type for two arithmetic types T1 and T2 under the
usual arithmetic conversions. The default conversions have already
been applied, and enumerated types converted to their compatible
/* When we get here we should have two vectors of the same size.
Just prefer the unsigned one if present. */
if (TYPE_UNSIGNED (t1))
- return build_type_attribute_variant (t1, attributes);
+ return merge_type_attributes_from (t1, t2);
else
- return build_type_attribute_variant (t2, attributes);
+ return merge_type_attributes_from (t2, t1);
}
/* If only one is real, use it as the result. */
--- /dev/null
+# Copyright (C) 2014-2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't an ARM or AArch64 target.
+if {![istarget arm*-*-*]
+ && ![istarget aarch64*-*-*]} then {
+ return
+}
+
+# Load support procs.
+load_lib g++-dg.exp
+
+# Initialize `dg'.
+load_lib c-torture.exp
+
+dg-init
+
+# The default action for a test is 'run'. Save current default.
+global dg-do-what-default
+set save-dg-do-what-default ${dg-do-what-default}
+
+# For ARM, make sure that we have a target compatible with NEON, and do
+# not attempt to run execution tests if the hardware doesn't support it.
+if {[istarget arm*-*-*]} then {
+ if {![check_effective_target_arm_neon_ok]} then {
+ return
+ }
+ if {![is-effective-target arm_neon_hw]} then {
+ set dg-do-what-default compile
+ } else {
+ set dg-do-what-default run
+ }
+} else {
+ set dg-do-what-default run
+}
+
+torture-init
+set-torture-options $C_TORTURE_OPTIONS {{}} $LTO_TORTURE_OPTIONS
+
+# Make sure Neon flags are provided, if necessary. Use fp16 if we can.
+# Use fp16 arithmetic operations if the hardware supports it.
+if {[check_effective_target_arm_v8_2a_fp16_neon_hw]} then {
+ set additional_flags [add_options_for_arm_v8_2a_fp16_neon ""]
+} elseif {[check_effective_target_arm_neon_fp16_ok]} then {
+ set additional_flags [add_options_for_arm_neon_fp16 ""]
+} else {
+ set additional_flags [add_options_for_arm_neon ""]
+}
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] \
+ "" ${additional_flags}
+
+# All done.
+set dg-do-what-default ${save-dg-do-what-default}
+torture-finish
+dg-finish
--- /dev/null
+/* { dg-do compile } */
+
+#include <arm_neon.h>
+
+using int32_elt = __typeof(((int32x4_t *) nullptr)[0][0]);
+using uint32_elt = __typeof(((uint32x4_t *) nullptr)[0][0]);
+
+typedef int32_elt gnu_int32x4_t __attribute__((vector_size(16)));
+typedef uint32_elt gnu_uint32x4_t __attribute__((vector_size(16)));
+
+template<typename T> struct id;
+template<> struct id<gnu_int32x4_t> { static const int value = 1; };
+template<> struct id<gnu_uint32x4_t> { static const int value = 2; };
+template<> struct id<int32x4_t> { static const int value = 3; };
+template<> struct id<uint32x4_t> { static const int value = 4; };
+
+#define CHECK_TYPE(EXPR, TYPE) \
+ static_assert(id<decltype(EXPR)>::value == id<TYPE>::value, "foo")
+
+void
+f (gnu_int32x4_t sg, gnu_uint32x4_t ug, int32x4_t sn, uint32x4_t un, bool c)
+{
+ CHECK_TYPE (sg, gnu_int32x4_t);
+ CHECK_TYPE (ug, gnu_uint32x4_t);
+ CHECK_TYPE (sn, int32x4_t);
+ CHECK_TYPE (un, uint32x4_t);
+
+ CHECK_TYPE (sg + 1, gnu_int32x4_t);
+ CHECK_TYPE (ug + 1, gnu_uint32x4_t);
+ CHECK_TYPE (sn + 1, int32x4_t);
+ CHECK_TYPE (un + 1, uint32x4_t);
+
+ CHECK_TYPE (1 + sg, gnu_int32x4_t);
+ CHECK_TYPE (1 + ug, gnu_uint32x4_t);
+ CHECK_TYPE (1 + sn, int32x4_t);
+ CHECK_TYPE (1 + un, uint32x4_t);
+
+ CHECK_TYPE (sg + sg, gnu_int32x4_t);
+ CHECK_TYPE (ug + ug, gnu_uint32x4_t);
+ CHECK_TYPE (sn + sn, int32x4_t);
+ CHECK_TYPE (un + un, uint32x4_t);
+
+ // In C++, unlike C, the behavior is to prefer unsigned types over
+ // signed types.
+ CHECK_TYPE (sg + ug, gnu_uint32x4_t);
+ CHECK_TYPE (ug + sg, gnu_uint32x4_t);
+ CHECK_TYPE (sn + un, uint32x4_t);
+ CHECK_TYPE (un + sn, uint32x4_t);
+
+ // That being the case, it seems more consistent to do the same thing
+ // for mixed GNU and arm_neon.h operations.
+ CHECK_TYPE (sg + un, uint32x4_t);
+ CHECK_TYPE (un + sg, uint32x4_t);
+ CHECK_TYPE (sn + ug, gnu_uint32x4_t);
+ CHECK_TYPE (ug + sn, gnu_uint32x4_t);
+
+ // If the types have the same signedness, the traditional behavior is
+ // to pick the first type if it is unsigned and the second type otherwise.
+ // This is not necessarily sensible, but dates back to at least GCC 9.1.
+ // We could probably change it.
+ CHECK_TYPE (sg + sn, int32x4_t);
+ CHECK_TYPE (sn + sg, gnu_int32x4_t);
+ CHECK_TYPE (un + ug, uint32x4_t);
+ CHECK_TYPE (ug + un, gnu_uint32x4_t);
+
+ CHECK_TYPE (c ? sg + sg : sg, gnu_int32x4_t);
+ CHECK_TYPE (c ? ug + ug : ug, gnu_uint32x4_t);
+ CHECK_TYPE (c ? sn + sn : sn, int32x4_t);
+ CHECK_TYPE (c ? un + un : un, uint32x4_t);
+
+ CHECK_TYPE (c ? sg + 1 : sg, gnu_int32x4_t);
+ CHECK_TYPE (c ? ug + 1 : ug, gnu_uint32x4_t);
+ CHECK_TYPE (c ? sn + 1 : sn, int32x4_t);
+ CHECK_TYPE (c ? un + 1 : un, uint32x4_t);
+
+ CHECK_TYPE (c ? 1 + sg : sg, gnu_int32x4_t);
+ CHECK_TYPE (c ? 1 + ug : ug, gnu_uint32x4_t);
+ CHECK_TYPE (c ? 1 + sn : sn, int32x4_t);
+ CHECK_TYPE (c ? 1 + un : un, uint32x4_t);
+
+ CHECK_TYPE (c ? sg : sg + sg, gnu_int32x4_t);
+ CHECK_TYPE (c ? ug : ug + ug, gnu_uint32x4_t);
+ CHECK_TYPE (c ? sn : sn + sn, int32x4_t);
+ CHECK_TYPE (c ? un : un + un, uint32x4_t);
+
+ CHECK_TYPE (c ? sg : sg + 1, gnu_int32x4_t);
+ CHECK_TYPE (c ? ug : ug + 1, gnu_uint32x4_t);
+ CHECK_TYPE (c ? sn : sn + 1, int32x4_t);
+ CHECK_TYPE (c ? un : un + 1, uint32x4_t);
+
+ CHECK_TYPE (c ? sg : 1 + sg, gnu_int32x4_t);
+ CHECK_TYPE (c ? ug : 1 + ug, gnu_uint32x4_t);
+ CHECK_TYPE (c ? sn : 1 + sn, int32x4_t);
+ CHECK_TYPE (c ? un : 1 + un, uint32x4_t);
+
+ CHECK_TYPE (c ? sg + sg : sg + sg, gnu_int32x4_t);
+ CHECK_TYPE (c ? ug + ug : ug + ug, gnu_uint32x4_t);
+ CHECK_TYPE (c ? sn + sn : sn + sn, int32x4_t);
+ CHECK_TYPE (c ? un + un : un + un, uint32x4_t);
+
+ CHECK_TYPE (c ? sg + sg : sg + 1, gnu_int32x4_t);
+ CHECK_TYPE (c ? ug + ug : ug + 1, gnu_uint32x4_t);
+ CHECK_TYPE (c ? sn + sn : sn + 1, int32x4_t);
+ CHECK_TYPE (c ? un + un : un + 1, uint32x4_t);
+
+ CHECK_TYPE (c ? 1 + sg : sg + sg, gnu_int32x4_t);
+ CHECK_TYPE (c ? 1 + ug : ug + ug, gnu_uint32x4_t);
+ CHECK_TYPE (c ? 1 + sn : sn + sn, int32x4_t);
+ CHECK_TYPE (c ? 1 + un : un + un, uint32x4_t);
+}