diff mbox

[committed] Remove VEC_EXTRACT_EVEN/ODD_EXPR

Message ID 4EF4FD2B.9050604@redhat.com
State New
Headers show

Commit Message

Richard Henderson Dec. 23, 2011, 10:14 p.m. UTC
Having now committed patches to convert all targets to vec_perm_const, supporting the interleave and even/odd permutations, we can now remove the VEC_INTERLEAVE_HIGH/LOW_EXPR and VEC_EXTRACT_EVEN/ODD_EXPR  codes as redundant with the primary VEC_PERM_EXPR code.

I have committed the patch previously posted by Jakub (and approved by Richi) that removes VEC_INTERLEAVE_HIGH/LOW_EXPR.  I have also committed thefollowing patch which removes VEC_EXTRACT_EVEN/ODD_EXPR.

All re-tested on x86_64-linux.


r~
* tree.def (VEC_EXTRACT_EVEN_EXPR, VEC_EXTRACT_ODD_EXPR): Remove.
	* cfgexpand.c (expand_debug_expr): Don't handle them.
	* expr.c (expand_expr_real_2): Likewise.
	* fold-const.c (fold_binary_loc): Likewise.
	* gimple-pretty-print.c (dump_binary_rhs): Likewise.
	* tree-cfg.c (verify_gimple_assign_binary): Likewise.
	* tree-inline.c (estimate_operator_cost): Likewise.
	* tree-pretty-print.c (dump_generic_node): Likewise.
	* tree-vect-generic.c (expand_vector_operations_1): Likewise.
	* optabs.c (optab_for_tree_code): Likewise.
	(can_vec_perm_for_code_p): Remove.
	(expand_binop): Don't try it.
	(init_optabs): Don't init vec_extract_even/odd_optab.
	* genopinit.c (optabs): Likewise.
	* optabs.h (OTI_vec_extract_even, OTI_vec_extract_odd): Remove.
	(vec_extract_even_optab, vec_extract_odd_optab): Remove.
	* tree-vect-data-refs.c (vect_strided_store_supported): Tidy code.
	(vect_permute_store_chain): Use TYPE_VECTOR_SUBPARTS instead of
	GET_MODE_NUNITS; check vect_gen_perm_mask return value instead of
	asserting vect_strided_store_supported.
	(vect_strided_load_supported): Use can_vec_perm_p.
	(vect_permute_load_chain): Use VEC_PERM_EXPR.

	* doc/generic.texi (VEC_EXTRACT_EVEN_EXPR): Remove.
	(VEC_EXTRACT_ODD_EXPR): Remove.
	* doc/md.texi (vec_extract_even, vec_extract_odd): Remove.
diff mbox

Patch

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index dfe5442..2b2e464 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -3449,8 +3449,6 @@  expand_debug_expr (tree exp)
     case REDUC_MIN_EXPR:
     case REDUC_PLUS_EXPR:
     case VEC_COND_EXPR:
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
     case VEC_LSHIFT_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
     case VEC_PACK_SAT_EXPR:
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index 4f26238..31e8855 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -1695,8 +1695,6 @@  its sole argument yields the representation for @code{ap}.
 @tindex VEC_PACK_TRUNC_EXPR
 @tindex VEC_PACK_SAT_EXPR
 @tindex VEC_PACK_FIX_TRUNC_EXPR
-@tindex VEC_EXTRACT_EVEN_EXPR
-@tindex VEC_EXTRACT_ODD_EXPR
 
 @table @code
 @item VEC_LSHIFT_EXPR
@@ -1765,13 +1763,6 @@  of elements of a floating point type.  The result is a vector that contains
 twice as many elements of an integral type whose size is half as wide.  The
 elements of the two vectors are merged (concatenated) to form the output
 vector.
-
-@item VEC_EXTRACT_EVEN_EXPR
-@itemx VEC_EXTRACT_ODD_EXPR
-These nodes represent extracting of the even/odd elements of the two input
-vectors, respectively. Their operands and result are vectors that contain the
-same number of elements of the same type.
-
 @end table
 
 
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 6dd6a58..93183e6 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -4145,20 +4145,6 @@  operand 1 is new value of field and operand 2 specify the field index.
 Extract given field from the vector value.  Operand 1 is the vector, operand 2
 specify field index and operand 0 place to store value into.
 
