@@ -5990,7 +5990,7 @@ c_parser_alignof_expression (c_parser *parser)
}
/* Helper function to read arguments of builtins which are interfaces
- for the middle-end nodes like COMPLEX_EXPR, VEC_SHUFFLE_EXPR and
+ for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and
others. The name of the builtin is passed using BNAME parameter.
Function returns true if there were no errors while parsing and
stores the arguments in CEXPR_LIST. */
@@ -6534,13 +6534,13 @@ c_parser_postfix_expression (c_parser *parser)
if (VEC_length (c_expr_t, cexpr_list) == 2)
expr.value =
- c_build_vec_shuffle_expr
+ c_build_vec_perm_expr
(loc, VEC_index (c_expr_t, cexpr_list, 0)->value,
NULL_TREE, VEC_index (c_expr_t, cexpr_list, 1)->value);
else if (VEC_length (c_expr_t, cexpr_list) == 3)
expr.value =
- c_build_vec_shuffle_expr
+ c_build_vec_perm_expr
(loc, VEC_index (c_expr_t, cexpr_list, 0)->value,
VEC_index (c_expr_t, cexpr_list, 1)->value,
VEC_index (c_expr_t, cexpr_list, 2)->value);
@@ -595,7 +595,7 @@ extern tree c_begin_omp_task (void);
extern tree c_finish_omp_task (location_t, tree, tree);
extern tree c_finish_omp_clauses (tree);
extern tree c_build_va_arg (location_t, tree, tree);
-extern tree c_build_vec_shuffle_expr (location_t, tree, tree, tree);
+extern tree c_build_vec_perm_expr (location_t, tree, tree, tree);
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
@@ -2846,7 +2846,7 @@ build_function_call_vec (location_t loc, tree function, VEC(tree,gc) *params,
return require_complete_type (result);
}
-/* Build a VEC_SHUFFLE_EXPR if V0, V1 and MASK are not error_mark_nodes
+/* Build a VEC_PERM_EXPR if V0, V1 and MASK are not error_mark_nodes
and have vector types, V0 has the same type as V1, and the number of
elements of V0, V1, MASK is the same.
@@ -2857,9 +2857,9 @@ build_function_call_vec (location_t loc, tree function, VEC(tree,gc) *params,
an implementation accident and this semantics is not guaranteed to
the user. */
tree
-c_build_vec_shuffle_expr (location_t loc, tree v0, tree v1, tree mask)
+c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask)
{
- tree vec_shuffle;
+ tree ret;
bool wrap = true;
bool maybe_const = false;
bool two_arguments = false;
@@ -2915,7 +2915,7 @@ c_build_vec_shuffle_expr (location_t loc, tree v0, tree v1, tree mask)
return error_mark_node;
}
- /* Avoid C_MAYBE_CONST_EXPRs inside VEC_SHUFFLE_EXPR. */
+ /* Avoid C_MAYBE_CONST_EXPRs inside VEC_PERM_EXPR. */
v0 = c_fully_fold (v0, false, &maybe_const);
wrap &= maybe_const;
@@ -2930,12 +2930,12 @@ c_build_vec_shuffle_expr (location_t loc, tree v0, tree v1, tree mask)
mask = c_fully_fold (mask, false, &maybe_const);
wrap &= maybe_const;
- vec_shuffle = build3 (VEC_SHUFFLE_EXPR, TREE_TYPE (v0), v0, v1, mask);
+ ret = build3 (VEC_PERM_EXPR, TREE_TYPE (v0), v0, v1, mask);
if (!wrap)
- vec_shuffle = c_wrap_maybe_const (vec_shuffle, true);
+ ret = c_wrap_maybe_const (ret, true);
- return vec_shuffle;
+ return ret;
}
/* Convert the argument expressions in the vector VALUES
@@ -123,7 +123,7 @@ extern bool ix86_expand_int_movcc (rtx[]);
extern bool ix86_expand_fp_movcc (rtx[]);
extern bool ix86_expand_fp_vcond (rtx[]);
extern bool ix86_expand_int_vcond (rtx[]);
-extern void ix86_expand_vshuffle (rtx[]);
+extern void ix86_expand_vec_perm (rtx[]);
extern void ix86_expand_sse_unpack (rtx[], bool, bool);
extern bool ix86_expand_int_addcc (rtx[]);
extern rtx ix86_expand_call (rtx, rtx, rtx, rtx, rtx, bool);
@@ -19325,8 +19325,10 @@ ix86_expand_int_vcond (rtx operands[])
return true;
}
+/* Expand a variable vector permutation. */
+
void
-ix86_expand_vshuffle (rtx operands[])
+ix86_expand_vec_perm (rtx operands[])
{
rtx target = operands[0];
rtx op0 = operands[1];
@@ -6199,19 +6199,19 @@
;; ??? Irritatingly, the 256-bit VPSHUFB only shuffles within the 128-bit
;; lanes. For now, we don't try to support V32QI or V16HImode. So we
;; don't want to use VI_AVX2.
-(define_mode_iterator VSHUFFLE_AVX2
+(define_mode_iterator VEC_PERM_AVX2
[V16QI V8HI V4SI V2DI V4SF V2DF
(V8SI "TARGET_AVX2") (V4DI "TARGET_AVX2")
(V8SF "TARGET_AVX2") (V4DF "TARGET_AVX2")])
-(define_expand "vshuffle<mode>"
- [(match_operand:VSHUFFLE_AVX2 0 "register_operand" "")
- (match_operand:VSHUFFLE_AVX2 1 "register_operand" "")
- (match_operand:VSHUFFLE_AVX2 2 "register_operand" "")
+(define_expand "vec_perm<mode>"
+ [(match_operand:VEC_PERM_AVX2 0 "register_operand" "")
+ (match_operand:VEC_PERM_AVX2 1 "register_operand" "")
+ (match_operand:VEC_PERM_AVX2 2 "register_operand" "")
(match_operand:<sseintvecmode> 3 "register_operand" "")]
"TARGET_SSSE3 || TARGET_AVX || TARGET_XOP"
{
- ix86_expand_vshuffle (operands);
+ ix86_expand_vec_perm (operands);
DONE;
})
@@ -6586,16 +6586,18 @@ c = a == b; /* The result would be @{0,-1, 0,-1@} */
Vector shuffling is available using functions
@code{__builtin_shuffle (vec, mask)} and
-@code{__builtin_shuffle (vec0, vec1, mask)}. Both functions construct
-a permutation of elements from one or two vectors and return a vector
-of the same type as input vector(s). The mask is a vector of
-integer-typed elements. The size of each element of the mask must be
-the same as the size of each input vector element. The number of
-elements in input vector(s) and mask must be the same.
+@code{__builtin_shuffle (vec0, vec1, mask)}.
+Both functions construct a permutation of elements from one or two
+vectors and return a vector of the same type as the input vector(s).
+The @var{mask} is an integral vector with the same width (@var{W})
+and element count (@var{N}) as the output vector.
-The elements of the input vectors are numbered from left to right across
-one or both of the vectors. Each element in the mask specifies a number
-of element from the input vector(s). Consider the following example.
+The elements of the input vectors are numbered in memory ordering of
+@var{vec0} beginning at 0 and @var{vec1} beginning at @var{N}. The
+elements of @var{mask} are considered modulo @var{N} in the single-operand
+case and modulo @math{2*@var{N}} in the two-operand case.
+
+Consider the following example,
@smallexample
typedef int v4si __attribute__ ((vector_size (16)));
@@ -6610,6 +6612,9 @@ res = __builtin_shuffle (a, mask1); /* res is @{1,2,2,4@} */
res = __builtin_shuffle (a, b, mask2); /* res is @{1,5,3,6@} */
@end smallexample
+Note that @code{__builtin_shuffle} is intentionally semantically
+compatible with the OpenCL @code{shuffle} and @code{shuffle2} functions.
+
You can declare variables and use them in function calls and returns, as
well as in assignments and some casts. You can specify a vector type as
a return type for a function. Vector types can also be used as function
@@ -6620,20 +6625,6 @@ to and from other datatypes of the same size).
You cannot operate between vectors of different lengths or different
signedness without a cast.
-A port that supports hardware vector operations, usually provides a set
-of built-in functions that can be used to operate on vectors. For
-example, a function to add two vectors and multiply the result by a
-third could look like this:
-
-@smallexample
-v4si f (v4si a, v4si b, v4si c)
-@{
- v4si tmp = __builtin_addv4si (a, b);
- return __builtin_mulv4si (tmp, c);
-@}
-
-@end smallexample
-
@node Offsetof
@section Offsetof
@findex __builtin_offsetof
@@ -4028,6 +4028,34 @@ will be set to the value @var{op1} & @var{msk} | @var{op2} & ~@var{msk}
where @var{msk} is computed by element-wise evaluation of the vector
comparison with a truth value of all-ones and a false value of all-zeros.
+@cindex @code{vec_perm@var{m}} instruction pattern
+@item @samp{vec_perm@var{m}}
+Output a (variable) vector permutation. Operand 0 is the destination
+to receive elements from operand 1 and operand 2, which are of mode
+@var{m}. Operand 3 is the @dfn{selector}. It is an integral mode
+vector of the same width and number of elements as mode @var{m}.
+
+The input elements are numbered from 0 in operand 1 through
+@math{2*@var{N}-1} in operand 2. The elements of the selector must
+be computed modulo @math{2*@var{N}}. Note that if
+@code{rtx_equal_p(operand1, operand2)}, this can be implemented
+with just operand 1 and selector elements modulo @var{N}.
+
+@cindex @code{vec_perm_const@var{m}) instruction pattern
+@item @samp{vec_perm_const@var{m}}
+Like @samp{vec_perm} except that the permutation is a compile-time
+constant. That is, operand 3, the @dfn{selector}, is a @code{CONST_VECTOR}.
+
+Some targets cannot perform a permutation with a variable selector,
+but can efficiently perform a constant permutation. Further, the
+target hook @code{vec_perm_ok} is queried to determine if the
+specific constant permutation is available efficiently; the named
+pattern is never expanded without @code{vec_perm_ok} returning true.
+
+There is no need for a target to supply both @samp{vec_perm@var{m}}
+and @samp{vec_perm_const@var{m}} if the former can trivially implement
+the operation with, say, the vector constant loaded into a register.
+
@cindex @code{push@var{m}1} instruction pattern
@item @samp{push@var{m}1}
Output a push instruction. Operand 0 is value to push. Used only when
@@ -8605,9 +8605,10 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
case VEC_PACK_FIX_TRUNC_EXPR:
mode = TYPE_MODE (TREE_TYPE (treeop0));
goto binop;
-
- case VEC_SHUFFLE_EXPR:
- target = expand_vec_shuffle_expr (type, treeop0, treeop1, treeop2, target);
+
+ case VEC_PERM_EXPR:
+ target = expand_vec_perm_expr (type, treeop0, treeop1, treeop2, target);
+ gcc_assert (target);
return target;
case DOT_PROD_EXPR:
@@ -253,7 +253,7 @@ static const char * const optabs[] =
"set_optab_handler (vec_shl_optab, $A, CODE_FOR_$(vec_shl_$a$))",
"set_optab_handler (vec_shr_optab, $A, CODE_FOR_$(vec_shr_$a$))",
"set_optab_handler (vec_realign_load_optab, $A, CODE_FOR_$(vec_realign_load_$a$))",
- "set_direct_optab_handler (vshuffle_optab, $A, CODE_FOR_$(vshuffle$a$))",
+ "set_direct_optab_handler (vec_perm_optab, $A, CODE_FOR_$(vec_perm$a$))",
"set_convert_optab_handler (vcond_optab, $A, $B, CODE_FOR_$(vcond$a$b$))",
"set_convert_optab_handler (vcondu_optab, $A, $B, CODE_FOR_$(vcondu$a$b$))",
"set_optab_handler (ssum_widen_optab, $A, CODE_FOR_$(widen_ssum$I$a3$))",
@@ -418,8 +418,8 @@ dump_ternary_rhs (pretty_printer *buffer, gimple gs, int spc, int flags)
pp_string (buffer, ">");
break;
- case VEC_SHUFFLE_EXPR:
- pp_string (buffer, "VEC_SHUFFLE_EXPR <");
+ case VEC_PERM_EXPR:
+ pp_string (buffer, "VEC_PERM_EXPR <");
dump_generic_node (buffer, gimple_assign_rhs1 (gs), spc, flags, false);
pp_string (buffer, ", ");
dump_generic_node (buffer, gimple_assign_rhs2 (gs), spc, flags, false);
@@ -2639,7 +2639,7 @@ get_gimple_rhs_num_ops (enum tree_code code)
|| (SYM) == DOT_PROD_EXPR \
|| (SYM) == REALIGN_LOAD_EXPR \
|| (SYM) == VEC_COND_EXPR \
- || (SYM) == VEC_SHUFFLE_EXPR \
+ || (SYM) == VEC_PERM_EXPR \
|| (SYM) == FMA_EXPR) ? GIMPLE_TERNARY_RHS \
: ((SYM) == CONSTRUCTOR \
|| (SYM) == OBJ_TYPE_REF \
@@ -7287,7 +7287,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
}
case FMA_EXPR:
- case VEC_SHUFFLE_EXPR:
+ case VEC_PERM_EXPR:
/* Classified as tcc_expression. */
goto expr_3;
@@ -6620,10 +6620,10 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
return gen_rtx_fmt_ee (rcode, VOIDmode, ops[0].value, ops[1].value);
}
-/* Return true if VEC_SHUFFLE_EXPR can be expanded using SIMD extensions
+/* Return true if VEC_PERM_EXPR can be expanded using SIMD extensions
of the CPU. */
bool
-expand_vec_shuffle_expr_p (enum machine_mode mode, tree v0, tree v1, tree mask)
+expand_vec_perm_expr_p (enum machine_mode mode, tree v0, tree v1, tree mask)
{
int v0_mode_s = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (v0))));
int mask_mode_s = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (mask))));
@@ -6639,19 +6639,19 @@ expand_vec_shuffle_expr_p (enum machine_mode mode, tree v0, tree v1, tree mask)
!= TYPE_VECTOR_SUBPARTS (TREE_TYPE (mask)))
return false;
- return direct_optab_handler (vshuffle_optab, mode) != CODE_FOR_nothing;
+ return direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing;
}
/* Generate instructions for VEC_COND_EXPR given its type and three
operands. */
rtx
-expand_vec_shuffle_expr (tree type, tree v0, tree v1, tree mask, rtx target)
+expand_vec_perm_expr (tree type, tree v0, tree v1, tree mask, rtx target)
{
struct expand_operand ops[4];
enum insn_code icode;
enum machine_mode mode = TYPE_MODE (type);
- gcc_checking_assert (expand_vec_shuffle_expr_p (mode, v0, v1, mask));
+ gcc_checking_assert (expand_vec_perm_expr_p (mode, v0, v1, mask));
if (TREE_CODE (mask) == VECTOR_CST)
{
@@ -6659,7 +6659,7 @@ expand_vec_shuffle_expr (tree type, tree v0, tree v1, tree mask, rtx target)
tree fn = targetm.vectorize.builtin_vec_perm (TREE_TYPE (v0), &m_type);
if (!fn)
- goto vshuffle;
+ goto vec_perm;
if (m_type != TREE_TYPE (TREE_TYPE (mask)))
{
@@ -6674,8 +6674,8 @@ expand_vec_shuffle_expr (tree type, tree v0, tree v1, tree mask, rtx target)
return expand_expr_real_1 (call, target, VOIDmode, EXPAND_NORMAL, NULL);
}
- vshuffle:
- icode = direct_optab_handler (vshuffle_optab, mode);
+ vec_perm:
+ icode = direct_optab_handler (vec_perm_optab, mode);
if (icode == CODE_FOR_nothing)
return 0;
@@ -377,6 +377,9 @@ enum optab_index
OTI_vec_pack_sfix_trunc,
OTI_vec_pack_ufix_trunc,
+ /* Vector shuffling. */
+ OTI_vec_perm,
+
/* Perform a raise to the power of integer. */
OTI_powi,
@@ -557,6 +560,7 @@ enum optab_index
#define vec_pack_usat_optab (&optab_table[OTI_vec_pack_usat])
#define vec_pack_sfix_trunc_optab (&optab_table[OTI_vec_pack_sfix_trunc])
#define vec_pack_ufix_trunc_optab (&optab_table[OTI_vec_pack_ufix_trunc])
+#define vec_perm_optab (&direct_optab_table[(int) OTI_vec_perm])
#define powi_optab (&optab_table[OTI_powi])
@@ -617,7 +621,6 @@ enum convert_optab_index
#define vec_store_lanes_optab (&convert_optab_table[COI_vec_store_lanes])
#define vcond_optab (&convert_optab_table[(int) COI_vcond])
#define vcondu_optab (&convert_optab_table[(int) COI_vcondu])
-#define vshuffle_optab (&direct_optab_table[(int) DOI_vshuffle])
/* Contains the optab used for each rtx code. */
extern optab code_to_optab[NUM_RTX_CODE + 1];
@@ -639,9 +642,6 @@ enum direct_optab_index
DOI_reload_in,
DOI_reload_out,
- /* Vector shuffling. */
- DOI_vshuffle,
-
/* Block move operation. */
DOI_movmem,
@@ -888,11 +888,11 @@ extern rtx expand_vec_cond_expr (tree, tree, tree, tree, rtx);
/* Generate code for VEC_LSHIFT_EXPR and VEC_RSHIFT_EXPR. */
extern rtx expand_vec_shift_expr (sepops, rtx);
-/* Return tree if target supports vector operations for VEC_SHUFFLE_EXPR. */
-bool expand_vec_shuffle_expr_p (enum machine_mode, tree, tree, tree);
+/* Return tree if target supports vector operations for VEC_PERM_EXPR. */
+bool expand_vec_perm_expr_p (enum machine_mode, tree, tree, tree);
-/* Generate code for VEC_SHUFFLE_EXPR. */
-extern rtx expand_vec_shuffle_expr (tree, tree, tree, tree, rtx);
+/* Generate code for VEC_PERM_EXPR. */
+extern rtx expand_vec_perm_expr (tree, tree, tree, tree, rtx);
/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
if the target does not have such an insn. */
@@ -3727,11 +3727,11 @@ verify_gimple_assign_ternary (gimple stmt)
}
break;
- case VEC_SHUFFLE_EXPR:
+ case VEC_PERM_EXPR:
if (!useless_type_conversion_p (lhs_type, rhs1_type)
|| !useless_type_conversion_p (lhs_type, rhs2_type))
{
- error ("type mismatch in vector shuffle expression");
+ error ("type mismatch in vector permute expression");
debug_generic_expr (lhs_type);
debug_generic_expr (rhs1_type);
debug_generic_expr (rhs2_type);
@@ -3743,7 +3743,7 @@ verify_gimple_assign_ternary (gimple stmt)
|| TREE_CODE (rhs2_type) != VECTOR_TYPE
|| TREE_CODE (rhs3_type) != VECTOR_TYPE)
{
- error ("vector types expected in vector shuffle expression");
+ error ("vector types expected in vector permute expression");
debug_generic_expr (lhs_type);
debug_generic_expr (rhs1_type);
debug_generic_expr (rhs2_type);
@@ -3758,7 +3758,7 @@ verify_gimple_assign_ternary (gimple stmt)
!= TYPE_VECTOR_SUBPARTS (lhs_type))
{
error ("vectors with different element number found "
- "in vector shuffle expression");
+ "in vector permute expression");
debug_generic_expr (lhs_type);
debug_generic_expr (rhs1_type);
debug_generic_expr (rhs2_type);
@@ -3770,7 +3770,7 @@ verify_gimple_assign_ternary (gimple stmt)
|| GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs3_type)))
!= GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs1_type))))
{
- error ("invalid mask type in vector shuffle expression");
+ error ("invalid mask type in vector permute expression");
debug_generic_expr (lhs_type);
debug_generic_expr (rhs1_type);
debug_generic_expr (rhs2_type);
@@ -3285,7 +3285,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights,
??? We may consider mapping RTL costs to this. */
case COND_EXPR:
case VEC_COND_EXPR:
- case VEC_SHUFFLE_EXPR:
+ case VEC_PERM_EXPR:
case PLUS_EXPR:
case POINTER_PLUS_EXPR:
@@ -2070,8 +2070,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
pp_string (buffer, " > ");
break;
- case VEC_SHUFFLE_EXPR:
- pp_string (buffer, " VEC_SHUFFLE_EXPR < ");
+ case VEC_PERM_EXPR:
+ pp_string (buffer, " VEC_PERM_EXPR < ");
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
pp_string (buffer, " , ");
dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
@@ -943,7 +943,7 @@ get_expr_operands (gimple stmt, tree *expr_p, int flags)
case COND_EXPR:
case VEC_COND_EXPR:
- case VEC_SHUFFLE_EXPR:
+ case VEC_PERM_EXPR:
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), uflags);
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags);
get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags);
@@ -597,21 +597,21 @@ vector_element (gimple_stmt_iterator *gsi, tree vect, tree idx, tree *ptmpvec)
idx, NULL_TREE, NULL_TREE);
}
-/* Check if VEC_SHUFFLE_EXPR within the given setting is supported
+/* Check if VEC_PERM_EXPR within the given setting is supported
by hardware, or lower it piecewise.
- When VEC_SHUFFLE_EXPR has the same first and second operands:
- VEC_SHUFFLE_EXPR <v0, v0, mask> the lowered version would be
+ When VEC_PERM_EXPR has the same first and second operands:
+ VEC_PERM_EXPR <v0, v0, mask> the lowered version would be
{v0[mask[0]], v0[mask[1]], ...}
MASK and V0 must have the same number of elements.
- Otherwise VEC_SHUFFLE_EXPR <v0, v1, mask> is lowered to
+ Otherwise VEC_PERM_EXPR <v0, v1, mask> is lowered to
{mask[0] < len(v0) ? v0[mask[0]] : v1[mask[0]], ...}
V0 and V1 must have the same type. MASK, V0, V1 must have the
same number of arguments. */
static void
-lower_vec_shuffle (gimple_stmt_iterator *gsi)
+lower_vec_perm (gimple_stmt_iterator *gsi)
{
gimple stmt = gsi_stmt (*gsi);
tree mask = gimple_assign_rhs3 (stmt);
@@ -628,7 +628,7 @@ lower_vec_shuffle (gimple_stmt_iterator *gsi)
bool two_operand_p = !operand_equal_p (vec0, vec1, 0);
unsigned i;
- if (expand_vec_shuffle_expr_p (TYPE_MODE (vect_type), vec0, vec1, mask))
+ if (expand_vec_perm_expr_p (TYPE_MODE (vect_type), vec0, vec1, mask))
return;
v = VEC_alloc (constructor_elt, gc, elements);
@@ -721,9 +721,9 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
rhs_class = get_gimple_rhs_class (code);
lhs = gimple_assign_lhs (stmt);
- if (code == VEC_SHUFFLE_EXPR)
+ if (code == VEC_PERM_EXPR)
{
- lower_vec_shuffle (gsi);
+ lower_vec_perm (gsi);
return;
}
@@ -497,18 +497,19 @@ DEFTREECODE (COND_EXPR, "cond_expr", tcc_expression, 3)
*/
DEFTREECODE (VEC_COND_EXPR, "vec_cond_expr", tcc_expression, 3)
-/* Vector shuffle expression. A = VEC_SHUFFLE_EXPR<v0, v1, mask>
- means
+/* Vector permutation expression. A = VEC_PERM_EXPR<v0, v1, mask> means
- foreach i in length (mask):
- A = mask[i] < length (v0) ? v0[mask[i]] : v1[mask[i] - length (mask)]
+ N = length(mask)
+ foreach i in N:
+ M = mask[i] % (2*N)
+ A = M < N ? v0[M] : v1[M-N]
V0 and V1 are vectors of the same type. MASK is an integer-typed
vector. The number of MASK elements must be the same with the
number of elements in V0 and V1. The size of the inner type
of the MASK and of the V0 and V1 must be the same.
*/
-DEFTREECODE (VEC_SHUFFLE_EXPR, "vec_shuffle_expr", tcc_expression, 3)
+DEFTREECODE (VEC_PERM_EXPR, "vec_perm_expr", tcc_expression, 3)
/* Declare local variables, including making RTL and allocating space.
BIND_EXPR_VARS is a chain of VAR_DECL nodes for the variables.