diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index baec5fe..ce14489 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2753,7 +2753,7 @@ tree-vect-slp.o: tree-vect-slp.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(TM_H) $(GGC_H) $(TREE_H) $(TARGET_H) $(BASIC_BLOCK_H) \
    $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(CFGLOOP_H) $(CFGLAYOUT_H) \
    $(EXPR_H) $(RECOG_H) $(OPTABS_H) $(TREE_VECTORIZER_H) tree-pretty-print.h \
-   gimple-pretty-print.h $(TREE_DATA_REF_H)
+   gimple-pretty-print.h $(TREE_DATA_REF_H) langhooks.h
 tree-vect-stmts.o: tree-vect-stmts.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(TM_H) $(GGC_H) $(TREE_H) $(TARGET_H) $(BASIC_BLOCK_H) \
    $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(CFGLOOP_H) $(CFGLAYOUT_H) \
diff --git a/gcc/optabs.c b/gcc/optabs.c
index e9a23f4..a373d7a 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6686,7 +6686,7 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
 }
 
 /* Return true if VEC_PERM_EXPR can be expanded using SIMD extensions
-   of the CPU.  */
+   of the CPU.  SEL may be NULL, which stands for an unknown constant.  */
 
 bool
 can_vec_perm_expr_p (tree type, tree sel)
@@ -6699,10 +6699,10 @@ can_vec_perm_expr_p (tree type, tree sel)
   if (!VECTOR_MODE_P (mode))
     return false;
 
-  if (TREE_CODE (sel) == VECTOR_CST)
+  if (sel == NULL || TREE_CODE (sel) == VECTOR_CST)
     {
       if (direct_optab_handler (vec_perm_const_optab, mode) != CODE_FOR_nothing
-	  && targetm.vectorize.builtin_vec_perm_ok (type, sel))
+	  && (sel == NULL || targetm.vectorize.builtin_vec_perm_ok (type, sel)))
 	return true;
     }
 
@@ -6722,7 +6722,7 @@ can_vec_perm_expr_p (tree type, tree sel)
 
   /* In order to support the lowering of non-constant permutations,
      we need to support shifts and adds.  */