-@cindex @code{vec_extract_even@var{m}} instruction pattern
-@item @samp{vec_extract_even@var{m}}
-Extract even elements from the input vectors (operand 1 and operand 2).
-The even elements of operand 2 are concatenated to the even elements of operand
-1 in their original order. The result is stored in operand 0.
-The output and input vectors should have the same modes.
-
-@cindex @code{vec_extract_odd@var{m}} instruction pattern
-@item @samp{vec_extract_odd@var{m}}
-Extract odd elements from the input vectors (operand 1 and operand 2).
-The odd elements of operand 2 are concatenated to the odd elements of operand
-1 in their original order. The result is stored in operand 0.
-The output and input vectors should have the same modes.
-
 @cindex @code{vec_init@var{m}} instruction pattern
 @item @samp{vec_init@var{m}}
 Initialize the vector to given values.  Operand 0 is the vector to initialize
diff --git a/gcc/expr.c b/gcc/expr.c
index cb28f48..c10f915 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -8647,10 +8647,6 @@  expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
         return temp;
       }
 
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
-      goto binop;
-
     case VEC_LSHIFT_EXPR:
     case VEC_RSHIFT_EXPR:
       {
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 89c68cf..5d3196b 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -13501,33 +13501,6 @@  fold_binary_loc (location_t loc,
       /* An ASSERT_EXPR should never be passed to fold_binary.  */
       gcc_unreachable ();
 
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
-      if ((TREE_CODE (arg0) == VECTOR_CST
-	   || TREE_CODE (arg0) == CONSTRUCTOR)
-	  && (TREE_CODE (arg1) == VECTOR_CST
-	      || TREE_CODE (arg1) == CONSTRUCTOR))
-	{
-	  unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
-	  unsigned char *sel = XALLOCAVEC (unsigned char, nelts);
-
-	  for (i = 0; i < nelts; i++)
-	    switch (code)
-	      {
-	      case VEC_EXTRACT_EVEN_EXPR:
-		sel[i] = i * 2;
-		break;
-	      case VEC_EXTRACT_ODD_EXPR:
-		sel[i] = i * 2 + 1;
-		break;
-	      default:
-		gcc_unreachable ();
-	      }
-
-	  return fold_vec_perm (type, arg0, arg1, sel);
-	}
-      return NULL_TREE;
-
     case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
       {
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 9cd77fa..baccd45 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -267,8 +267,6 @@  static const char * const optabs[] =
   "set_direct_optab_handler (atomic_or_optab, $A, CODE_FOR_$(atomic_or$I$a$))",
   "set_optab_handler (vec_set_optab, $A, CODE_FOR_$(vec_set$a$))",
   "set_optab_handler (vec_extract_optab, $A, CODE_FOR_$(vec_extract$a$))",
-  "set_optab_handler (vec_extract_even_optab, $A, CODE_FOR_$(vec_extract_even$a$))",
-  "set_optab_handler (vec_extract_odd_optab, $A, CODE_FOR_$(vec_extract_odd$a$))",
   "set_optab_handler (vec_init_optab, $A, CODE_FOR_$(vec_init$a$))",
   "set_optab_handler (vec_shl_optab, $A, CODE_FOR_$(vec_shl_$a$))",
   "set_optab_handler (vec_shr_optab, $A, CODE_FOR_$(vec_shr_$a$))",
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index b93d66d..3ba7183 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -345,8 +345,6 @@  dump_binary_rhs (pretty_printer *buffer, gimple gs, int spc, int flags)
     case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_SAT_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
     case VEC_WIDEN_LSHIFT_HI_EXPR:
     case VEC_WIDEN_LSHIFT_LO_EXPR:
       for (p = tree_code_name [(int) code]; *p; p++)
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 1c13b5a..b586eb9 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -547,12 +547,6 @@  optab_for_tree_code (enum tree_code code, const_tree type,
     case ABS_EXPR:
       return trapv ? absv_optab : abs_optab;
 
-    case VEC_EXTRACT_EVEN_EXPR:
-      return vec_extract_even_optab;
-
-    case VEC_EXTRACT_ODD_EXPR:
-      return vec_extract_odd_optab;
-
     default:
       return NULL;
     }
@@ -1600,26 +1594,6 @@  expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
 	}
     }
 
-  /* Certain vector operations can be implemented with vector permutation.  */
-  if (VECTOR_MODE_P (mode))
-    {
-      enum tree_code tcode = ERROR_MARK;
-      rtx sel;
-
-      if (binoptab == vec_extract_even_optab)
-	tcode = VEC_EXTRACT_EVEN_EXPR;
-      else if (binoptab == vec_extract_odd_optab)
-	tcode = VEC_EXTRACT_ODD_EXPR;
-
-      if (tcode != ERROR_MARK
-	  && can_vec_perm_for_code_p (tcode, mode, &sel))
-	{
-	  temp = expand_vec_perm (mode, op0, op1, sel, target);
-	  gcc_assert (temp != NULL);
-	  return temp;
-	}
-    }
-
   /* Look for a wider mode of the same class for which we think we
      can open-code the operation.  Check for a widening multiply at the
      wider mode as well.  */
@@ -6259,8 +6233,6 @@  init_optabs (void)
   init_optab (udot_prod_optab, UNKNOWN);
 
   init_optab (vec_extract_optab, UNKNOWN);
-  init_optab (vec_extract_even_optab, UNKNOWN);
-  init_optab (vec_extract_odd_optab, UNKNOWN);
   init_optab (vec_set_optab, UNKNOWN);
   init_optab (vec_init_optab, UNKNOWN);
   init_optab (vec_shl_optab, UNKNOWN);
@@ -6868,86 +6840,6 @@  can_vec_perm_p (enum machine_mode mode, bool variable,
   return true;
 }
 
-/* Return true if we can implement with VEC_PERM_EXPR for this target.
-   If PSEL is non-null, return the selector for the permutation.  */
-
-bool
-can_vec_perm_for_code_p (enum tree_code code, enum machine_mode mode,
-			 rtx *psel)
-{
-  bool need_sel_test = false;
-  enum insn_code icode;
-
-  /* If the target doesn't implement a vector mode for the vector type,
-     then no operations are supported.  */
-  if (!VECTOR_MODE_P (mode))
-    return false;
-
-  /* Do as many tests as possible without reqiring the selector.  */
-  icode = direct_optab_handler (vec_perm_optab, mode);
-  if (icode == CODE_FOR_nothing && GET_MODE_INNER (mode) != QImode)
-    {
-      enum machine_mode qimode
-	= mode_for_vector (QImode, GET_MODE_SIZE (mode));
-      if (VECTOR_MODE_P (qimode))
-	icode = direct_optab_handler (vec_perm_optab, qimode);
-    }
-  if (icode == CODE_FOR_nothing)
-    {
-      icode = direct_optab_handler (vec_perm_const_optab, mode);
-      if (icode != CODE_FOR_nothing
-	  && targetm.vectorize.vec_perm_const_ok != NULL)
-	need_sel_test = true;
-    }
-  if (icode == CODE_FOR_nothing)
-    return false;
-
-  /* If the selector is required, or if we need to test it, build it.  */
-  if (psel || need_sel_test)
-    {
-      int i, nelt = GET_MODE_NUNITS (mode), alt = 0;
-      unsigned char *data = XALLOCAVEC (unsigned char, nelt);
-
-      switch (code)
-	{
-	case VEC_EXTRACT_ODD_EXPR:
-	  alt = 1;
-	  /* FALLTHRU */
-	case VEC_EXTRACT_EVEN_EXPR:
-	  for (i = 0; i < nelt; ++i)
-	    data[i] = i * 2 + alt;
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
-
-      if (need_sel_test
-	  && !targetm.vectorize.vec_perm_const_ok (mode, data))
-	return false;
-
-      if (psel)
-	{
-	  rtvec vec = rtvec_alloc (nelt);
-	  enum machine_mode imode = mode;
-
-	  for (i = 0; i < nelt; ++i)
-	    RTVEC_ELT (vec, i) = GEN_INT (data[i]);
-
-	  if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
-	    {
-	      imode = int_mode_for_mode (GET_MODE_INNER (mode));
-	      imode = mode_for_vector (imode, nelt);
-	      gcc_assert (GET_MODE_CLASS (imode) == MODE_VECTOR_INT);
-	    }
-
-	  *psel = gen_rtx_CONST_VECTOR (imode, vec);
-	}
-    }
-
-  return true;
-}
-
 /* A subroutine of expand_vec_perm for expanding one vec_perm insn.  */
 
 static rtx
diff --git a/gcc/optabs.h b/gcc/optabs.h
index a7c43ac..cc4854d 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -332,9 +332,6 @@  enum optab_index
   OTI_vec_set,
   /* Extract specified field of vector operand.  */
   OTI_vec_extract,
-  /* Extract even/odd fields of vector operands.  */
-  OTI_vec_extract_even,
-  OTI_vec_extract_odd,
   /* Initialize vector operand.  */
   OTI_vec_init,
   /* Whole vector shift. The shift amount is in bits.  */
@@ -559,8 +556,6 @@  enum optab_index
 
 #define vec_set_optab (&optab_table[OTI_vec_set])
 #define vec_extract_optab (&optab_table[OTI_vec_extract])
-#define vec_extract_even_optab (&optab_table[OTI_vec_extract_even])
-#define vec_extract_odd_optab (&optab_table[OTI_vec_extract_odd])
 #define vec_init_optab (&optab_table[OTI_vec_init])
 #define vec_shl_optab (&optab_table[OTI_vec_shl])
 #define vec_shr_optab (&optab_table[OTI_vec_shr])
@@ -1003,9 +998,6 @@  extern rtx expand_vec_shift_expr (sepops, rtx);
 /* Return tree if target supports vector operations for VEC_PERM_EXPR.  */
 extern bool can_vec_perm_p (enum machine_mode, bool, const unsigned char *);
 
-/* Return true if target supports vector operations using VEC_PERM_EXPR.  */
-extern bool can_vec_perm_for_code_p (enum tree_code, enum machine_mode, rtx *);
-
 /* Generate code for VEC_PERM_EXPR.  */
 extern rtx expand_vec_perm (enum machine_mode, rtx, rtx, rtx, rtx);
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 1fce531..6e1a604 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3711,8 +3711,6 @@  do_pointer_plus_expr_check:
     case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_SAT_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
       /* FIXME.  */
       return false;
 
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index fb55346..c6ae65e 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -3399,8 +3399,6 @@  estimate_operator_cost (enum tree_code code, eni_weights *weights,
     case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_SAT_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
     case VEC_WIDEN_LSHIFT_HI_EXPR:
     case VEC_WIDEN_LSHIFT_LO_EXPR:
 
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 9363aea..4b9b453 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2388,22 +2388,6 @@  dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       dump_block_node (buffer, node, spc, flags);
       break;
 
-    case VEC_EXTRACT_EVEN_EXPR:
-      pp_string (buffer, " VEC_EXTRACT_EVEN_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);
-      pp_string (buffer, " > ");
-      break;
-
-    case VEC_EXTRACT_ODD_EXPR:
-      pp_string (buffer, " VEC_EXTRACT_ODD_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);
-      pp_string (buffer, " > ");
-      break;
-
     default:
       NIY;
     }
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index e6f0381..43f7662 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -3794,15 +3794,13 @@  vect_create_destination_var (tree scalar_dest, tree vectype)
 
 /* Function vect_strided_store_supported.
 
-   Returns TRUE is INTERLEAVE_HIGH and INTERLEAVE_LOW operations are supported,
-   and FALSE otherwise.  */
+   Returns TRUE if interleave high and interleave low permutations
+   are supported, and FALSE otherwise.  */
 
 bool
 vect_strided_store_supported (tree vectype, unsigned HOST_WIDE_INT count)
 {
-  enum machine_mode mode;
-
-  mode = TYPE_MODE (vectype);
+  enum machine_mode mode = TYPE_MODE (vectype);
 
   /* vect_permute_store_chain requires the group size to be a power of two.  */
   if (exact_log2 (count) == -1)
@@ -3813,7 +3811,7 @@  vect_strided_store_supported (tree vectype, unsigned HOST_WIDE_INT count)
       return false;
     }
 
-  /* Check that the operation is supported.  */
+  /* Check that the permutation is supported.  */
   if (VECTOR_MODE_P (mode))
     {
       unsigned int i, nelt = GET_MODE_NUNITS (mode);
@@ -3923,11 +3921,9 @@  vect_permute_store_chain (VEC(tree,heap) *dr_chain,
   tree vectype = STMT_VINFO_VECTYPE (vinfo_for_stmt (stmt));
   tree perm_mask_low, perm_mask_high;
   unsigned int i, n;
-  unsigned int j, nelt = GET_MODE_NUNITS (TYPE_MODE (vectype));
+  unsigned int j, nelt = TYPE_VECTOR_SUBPARTS (vectype);
   unsigned char *sel = XALLOCAVEC (unsigned char, nelt);
 
-  gcc_assert (vect_strided_store_supported (vectype, length));
-
   *result_chain = VEC_copy (tree, heap, dr_chain);
 
   for (i = 0, n = nelt / 2; i < n; i++)
@@ -3936,9 +3932,12 @@  vect_permute_store_chain (VEC(tree,heap) *dr_chain,
       sel[i * 2 + 1] = i + nelt;
     }
   perm_mask_high = vect_gen_perm_mask (vectype, sel);
+  gcc_assert (perm_mask_high != NULL);
+
   for (i = 0; i < nelt; i++)
     sel[i] += nelt / 2;
   perm_mask_low = vect_gen_perm_mask (vectype, sel);
+  gcc_assert (perm_mask_low != NULL);
 
   for (i = 0, n = exact_log2 (length); i < n; i++)
     {
@@ -4246,16 +4245,13 @@  vect_setup_realignment (gimple stmt, gimple_stmt_iterator *gsi,
 
 /* Function vect_strided_load_supported.
 
-   Returns TRUE is EXTRACT_EVEN and EXTRACT_ODD operations are supported,
+   Returns TRUE if even and odd permutations are supported,
    and FALSE otherwise.  */
 
 bool
 vect_strided_load_supported (tree vectype, unsigned HOST_WIDE_INT count)
 {
-  optab ee_optab, eo_optab;
-  enum machine_mode mode;
-
-  mode = TYPE_MODE (vectype);
+  enum machine_mode mode = TYPE_MODE (vectype);
 
   /* vect_permute_load_chain requires the group size to be a power of two.  */
   if (exact_log2 (count) == -1)
@@ -4266,18 +4262,22 @@  vect_strided_load_supported (tree vectype, unsigned HOST_WIDE_INT count)
       return false;
     }
 
-  ee_optab = optab_for_tree_code (VEC_EXTRACT_EVEN_EXPR,
-				  vectype, optab_default);
-  eo_optab = optab_for_tree_code (VEC_EXTRACT_ODD_EXPR,
-				  vectype, optab_default);
-  if (ee_optab && eo_optab
-      && optab_handler (ee_optab, mode) != CODE_FOR_nothing
-      && optab_handler (eo_optab, mode) != CODE_FOR_nothing)
-    return true;
+  /* Check that the permutation is supported.  */
+  if (VECTOR_MODE_P (mode))
+    {
+      unsigned int i, nelt = GET_MODE_NUNITS (mode);
+      unsigned char *sel = XALLOCAVEC (unsigned char, nelt);
 
-  if (can_vec_perm_for_code_p (VEC_EXTRACT_EVEN_EXPR, mode, NULL)
-      && can_vec_perm_for_code_p (VEC_EXTRACT_ODD_EXPR, mode, NULL))
-    return true;
+      for (i = 0; i < nelt; i++)
+	sel[i] = i * 2;
+      if (can_vec_perm_p (mode, false, sel))
+	{
+	  for (i = 0; i < nelt; i++)
+	    sel[i] = i * 2 + 1;
+	  if (can_vec_perm_p (mode, false, sel))
+	    return true;
+	}
+    }
 
   if (vect_print_dump_info (REPORT_DETAILS))
     fprintf (vect_dump, "extract even/odd not supported by target");
@@ -4379,17 +4379,28 @@  vect_permute_load_chain (VEC(tree,heap) *dr_chain,
 			 VEC(tree,heap) **result_chain)
 {
   tree perm_dest, data_ref, first_vect, second_vect;
+  tree perm_mask_even, perm_mask_odd;
   gimple perm_stmt;
   tree vectype = STMT_VINFO_VECTYPE (vinfo_for_stmt (stmt));
-  int i;
-  unsigned int j;
-
-  gcc_assert (vect_strided_load_supported (vectype, length));
+  unsigned int i, j, log_length = exact_log2 (length);
+  unsigned nelt = TYPE_VECTOR_SUBPARTS (vectype);
+  unsigned char *sel = XALLOCAVEC (unsigned char, nelt);
 
   *result_chain = VEC_copy (tree, heap, dr_chain);
-  for (i = 0; i < exact_log2 (length); i++)
+
+  for (i = 0; i < nelt; ++i)
+    sel[i] = i * 2;
+  perm_mask_even = vect_gen_perm_mask (vectype, sel);
+  gcc_assert (perm_mask_even != NULL);
+
+  for (i = 0; i < nelt; ++i)
+    sel[i] = i * 2 + 1;
+  perm_mask_odd = vect_gen_perm_mask (vectype, sel);
+  gcc_assert (perm_mask_odd != NULL);
+
+  for (i = 0; i < log_length; i++)
     {
-      for (j = 0; j < length; j +=2)
+      for (j = 0; j < length; j += 2)
 	{
 	  first_vect = VEC_index (tree, dr_chain, j);
 	  second_vect = VEC_index (tree, dr_chain, j+1);
@@ -4399,9 +4410,9 @@  vect_permute_load_chain (VEC(tree,heap) *dr_chain,
 	  DECL_GIMPLE_REG_P (perm_dest) = 1;
 	  add_referenced_var (perm_dest);
 
-	  perm_stmt = gimple_build_assign_with_ops (VEC_EXTRACT_EVEN_EXPR,
-						    perm_dest, first_vect,
-						    second_vect);
+	  perm_stmt = gimple_build_assign_with_ops3 (VEC_PERM_EXPR, perm_dest,
+						     first_vect, second_vect,
+						     perm_mask_even);
 
 	  data_ref = make_ssa_name (perm_dest, perm_stmt);
 	  gimple_assign_set_lhs (perm_stmt, data_ref);
@@ -4415,9 +4426,10 @@  vect_permute_load_chain (VEC(tree,heap) *dr_chain,
 	  DECL_GIMPLE_REG_P (perm_dest) = 1;
 	  add_referenced_var (perm_dest);
 
-	  perm_stmt = gimple_build_assign_with_ops (VEC_EXTRACT_ODD_EXPR,
-						    perm_dest, first_vect,
-						    second_vect);
+	  perm_stmt = gimple_build_assign_with_ops3 (VEC_PERM_EXPR, perm_dest,
+						     first_vect, second_vect,
+						     perm_mask_odd);
+
 	  data_ref = make_ssa_name (perm_dest, perm_stmt);
 	  gimple_assign_set_lhs (perm_stmt, data_ref);
 	  vect_finish_stmt_generation (stmt, perm_stmt, gsi);
diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c
index 3d97ba0..9dec8c6 100644
--- a/gcc/tree-vect-generic.c
+++ b/gcc/tree-vect-generic.c
@@ -773,13 +773,6 @@  expand_vector_operations_1 (gimple_stmt_iterator *gsi)
       || code == VIEW_CONVERT_EXPR)
     return;
 
-  /* These are only created by the vectorizer, after having queried
-     the target support.  It's more than just looking at the optab,
-     and there's no need to do it again.  */
-  if (code == VEC_EXTRACT_EVEN_EXPR
-      || code == VEC_EXTRACT_ODD_EXPR)
-    return;
-
   gcc_assert (code != CONVERT_EXPR);
 
   /* The signedness is determined from input argument.  */
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index a08b009..4deb16b 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -4542,8 +4542,8 @@  vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt,
 
      Then permutation statements are generated:
 
-     VS5: vx5 = VEC_EXTRACT_EVEN_EXPR < vx0, vx1 >
-     VS6: vx6 = VEC_EXTRACT_ODD_EXPR < vx0, vx1 >
+     VS5: vx5 = VEC_PERM_EXPR < vx0, vx1, { 0, 2, ..., i*2 } >
+     VS6: vx6 = VEC_PERM_EXPR < vx0, vx1, { 1, 3, ..., i*2+1 } >
        ...
 
      And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
diff --git a/gcc/tree.def b/gcc/tree.def
index 2f096f9..a307249 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1188,10 +1188,6 @@  DEFTREECODE (VEC_PACK_SAT_EXPR, "vec_pack_sat_expr", tcc_binary, 2)
    the output vector.  */
 DEFTREECODE (VEC_PACK_FIX_TRUNC_EXPR, "vec_pack_fix_trunc_expr", tcc_binary, 2)
 
-/* Extract even/odd fields from vectors.  */
-DEFTREECODE (VEC_EXTRACT_EVEN_EXPR, "vec_extract_even_expr", tcc_binary, 2)
-DEFTREECODE (VEC_EXTRACT_ODD_EXPR, "vec_extract_odd_expr", tcc_binary, 2)
-
 /* Widening vector shift left in bits.
    Operand 0 is a vector to be shifted with N elements of size S.
    Operand 1 is an integer shift amount in bits.