From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1666) id 29D163857C67; Mon, 31 May 2021 07:33:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 29D163857C67 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Richard Biener To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-1128] c++/88601 - [C/C++] __builtin_shufflevector support X-Act-Checkin: gcc X-Git-Author: Richard Biener X-Git-Refname: refs/heads/master X-Git-Oldrev: df4e0359dad239854af0ea9eacb8e7e3719557d0 X-Git-Newrev: ef8176e0fac935c095cc39f4ecdfd43cdb8cb3f3 Message-Id: <20210531073305.29D163857C67@sourceware.org> Date: Mon, 31 May 2021 07:33:05 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 31 May 2021 07:33:05 -0000 https://gcc.gnu.org/g:ef8176e0fac935c095cc39f4ecdfd43cdb8cb3f3 commit r12-1128-gef8176e0fac935c095cc39f4ecdfd43cdb8cb3f3 Author: Richard Biener Date: Fri May 21 11:33:30 2021 +0200 c++/88601 - [C/C++] __builtin_shufflevector support This adds support for the clang __builtin_shufflevector extension to the C and C++ frontends. The builtin is lowered to VEC_PERM_EXPR. Because VEC_PERM_EXPR does not support different sized vector inputs or result or the special permute index of -1 (don't-care) c_build_shufflevector applies lowering by widening inputs and output to the widest vector, replacing -1 by a defined index and subsetting the final vector if we produced a wider result than desired. Code generation thus can be sub-optimal, followup patches will aim to fix that by recovering from part of the missing features during RTL expansion and by relaxing the constraints of the GIMPLE IL with regard to VEC_PERM_EXPR. 2021-05-21 Richard Biener PR c++/88601 gcc/c-family/ * c-common.c: Include tree-vector-builder.h and vec-perm-indices.h. (c_common_reswords): Add __builtin_shufflevector. (c_build_shufflevector): New funtion. * c-common.h (enum rid): Add RID_BUILTIN_SHUFFLEVECTOR. (c_build_shufflevector): Declare. gcc/c/ * c-decl.c (names_builtin_p): Handle RID_BUILTIN_SHUFFLEVECTOR. * c-parser.c (c_parser_postfix_expression): Likewise. gcc/cp/ * cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_SHUFFLEVECTOR. * cp-tree.h (build_x_shufflevector): Declare. * parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_SHUFFLEVECTOR. * pt.c (tsubst_copy_and_build): Handle IFN_SHUFFLEVECTOR. * typeck.c (build_x_shufflevector): Build either a lowered VEC_PERM_EXPR or an unlowered shufflevector via a temporary internal function IFN_SHUFFLEVECTOR. gcc/ * internal-fn.c (expand_SHUFFLEVECTOR): Define. * internal-fn.def (SHUFFLEVECTOR): New. * internal-fn.h (expand_SHUFFLEVECTOR): Declare. * doc/extend.texi: Document __builtin_shufflevector. gcc/testsuite/ * c-c++-common/builtin-shufflevector-2.c: New testcase. * c-c++-common/torture/builtin-shufflevector-1.c: Likewise. * g++.dg/ext/builtin-shufflevector-1.C: Likewise. * g++.dg/ext/builtin-shufflevector-2.C: Likewise. Diff: --- gcc/c-family/c-common.c | 139 +++++++++++++++++++++ gcc/c-family/c-common.h | 4 +- gcc/c/c-decl.c | 1 + gcc/c/c-parser.c | 38 ++++++ gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.h | 3 + gcc/cp/parser.c | 15 +++ gcc/cp/pt.c | 9 ++ gcc/cp/typeck.c | 36 ++++++ gcc/doc/extend.texi | 28 +++++ gcc/internal-fn.c | 6 + gcc/internal-fn.def | 3 + gcc/internal-fn.h | 1 + .../c-c++-common/builtin-shufflevector-2.c | 18 +++ .../c-c++-common/torture/builtin-shufflevector-1.c | 49 ++++++++ gcc/testsuite/g++.dg/ext/builtin-shufflevector-1.C | 18 +++ gcc/testsuite/g++.dg/ext/builtin-shufflevector-2.C | 12 ++ 17 files changed, 380 insertions(+), 1 deletion(-) diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index b7daa2e2654..c4eb2b1c920 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -51,6 +51,8 @@ along with GCC; see the file COPYING3. If not see #include "c-spellcheck.h" #include "selftest.h" #include "debug.h" +#include "tree-vector-builder.h" +#include "vec-perm-indices.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -383,6 +385,7 @@ const struct c_common_resword c_common_reswords[] = { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 }, { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY }, { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 }, + { "__builtin_shufflevector", RID_BUILTIN_SHUFFLEVECTOR, 0 }, { "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY }, { "__builtin_offsetof", RID_OFFSETOF, 0 }, { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY }, @@ -1108,6 +1111,142 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask, return ret; } +/* Build a VEC_PERM_EXPR if V0, V1 are not error_mark_nodes + and have vector types, V0 has the same element type as V1, and the + number of elements the result is that of MASK. */ +tree +c_build_shufflevector (location_t loc, tree v0, tree v1, vec mask, + bool complain) +{ + tree ret; + bool wrap = true; + bool maybe_const = false; + + if (v0 == error_mark_node || v1 == error_mark_node) + return error_mark_node; + + if (!gnu_vector_type_p (TREE_TYPE (v0)) + || !gnu_vector_type_p (TREE_TYPE (v1))) + { + if (complain) + error_at (loc, "%<__builtin_shufflevector%> arguments must be vectors"); + return error_mark_node; + } + + /* ??? In principle one could select a constant part of a variable size + vector but things get a bit awkward with trying to support this here. */ + unsigned HOST_WIDE_INT v0n, v1n; + if (!TYPE_VECTOR_SUBPARTS (TREE_TYPE (v0)).is_constant (&v0n) + || !TYPE_VECTOR_SUBPARTS (TREE_TYPE (v1)).is_constant (&v1n)) + { + if (complain) + error_at (loc, "%<__builtin_shufflevector%> arguments must be constant" + " size vectors"); + return error_mark_node; + } + + if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (v0))) + != TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (v1)))) + { + if (complain) + error_at (loc, "%<__builtin_shufflevector%> argument vectors must " + "have the same element type"); + return error_mark_node; + } + + if (!pow2p_hwi (mask.length ())) + { + if (complain) + error_at (loc, "%<__builtin_shufflevector%> must specify a result " + "with a power of two number of elements"); + return error_mark_node; + } + + if (!c_dialect_cxx ()) + { + /* Avoid C_MAYBE_CONST_EXPRs inside VEC_PERM_EXPR. */ + v0 = c_fully_fold (v0, false, &maybe_const); + wrap &= maybe_const; + + v1 = c_fully_fold (v1, false, &maybe_const); + wrap &= maybe_const; + } + + unsigned HOST_WIDE_INT maskl = MAX (mask.length (), MAX (v0n, v1n)); + unsigned HOST_WIDE_INT pad = (v0n < maskl ? maskl - v0n : 0); + vec_perm_builder sel (maskl, maskl, 1); + unsigned i; + for (i = 0; i < mask.length (); ++i) + { + tree idx = mask[i]; + if (!tree_fits_shwi_p (idx)) + { + if (complain) + error_at (loc, "invalid element index %qE to " + "%<__builtin_shufflevector%>", idx); + return error_mark_node; + } + HOST_WIDE_INT iidx = tree_to_shwi (idx); + if (iidx < -1 + || (iidx != -1 + && (unsigned HOST_WIDE_INT) iidx >= v0n + v1n)) + { + if (complain) + error_at (loc, "invalid element index %qE to " + "%<__builtin_shufflevector%>", idx); + return error_mark_node; + } + /* ??? Our VEC_PERM_EXPR does not allow for -1 yet. */ + if (iidx == -1) + iidx = i; + /* ??? Our VEC_PERM_EXPR does not allow different sized inputs, + so pad out a smaller v0. */ + else if ((unsigned HOST_WIDE_INT) iidx >= v0n) + iidx += pad; + sel.quick_push (iidx); + } + /* ??? VEC_PERM_EXPR does not support a result that is smaller than + the inputs, so we have to pad id out. */ + for (; i < maskl; ++i) + sel.quick_push (i); + + vec_perm_indices indices (sel, 2, maskl); + + tree ret_type = build_vector_type (TREE_TYPE (TREE_TYPE (v0)), maskl); + tree mask_type = build_vector_type (build_nonstandard_integer_type + (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (ret_type))), 1), + maskl); + /* Pad out arguments to the common vector size. */ + if (v0n < maskl) + { + constructor_elt elt = { NULL_TREE, build_zero_cst (TREE_TYPE (v0)) }; + v0 = build_constructor_single (ret_type, NULL_TREE, v0); + for (i = 1; i < maskl / v0n; ++i) + vec_safe_push (CONSTRUCTOR_ELTS (v0), elt); + } + if (v1n < maskl) + { + constructor_elt elt = { NULL_TREE, build_zero_cst (TREE_TYPE (v1)) }; + v1 = build_constructor_single (ret_type, NULL_TREE, v1); + for (i = 1; i < maskl / v1n; ++i) + vec_safe_push (CONSTRUCTOR_ELTS (v1), elt); + } + ret = build3_loc (loc, VEC_PERM_EXPR, ret_type, v0, v1, + vec_perm_indices_to_tree (mask_type, indices)); + /* Get the lowpart we are interested in. */ + if (mask.length () < maskl) + { + tree lpartt = build_vector_type (TREE_TYPE (ret_type), mask.length ()); + ret = build3_loc (loc, BIT_FIELD_REF, + lpartt, ret, TYPE_SIZE (lpartt), bitsize_zero_node); + } + + if (!c_dialect_cxx () && !wrap) + ret = c_wrap_maybe_const (ret, true); + + return ret; +} + /* Build a VEC_CONVERT ifn for __builtin_convertvector builtin. */ tree diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index f30b6c6ac33..be4b29a017b 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -107,7 +107,7 @@ enum rid RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG, RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, - RID_BUILTIN_CONVERTVECTOR, RID_BUILTIN_TGMATH, + RID_BUILTIN_SHUFFLEVECTOR, RID_BUILTIN_CONVERTVECTOR, RID_BUILTIN_TGMATH, RID_BUILTIN_HAS_ATTRIBUTE, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, @@ -1048,6 +1048,8 @@ extern bool lvalue_p (const_tree); extern bool vector_targets_convertible_p (const_tree t1, const_tree t2); extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note); extern tree c_build_vec_perm_expr (location_t, tree, tree, tree, bool = true); +extern tree c_build_shufflevector (location_t, tree, tree, + vec, bool = true); extern tree c_build_vec_convert (location_t, tree, location_t, tree, bool = true); extern void init_c_lex (void); diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 3c7b306809d..28f851b9d0b 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -10547,6 +10547,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_CONVERTVECTOR: case RID_BUILTIN_HAS_ATTRIBUTE: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: case RID_CHOOSE_EXPR: case RID_OFFSETOF: case RID_TYPES_COMPATIBLE_P: diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d71fd0abe90..c491b128da5 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -10000,6 +10000,44 @@ c_parser_postfix_expression (c_parser *parser) set_c_expr_source_range (&expr, loc, close_paren_loc); break; } + case RID_BUILTIN_SHUFFLEVECTOR: + { + vec *cexpr_list; + unsigned int i; + c_expr_t *p; + location_t close_paren_loc; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_shufflevector", + &cexpr_list, false, + &close_paren_loc)) + { + expr.set_error (); + break; + } + + FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p) + *p = convert_lvalue_to_rvalue (loc, *p, true, true); + + if (vec_safe_length (cexpr_list) < 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shuffle%>"); + expr.set_error (); + } + else + { + auto_vec mask; + for (i = 2; i < cexpr_list->length (); ++i) + mask.safe_push ((*cexpr_list)[i].value); + expr.value = c_build_shufflevector (loc, (*cexpr_list)[0].value, + (*cexpr_list)[1].value, + mask); + } + set_c_expr_source_range (&expr, loc, close_paren_loc); + break; + } case RID_BUILTIN_CONVERTVECTOR: { location_t start_loc = loc; diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 9847270694a..46b2248574c 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -390,6 +390,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_CONVERTVECTOR: case RID_BUILTIN_HAS_ATTRIBUTE: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: case RID_BUILTIN_BIT_CAST: case RID_OFFSETOF: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index aa202715873..c95a820037f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7895,6 +7895,9 @@ extern tree cp_build_binary_op (const op_location_t &, extern tree build_x_vec_perm_expr (location_t, tree, tree, tree, tsubst_flags_t); +extern tree build_x_shufflevector (location_t, + vec *, + tsubst_flags_t); #define cxx_sizeof(T) cxx_sizeof_or_alignof_type (input_location, T, SIZEOF_EXPR, false, true) extern tree build_simple_component_ref (tree, tree); extern tree build_ptrmemfunc_access_expr (tree, tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 84c6be87873..4a46828e162 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7295,6 +7295,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_ADDRESSOF: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: { vec *vec; @@ -7357,6 +7358,20 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_BUILTIN_SHUFFLEVECTOR: + if (vec->length () < 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shufflevector%>"); + postfix_expression = error_mark_node; + } + else + { + postfix_expression + = build_x_shufflevector (loc, vec, tf_warning_or_error); + } + break; + default: gcc_unreachable (); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b476ca8948d..31302803c62 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20397,6 +20397,15 @@ tsubst_copy_and_build (tree t, RETURN (ret); break; + case IFN_SHUFFLEVECTOR: + { + ret = build_x_shufflevector (input_location, call_args, + complain); + if (ret != error_mark_node) + RETURN (ret); + break; + } + default: /* Unsupported internal function with arguments. */ gcc_unreachable (); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 3df4117e4e7..dbb2370510c 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5989,6 +5989,42 @@ build_x_vec_perm_expr (location_t loc, orig_arg1, orig_arg2); return exp; } + +/* Build a VEC_PERM_EXPR. + This is a simple wrapper for c_build_shufflevector. */ +tree +build_x_shufflevector (location_t loc, vec *args, + tsubst_flags_t complain) +{ + tree arg0 = (*args)[0]; + tree arg1 = (*args)[1]; + if (processing_template_decl) + { + for (unsigned i = 0; i < args->length (); ++i) + if (type_dependent_expression_p ((*args)[i])) + { + tree exp = build_min_nt_call_vec (NULL, args); + CALL_EXPR_IFN (exp) = IFN_SHUFFLEVECTOR; + return exp; + } + arg0 = build_non_dependent_expr (arg0); + arg1 = build_non_dependent_expr (arg1); + /* ??? Nothing needed for the index arguments? */ + } + auto_vec mask; + for (unsigned i = 2; i < args->length (); ++i) + { + tree idx = maybe_constant_value ((*args)[i]); + mask.safe_push (idx); + } + tree exp = c_build_shufflevector (loc, arg0, arg1, mask, complain & tf_error); + if (processing_template_decl && exp != error_mark_node) + { + exp = build_min_non_dep_call_vec (exp, NULL, args); + CALL_EXPR_IFN (exp) = IFN_SHUFFLEVECTOR; + } + return exp; +} /* Return a tree for the sum or difference (RESULTCODE says which) of pointer PTROP and integer INTOP. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index bfe9c21bddf..8711745bbe8 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -11849,6 +11849,34 @@ to and from other datatypes of the same size). You cannot operate between vectors of different lengths or different signedness without a cast. +@findex __builtin_shufflevector +Vector shuffling is available using the +@code{__builtin_shufflevector (vec1, vec2, index...)} +function. @var{vec1} and @var{vec2} must be expressions with +vector type with a compatible element type. The result of +@code{__builtin_shufflevector} is a vector with the same element type +as @var{vec1} and @var{vec2} but that has an element count equal to +the number of indices specified. + +The @var{index} arguments are a list of integers that specify the +elements indices of the first two vectors that should be extracted and +returned in a new vector. These element indices are numbered sequentially +starting with the first vector, continuing into the second vector. +An index of -1 can be used to indicate that the corresponding element in +the returned vector is a don't care and can be freely chosen to optimized +the generated code sequence performing the shuffle operation. + +Consider the following example, +@smallexample +typedef int v4si __attribute__ ((vector_size (16))); +typedef int v8si __attribute__ ((vector_size (32))); + +v8si a = @{1,-2,3,-4,5,-6,7,-8@}; +v4si b = __builtin_shufflevector (a, a, 0, 2, 4, 6); /* b is @{1,3,5,7@} */ +v4si c = @{-2,-4,-6,-8@}; +v8si d = __builtin_shufflevector (c, b, 4, 0, 5, 1, 6, 2, 7, 3); /* d is a */ +@end smallexample + @findex __builtin_convertvector Vector conversion is available using the @code{__builtin_convertvector (vec, vectype)} diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index f06c2711cb7..fb8b43d1ce2 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -4121,6 +4121,12 @@ vectorized_internal_fn_supported_p (internal_fn ifn, tree type) && direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED)); } +void +expand_SHUFFLEVECTOR (internal_fn, gcall *) +{ + gcc_unreachable (); +} + void expand_PHI (internal_fn, gcall *) { diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index daeace7a34e..b2f414d2131 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -405,6 +405,9 @@ DEF_INTERNAL_FN (CO_FRAME, ECF_PURE | ECF_NOTHROW | ECF_LEAF, NULL) /* A NOP function with arbitrary arguments and return value. */ DEF_INTERNAL_FN (NOP, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) +/* Temporary vehicle for __builtin_shufflevector. */ +DEF_INTERNAL_FN (SHUFFLEVECTOR, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) + #undef DEF_INTERNAL_INT_FN #undef DEF_INTERNAL_FLT_FN #undef DEF_INTERNAL_FLT_FLOATN_FN diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h index 5bc5660c1ff..19d0f849a5a 100644 --- a/gcc/internal-fn.h +++ b/gcc/internal-fn.h @@ -233,6 +233,7 @@ extern void expand_addsub_overflow (location_t, tree_code, tree, tree, tree, extern void expand_internal_call (gcall *); extern void expand_internal_call (internal_fn, gcall *); extern void expand_PHI (internal_fn, gcall *); +extern void expand_SHUFFLEVECTOR (internal_fn, gcall *); extern bool vectorized_internal_fn_supported_p (internal_fn, tree); diff --git a/gcc/testsuite/c-c++-common/builtin-shufflevector-2.c b/gcc/testsuite/c-c++-common/builtin-shufflevector-2.c new file mode 100644 index 00000000000..78cec1684fc --- /dev/null +++ b/gcc/testsuite/c-c++-common/builtin-shufflevector-2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ + +typedef long v4di __attribute__((vector_size(4 * sizeof (long)))); +typedef int v4si __attribute__((vector_size(4 * sizeof (int)))); +typedef int v8si __attribute__((vector_size(8 * sizeof (int)))); + +v4si res, a, b; +v4di resl, al, bl; +v8si res8, a8, b8; +void foo (void) +{ + res = __builtin_shufflevector (a, 0, 0, 1, 4, 5); /* { dg-error "must be vectors" } */ + res = __builtin_shufflevector (a, b, 0, 1, 4, 5, 6); /* { dg-error "power of two" } */ + res = __builtin_shufflevector (a, b, 0, 1, 4, 8); /* { dg-error "invalid" } */ + res = __builtin_shufflevector (a, b, 0, 1, -4, 5); /* { dg-error "invalid" } */ + res = __builtin_shufflevector (a, bl, 0, 1, 4, 5); /* { dg-error "same element type" } */ + resl = __builtin_shufflevector (a, b, 0, 1, 4, 5); /* { dg-error "" } incompatible types */ +} diff --git a/gcc/testsuite/c-c++-common/torture/builtin-shufflevector-1.c b/gcc/testsuite/c-c++-common/torture/builtin-shufflevector-1.c new file mode 100644 index 00000000000..c8647364795 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/builtin-shufflevector-1.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ + +typedef long v4di __attribute__((vector_size(4 * sizeof (long)))); +typedef int v4si __attribute__((vector_size(4 * sizeof (int)))); +typedef int v8si __attribute__((vector_size(8 * sizeof (int)))); + +v4si res[5], a, b; +v4di resl, al, bl; +v8si res8[3], a8, b8; +void __attribute__((noipa)) +foo (void) +{ + res[0] = __builtin_shufflevector (a, b, 0, 1, 4, 5); + res[1] = __builtin_shufflevector (a, b, 0, 1, -1, 5); + res8[0] = __builtin_shufflevector (a, b, 0, 1, 2, 2 + 1, 4, 5, 6, 7); + res[2] = __builtin_shufflevector (a8, b8, 0, 8, 1, 9); + res[3] = __builtin_shufflevector (a8, b, 0, 8, 1, 9); + res[4] = __builtin_shufflevector (a, b8, 0, 4, 1, 5); + res8[1] = __builtin_shufflevector (a8, b, 0, 8, 1, 9, 10, 11, 2, 3); + res8[2] = __builtin_shufflevector (a, b8, 0, 4, 1, 5, -1, -1, -1, -1); +} + +#define comp(a, b, n) \ + for (unsigned i = 0; i < n; ++i) \ + if ((a)[i] != (b)[i]) \ + __builtin_abort (); + +int main() +{ + a = (v4si) { 0, 1, 2, 3 }; + b = (v4si) { 4, 5, 6, 7 }; + a8 = (v8si) { 0, 1, 2, 3, 4, 5, 6, 7 }; + b8 = (v8si) { 8, 9, 10, 11, 12, 13, 14, 15 }; + foo (); + comp (res[0], ((v4si) { 0, 1, 4, 5}), 4) + res[1][2] = 9; + comp (res[1], ((v4si) { 0, 1, 9, 5}), 4) + comp (res8[0], ((v8si) { 0, 1, 2, 3, 4, 5, 6, 7 }), 8) + comp (res[2], ((v4si) { 0, 8, 1, 9}), 4) + comp (res[3], ((v4si) { 0, 4, 1, 5}), 4) + comp (res[4], ((v4si) { 0, 8, 1, 9}), 4) + comp (res8[1], ((v8si) { 0, 4, 1, 5, 6, 7, 2, 3 }), 8) + res8[2][4] = 42; + res8[2][5] = 42; + res8[2][6] = 42; + res8[2][7] = 42; + comp (res8[2], ((v8si) { 0, 8, 1, 9, 42, 42, 42, 42 }), 8) + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/builtin-shufflevector-1.C b/gcc/testsuite/g++.dg/ext/builtin-shufflevector-1.C new file mode 100644 index 00000000000..da838e8ca6c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin-shufflevector-1.C @@ -0,0 +1,18 @@ +// { dg-do compile { target c++11 } } + +template +struct shufflevector +{ + static auto shuffle (T1 a, T2 b) + -> decltype (__builtin_shufflevector (a, b, args...)) + { + return __builtin_shufflevector (a, b, args...); + } +}; + +typedef int v4si __attribute__((vector_size (16))); +v4si a, b, c; +int main() +{ + c = shufflevector::shuffle (a, b); +} diff --git a/gcc/testsuite/g++.dg/ext/builtin-shufflevector-2.C b/gcc/testsuite/g++.dg/ext/builtin-shufflevector-2.C new file mode 100644 index 00000000000..c8d096c5295 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin-shufflevector-2.C @@ -0,0 +1,12 @@ +// { dg-do compile } + +typedef double v2df __attribute__((vector_size(2 * sizeof (double)))); + +template +struct Shuffle { + void f(T t, U u, v2df a, v2df b) { + (void)__builtin_shufflevector(t, u, N, M); // { dg-error "invalid" } + } +}; + +template struct Shuffle;