-  if (TREE_CODE (sel) != VECTOR_CST)
+  if (sel != NULL && TREE_CODE (sel) != VECTOR_CST)
     {
       if (GET_MODE_UNIT_SIZE (mode) > 2
 	  && optab_handler (ashl_optab, mode) == CODE_FOR_nothing
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 4b205bf..852d94c 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -1,5 +1,5 @@
 /* SLP - Basic Block Vectorization
-   Copyright (C) 2007, 2008, 2009, 2010
+   Copyright (C) 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Dorit Naishlos <dorit@il.ibm.com>
    and Ira Rosen <irar@il.ibm.com>
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "optabs.h"
 #include "tree-vectorizer.h"
+#include "langhooks.h"
 
 /* Extract the location of the basic block in the source code.
    Return the basic block location if succeed and NULL if not.  */
@@ -2226,8 +2227,7 @@ static inline void
 vect_create_mask_and_perm (gimple stmt, gimple next_scalar_stmt,
                            tree mask, int first_vec_indx, int second_vec_indx,
                            gimple_stmt_iterator *gsi, slp_tree node,
-                           tree builtin_decl, tree vectype,
-                           VEC(tree,heap) *dr_chain,
+                           tree vectype, VEC(tree,heap) *dr_chain,
                            int ncopies, int vect_stmts_counter)
 {
   tree perm_dest;
@@ -2251,10 +2251,10 @@ vect_create_mask_and_perm (gimple stmt, gimple next_scalar_stmt,
       second_vec = VEC_index (tree, dr_chain, second_vec_indx);
 
       /* Generate the permute statement.  */
-      perm_stmt = gimple_build_call (builtin_decl,
-				     3, first_vec, second_vec, mask);
+      perm_stmt = gimple_build_assign_with_ops3 (VEC_PERM_EXPR, perm_dest,
+						 first_vec, second_vec, mask);
       data_ref = make_ssa_name (perm_dest, perm_stmt);
-      gimple_call_set_lhs (perm_stmt, data_ref);
+      gimple_set_lhs (perm_stmt, data_ref);
       vect_finish_stmt_generation (stmt, perm_stmt, gsi);
 
       /* Store the vector statement in NODE.  */
@@ -2361,9 +2361,9 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
 {
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
   tree mask_element_type = NULL_TREE, mask_type;
-  int i, j, k, m, scale, mask_nunits, nunits, vec_index = 0, scalar_index;
+  int i, j, k, nunits, vec_index = 0, scalar_index;
   slp_tree node;
-  tree vectype = STMT_VINFO_VECTYPE (stmt_info), builtin_decl;
+  tree vectype = STMT_VINFO_VECTYPE (stmt_info);
   gimple next_scalar_stmt;
   int group_size = SLP_INSTANCE_GROUP_SIZE (slp_node_instance);
   int first_mask_element;
@@ -2374,35 +2374,24 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
   bool mask_fixed = false;
   bool needs_first_vector = false;
 
-  if (!targetm.vectorize.builtin_vec_perm)
+  if (!can_vec_perm_expr_p (vectype, NULL_TREE))
     {
       if (vect_print_dump_info (REPORT_DETAILS))
         {
-          fprintf (vect_dump, "no builtin for vect permute for ");
+          fprintf (vect_dump, "no vect permute for ");
           print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM);
         }
-
-       return false;
-    }
-
-  builtin_decl = targetm.vectorize.builtin_vec_perm (vectype,
-                                                     &mask_element_type);
-  if (!builtin_decl || !mask_element_type)
-    {
-      if (vect_print_dump_info (REPORT_DETAILS))
-        {
-          fprintf (vect_dump, "no builtin for vect permute for ");
-          print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM);
-        }
-
-       return false;
+      return false;
     }
 
+  /* The generic VEC_PERM_EXPR code always uses an integral type of the
+     same size as the vector element being permuted.  */
+  mask_element_type
+    = lang_hooks.types.type_for_size
+    (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (vectype))), 1);
   mask_type = get_vectype_for_scalar_type (mask_element_type);
-  mask_nunits = TYPE_VECTOR_SUBPARTS (mask_type);
-  mask = (int *) xmalloc (sizeof (int) * mask_nunits);
   nunits = TYPE_VECTOR_SUBPARTS (vectype);
-  scale = mask_nunits / nunits;
+  mask = (int *) xmalloc (sizeof (int) * nunits);
   unroll_factor = SLP_INSTANCE_UNROLLING_FACTOR (slp_node_instance);
 
   /* The number of vector stmts to generate based only on SLP_NODE_INSTANCE
@@ -2425,8 +2414,7 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
      for b's: b0b0b0b1 b1b1b2b2 b2b3b3b3
      ...
 
-     The masks for a's should be: {0,0,0,3} {3,3,6,6} {6,9,9,9} (in target
-     scpecific type, e.g., in bytes for Altivec.
+     The masks for a's should be: {0,0,0,3} {3,3,6,6} {6,9,9,9}.
      The last mask is illegal since we assume two operands for permute
      operation, and the mask element values can't be outside that range.
      Hence, the last mask must be converted into {2,5,5,5}.
@@ -2451,20 +2439,17 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
         {
           for (k = 0; k < group_size; k++)
             {
-              first_mask_element = (i + j * group_size) * scale;
-              for (m = 0; m < scale; m++)
-                {
-                  if (!vect_get_mask_element (stmt, first_mask_element, m,
-                                   mask_nunits, only_one_vec, index, mask,
-                                   &current_mask_element, &need_next_vector,
-                                   &number_of_mask_fixes, &mask_fixed,
-                                   &needs_first_vector))
-                    return false;
-
-                  mask[index++] = current_mask_element;
-                }
+              first_mask_element = i + j * group_size;
+              if (!vect_get_mask_element (stmt, first_mask_element, 0,
+					  nunits, only_one_vec, index,
+					  mask, &current_mask_element,
+					  &need_next_vector,
+					  &number_of_mask_fixes, &mask_fixed,
+					  &needs_first_vector))
+		return false;
+	      mask[index++] = current_mask_element;
 
-              if (index == mask_nunits)
+              if (index == nunits)
                 {
 		  tree mask_vec = NULL;
 
@@ -2476,8 +2461,7 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
 		  mask_vec = build_vector (mask_type, mask_vec);
 		  index = 0;
 
-		  if (!targetm.vectorize.builtin_vec_perm_ok (vectype,
-							      mask_vec))
+		  if (!can_vec_perm_expr_p (vectype, mask_vec))
 		    {
 		      if (vect_print_dump_info (REPORT_DETAILS))
 			{
@@ -2501,7 +2485,7 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
 
                       vect_create_mask_and_perm (stmt, next_scalar_stmt,
                                mask_vec, first_vec_index, second_vec_index,
-			       gsi, node, builtin_decl, vectype, dr_chain,
+			       gsi, node, vectype, dr_chain,
 			       ncopies, vect_stmts_counter++);
                     }
                 }
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index f2ac8c7..d986ff8 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -3996,41 +3996,33 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt,
 }
 
 /* Given a vector type VECTYPE returns a builtin DECL to be used
-   for vector permutation and stores a mask into *MASK that implements
-   reversal of the vector elements.  If that is impossible to do
-   returns NULL (and *MASK is unchanged).  */
+   for vector permutation and returns the mask that implements
+   reversal of the vector elements.  If that is impossible to do,
+   returns NULL.  */
 
 static tree
-perm_mask_for_reverse (tree vectype, tree *mask)
+perm_mask_for_reverse (tree vectype)
 {
-  tree builtin_decl;
-  tree mask_element_type, mask_type;
-  tree mask_vec = NULL;
-  int i;
-  int nunits;
-  if (!targetm.vectorize.builtin_vec_perm)
-    return NULL;
+  tree mask_element_type, mask_type, mask_vec = NULL;
+  int i, nunits;
 
-  builtin_decl = targetm.vectorize.builtin_vec_perm (vectype,
-                                                     &mask_element_type);
-  if (!builtin_decl || !mask_element_type)
+  if (!can_vec_perm_expr_p (vectype, NULL_TREE))
     return NULL;
 
+  mask_element_type
+    = lang_hooks.types.type_for_size
+    (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (vectype))), 1);
   mask_type = get_vectype_for_scalar_type (mask_element_type);
   nunits = TYPE_VECTOR_SUBPARTS (vectype);
