diff mbox

Rename vshuffle/vec_shuffle to vec_perm

Message ID 4E8F81E1.2040701@redhat.com
State New
Headers show

Commit Message

Richard Henderson Oct. 7, 2011, 10:49 p.m. UTC
Our existing vector permutation support uses the name vec_perm.
The new support added for __builtin_shuffle used a variety of
names.  This brings all the internals into line with vec_perm.

I've added documentation for the (existing) variable permute
rtl named pattern (vec_perm).  I've also added documentation for
the (intended) constant permute rtl named pattern (vec_perm_const).
I've not actually added the support for vec_perm_const yet, but
plan to do so shortly.  It was just easiest to do the docs for
both at the same time.

The builtin is still named shuffle in honor of the OpenCL primitive
on which this feature is based.  I've improved the documentation
for the builtin a bit to make it clear that the selector modulus
is part of the interface.

Tested on x86_64-linux.


r~
+	* doc/extend.texi (__builtin_shuffle): Improve the description to
+	include the modulus of the selector.  Mention OpenCL.
+	* doc/md.texi (vec_perm, vec_perm_const): Document named patterns.
+
+	* tree.def (VEC_PERM_EXPR): Rename from VEC_SHUFFLE_EXPR.
+	* genopinit.c (optabs): Rename vshuffle to vec_perm.
+	* c-typeck.c (c_build_vec_perm_expr): Rename from
+	c_build_vec_shuffle_expr.  Update for name changes.
+	* optabs.c (expand_vec_perm_expr_p): Rename from
+	expand_vec_shuffle_expr_p.
+	(expand_vec_perm_expr): Rename from expand_vec_shuffle_expr.
+	* optabs.h (OTI_vec_perm): Rename from DOI_vshuffle.
+	(vec_perm_optab): Rename from vshuffle_optab.
+	* expr.c, gimple-pretty-print.c, gimple.c, gimplify.c,
+	c-tree.h, c-parser.c, tree-cfg.c, tree-inline.c, tree-pretty-print.c,
+	tree-ssa-operands.c, tree-vect-generic.c: Update for name changes.
+
+	* config/i386/i386.c (ix86_expand_vec_perm): Rename from
+	ix86_expand_vshuffle.
+	* config/i386/i386-protos.h: Update.
+	* config/i386/sse.md (VEC_PERM_AVX2): Rename from VSHUFFLE_AVX2.
+	(vec_perm<VEC_PERM_AVX2>): Rename from vshuffle<VSHUFFLE_AVX2>.

Comments

H.J. Lu Oct. 8, 2011, 10:56 p.m. UTC | #1
On Fri, Oct 7, 2011 at 3:49 PM, Richard Henderson <rth@redhat.com> wrote:
> Our existing vector permutation support uses the name vec_perm.
> The new support added for __builtin_shuffle used a variety of
> names.  This brings all the internals into line with vec_perm.
>
> I've added documentation for the (existing) variable permute
> rtl named pattern (vec_perm).  I've also added documentation for
> the (intended) constant permute rtl named pattern (vec_perm_const).
> I've not actually added the support for vec_perm_const yet, but
> plan to do so shortly.  It was just easiest to do the docs for
> both at the same time.
>
> The builtin is still named shuffle in honor of the OpenCL primitive
> on which this feature is based.  I've improved the documentation
> for the builtin a bit to make it clear that the selector modulus
> is part of the interface.
>
> Tested on x86_64-linux.
>

Is this a typo:

@@ -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])
H.J. Lu Oct. 8, 2011, 10:59 p.m. UTC | #2
On Sat, Oct 8, 2011 at 3:56 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Oct 7, 2011 at 3:49 PM, Richard Henderson <rth@redhat.com> wrote:
>> Our existing vector permutation support uses the name vec_perm.
>> The new support added for __builtin_shuffle used a variety of
>> names.  This brings all the internals into line with vec_perm.
>>
>> I've added documentation for the (existing) variable permute
>> rtl named pattern (vec_perm).  I've also added documentation for
>> the (intended) constant permute rtl named pattern (vec_perm_const).
>> I've not actually added the support for vec_perm_const yet, but
>> plan to do so shortly.  It was just easiest to do the docs for
>> both at the same time.
>>
>> The builtin is still named shuffle in honor of the OpenCL primitive
>> on which this feature is based.  I've improved the documentation
>> for the builtin a bit to make it clear that the selector modulus
>> is part of the interface.
>>
>> Tested on x86_64-linux.
>>
>
> Is this a typo:
>
> @@ -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])
>

DOI_vshuffle is renamed/moved to OTI_vec_perm.  But the rename/move
is incomplete, which caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50665
Joseph Myers Oct. 9, 2011, 1:09 p.m. UTC | #3
On Fri, 7 Oct 2011, Richard Henderson wrote:

> I've added documentation for the (existing) variable permute
> rtl named pattern (vec_perm).  I've also added documentation for
> the (intended) constant permute rtl named pattern (vec_perm_const).

That looks like it broke "make pdf" (something did at about that time and 
this patch is the most likely candidate).

> +@cindex @code{vec_perm_const@var{m}) instruction pattern

has opening '{' matched with closing ')'.
Richard Henderson Oct. 10, 2011, 4:22 p.m. UTC | #4
On 10/09/2011 06:09 AM, Joseph S. Myers wrote:
> That looks like it broke "make pdf" (something did at about that time and 
> this patch is the most likely candidate).
> 
>> +@cindex @code{vec_perm_const@var{m}) instruction pattern
> 
> has opening '{' matched with closing ')'.
> 

Fixed, thanks.


r~
diff mbox

Patch

diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index a1ed48d..c948b80 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -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);
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index 0e46525..b3e756c 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -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.  */
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index e7528a7..6dc0210 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -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
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 0bbfa9b..eea038e 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -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);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 9611f1f..21ce9b2 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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];
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index 80284b5..f135716 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -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;
 })
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index c3ebf09..11118ed 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 1aa8552..b61a99b 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -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
diff --git a/gcc/expr.c b/gcc/expr.c
index d1807b0..4ae61d7 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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:
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 4672075..4eefa03 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -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$))",
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 2dbdebe..577d28b 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -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);
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 2c655cd..19f02dc 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -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						    \
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 90de915..9713218 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -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;
 
diff --git a/gcc/optabs.c b/gcc/optabs.c
index aa233d5..0ba1333 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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;
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 5d5593b..4b46bda 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -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.  */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 598ef2a..bcf71b9 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -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);
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 8c60f4d..e2f76e1 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -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:
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index c61e901..8acabb1 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -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);
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index d163037..9cd656b 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -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);
diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c
index 8f9f2a8..1d11701 100644
--- a/gcc/tree-vect-generic.c
+++ b/gcc/tree-vect-generic.c
@@ -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;
     }
 
diff --git a/gcc/tree.def b/gcc/tree.def
index 44c4ee8..3e59819 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -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.