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:
Jakub Jelinek 2019-01-07 09:49:08 +01:00 committed by Jakub Jelinek
parent f881693c53
commit d8fcab6894
22 changed files with 933 additions and 17 deletions

View File

@ -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.

View File

@ -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

View File

@ -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. */

View File

@ -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);

View File

@ -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.

View File

@ -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 ());

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 ();

View File

@ -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"

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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" } */
}

View File

@ -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;
}

View File

@ -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, "");

View File

@ -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;
}

View File

@ -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);