-  if (!mask_type
-      || TYPE_VECTOR_SUBPARTS (vectype) != TYPE_VECTOR_SUBPARTS (mask_type))
-    return NULL;
 
   for (i = 0; i < nunits; i++)
     mask_vec = tree_cons (NULL, build_int_cst (mask_element_type, i), mask_vec);
   mask_vec = build_vector (mask_type, mask_vec);
 
-  if (!targetm.vectorize.builtin_vec_perm_ok (vectype, mask_vec))
+  if (!can_vec_perm_expr_p (vectype, mask_vec))
     return NULL;
-  if (mask)
-    *mask = mask_vec;
-  return builtin_decl;
+
+  return mask_vec;
 }
 
 /* Given a vector variable X, that was generated for the scalar LHS of
@@ -4041,27 +4033,16 @@ static tree
 reverse_vec_elements (tree x, gimple stmt, gimple_stmt_iterator *gsi)
 {
   tree vectype = TREE_TYPE (x);
-  tree mask_vec, builtin_decl;
-  tree perm_dest, data_ref;
+  tree mask_vec, perm_dest, data_ref;
   gimple perm_stmt;
 
-  builtin_decl = perm_mask_for_reverse (vectype, &mask_vec);
+  mask_vec = perm_mask_for_reverse (vectype);
 
   perm_dest = vect_create_destination_var (gimple_assign_lhs (stmt), vectype);
 
   /* Generate the permute statement.  */
-  perm_stmt = gimple_build_call (builtin_decl, 3, x, x, mask_vec);
-  if (!useless_type_conversion_p (vectype,
-				  TREE_TYPE (TREE_TYPE (builtin_decl))))
-    {
-      tree tem = create_tmp_reg (TREE_TYPE (TREE_TYPE (builtin_decl)), NULL);
-      tem = make_ssa_name (tem, perm_stmt);
-      gimple_call_set_lhs (perm_stmt, tem);
-      vect_finish_stmt_generation (stmt, perm_stmt, gsi);
-      perm_stmt = gimple_build_assign (NULL_TREE,
-				       build1 (VIEW_CONVERT_EXPR,
-					       vectype, tem));
-    }
+  perm_stmt = gimple_build_assign_with_ops3 (VEC_PERM_EXPR, perm_dest,
+					     x, x, mask_vec);
   data_ref = make_ssa_name (perm_dest, perm_stmt);
   gimple_set_lhs (perm_stmt, data_ref);
   vect_finish_stmt_generation (stmt, perm_stmt, gsi);
@@ -4237,7 +4218,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt,
 	    fprintf (vect_dump, "negative step but alignment required.");
 	  return false;
 	}
-      if (!perm_mask_for_reverse (vectype, NULL))
+      if (!perm_mask_for_reverse (vectype))
 	{
 	  if (vect_print_dump_info (REPORT_DETAILS))
 	    fprintf (vect_dump, "negative step and reversing not supported.");
