From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 39408 invoked by alias); 7 Jan 2019 08:27:04 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 39394 invoked by uid 89); 7 Jan 2019 08:27:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.9 required=5.0 tests=BAYES_00,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS,TIME_LIMIT_EXCEEDED autolearn=unavailable version=3.3.2 spammy=retain, Cant, Can't, UD:v X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 07 Jan 2019 08:26:53 +0000 Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id CDDE8ABE3; Mon, 7 Jan 2019 08:26:50 +0000 (UTC) Date: Mon, 07 Jan 2019 08:27:00 -0000 From: Richard Biener To: Jakub Jelinek cc: Richard Sandiford , Jason Merrill , "Joseph S. Myers" , Jan Hubicka , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] Add __builtin_convertvector support (PR c++/85052, take 2) In-Reply-To: <20190103222406.GS30353@tucnak> Message-ID: References: <20190103100640.GM30353@tucnak> <20190103110412.GO30353@tucnak> <20190103222406.GS30353@tucnak> User-Agent: Alpine 2.20 (LSU 67 2015-01-07) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-SW-Source: 2019-01/txt/msg00268.txt.bz2 On Thu, 3 Jan 2019, Jakub Jelinek wrote: > On Thu, Jan 03, 2019 at 06:32:44PM +0100, Marc Glisse wrote: > > > That said, not sure if e.g. using an opaque builtin for the conversion that > > > supportable_convert_operation sometimes uses is better over this ifn. > > > What exact optimization opportunities you are looking for if it is lowered > > > earlier? I have the VECTOR_CST folding in place... > > > > I don't know, any kind of optimization we currently do on scalars... For > > conversions between integers and floats, that seems to be very limited, > > maybe combine consecutive casts in rare cases. For sign changes, we have a > > number of transformations in match.pd that are fine with an intermediate > > cast that only changes the sign (I even introduced nop_convert to handle > > vectors at the same time). I guess we could handle this IFN as well. It is > > For the sign only changes (non-narrowing/widening), the FE is already > emitting a VIEW_CONVERT_EXPR instead of the IFN. > > Anyway, here is an updated version of the patch, that: > 1) has doc/extend.texi changes > 2) adds the missing function comment > 3) has the tweak suggested by Richard Sandiford > 4) has implemented 2x narrowing and 2x widening vector support, haven't done > the multi cvt cases yet though > > Bootstrapped/regtested on x86_64-linux and i686-linux. OK for trunk. Thanks, Richard. > 2019-01-03 Jakub Jelinek > > PR c++/85052 > * tree-vect-generic.c: Include insn-config.h and recog.h. > (expand_vector_piecewise): Add defaulted ret_type argument, > if non-NULL, use that in preference to type for the result type. > (expand_vector_parallel): Formatting fix. > (do_vec_conversion, do_vec_narrowing_conversion, > expand_vector_conversion): New functions. > (expand_vector_operations_1): Call expand_vector_conversion > for VEC_CONVERT ifn calls. > * internal-fn.def (VEC_CONVERT): New internal function. > * internal-fn.c (expand_VEC_CONVERT): New function. > * fold-const-call.c (fold_const_vec_convert): New function. > (fold_const_call): Use it for CFN_VEC_CONVERT. > * doc/extend.texi (__builtin_convertvector): Document. > c-family/ > * c-common.h (enum rid): Add RID_BUILTIN_CONVERTVECTOR. > (c_build_vec_convert): Declare. > * c-common.c (c_build_vec_convert): New function. > c/ > * c-parser.c (c_parser_postfix_expression): Parse > __builtin_convertvector. > cp/ > * cp-tree.h (cp_build_vec_convert): Declare. > * parser.c (cp_parser_postfix_expression): Parse > __builtin_convertvector. > * constexpr.c: Include fold-const-call.h. > (cxx_eval_internal_function): Handle IFN_VEC_CONVERT. > (potential_constant_expression_1): Likewise. > * semantics.c (cp_build_vec_convert): New function. > * pt.c (tsubst_copy_and_build): Handle CALL_EXPR to > IFN_VEC_CONVERT. > testsuite/ > * c-c++-common/builtin-convertvector-1.c: New test. > * c-c++-common/torture/builtin-convertvector-1.c: New test. > * g++.dg/ext/builtin-convertvector-1.C: New test. > * g++.dg/cpp0x/constexpr-builtin4.C: New test. > > --- gcc/tree-vect-generic.c.jj 2019-01-02 20:48:25.880725772 +0100 > +++ gcc/tree-vect-generic.c 2019-01-03 17:45:43.005459518 +0100 > @@ -39,6 +39,8 @@ along with GCC; see the file COPYING3. > #include "tree-cfg.h" > #include "tree-vector-builder.h" > #include "vec-perm-indices.h" > +#include "insn-config.h" > +#include "recog.h" /* FIXME: for insn_data */ > > > static void expand_vector_operations_1 (gimple_stmt_iterator *); > @@ -267,7 +269,8 @@ do_negate (gimple_stmt_iterator *gsi, tr > static tree > expand_vector_piecewise (gimple_stmt_iterator *gsi, elem_op_func f, > tree type, tree inner_type, > - tree a, tree b, enum tree_code code) > + tree a, tree b, enum tree_code code, > + tree ret_type = NULL_TREE) > { > vec *v; > tree part_width = TYPE_SIZE (inner_type); > @@ -278,23 +281,27 @@ expand_vector_piecewise (gimple_stmt_ite > int i; > location_t loc = gimple_location (gsi_stmt (*gsi)); > > - if (types_compatible_p (gimple_expr_type (gsi_stmt (*gsi)), type)) > + if (ret_type > + || types_compatible_p (gimple_expr_type (gsi_stmt (*gsi)), type)) > warning_at (loc, OPT_Wvector_operation_performance, > "vector operation will be expanded piecewise"); > else > warning_at (loc, OPT_Wvector_operation_performance, > "vector operation will be expanded in parallel"); > > + if (!ret_type) > + ret_type = type; > vec_alloc (v, (nunits + delta - 1) / delta); > for (i = 0; i < nunits; > i += delta, index = int_const_binop (PLUS_EXPR, index, part_width)) > { > - tree result = f (gsi, inner_type, a, b, index, part_width, code, type); > + tree result = f (gsi, inner_type, a, b, index, part_width, code, > + ret_type); > constructor_elt ce = {NULL_TREE, result}; > v->quick_push (ce); > } > > - return build_constructor (type, v); > + return build_constructor (ret_type, v); > } > > /* Expand a vector operation to scalars with the freedom to use > @@ -302,8 +309,7 @@ expand_vector_piecewise (gimple_stmt_ite > in the vector type. */ > static tree > expand_vector_parallel (gimple_stmt_iterator *gsi, elem_op_func f, tree type, > - tree a, tree b, > - enum tree_code code) > + tree a, tree b, enum tree_code code) > { > tree result, compute_type; > int n_words = tree_to_uhwi (TYPE_SIZE_UNIT (type)) / UNITS_PER_WORD; > @@ -1547,6 +1553,299 @@ expand_vector_scalar_condition (gimple_s > update_stmt (gsi_stmt (*gsi)); > } > > +/* Callback for expand_vector_piecewise to do VEC_CONVERT ifn call > + lowering. If INNER_TYPE is not a vector type, this is a scalar > + fallback. */ > + > +static tree > +do_vec_conversion (gimple_stmt_iterator *gsi, tree inner_type, tree a, > + tree decl, tree bitpos, tree bitsize, > + enum tree_code code, tree type) > +{ > + a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos); > + if (!VECTOR_TYPE_P (inner_type)) > + return gimplify_build1 (gsi, code, TREE_TYPE (type), a); > + if (code == CALL_EXPR) > + { > + gimple *g = gimple_build_call (decl, 1, a); > + tree lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (decl))); > + gimple_call_set_lhs (g, lhs); > + gsi_insert_before (gsi, g, GSI_SAME_STMT); > + return lhs; > + } > + else > + { > + tree outer_type = build_vector_type (TREE_TYPE (type), > + TYPE_VECTOR_SUBPARTS (inner_type)); > + return gimplify_build1 (gsi, code, outer_type, a); > + } > +} > + > +/* Similarly, but for narrowing conversion. */ > + > +static tree > +do_vec_narrow_conversion (gimple_stmt_iterator *gsi, tree inner_type, tree a, > + tree, tree bitpos, tree, enum tree_code code, > + tree type) > +{ > + tree itype = build_vector_type (TREE_TYPE (inner_type), > + exact_div (TYPE_VECTOR_SUBPARTS (inner_type), > + 2)); > + tree b = tree_vec_extract (gsi, itype, a, TYPE_SIZE (itype), bitpos); > + tree c = tree_vec_extract (gsi, itype, a, TYPE_SIZE (itype), > + int_const_binop (PLUS_EXPR, bitpos, > + TYPE_SIZE (itype))); > + tree outer_type = build_vector_type (TREE_TYPE (type), > + TYPE_VECTOR_SUBPARTS (inner_type)); > + return gimplify_build2 (gsi, code, outer_type, b, c); > +} > + > +/* Expand VEC_CONVERT ifn call. */ > + > +static void > +expand_vector_conversion (gimple_stmt_iterator *gsi) > +{ > + gimple *stmt = gsi_stmt (*gsi); > + gimple *g; > + tree lhs = gimple_call_lhs (stmt); > + tree arg = gimple_call_arg (stmt, 0); > + tree decl = NULL_TREE; > + tree ret_type = TREE_TYPE (lhs); > + tree arg_type = TREE_TYPE (arg); > + tree new_rhs, compute_type = TREE_TYPE (arg_type); > + enum tree_code code = NOP_EXPR; > + enum tree_code code1 = ERROR_MARK; > + enum { NARROW, NONE, WIDEN } modifier = NONE; > + optab optab1 = unknown_optab; > + > + gcc_checking_assert (VECTOR_TYPE_P (ret_type) && VECTOR_TYPE_P (arg_type)); > + gcc_checking_assert (tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (ret_type)))); > + gcc_checking_assert (tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (arg_type)))); > + if (INTEGRAL_TYPE_P (TREE_TYPE (ret_type)) > + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg_type))) > + code = FIX_TRUNC_EXPR; > + else if (INTEGRAL_TYPE_P (TREE_TYPE (arg_type)) > + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (ret_type))) > + code = FLOAT_EXPR; > + if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (ret_type))) > + < tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg_type)))) > + modifier = NARROW; > + else if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (ret_type))) > + > tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg_type)))) > + modifier = WIDEN; > + > + if (modifier == NONE && (code == FIX_TRUNC_EXPR || code == FLOAT_EXPR)) > + { > + if (supportable_convert_operation (code, ret_type, arg_type, &decl, > + &code1)) > + { > + if (code1 == CALL_EXPR) > + { > + g = gimple_build_call (decl, 1, arg); > + gimple_call_set_lhs (g, lhs); > + } > + else > + g = gimple_build_assign (lhs, code1, arg); > + gsi_replace (gsi, g, false); > + return; > + } > + /* Can't use get_compute_type here, as supportable_convert_operation > + doesn't necessarily use an optab and needs two arguments. */ > + tree vec_compute_type > + = type_for_widest_vector_mode (TREE_TYPE (arg_type), mov_optab); > + if (vec_compute_type > + && VECTOR_MODE_P (TYPE_MODE (vec_compute_type)) > + && subparts_gt (arg_type, vec_compute_type)) > + { > + unsigned HOST_WIDE_INT nelts > + = constant_lower_bound (TYPE_VECTOR_SUBPARTS (vec_compute_type)); > + while (nelts > 1) > + { > + tree ret1_type = build_vector_type (TREE_TYPE (ret_type), nelts); > + tree arg1_type = build_vector_type (TREE_TYPE (arg_type), nelts); > + if (supportable_convert_operation (code, ret1_type, arg1_type, > + &decl, &code1)) > + { > + new_rhs = expand_vector_piecewise (gsi, do_vec_conversion, > + ret_type, arg1_type, arg, > + decl, code1); > + g = gimple_build_assign (lhs, new_rhs); > + gsi_replace (gsi, g, false); > + return; > + } > + nelts = nelts / 2; > + } > + } > + } > + else if (modifier == NARROW) > + { > + switch (code) > + { > + CASE_CONVERT: > + code1 = VEC_PACK_TRUNC_EXPR; > + optab1 = optab_for_tree_code (code1, arg_type, optab_default); > + break; > + case FIX_TRUNC_EXPR: > + code1 = VEC_PACK_FIX_TRUNC_EXPR; > + /* The signedness is determined from output operand. */ > + optab1 = optab_for_tree_code (code1, ret_type, optab_default); > + break; > + case FLOAT_EXPR: > + code1 = VEC_PACK_FLOAT_EXPR; > + optab1 = optab_for_tree_code (code1, arg_type, optab_default); > + break; > + default: > + gcc_unreachable (); > + } > + > + if (optab1) > + compute_type = get_compute_type (code1, optab1, arg_type); > + enum insn_code icode1; > + if (VECTOR_TYPE_P (compute_type) > + && ((icode1 = optab_handler (optab1, TYPE_MODE (compute_type))) > + != CODE_FOR_nothing) > + && VECTOR_MODE_P (insn_data[icode1].operand[0].mode)) > + { > + tree cretd_type > + = build_vector_type (TREE_TYPE (ret_type), > + TYPE_VECTOR_SUBPARTS (compute_type) * 2); > + if (insn_data[icode1].operand[0].mode == TYPE_MODE (cretd_type)) > + { > + if (compute_type == arg_type) > + { > + new_rhs = gimplify_build2 (gsi, code1, cretd_type, > + arg, build_zero_cst (arg_type)); > + new_rhs = tree_vec_extract (gsi, ret_type, new_rhs, > + TYPE_SIZE (ret_type), > + bitsize_int (0)); > + g = gimple_build_assign (lhs, new_rhs); > + gsi_replace (gsi, g, false); > + return; > + } > + tree dcompute_type > + = build_vector_type (TREE_TYPE (compute_type), > + TYPE_VECTOR_SUBPARTS (compute_type) * 2); > + if (TYPE_MAIN_VARIANT (dcompute_type) > + == TYPE_MAIN_VARIANT (arg_type)) > + new_rhs = do_vec_narrow_conversion (gsi, dcompute_type, arg, > + NULL_TREE, bitsize_int (0), > + NULL_TREE, code1, > + ret_type); > + else > + new_rhs = expand_vector_piecewise (gsi, > + do_vec_narrow_conversion, > + arg_type, dcompute_type, > + arg, NULL_TREE, code1, > + ret_type); > + g = gimple_build_assign (lhs, new_rhs); > + gsi_replace (gsi, g, false); > + return; > + } > + } > + } > + else if (modifier == WIDEN) > + { > + enum tree_code code2 = ERROR_MARK; > + optab optab2 = unknown_optab; > + switch (code) > + { > + CASE_CONVERT: > + code1 = VEC_UNPACK_LO_EXPR; > + code2 = VEC_UNPACK_HI_EXPR; > + break; > + case FIX_TRUNC_EXPR: > + code1 = VEC_UNPACK_FIX_TRUNC_LO_EXPR; > + code2 = VEC_UNPACK_FIX_TRUNC_HI_EXPR; > + break; > + case FLOAT_EXPR: > + code1 = VEC_UNPACK_FLOAT_LO_EXPR; > + code2 = VEC_UNPACK_FLOAT_HI_EXPR; > + break; > + default: > + gcc_unreachable (); > + } > + if (BYTES_BIG_ENDIAN) > + std::swap (code1, code2); > + > + if (code == FIX_TRUNC_EXPR) > + { > + /* The signedness is determined from output operand. */ > + optab1 = optab_for_tree_code (code1, ret_type, optab_default); > + optab2 = optab_for_tree_code (code2, ret_type, optab_default); > + } > + else > + { > + optab1 = optab_for_tree_code (code1, arg_type, optab_default); > + optab2 = optab_for_tree_code (code2, arg_type, optab_default); > + } > + > + if (optab1 && optab2) > + compute_type = get_compute_type (code1, optab1, arg_type); > + > + enum insn_code icode1, icode2; > + if (VECTOR_TYPE_P (compute_type) > + && ((icode1 = optab_handler (optab1, TYPE_MODE (compute_type))) > + != CODE_FOR_nothing) > + && ((icode2 = optab_handler (optab2, TYPE_MODE (compute_type))) > + != CODE_FOR_nothing) > + && VECTOR_MODE_P (insn_data[icode1].operand[0].mode) > + && (insn_data[icode1].operand[0].mode > + == insn_data[icode2].operand[0].mode)) > + { > + poly_uint64 nunits > + = exact_div (TYPE_VECTOR_SUBPARTS (compute_type), 2); > + tree cretd_type = build_vector_type (TREE_TYPE (ret_type), nunits); > + if (insn_data[icode1].operand[0].mode == TYPE_MODE (cretd_type)) > + { > + vec *v; > + tree part_width = TYPE_SIZE (compute_type); > + tree index = bitsize_int (0); > + int nunits = nunits_for_known_piecewise_op (arg_type); > + int delta = tree_to_uhwi (part_width) > + / tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg_type))); > + int i; > + location_t loc = gimple_location (gsi_stmt (*gsi)); > + > + if (compute_type != arg_type) > + warning_at (loc, OPT_Wvector_operation_performance, > + "vector operation will be expanded piecewise"); > + else > + { > + nunits = 1; > + delta = 1; > + } > + > + vec_alloc (v, (nunits + delta - 1) / delta * 2); > + for (i = 0; i < nunits; > + i += delta, index = int_const_binop (PLUS_EXPR, index, > + part_width)) > + { > + tree a = arg; > + if (compute_type != arg_type) > + a = tree_vec_extract (gsi, compute_type, a, part_width, > + index); > + tree result = gimplify_build1 (gsi, code1, cretd_type, a); > + constructor_elt ce = { NULL_TREE, result }; > + v->quick_push (ce); > + ce.value = gimplify_build1 (gsi, code2, cretd_type, a); > + v->quick_push (ce); > + } > + > + new_rhs = build_constructor (ret_type, v); > + g = gimple_build_assign (lhs, new_rhs); > + gsi_replace (gsi, g, false); > + return; > + } > + } > + } > + > + new_rhs = expand_vector_piecewise (gsi, do_vec_conversion, arg_type, > + TREE_TYPE (arg_type), arg, > + NULL_TREE, code, ret_type); > + g = gimple_build_assign (lhs, new_rhs); > + gsi_replace (gsi, g, false); > +} > + > /* Process one statement. If we identify a vector operation, expand it. */ > > static void > @@ -1561,7 +1860,11 @@ expand_vector_operations_1 (gimple_stmt_ > /* Only consider code == GIMPLE_ASSIGN. */ > gassign *stmt = dyn_cast (gsi_stmt (*gsi)); > if (!stmt) > - return; > + { > + if (gimple_call_internal_p (gsi_stmt (*gsi), IFN_VEC_CONVERT)) > + expand_vector_conversion (gsi); > + return; > + } > > code = gimple_assign_rhs_code (stmt); > rhs_class = get_gimple_rhs_class (code); > --- gcc/internal-fn.def.jj 2019-01-02 20:48:26.358718031 +0100 > +++ gcc/internal-fn.def 2019-01-03 14:51:51.044132528 +0100 > @@ -296,6 +296,7 @@ DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST > DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (TSAN_FUNC_EXIT, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (VA_ARG, ECF_NOTHROW | ECF_LEAF, NULL) > +DEF_INTERNAL_FN (VEC_CONVERT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) > > /* An unduplicable, uncombinable function. Generally used to preserve > a CFG property in the face of jump threading, tail merging or > --- gcc/internal-fn.c.jj 2019-01-02 20:48:26.411717172 +0100 > +++ gcc/internal-fn.c 2019-01-03 14:51:51.045132512 +0100 > @@ -2581,6 +2581,15 @@ expand_VA_ARG (internal_fn, gcall *) > gcc_unreachable (); > } > > +/* IFN_VEC_CONVERT is supposed to be expanded at pass_lower_vector. So this > + dummy function should never be called. */ > + > +static void > +expand_VEC_CONVERT (internal_fn, gcall *) > +{ > + gcc_unreachable (); > +} > + > /* Expand the IFN_UNIQUE function according to its first argument. */ > > static void > --- gcc/fold-const-call.c.jj 2019-01-02 20:48:25.888725643 +0100 > +++ gcc/fold-const-call.c 2019-01-03 14:51:51.046132495 +0100 > @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. > #include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO. */ > #include "builtins.h" > #include "gimple-expr.h" > +#include "tree-vector-builder.h" > > /* Functions that test for certain constant types, abstracting away the > decision about whether to check for overflow. */ > @@ -645,6 +646,40 @@ fold_const_reduction (tree type, tree ar > return res; > } > > +/* Fold a call to IFN_VEC_CONVERT (ARG) returning TYPE. */ > + > +static tree > +fold_const_vec_convert (tree ret_type, tree arg) > +{ > + enum tree_code code = NOP_EXPR; > + tree arg_type = TREE_TYPE (arg); > + if (TREE_CODE (arg) != VECTOR_CST) > + return NULL_TREE; > + > + gcc_checking_assert (VECTOR_TYPE_P (ret_type) && VECTOR_TYPE_P (arg_type)); > + > + if (INTEGRAL_TYPE_P (TREE_TYPE (ret_type)) > + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg_type))) > + code = FIX_TRUNC_EXPR; > + else if (INTEGRAL_TYPE_P (TREE_TYPE (arg_type)) > + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (ret_type))) > + code = FLOAT_EXPR; > + > + tree_vector_builder elts; > + elts.new_unary_operation (ret_type, arg, true); > + unsigned int count = elts.encoded_nelts (); > + for (unsigned int i = 0; i < count; ++i) > + { > + tree elt = fold_unary (code, TREE_TYPE (ret_type), > + VECTOR_CST_ELT (arg, i)); > + if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) > + return NULL_TREE; > + elts.quick_push (elt); > + } > + > + return elts.build (); > +} > + > /* Try to evaluate: > > *RESULT = FN (*ARG) > @@ -1232,6 +1267,9 @@ fold_const_call (combined_fn fn, tree ty > case CFN_REDUC_XOR: > return fold_const_reduction (type, arg, BIT_XOR_EXPR); > > + case CFN_VEC_CONVERT: > + return fold_const_vec_convert (type, arg); > + > default: > return fold_const_call_1 (fn, type, arg); > } > --- gcc/doc/extend.texi.jj 2019-01-01 12:37:51.698408227 +0100 > +++ gcc/doc/extend.texi 2019-01-03 15:12:13.393986153 +0100 > @@ -10594,6 +10594,33 @@ to and from other datatypes of the same > You cannot operate between vectors of different lengths or different > signedness without a cast. > > +@findex __builtin_convertvector > +Vector conversion is available using the > +@code{__builtin_convertvector (vec, vectype)} > +function. @var{vec} must be an expression with integral or floating > +vector type and @var{vectype} an integral or floating vector type with the > +same number of elements. The result has @var{vectype} type and value of > +a C cast of every element of @var{vec} to the element type of @var{vectype}. > + > +Consider the following example, > +@smallexample > +typedef int v4si __attribute__ ((vector_size (16))); > +typedef float v4sf __attribute__ ((vector_size (16))); > +typedef double v4df __attribute__ ((vector_size (32))); > +typedef unsigned long long v4di __attribute__ ((vector_size (32))); > + > +v4si a = @{1,-2,3,-4@}; > +v4sf b = @{1.5f,-2.5f,3.f,7.f@}; > +v4di c = @{1ULL,5ULL,0ULL,10ULL@}; > +v4sf d = __builtin_convertvector (a, v4sf); /* d is @{1.f,-2.f,3.f,-4.f@} */ > +/* Equivalent of: > + v4sf d = @{ (float)a[0], (float)a[1], (float)a[2], (float)a[3] @}; */ > +v4df e = __builtin_convertvector (a, v4df); /* e is @{1.,-2.,3.,-4.@} */ > +v4df f = __builtin_convertvector (b, v4df); /* f is @{1.5,-2.5,3.,7.@} */ > +v4si g = __builtin_convertvector (f, v4si); /* g is @{1,-2,3,7@} */ > +v4si h = __builtin_convertvector (c, v4si); /* h is @{1,5,0,10@} */ > +@end smallexample > + > @node Offsetof > @section Support for @code{offsetof} > @findex __builtin_offsetof > --- gcc/c-family/c-common.h.jj 2019-01-02 20:48:26.000723830 +0100 > +++ gcc/c-family/c-common.h 2019-01-03 14:51:51.046132495 +0100 > @@ -102,7 +102,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_TGMATH, > + RID_BUILTIN_CONVERTVECTOR, RID_BUILTIN_TGMATH, > RID_BUILTIN_HAS_ATTRIBUTE, > RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, > > @@ -1001,6 +1001,7 @@ 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_vec_convert (location_t, tree, location_t, tree, bool = true); > > extern void init_c_lex (void); > > --- gcc/c-family/c-common.c.jj 2019-01-02 20:48:25.958724510 +0100 > +++ gcc/c-family/c-common.c 2019-01-03 14:51:51.048132462 +0100 > @@ -376,6 +376,7 @@ const struct c_common_resword c_common_r > RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY }, > { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, > { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY }, > + { "__builtin_convertvector", RID_BUILTIN_CONVERTVECTOR, 0 }, > { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 }, > { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY }, > { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 }, > @@ -1070,6 +1071,70 @@ c_build_vec_perm_expr (location_t loc, t > ret = c_wrap_maybe_const (ret, true); > > return ret; > +} > + > +/* Build a VEC_CONVERT ifn for __builtin_convertvector builtin. */ > + > +tree > +c_build_vec_convert (location_t loc1, tree expr, location_t loc2, tree type, > + bool complain) > +{ > + if (error_operand_p (type)) > + return error_mark_node; > + if (error_operand_p (expr)) > + return error_mark_node; > + > + if (!VECTOR_INTEGER_TYPE_P (TREE_TYPE (expr)) > + && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (expr))) > + { > + if (complain) > + error_at (loc1, "%<__builtin_convertvector%> first argument must " > + "be an integer or floating vector"); > + return error_mark_node; > + } > + > + if (!VECTOR_INTEGER_TYPE_P (type) && !VECTOR_FLOAT_TYPE_P (type)) > + { > + if (complain) > + error_at (loc2, "%<__builtin_convertvector%> second argument must " > + "be an integer or floating vector type"); > + return error_mark_node; > + } > + > + if (maybe_ne (TYPE_VECTOR_SUBPARTS (TREE_TYPE (expr)), > + TYPE_VECTOR_SUBPARTS (type))) > + { > + if (complain) > + error_at (loc1, "%<__builtin_convertvector%> number of elements " > + "of the first argument vector and the second argument " > + "vector type should be the same"); > + return error_mark_node; > + } > + > + if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr))) > + == TYPE_MAIN_VARIANT (TREE_TYPE (type))) > + || (VECTOR_INTEGER_TYPE_P (TREE_TYPE (expr)) > + && VECTOR_INTEGER_TYPE_P (type) > + && (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (expr))) > + == TYPE_PRECISION (TREE_TYPE (type))))) > + return build1_loc (loc1, VIEW_CONVERT_EXPR, type, expr); > + > + bool wrap = true; > + bool maybe_const = false; > + tree ret; > + if (!c_dialect_cxx ()) > + { > + /* Avoid C_MAYBE_CONST_EXPRs inside of VEC_CONVERT argument. */ > + expr = c_fully_fold (expr, false, &maybe_const); > + wrap &= maybe_const; > + } > + > + ret = build_call_expr_internal_loc (loc1, IFN_VEC_CONVERT, type, 1, expr); > + > + if (!wrap) > + ret = c_wrap_maybe_const (ret, true); > + > + return ret; > } > > /* Like tree.c:get_narrower, but retain conversion from C++0x scoped enum > --- gcc/c/c-parser.c.jj 2019-01-02 20:48:25.460732573 +0100 > +++ gcc/c/c-parser.c 2019-01-03 14:51:51.053132380 +0100 > @@ -8038,6 +8038,7 @@ enum tgmath_parm_kind > __builtin_shuffle ( assignment-expression , > assignment-expression , > assignment-expression, ) > + __builtin_convertvector ( assignment-expression , type-name ) > > offsetof-member-designator: > identifier > @@ -9113,17 +9114,14 @@ c_parser_postfix_expression (c_parser *p > *p = convert_lvalue_to_rvalue (loc, *p, true, true); > > if (vec_safe_length (cexpr_list) == 2) > - expr.value = > - c_build_vec_perm_expr > - (loc, (*cexpr_list)[0].value, > - NULL_TREE, (*cexpr_list)[1].value); > + expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, > + NULL_TREE, > + (*cexpr_list)[1].value); > > else if (vec_safe_length (cexpr_list) == 3) > - expr.value = > - c_build_vec_perm_expr > - (loc, (*cexpr_list)[0].value, > - (*cexpr_list)[1].value, > - (*cexpr_list)[2].value); > + expr.value = c_build_vec_perm_expr (loc, (*cexpr_list)[0].value, > + (*cexpr_list)[1].value, > + (*cexpr_list)[2].value); > else > { > error_at (loc, "wrong number of arguments to " > @@ -9133,6 +9131,41 @@ c_parser_postfix_expression (c_parser *p > set_c_expr_source_range (&expr, loc, close_paren_loc); > break; > } > + case RID_BUILTIN_CONVERTVECTOR: > + { > + location_t start_loc = loc; > + c_parser_consume_token (parser); > + matching_parens parens; > + if (!parens.require_open (parser)) > + { > + expr.set_error (); > + break; > + } > + e1 = c_parser_expr_no_commas (parser, NULL); > + mark_exp_read (e1.value); > + if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) > + { > + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); > + expr.set_error (); > + break; > + } > + loc = c_parser_peek_token (parser)->location; > + t1 = c_parser_type_name (parser); > + location_t end_loc = c_parser_peek_token (parser)->get_finish (); > + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, > + "expected %<)%>"); > + if (t1 == NULL) > + expr.set_error (); > + else > + { > + tree type_expr = NULL_TREE; > + expr.value = c_build_vec_convert (start_loc, e1.value, loc, > + groktypename (t1, &type_expr, > + NULL)); > + set_c_expr_source_range (&expr, start_loc, end_loc); > + } > + } > + break; > case RID_AT_SELECTOR: > { > gcc_assert (c_dialect_objc ()); > --- gcc/cp/cp-tree.h.jj 2019-01-02 20:48:25.716728429 +0100 > +++ gcc/cp/cp-tree.h 2019-01-03 14:51:51.053132380 +0100 > @@ -7142,6 +7142,8 @@ extern bool is_lambda_ignored_entity > extern bool lambda_static_thunk_p (tree); > extern tree finish_builtin_launder (location_t, tree, > tsubst_flags_t); > +extern tree cp_build_vec_convert (tree, location_t, tree, > + tsubst_flags_t); > extern void start_lambda_scope (tree); > extern void record_lambda_scope (tree); > extern void record_null_lambda_scope (tree); > --- gcc/cp/parser.c.jj 2019-01-02 20:48:25.695728768 +0100 > +++ gcc/cp/parser.c 2019-01-03 14:51:51.057132315 +0100 > @@ -7031,6 +7031,32 @@ cp_parser_postfix_expression (cp_parser > break; > } > > + case RID_BUILTIN_CONVERTVECTOR: > + { > + tree expression; > + tree type; > + /* Consume the `__builtin_convertvector' token. */ > + cp_lexer_consume_token (parser->lexer); > + /* Look for the opening `('. */ > + matching_parens parens; > + parens.require_open (parser); > + /* Now, parse the assignment-expression. */ > + expression = cp_parser_assignment_expression (parser); > + /* Look for the `,'. */ > + cp_parser_require (parser, CPP_COMMA, RT_COMMA); > + location_t type_location > + = cp_lexer_peek_token (parser->lexer)->location; > + /* Parse the type-id. */ > + { > + type_id_in_expr_sentinel s (parser); > + type = cp_parser_type_id (parser); > + } > + /* Look for the closing `)'. */ > + parens.require_close (parser); > + return cp_build_vec_convert (expression, type_location, type, > + tf_warning_or_error); > + } > + > default: > { > tree type; > --- gcc/cp/constexpr.c.jj 2019-01-02 20:48:25.624729917 +0100 > +++ gcc/cp/constexpr.c 2019-01-03 14:51:51.057132315 +0100 > @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. > #include "ubsan.h" > #include "gimple-fold.h" > #include "timevar.h" > +#include "fold-const-call.h" > > static bool verify_constant (tree, bool, bool *, bool *); > #define VERIFY_CONSTANT(X) \ > @@ -1449,6 +1450,20 @@ cxx_eval_internal_function (const conste > return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), > false, non_constant_p, overflow_p); > > + case IFN_VEC_CONVERT: > + { > + tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), > + false, non_constant_p, > + overflow_p); > + if (TREE_CODE (arg) == VECTOR_CST) > + return fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg); > + else > + { > + *non_constant_p = true; > + return t; > + } > + } > + > default: > if (!ctx->quiet) > error_at (cp_expr_loc_or_loc (t, input_location), > @@ -5623,7 +5638,9 @@ potential_constant_expression_1 (tree t, > case IFN_SUB_OVERFLOW: > case IFN_MUL_OVERFLOW: > case IFN_LAUNDER: > + case IFN_VEC_CONVERT: > bail = false; > + break; > > default: > break; > --- gcc/cp/semantics.c.jj 2019-01-02 20:48:25.802727035 +0100 > +++ gcc/cp/semantics.c 2019-01-03 14:51:51.058132298 +0100 > @@ -9933,4 +9933,26 @@ finish_builtin_launder (location_t loc, > TREE_TYPE (arg), 1, arg); > } > > +/* Finish __builtin_convertvector (arg, type). */ > + > +tree > +cp_build_vec_convert (tree arg, location_t loc, tree type, > + tsubst_flags_t complain) > +{ > + if (error_operand_p (type)) > + return error_mark_node; > + if (error_operand_p (arg)) > + return error_mark_node; > + > + tree ret = NULL_TREE; > + if (!type_dependent_expression_p (arg) && !dependent_type_p (type)) > + ret = c_build_vec_convert (cp_expr_loc_or_loc (arg, input_location), arg, > + loc, type, (complain & tf_error) != 0); > + > + if (!processing_template_decl) > + return ret; > + > + return build_call_expr_internal_loc (loc, IFN_VEC_CONVERT, type, 1, arg); > +} > + > #include "gt-cp-semantics.h" > --- gcc/cp/pt.c.jj 2019-01-02 20:48:25.592730436 +0100 > +++ gcc/cp/pt.c 2019-01-03 14:51:51.060132265 +0100 > @@ -18813,6 +18813,27 @@ tsubst_copy_and_build (tree t, > (*call_args)[0], complain); > break; > > + case IFN_VEC_CONVERT: > + gcc_assert (nargs == 1); > + if (vec_safe_length (call_args) != 1) > + { > + error_at (cp_expr_loc_or_loc (t, input_location), > + "wrong number of arguments to " > + "%<__builtin_convertvector%>"); > + ret = error_mark_node; > + break; > + } > + ret = cp_build_vec_convert ((*call_args)[0], input_location, > + tsubst (TREE_TYPE (t), args, > + complain, in_decl), > + complain); > + if (TREE_CODE (ret) == VIEW_CONVERT_EXPR) > + { > + release_tree_vector (call_args); > + RETURN (ret); > + } > + break; > + > default: > /* Unsupported internal function with arguments. */ > gcc_unreachable (); > --- gcc/testsuite/c-c++-common/builtin-convertvector-1.c.jj 2019-01-03 14:51:51.060132265 +0100 > +++ gcc/testsuite/c-c++-common/builtin-convertvector-1.c 2019-01-03 14:51:51.060132265 +0100 > @@ -0,0 +1,15 @@ > +typedef int v8si __attribute__((vector_size (8 * sizeof (int)))); > +typedef long long v4di __attribute__((vector_size (4 * sizeof (long long)))); > + > +void > +foo (v8si *x, v4di *y, int z) > +{ > + __builtin_convertvector (*y, v8si); /* { dg-error "number of elements of the first argument vector and the second argument vector type should be the same" } */ > + __builtin_convertvector (*x, v4di); /* { dg-error "number of elements of the first argument vector and the second argument vector type should be the same" } */ > + __builtin_convertvector (*x, int); /* { dg-error "second argument must be an integer or floating vector type" } */ > + __builtin_convertvector (z, v4di); /* { dg-error "first argument must be an integer or floating vector" } */ > + __builtin_convertvector (); /* { dg-error "expected" } */ > + __builtin_convertvector (*x); /* { dg-error "expected" } */ > + __builtin_convertvector (*x, *y); /* { dg-error "expected" } */ > + __builtin_convertvector (*x, v8si, 1);/* { dg-error "expected" } */ > +} > --- gcc/testsuite/c-c++-common/torture/builtin-convertvector-1.c.jj 2019-01-03 14:51:51.060132265 +0100 > +++ gcc/testsuite/c-c++-common/torture/builtin-convertvector-1.c 2019-01-03 14:51:51.060132265 +0100 > @@ -0,0 +1,131 @@ > +extern > +#ifdef __cplusplus > +"C" > +#endif > +void abort (void); > +typedef int v4si __attribute__((vector_size (4 * sizeof (int)))); > +typedef unsigned int v4usi __attribute__((vector_size (4 * sizeof (unsigned int)))); > +typedef float v4sf __attribute__((vector_size (4 * sizeof (float)))); > +typedef double v4df __attribute__((vector_size (4 * sizeof (double)))); > +typedef long long v256di __attribute__((vector_size (256 * sizeof (long long)))); > +typedef double v256df __attribute__((vector_size (256 * sizeof (double)))); > + > +void > +f1 (v4usi *x, v4si *y) > +{ > + *y = __builtin_convertvector (*x, v4si); > +} > + > +void > +f2 (v4sf *x, v4si *y) > +{ > + *y = __builtin_convertvector (*x, v4si); > +} > + > +void > +f3 (v4si *x, v4sf *y) > +{ > + *y = __builtin_convertvector (*x, v4sf); > +} > + > +void > +f4 (v4df *x, v4si *y) > +{ > + *y = __builtin_convertvector (*x, v4si); > +} > + > +void > +f5 (v4si *x, v4df *y) > +{ > + *y = __builtin_convertvector (*x, v4df); > +} > + > +void > +f6 (v256df *x, v256di *y) > +{ > + *y = __builtin_convertvector (*x, v256di); > +} > + > +void > +f7 (v256di *x, v256df *y) > +{ > + *y = __builtin_convertvector (*x, v256df); > +} > + > +void > +f8 (v4df *x) > +{ > + v4si a = { 1, 2, -3, -4 }; > + *x = __builtin_convertvector (a, v4df); > +} > + > +int > +main () > +{ > + union U1 { v4si v; int a[4]; } u1; > + union U2 { v4usi v; unsigned int a[4]; } u2; > + union U3 { v4sf v; float a[4]; } u3; > + union U4 { v4df v; double a[4]; } u4; > + union U5 { v256di v; long long a[256]; } u5; > + union U6 { v256df v; double a[256]; } u6; > + int i; > + for (i = 0; i < 4; i++) > + u2.a[i] = i * 2; > + f1 (&u2.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != i * 2) > + abort (); > + else > + u3.a[i] = i - 2.25f; > + f2 (&u3.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != (i == 3 ? 0 : i - 2)) > + abort (); > + else > + u3.a[i] = i + 0.75f; > + f2 (&u3.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != i) > + abort (); > + else > + u1.a[i] = 7 * i - 5; > + f3 (&u1.v, &u3.v); > + for (i = 0; i < 4; i++) > + if (u3.a[i] != 7 * i - 5) > + abort (); > + else > + u4.a[i] = i - 2.25; > + f4 (&u4.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != (i == 3 ? 0 : i - 2)) > + abort (); > + else > + u4.a[i] = i + 0.75; > + f4 (&u4.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != i) > + abort (); > + else > + u1.a[i] = 7 * i - 5; > + f5 (&u1.v, &u4.v); > + for (i = 0; i < 4; i++) > + if (u4.a[i] != 7 * i - 5) > + abort (); > + for (i = 0; i < 256; i++) > + u6.a[i] = i - 128.25; > + f6 (&u6.v, &u5.v); > + for (i = 0; i < 256; i++) > + if (u5.a[i] != i - 128 - (i > 128)) > + abort (); > + else > + u5.a[i] = i - 128; > + f7 (&u5.v, &u6.v); > + for (i = 0; i < 256; i++) > + if (u6.a[i] != i - 128) > + abort (); > + f8 (&u4.v); > + for (i = 0; i < 4; i++) > + if (u4.a[i] != (i >= 2 ? -1 - i : i + 1)) > + abort (); > + return 0; > +} > --- gcc/testsuite/g++.dg/ext/builtin-convertvector-1.C.jj 2019-01-03 14:51:51.061132249 +0100 > +++ gcc/testsuite/g++.dg/ext/builtin-convertvector-1.C 2019-01-03 14:51:51.061132249 +0100 > @@ -0,0 +1,137 @@ > +// { dg-do run } > + > +extern "C" void abort (); > +typedef int v4si __attribute__((vector_size (4 * sizeof (int)))); > +typedef unsigned int v4usi __attribute__((vector_size (4 * sizeof (unsigned int)))); > +typedef float v4sf __attribute__((vector_size (4 * sizeof (float)))); > +typedef double v4df __attribute__((vector_size (4 * sizeof (double)))); > +typedef long long v256di __attribute__((vector_size (256 * sizeof (long long)))); > +typedef double v256df __attribute__((vector_size (256 * sizeof (double)))); > + > +template > +void > +f1 (v4usi *x, v4si *y) > +{ > + *y = __builtin_convertvector (*x, v4si); > +} > + > +template > +void > +f2 (T *x, v4si *y) > +{ > + *y = __builtin_convertvector (*x, v4si); > +} > + > +template > +void > +f3 (v4si *x, T *y) > +{ > + *y = __builtin_convertvector (*x, T); > +} > + > +template > +void > +f4 (v4df *x, v4si *y) > +{ > + *y = __builtin_convertvector (*x, v4si); > +} > + > +template > +void > +f5 (T *x, U *y) > +{ > + *y = __builtin_convertvector (*x, U); > +} > + > +template > +void > +f6 (v256df *x, T *y) > +{ > + *y = __builtin_convertvector (*x, T); > +} > + > +template > +void > +f7 (v256di *x, v256df *y) > +{ > + *y = __builtin_convertvector (*x, v256df); > +} > + > +template > +void > +f8 (v4df *x) > +{ > + v4si a = { 1, 2, -3, -4 }; > + *x = __builtin_convertvector (a, v4df); > +} > + > +int > +main () > +{ > + union U1 { v4si v; int a[4]; } u1; > + union U2 { v4usi v; unsigned int a[4]; } u2; > + union U3 { v4sf v; float a[4]; } u3; > + union U4 { v4df v; double a[4]; } u4; > + union U5 { v256di v; long long a[256]; } u5; > + union U6 { v256df v; double a[256]; } u6; > + int i; > + for (i = 0; i < 4; i++) > + u2.a[i] = i * 2; > + f1<0> (&u2.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != i * 2) > + abort (); > + else > + u3.a[i] = i - 2.25f; > + f2 (&u3.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != (i == 3 ? 0 : i - 2)) > + abort (); > + else > + u3.a[i] = i + 0.75f; > + f2 (&u3.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != i) > + abort (); > + else > + u1.a[i] = 7 * i - 5; > + f3 (&u1.v, &u3.v); > + for (i = 0; i < 4; i++) > + if (u3.a[i] != 7 * i - 5) > + abort (); > + else > + u4.a[i] = i - 2.25; > + f4<12> (&u4.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != (i == 3 ? 0 : i - 2)) > + abort (); > + else > + u4.a[i] = i + 0.75; > + f4<13> (&u4.v, &u1.v); > + for (i = 0; i < 4; i++) > + if (u1.a[i] != i) > + abort (); > + else > + u1.a[i] = 7 * i - 5; > + f5 (&u1.v, &u4.v); > + for (i = 0; i < 4; i++) > + if (u4.a[i] != 7 * i - 5) > + abort (); > + for (i = 0; i < 256; i++) > + u6.a[i] = i - 128.25; > + f6 (&u6.v, &u5.v); > + for (i = 0; i < 256; i++) > + if (u5.a[i] != i - 128 - (i > 128)) > + abort (); > + else > + u5.a[i] = i - 128; > + f7<-1> (&u5.v, &u6.v); > + for (i = 0; i < 256; i++) > + if (u6.a[i] != i - 128) > + abort (); > + f8<5> (&u4.v); > + for (i = 0; i < 4; i++) > + if (u4.a[i] != (i >= 2 ? -1 - i : i + 1)) > + abort (); > + return 0; > +} > --- gcc/testsuite/g++.dg/cpp0x/constexpr-builtin4.C.jj 2019-01-03 14:51:51.061132249 +0100 > +++ gcc/testsuite/g++.dg/cpp0x/constexpr-builtin4.C 2019-01-03 14:51:51.061132249 +0100 > @@ -0,0 +1,17 @@ > +// { dg-do compile { target c++11 } } > +// { dg-additional-options "-Wno-psabi" } > + > +typedef int v4si __attribute__((vector_size (4 * sizeof (int)))); > +typedef float v4sf __attribute__((vector_size (4 * sizeof (float)))); > +constexpr v4sf a = __builtin_convertvector (v4si { 1, 2, -3, -4 }, v4sf); > + > +constexpr v4sf > +foo (v4si x) > +{ > + return __builtin_convertvector (x, v4sf); > +} > + > +constexpr v4sf b = foo (v4si { 3, 4, -1, -2 }); > + > +static_assert (a[0] == 1.0f && a[1] == 2.0f && a[2] == -3.0f && a[3] == -4.0f, ""); > +static_assert (b[0] == 3.0f && b[1] == 4.0f && b[2] == -1.0f && b[3] == -2.0f, ""); > > > Jakub > > -- Richard Biener SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)