From patchwork Thu Jan 3 22:24:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1020533 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-493360-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="gyfX1qpr"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43W2Y11Hrxz9s3l for ; Fri, 4 Jan 2019 09:25:08 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:references:mime-version :content-type:in-reply-to; q=dns; s=default; b=VsogvAI8HGCWK+JWT GjokEzEAfwXNj/w1xXPXUS+xGAEijZ4p5lxkj+kXCRUmNwoF96b3tega3ak1T7cA eE3eyh2yOp2JOyc1rxbDIlwxlnJKwMTgsVxytpvzC1Kwa4JbRix8yyehRB+QAKF8 afK/9xTEN05CL8OCXGV2Gx0Bh4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:references:mime-version :content-type:in-reply-to; s=default; bh=QdEArwfdPb1FAWbbpZMgHTb jf6I=; b=gyfX1qprsqpFu81d+jVm/tZpPFwfI76N2tJIBR32OXCDonMB8qIv5l7 B4QGbXFe1h1mOa8Q9Lxf1TdRIdPStPPnDieTMgaLe/pZ5nl9tu/ZHJzzjMgn+xKu 4g22JX4J28yLUolkUgUw27KyvWQk7++WhjhnNP90hJ0jhtrWr2n4= Received: (qmail 72293 invoked by alias); 3 Jan 2019 22:24:47 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 72016 invoked by uid 89); 3 Jan 2019 22:24:33 -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_HELO_PASS, TIME_LIMIT_EXCEEDED autolearn=unavailable version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 03 Jan 2019 22:24:23 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DE48C88318; Thu, 3 Jan 2019 22:24:12 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-116-18.ams2.redhat.com [10.36.116.18]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0979A5D757; Thu, 3 Jan 2019 22:24:11 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id x03MO9Vd031428; Thu, 3 Jan 2019 23:24:09 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id x03MO6lc031427; Thu, 3 Jan 2019 23:24:06 +0100 Date: Thu, 3 Jan 2019 23:24:06 +0100 From: Jakub Jelinek To: Richard Biener , Richard Sandiford , Jason Merrill , "Joseph S. Myers" , Jan Hubicka Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] Add __builtin_convertvector support (PR c++/85052, take 2) Message-ID: <20190103222406.GS30353@tucnak> Reply-To: Jakub Jelinek References: <20190103100640.GM30353@tucnak> <20190103110412.GO30353@tucnak> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) X-IsSubscribed: yes 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. 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. Jakub --- 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, "");