From d8fcab689435a29dba2862693689c624b257d1bf Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 7 Jan 2019 09:49:08 +0100 Subject: [PATCH] re PR c++/85052 (Implement support for clang's __builtin_convertvector) 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. From-SVN: r267632 --- gcc/ChangeLog | 17 + gcc/c-family/ChangeLog | 7 + gcc/c-family/c-common.c | 65 ++++ gcc/c-family/c-common.h | 3 +- gcc/c/ChangeLog | 6 + gcc/c/c-parser.c | 51 ++- gcc/cp/ChangeLog | 13 + gcc/cp/constexpr.c | 17 + gcc/cp/cp-tree.h | 2 + gcc/cp/parser.c | 26 ++ gcc/cp/pt.c | 21 ++ gcc/cp/semantics.c | 22 ++ gcc/doc/extend.texi | 27 ++ gcc/fold-const-call.c | 38 +++ gcc/internal-fn.c | 9 + gcc/internal-fn.def | 1 + gcc/testsuite/ChangeLog | 8 + .../c-c++-common/builtin-convertvector-1.c | 15 + .../torture/builtin-convertvector-1.c | 131 ++++++++ .../g++.dg/cpp0x/constexpr-builtin4.C | 17 + .../g++.dg/ext/builtin-convertvector-1.C | 137 ++++++++ gcc/tree-vect-generic.c | 317 +++++++++++++++++- 22 files changed, 933 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/builtin-convertvector-1.c create mode 100644 gcc/testsuite/c-c++-common/torture/builtin-convertvector-1.c create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-builtin4.C create mode 100644 gcc/testsuite/g++.dg/ext/builtin-convertvector-1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8fafc234bfe..25660bd1c8a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2019-01-07 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. + 2019-01-07 Tom de Vries * config/nvptx/nvptx-protos.h (nvptx_output_red_partition): Declare. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index b407f1cc18e..a7b56ff18e9 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2019-01-07 Jakub Jelinek + + PR c++/85052 + * c-common.h (enum rid): Add RID_BUILTIN_CONVERTVECTOR. + (c_build_vec_convert): Declare. + * c-common.c (c_build_vec_convert): New function. + 2019-01-04 Martin Sebor PR c/88546 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 5c380c14ca4..d2ea384d653 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -376,6 +376,7 @@ const struct c_common_resword c_common_reswords[] = 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 }, @@ -1072,6 +1073,70 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask, 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 to integral type. */ diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 3dec6f2741d..db16ae94b64 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -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); diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index ef11b4c62d7..fbd94f5607c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2019-01-07 Jakub Jelinek + + PR c++/85052 + * c-parser.c (c_parser_postfix_expression): Parse + __builtin_convertvector. + 2019-01-01 Jakub Jelinek Update copyright years. diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 972b629c092..76f314e1190 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -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 *parser) *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 *parser) 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 ()); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 32576c58b84..cbb70140c69 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2019-01-07 Jakub Jelinek + + PR c++/85052 + * 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. + 2019-01-03 Jakub Jelinek PR c++/88636 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 148150b4b7c..ed4bbeeb157 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #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 constexpr_ctx *ctx, tree t, 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, bool want_rval, bool strict, bool now, case IFN_SUB_OVERFLOW: case IFN_MUL_OVERFLOW: case IFN_LAUNDER: + case IFN_VEC_CONVERT: bail = false; + break; default: break; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 99e0734781c..794849b5066 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7142,6 +7142,8 @@ extern bool is_lambda_ignored_entity (tree); 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); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6ad2282c881..bca1739ace3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7031,6 +7031,32 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, 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; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 19594b74969..e216ef50378 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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 (); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 82fda5fd789..bc9d53800f7 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9933,4 +9933,26 @@ finish_builtin_launder (location_t loc, tree arg, tsubst_flags_t complain) 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" diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 19ef6a6760d..7f33be4f29c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -10596,6 +10596,33 @@ 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_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 diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c index 004f94ec19a..439043a85a0 100644 --- a/gcc/fold-const-call.c +++ b/gcc/fold-const-call.c @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #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 arg, tree_code code) 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 type, tree arg) 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); } diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 103e0c13c16..4f2ef45a0ff 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -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 diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 7313f925abc..e370eaa8476 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -296,6 +296,7 @@ DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c0bb2817873..a0d74152bad 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-01-07 Jakub Jelinek + + PR c++/85052 + * 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. + 2018-12-26 Mateusz B PR target/88521 diff --git a/gcc/testsuite/c-c++-common/builtin-convertvector-1.c b/gcc/testsuite/c-c++-common/builtin-convertvector-1.c new file mode 100644 index 00000000000..4bd0e4c5df5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/builtin-convertvector-1.c @@ -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" } */ +} diff --git a/gcc/testsuite/c-c++-common/torture/builtin-convertvector-1.c b/gcc/testsuite/c-c++-common/torture/builtin-convertvector-1.c new file mode 100644 index 00000000000..347dda7692d --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/builtin-convertvector-1.c @@ -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; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-builtin4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-builtin4.C new file mode 100644 index 00000000000..7f6bf3c21bc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-builtin4.C @@ -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, ""); diff --git a/gcc/testsuite/g++.dg/ext/builtin-convertvector-1.C b/gcc/testsuite/g++.dg/ext/builtin-convertvector-1.C new file mode 100644 index 00000000000..c803c065ff2 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin-convertvector-1.C @@ -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; +} diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index fb3d3414ea2..e9f5505acb3 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -39,6 +39,8 @@ along with GCC; see the file COPYING3. If not see #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, tree word_type, tree b, 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_iterator *gsi, elem_op_func f, 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_iterator *gsi, elem_op_func f, 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_stmt_iterator *gsi) 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_iterator *gsi) /* 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); -- 2.30.2