mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
f881693c53
commit
d8fcab6894
|
|
@ -1,3 +1,20 @@
|
|||
2019-01-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
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 <tdevries@suse.de>
|
||||
|
||||
* config/nvptx/nvptx-protos.h (nvptx_output_red_partition): Declare.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
2019-01-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
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 <msebor@redhat.com>
|
||||
|
||||
PR c/88546
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
2019-01-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/85052
|
||||
* c-parser.c (c_parser_postfix_expression): Parse
|
||||
__builtin_convertvector.
|
||||
|
||||
2019-01-01 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
Update copyright years.
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
|
|
|
|||
|
|
@ -1,3 +1,16 @@
|
|||
2019-01-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
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 <jakub@redhat.com>
|
||||
|
||||
PR c++/88636
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
21
gcc/cp/pt.c
21
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 ();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
2019-01-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
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 <mateuszb@poczta.onet.pl>
|
||||
|
||||
PR target/88521
|
||||
|
|
|
|||
|
|
@ -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" } */
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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, "");
|
||||
|
|
@ -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 <int N>
|
||||
void
|
||||
f1 (v4usi *x, v4si *y)
|
||||
{
|
||||
*y = __builtin_convertvector (*x, v4si);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
f2 (T *x, v4si *y)
|
||||
{
|
||||
*y = __builtin_convertvector (*x, v4si);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
f3 (v4si *x, T *y)
|
||||
{
|
||||
*y = __builtin_convertvector (*x, T);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
f4 (v4df *x, v4si *y)
|
||||
{
|
||||
*y = __builtin_convertvector (*x, v4si);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void
|
||||
f5 (T *x, U *y)
|
||||
{
|
||||
*y = __builtin_convertvector (*x, U);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
f6 (v256df *x, T *y)
|
||||
{
|
||||
*y = __builtin_convertvector (*x, T);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
f7 (v256di *x, v256df *y)
|
||||
{
|
||||
*y = __builtin_convertvector (*x, v256df);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
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;
|
||||
}
|
||||
|
|
@ -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<constructor_elt, va_gc> *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<constructor_elt, va_gc> *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 <gassign *> (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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue