re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / tree-vect-slp.c
index c2429b28693a9586a008fd3fb98edddb5d7f9bc0..e85e80dbbd10bec8cc7966fc8b11476b73803cc9 100644 (file)
@@ -1,6 +1,5 @@
 /* SLP - Basic Block Vectorization
-   Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2007-2015 Free Software Foundation, Inc.
    Contributed by Dorit Naishlos <dorit@il.ibm.com>
    and Ira Rosen <irar@il.ibm.com>
 
@@ -25,40 +24,67 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "dumpfile.h"
 #include "tm.h"
-#include "ggc.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
 #include "target.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
 #include "basic-block.h"
 #include "gimple-pretty-print.h"
-#include "tree-flow.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
 #include "tree-pass.h"
 #include "cfgloop.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "recog.h"             /* FIXME: for insn_data */
+#include "insn-codes.h"
 #include "optabs.h"
 #include "tree-vectorizer.h"
 #include "langhooks.h"
+#include "gimple-walk.h"
 
 /* Extract the location of the basic block in the source code.
    Return the basic block location if succeed and NULL if not.  */
 
-LOC
+source_location
 find_bb_location (basic_block bb)
 {
   gimple stmt = NULL;
   gimple_stmt_iterator si;
 
   if (!bb)
-    return UNKNOWN_LOC;
+    return UNKNOWN_LOCATION;
 
   for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
     {
       stmt = gsi_stmt (si);
-      if (gimple_location (stmt) != UNKNOWN_LOC)
+      if (gimple_location (stmt) != UNKNOWN_LOCATION)
         return gimple_location (stmt);
     }
 
-  return UNKNOWN_LOC;
+  return UNKNOWN_LOCATION;
 }
 
 
@@ -68,19 +94,18 @@ static void
 vect_free_slp_tree (slp_tree node)
 {
   int i;
-  slp_void_p child;
+  slp_tree child;
 
   if (!node)
     return;
 
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_free_slp_tree ((slp_tree) child);
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    vect_free_slp_tree (child);
 
-  VEC_free (slp_void_p, heap, SLP_TREE_CHILDREN (node));
-  VEC_free (gimple, heap, SLP_TREE_SCALAR_STMTS (node));
-
-  if (SLP_TREE_VEC_STMTS (node))
-    VEC_free (gimple, heap, SLP_TREE_VEC_STMTS (node));
+  SLP_TREE_CHILDREN (node).release ();
+  SLP_TREE_SCALAR_STMTS (node).release ();
+  SLP_TREE_VEC_STMTS (node).release ();
+  SLP_TREE_LOAD_PERMUTATION (node).release ();
 
   free (node);
 }
@@ -92,9 +117,7 @@ void
 vect_free_slp_instance (slp_instance instance)
 {
   vect_free_slp_tree (SLP_INSTANCE_TREE (instance));
-  VEC_free (int, heap, SLP_INSTANCE_LOAD_PERMUTATION (instance));
-  VEC_free (slp_tree, heap, SLP_INSTANCE_LOADS (instance));
-  VEC_free (stmt_info_for_cost, heap, SLP_INSTANCE_BODY_COST_VEC (instance));
+  SLP_INSTANCE_LOADS (instance).release ();
   free (instance);
 }
 
@@ -102,10 +125,10 @@ vect_free_slp_instance (slp_instance instance)
 /* Create an SLP node for SCALAR_STMTS.  */
 
 static slp_tree
-vect_create_new_slp_node (VEC (gimple, heap) *scalar_stmts)
+vect_create_new_slp_node (vec<gimple> scalar_stmts)
 {
   slp_tree node;
-  gimple stmt = VEC_index (gimple, scalar_stmts, 0);
+  gimple stmt = scalar_stmts[0];
   unsigned int nops;
 
   if (is_gimple_call (stmt))
@@ -121,8 +144,10 @@ vect_create_new_slp_node (VEC (gimple, heap) *scalar_stmts)
 
   node = XNEW (struct _slp_tree);
   SLP_TREE_SCALAR_STMTS (node) = scalar_stmts;
-  SLP_TREE_VEC_STMTS (node) = NULL;
-  SLP_TREE_CHILDREN (node) = VEC_alloc (slp_void_p, heap, nops);
+  SLP_TREE_VEC_STMTS (node).create (0);
+  SLP_TREE_CHILDREN (node).create (nops);
+  SLP_TREE_LOAD_PERMUTATION (node) = vNULL;
+  SLP_TREE_TWO_OPERATORS (node) = false;
 
   return node;
 }
@@ -130,23 +155,23 @@ vect_create_new_slp_node (VEC (gimple, heap) *scalar_stmts)
 
 /* Allocate operands info for NOPS operands, and GROUP_SIZE def-stmts for each
    operand.  */
-static VEC (slp_oprnd_info, heap) *
+static vec<slp_oprnd_info> 
 vect_create_oprnd_info (int nops, int group_size)
 {
   int i;
   slp_oprnd_info oprnd_info;
-  VEC (slp_oprnd_info, heap) *oprnds_info;
+  vec<slp_oprnd_info> oprnds_info;
 
-  oprnds_info = VEC_alloc (slp_oprnd_info, heap, nops);
+  oprnds_info.create (nops);
   for (i = 0; i < nops; i++)
     {
       oprnd_info = XNEW (struct _slp_oprnd_info);
-      oprnd_info->def_stmts = VEC_alloc (gimple, heap, group_size);
+      oprnd_info->def_stmts.create (group_size);
       oprnd_info->first_dt = vect_uninitialized_def;
-      oprnd_info->first_def_type = NULL_TREE;
-      oprnd_info->first_const_oprnd = NULL_TREE;
+      oprnd_info->first_op_type = NULL_TREE;
       oprnd_info->first_pattern = false;
-      VEC_quick_push (slp_oprnd_info, oprnds_info, oprnd_info);
+      oprnd_info->second_pattern = false;
+      oprnds_info.quick_push (oprnd_info);
     }
 
   return oprnds_info;
@@ -156,48 +181,71 @@ vect_create_oprnd_info (int nops, int group_size)
 /* Free operands info.  */
 
 static void
-vect_free_oprnd_info (VEC (slp_oprnd_info, heap) **oprnds_info)
+vect_free_oprnd_info (vec<slp_oprnd_info> &oprnds_info)
 {
   int i;
   slp_oprnd_info oprnd_info;
 
-  FOR_EACH_VEC_ELT (slp_oprnd_info, *oprnds_info, i, oprnd_info)
+  FOR_EACH_VEC_ELT (oprnds_info, i, oprnd_info)
     {
-      VEC_free (gimple, heap, oprnd_info->def_stmts);
+      oprnd_info->def_stmts.release ();
       XDELETE (oprnd_info);
     }
 
-  VEC_free (slp_oprnd_info, heap, *oprnds_info);
+  oprnds_info.release ();
+}
+
+
+/* Find the place of the data-ref in STMT in the interleaving chain that starts
+   from FIRST_STMT.  Return -1 if the data-ref is not a part of the chain.  */
+
+static int
+vect_get_place_in_interleaving_chain (gimple stmt, gimple first_stmt)
+{
+  gimple next_stmt = first_stmt;
+  int result = 0;
+
+  if (first_stmt != GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)))
+    return -1;
+
+  do
+    {
+      if (next_stmt == stmt)
+       return result;
+      next_stmt = GROUP_NEXT_ELEMENT (vinfo_for_stmt (next_stmt));
+      if (next_stmt)
+       result += GROUP_GAP (vinfo_for_stmt (next_stmt));
+    }
+  while (next_stmt);
+
+  return -1;
 }
 
 
 /* Get the defs for the rhs of STMT (collect them in OPRNDS_INFO), check that
    they are of a valid type and that they match the defs of the first stmt of
-   the SLP group (stored in OPRNDS_INFO).  */
+   the SLP group (stored in OPRNDS_INFO).  If there was a fatal error
+   return -1, if the error could be corrected by swapping operands of the
+   operation return 1, if everything is ok return 0.  */
 
-static bool
+static int 
 vect_get_and_check_slp_defs (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
-                             slp_tree slp_node, gimple stmt,
-                            int ncopies_for_cost, bool first,
-                             VEC (slp_oprnd_info, heap) **oprnds_info,
-                            stmt_vector_for_cost *prologue_cost_vec,
-                            stmt_vector_for_cost *body_cost_vec)
+                             gimple stmt, unsigned stmt_num,
+                             vec<slp_oprnd_info> *oprnds_info)
 {
   tree oprnd;
   unsigned int i, number_of_oprnds;
-  tree def, def_op0 = NULL_TREE;
+  tree def;
   gimple def_stmt;
   enum vect_def_type dt = vect_uninitialized_def;
-  enum vect_def_type dt_op0 = vect_uninitialized_def;
-  stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
-  tree lhs = gimple_get_lhs (stmt);
   struct loop *loop = NULL;
-  enum tree_code rhs_code;
-  bool different_types = false;
   bool pattern = false;
-  slp_oprnd_info oprnd_info, oprnd0_info, oprnd1_info;
-  int op_idx = 1;
-  tree compare_rhs = NULL_TREE;
+  slp_oprnd_info oprnd_info;
+  int first_op_idx = 1;
+  bool commutative = false;
+  bool first_op_cond = false;
+  bool first = stmt_num == 0;
+  bool second = stmt_num == 1;
 
   if (loop_vinfo)
     loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -205,47 +253,53 @@ vect_get_and_check_slp_defs (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
   if (is_gimple_call (stmt))
     {
       number_of_oprnds = gimple_call_num_args (stmt);
-      op_idx = 3;
+      first_op_idx = 3;
     }
   else if (is_gimple_assign (stmt))
     {
+      enum tree_code code = gimple_assign_rhs_code (stmt);
       number_of_oprnds = gimple_num_ops (stmt) - 1;
       if (gimple_assign_rhs_code (stmt) == COND_EXPR)
-        number_of_oprnds++;
+       {
+         first_op_cond = true;
+         commutative = true;
+         number_of_oprnds++;
+       }
+      else
+       commutative = commutative_tree_code (code);
     }
   else
-    return false;
+    return -1;
 
+  bool swapped = false;
   for (i = 0; i < number_of_oprnds; i++)
     {
-      if (compare_rhs)
+again:
+      if (first_op_cond)
        {
-         oprnd = compare_rhs;
-         compare_rhs = NULL_TREE;
+         if (i == 0 || i == 1)
+           oprnd = TREE_OPERAND (gimple_op (stmt, first_op_idx),
+                                 swapped ? !i : i);
+         else
+           oprnd = gimple_op (stmt, first_op_idx + i - 1);
        }
       else
-        oprnd = gimple_op (stmt, op_idx++);
+        oprnd = gimple_op (stmt, first_op_idx + (swapped ? !i : i));
 
-      oprnd_info = VEC_index (slp_oprnd_info, *oprnds_info, i);
-
-      if (COMPARISON_CLASS_P (oprnd))
-        {
-          compare_rhs = TREE_OPERAND (oprnd, 1);
-          oprnd = TREE_OPERAND (oprnd, 0);
-       }
+      oprnd_info = (*oprnds_info)[i];
 
       if (!vect_is_simple_use (oprnd, NULL, loop_vinfo, bb_vinfo, &def_stmt,
-                              &def, &dt)
-         || (!def_stmt && dt != vect_constant_def))
+                              &def, &dt))
        {
-         if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+         if (dump_enabled_p ())
            {
              dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                              "Build SLP failed: can't find def for ");
+                              "Build SLP failed: can't analyze def for ");
              dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, oprnd);
+              dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
            }
 
-         return false;
+         return -1;
        }
 
       /* Check if DEF_STMT is a part of a pattern in LOOP and get the def stmt
@@ -261,17 +315,30 @@ vect_get_and_check_slp_defs (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
          && !STMT_VINFO_LIVE_P (vinfo_for_stmt (def_stmt)))
         {
           pattern = true;
-          if (!first && !oprnd_info->first_pattern)
+          if (!first && !oprnd_info->first_pattern
+             /* Allow different pattern state for the defs of the
+                first stmt in reduction chains.  */
+             && (oprnd_info->first_dt != vect_reduction_def
+                 || (!second && !oprnd_info->second_pattern)))
            {
-             if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+             if (i == 0
+                 && !swapped
+                 && commutative)
+               {
+                 swapped = true;
+                 goto again;
+               }
+
+             if (dump_enabled_p ())
                {
                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                   "Build SLP failed: some of the stmts"
                                   " are in a pattern, and others are not ");
                  dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, oprnd);
+                  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                }
 
-             return false;
+             return 1;
             }
 
           def_stmt = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (def_stmt));
@@ -279,10 +346,10 @@ vect_get_and_check_slp_defs (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
 
           if (dt == vect_unknown_def_type)
             {
-              if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+              if (dump_enabled_p ())
                 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                "Unsupported pattern.");
-              return false;
+                                "Unsupported pattern.\n");
+              return -1;
             }
 
           switch (gimple_code (def_stmt))
@@ -296,49 +363,21 @@ vect_get_and_check_slp_defs (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
                 break;
 
               default:
-                if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                if (dump_enabled_p ())
                   dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                  "unsupported defining stmt: ");
-                return false;
+                                  "unsupported defining stmt:\n");
+                return -1;
             }
         }
 
+      if (second)
+       oprnd_info->second_pattern = pattern;
+
       if (first)
        {
          oprnd_info->first_dt = dt;
          oprnd_info->first_pattern = pattern;
-         if (def)
-           {
-             oprnd_info->first_def_type = TREE_TYPE (def);
-             oprnd_info->first_const_oprnd = NULL_TREE;
-           }
-         else
-            {
-              oprnd_info->first_def_type = NULL_TREE;
-              oprnd_info->first_const_oprnd = oprnd;
-            }
-
-         if (i == 0)
-           {
-             def_op0 = def;
-             dt_op0 = dt;
-             /* Analyze costs (for the first stmt of the group only).  */
-             if (REFERENCE_CLASS_P (lhs))
-               /* Store.  */
-                vect_model_store_cost (stmt_info, ncopies_for_cost, false,
-                                      dt, slp_node, prologue_cost_vec,
-                                      body_cost_vec);
-             else
-               {
-                 enum vect_def_type dts[2];
-                 dts[0] = dt;
-                 dts[1] = vect_uninitialized_def;
-                 /* Not memory operation (we don't call this function for
-                    loads).  */
-                 vect_model_simple_cost (stmt_info, ncopies_for_cost, dts,
-                                         prologue_cost_vec, body_cost_vec);
-               }
-           }
+         oprnd_info->first_op_type = TREE_TYPE (oprnd);
        }
       else
        {
@@ -349,64 +388,28 @@ vect_get_and_check_slp_defs (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
             vect_internal_def.  */
          if (((oprnd_info->first_dt != dt
                 && !(oprnd_info->first_dt == vect_reduction_def
-                     && dt == vect_internal_def))
-               || (oprnd_info->first_def_type != NULL_TREE
-                  && def
-                  && !types_compatible_p (oprnd_info->first_def_type,
-                                          TREE_TYPE (def))))
-              || (!def
-                  && !types_compatible_p (TREE_TYPE (oprnd_info->first_const_oprnd),
-                                          TREE_TYPE (oprnd)))
-              || different_types)
+                     && dt == vect_internal_def)
+               && !((oprnd_info->first_dt == vect_external_def
+                     || oprnd_info->first_dt == vect_constant_def)
+                    && (dt == vect_external_def
+                        || dt == vect_constant_def)))
+               || !types_compatible_p (oprnd_info->first_op_type,
+                                      TREE_TYPE (oprnd))))
            {
-             if (number_of_oprnds != 2)
+             /* Try swapping operands if we got a mismatch.  */
+             if (i == 0
+                 && !swapped
+                 && commutative)
                {
-                 if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-                   dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                    "Build SLP failed: different types ");
-
-                 return false;
-                }
+                 swapped = true;
+                 goto again;
+               }
 
-             /* Try to swap operands in case of binary operation.  */
-              if (i == 0)
-                different_types = true;
-              else
-               {
-                 oprnd0_info = VEC_index (slp_oprnd_info, *oprnds_info, 0);
-                 if (is_gimple_assign (stmt)
-                     && (rhs_code = gimple_assign_rhs_code (stmt))
-                     && TREE_CODE_CLASS (rhs_code) == tcc_binary
-                     && commutative_tree_code (rhs_code)
-                     && oprnd0_info->first_dt == dt
-                     && oprnd_info->first_dt == dt_op0
-                     && def_op0 && def
-                     && !(oprnd0_info->first_def_type
-                          && !types_compatible_p (oprnd0_info->first_def_type,
-                                                  TREE_TYPE (def)))
-                      && !(oprnd_info->first_def_type
-                           && !types_compatible_p (oprnd_info->first_def_type,
-                                                   TREE_TYPE (def_op0))))
-                    {
-                      if (dump_kind_p (MSG_NOTE))
-                       {
-                         dump_printf_loc (MSG_NOTE, vect_location,
-                                          "Swapping operands of ");
-                         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
-                       }
+             if (dump_enabled_p ())
+               dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                                "Build SLP failed: different types\n");
 
-                     swap_tree_operands (stmt, gimple_assign_rhs1_ptr (stmt),
-                                         gimple_assign_rhs2_ptr (stmt));
-                   }
-                  else
-                    {
-                     if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-                       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                        "Build SLP failed: different types ");
-
-                     return false;
-                   }
-               }
+             return 1;
            }
        }
 
@@ -419,123 +422,113 @@ vect_get_and_check_slp_defs (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
          break;
 
        case vect_internal_def:
-          if (different_types)
-            {
-             oprnd0_info = VEC_index (slp_oprnd_info, *oprnds_info, 0);
-             oprnd1_info = VEC_index (slp_oprnd_info, *oprnds_info, 0);
-              if (i == 0)
-                VEC_quick_push (gimple, oprnd1_info->def_stmts, def_stmt);
-              else
-                VEC_quick_push (gimple, oprnd0_info->def_stmts, def_stmt);
-            }
-         else
-           VEC_quick_push (gimple, oprnd_info->def_stmts, def_stmt);
-
+         oprnd_info->def_stmts.quick_push (def_stmt);
          break;
 
        default:
          /* FORNOW: Not supported.  */
-         if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+         if (dump_enabled_p ())
            {
              dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                               "Build SLP failed: illegal type of def ");
              dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, def);
+              dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
            }
 
-         return false;
+         return -1;
        }
     }
 
-  return true;
+  /* Swap operands.  */
+  if (swapped)
+    {
+      if (first_op_cond)
+       {
+         tree cond = gimple_assign_rhs1 (stmt);
+         swap_ssa_operands (stmt, &TREE_OPERAND (cond, 0),
+                            &TREE_OPERAND (cond, 1));
+         TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond)));
+       }
+      else
+       swap_ssa_operands (stmt, gimple_assign_rhs1_ptr (stmt),
+                          gimple_assign_rhs2_ptr (stmt));
+    }
+
+  return 0;
 }
 
 
-/* Recursively build an SLP tree starting from NODE.
-   Fail (and return FALSE) if def-stmts are not isomorphic, require data
-   permutation or are of unsupported types of operation.  Otherwise, return
-   TRUE.  */
+/* Verify if the scalar stmts STMTS are isomorphic, require data
+   permutation or are of unsupported types of operation.  Return
+   true if they are, otherwise return false and indicate in *MATCHES
+   which stmts are not isomorphic to the first one.  If MATCHES[0]
+   is false then this indicates the comparison could not be
+   carried out or the stmts will never be vectorized by SLP.  */
 
 static bool
-vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
-                     slp_tree *node, unsigned int group_size, int *outside_cost,
-                     int ncopies_for_cost, unsigned int *max_nunits,
-                     VEC (int, heap) **load_permutation,
-                     VEC (slp_tree, heap) **loads,
-                     unsigned int vectorization_factor, bool *loads_permuted,
-                    stmt_vector_for_cost *prologue_cost_vec,
-                    stmt_vector_for_cost *body_cost_vec)
+vect_build_slp_tree_1 (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
+                      vec<gimple> stmts, unsigned int group_size,
+                      unsigned nops, unsigned int *max_nunits,
+                      unsigned int vectorization_factor, bool *matches,
+                      bool *two_operators)
 {
   unsigned int i;
-  VEC (gimple, heap) *stmts = SLP_TREE_SCALAR_STMTS (*node);
-  gimple stmt = VEC_index (gimple, stmts, 0);
-  enum tree_code first_stmt_code = ERROR_MARK, rhs_code = ERROR_MARK;
+  gimple first_stmt = stmts[0], stmt = stmts[0];
+  enum tree_code first_stmt_code = ERROR_MARK;
+  enum tree_code alt_stmt_code = ERROR_MARK;
+  enum tree_code rhs_code = ERROR_MARK;
   enum tree_code first_cond_code = ERROR_MARK;
   tree lhs;
-  bool stop_recursion = false, need_same_oprnds = false;
-  tree vectype, scalar_type, first_op1 = NULL_TREE;
-  unsigned int ncopies;
+  bool need_same_oprnds = false;
+  tree vectype = NULL_TREE, scalar_type, first_op1 = NULL_TREE;
   optab optab;
   int icode;
-  enum machine_mode optab_op2_mode;
-  enum machine_mode vec_mode;
-  struct data_reference *first_dr;
+  machine_mode optab_op2_mode;
+  machine_mode vec_mode;
   HOST_WIDE_INT dummy;
-  bool permutation = false;
-  unsigned int load_place;
-  gimple first_load = NULL, prev_first_load = NULL, old_first_load = NULL;
-  VEC (slp_oprnd_info, heap) *oprnds_info;
-  unsigned int nops;
-  slp_oprnd_info oprnd_info;
+  gimple first_load = NULL, prev_first_load = NULL;
   tree cond;
 
-  if (is_gimple_call (stmt))
-    nops = gimple_call_num_args (stmt);
-  else if (is_gimple_assign (stmt))
-    {
-      nops = gimple_num_ops (stmt) - 1;
-      if (gimple_assign_rhs_code (stmt) == COND_EXPR)
-       nops++;
-    }
-  else
-    return false;
-
-  oprnds_info = vect_create_oprnd_info (nops, group_size);
-
   /* For every stmt in NODE find its def stmt/s.  */
-  FOR_EACH_VEC_ELT (gimple, stmts, i, stmt)
+  FOR_EACH_VEC_ELT (stmts, i, stmt)
     {
-      if (dump_kind_p (MSG_NOTE))
+      matches[i] = false;
+
+      if (dump_enabled_p ())
        {
          dump_printf_loc (MSG_NOTE, vect_location, "Build SLP for ");
          dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
+          dump_printf (MSG_NOTE, "\n");
        }
 
       /* Fail to vectorize statements marked as unvectorizable.  */
       if (!STMT_VINFO_VECTORIZABLE (vinfo_for_stmt (stmt)))
         {
-          if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+          if (dump_enabled_p ())
             {
               dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                               "Build SLP failed: unvectorizable statement ");
               dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+              dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
             }
-
-         vect_free_oprnd_info (&oprnds_info);
+         /* Fatal mismatch.  */
+         matches[0] = false;
           return false;
         }
 
       lhs = gimple_get_lhs (stmt);
       if (lhs == NULL_TREE)
        {
-         if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+         if (dump_enabled_p ())
            {
              dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                               "Build SLP failed: not GIMPLE_ASSIGN nor "
                               "GIMPLE_CALL ");
              dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+              dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
            }
-
-         vect_free_oprnd_info (&oprnds_info);
+         /* Fatal mismatch.  */
+         matches[0] = false;
          return false;
        }
 
@@ -544,15 +537,16 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
            && (cond = gimple_assign_rhs1 (stmt))
            && !COMPARISON_CLASS_P (cond))
         {
-          if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+          if (dump_enabled_p ())
             {
               dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
                               "Build SLP failed: condition is not "
                               "comparison ");
               dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+              dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
             }
-
-         vect_free_oprnd_info (&oprnds_info);
+         /* Fatal mismatch.  */
+         matches[0] = false;
           return false;
         }
 
@@ -560,18 +554,32 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
       vectype = get_vectype_for_scalar_type (scalar_type);
       if (!vectype)
         {
-          if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+          if (dump_enabled_p ())
             {
               dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
                               "Build SLP failed: unsupported data-type ");
               dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
                                 scalar_type);
+              dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
             }
-
-         vect_free_oprnd_info (&oprnds_info);
+         /* Fatal mismatch.  */
+         matches[0] = false;
           return false;
         }
 
+      /* If populating the vector type requires unrolling then fail
+         before adjusting *max_nunits for basic-block vectorization.  */
+      if (bb_vinfo
+         && TYPE_VECTOR_SUBPARTS (vectype) > group_size)
+       {
+         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
+                          "Build SLP failed: unrolling required "
+                          "in basic block SLP\n");
+         /* Fatal mismatch.  */
+         matches[0] = false;
+         return false;
+       }
+
       /* In case of multiple types we need to detect the smallest type.  */
       if (*max_nunits < TYPE_VECTOR_SUBPARTS (vectype))
         {
@@ -580,25 +588,25 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
             vectorization_factor = *max_nunits;
         }
 
-      ncopies = vectorization_factor / TYPE_VECTOR_SUBPARTS (vectype);
-
-      if (is_gimple_call (stmt))
+      if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
        {
          rhs_code = CALL_EXPR;
-         if (gimple_call_internal_p (stmt)
-             || gimple_call_tail_p (stmt)
-             || gimple_call_noreturn_p (stmt)
-             || !gimple_call_nothrow_p (stmt)
-             || gimple_call_chain (stmt))
+         if (gimple_call_internal_p (call_stmt)
+             || gimple_call_tail_p (call_stmt)
+             || gimple_call_noreturn_p (call_stmt)
+             || !gimple_call_nothrow_p (call_stmt)
+             || gimple_call_chain (call_stmt))
            {
-             if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+             if (dump_enabled_p ())
                {
                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
                                   "Build SLP failed: unsupported call type ");
-                 dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+                 dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
+                                   call_stmt, 0);
+                  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                }
-
-             vect_free_oprnd_info (&oprnds_info);
+             /* Fatal mismatch.  */
+             matches[0] = false;
              return false;
            }
        }
@@ -631,20 +639,22 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
 
                  if (!optab)
                    {
-                     if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                     if (dump_enabled_p ())
                        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                        "Build SLP failed: no optab.");
-                     vect_free_oprnd_info (&oprnds_info);
+                                        "Build SLP failed: no optab.\n");
+                     /* Fatal mismatch.  */
+                     matches[0] = false;
                      return false;
                    }
                  icode = (int) optab_handler (optab, vec_mode);
                  if (icode == CODE_FOR_nothing)
                    {
-                     if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                     if (dump_enabled_p ())
                        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                         "Build SLP failed: "
-                                        "op not supported by target.");
-                     vect_free_oprnd_info (&oprnds_info);
+                                        "op not supported by target.\n");
+                     /* Fatal mismatch.  */
+                     matches[0] = false;
                      return false;
                    }
                  optab_op2_mode = insn_data[icode].operand[2].mode;
@@ -663,63 +673,77 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
        }
       else
        {
+         if (first_stmt_code != rhs_code
+             && alt_stmt_code == ERROR_MARK)
+           alt_stmt_code = rhs_code;
          if (first_stmt_code != rhs_code
              && (first_stmt_code != IMAGPART_EXPR
                  || rhs_code != REALPART_EXPR)
              && (first_stmt_code != REALPART_EXPR
                  || rhs_code != IMAGPART_EXPR)
+             /* Handle mismatches in plus/minus by computing both
+                and merging the results.  */
+             && !((first_stmt_code == PLUS_EXPR
+                   || first_stmt_code == MINUS_EXPR)
+                  && (alt_stmt_code == PLUS_EXPR
+                      || alt_stmt_code == MINUS_EXPR)
+                  && rhs_code == alt_stmt_code)
               && !(STMT_VINFO_GROUPED_ACCESS (vinfo_for_stmt (stmt))
                    && (first_stmt_code == ARRAY_REF
+                       || first_stmt_code == BIT_FIELD_REF
                        || first_stmt_code == INDIRECT_REF
                        || first_stmt_code == COMPONENT_REF
                        || first_stmt_code == MEM_REF)))
            {
-             if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+             if (dump_enabled_p ())
                {
                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
                                   "Build SLP failed: different operation "
                                   "in stmt ");
                  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+                 dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                                  "original stmt ");
+                 dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
+                                   first_stmt, 0);
                }
-
-             vect_free_oprnd_info (&oprnds_info);
-             return false;
+             /* Mismatch.  */
+             continue;
            }
 
          if (need_same_oprnds
              && !operand_equal_p (first_op1, gimple_assign_rhs2 (stmt), 0))
            {
-             if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+             if (dump_enabled_p ())
                {
                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
                                   "Build SLP failed: different shift "
                                   "arguments in ");
                  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+                  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                }
-
-             vect_free_oprnd_info (&oprnds_info);
-             return false;
+             /* Mismatch.  */
+             continue;
            }
 
          if (rhs_code == CALL_EXPR)
            {
-             gimple first_stmt = VEC_index (gimple, stmts, 0);
+             gimple first_stmt = stmts[0];
              if (gimple_call_num_args (stmt) != nops
                  || !operand_equal_p (gimple_call_fn (first_stmt),
                                       gimple_call_fn (stmt), 0)
                  || gimple_call_fntype (first_stmt)
                     != gimple_call_fntype (stmt))
                {
-                 if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                 if (dump_enabled_p ())
                    {
                      dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
                                       "Build SLP failed: different calls in ");
                      dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
                                        stmt, 0);
+                      dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                    }
-
-                 vect_free_oprnd_info (&oprnds_info);
-                 return false;
+                 /* Mismatch.  */
+                 continue;
                }
            }
        }
@@ -730,44 +754,22 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
          if (REFERENCE_CLASS_P (lhs))
            {
              /* Store.  */
-             if (!vect_get_and_check_slp_defs (loop_vinfo, bb_vinfo, *node,
-                                               stmt, ncopies_for_cost,
-                                               (i == 0), &oprnds_info,
-                                               prologue_cost_vec,
-                                               body_cost_vec))
-               {
-                 vect_free_oprnd_info (&oprnds_info);
-                 return false;
-               }
+             ;
            }
          else
            {
              /* Load.  */
-              /* FORNOW: Check that there is no gap between the loads.  */
-              if ((GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) == stmt
-                   && GROUP_GAP (vinfo_for_stmt (stmt)) != 0)
-                  || (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) != stmt
-                      && GROUP_GAP (vinfo_for_stmt (stmt)) != 1))
-                {
-                  if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-                    {
-                      dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                      "Build SLP failed: grouped "
-                                      "loads have gaps ");
-                      dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
-                                       stmt, 0);
-                    }
-
-                 vect_free_oprnd_info (&oprnds_info);
-                  return false;
-                }
-
               /* Check that the size of interleaved loads group is not
                  greater than the SLP group size.  */
+             unsigned ncopies
+               = vectorization_factor / TYPE_VECTOR_SUBPARTS (vectype);
               if (loop_vinfo
-                  && GROUP_SIZE (vinfo_for_stmt (stmt)) > ncopies * group_size)
+                 && GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) == stmt
+                  && ((GROUP_SIZE (vinfo_for_stmt (stmt))
+                      - GROUP_GAP (vinfo_for_stmt (stmt)))
+                     > ncopies * group_size))
                 {
-                  if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                  if (dump_enabled_p ())
                     {
                       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                       "Build SLP failed: the number "
@@ -775,24 +777,21 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
                                       "the SLP group size ");
                       dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
                                        stmt, 0);
+                      dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                     }
-
-                 vect_free_oprnd_info (&oprnds_info);
+                 /* Fatal mismatch.  */
+                 matches[0] = false;
                   return false;
                 }
 
-             old_first_load = first_load;
               first_load = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt));
               if (prev_first_load)
                 {
                   /* Check that there are no loads from different interleaving
-                     chains in the same node.  The only exception is complex
-                     numbers.  */
-                  if (prev_first_load != first_load
-                      && rhs_code != REALPART_EXPR
-                      && rhs_code != IMAGPART_EXPR)
+                     chains in the same node.  */
+                  if (prev_first_load != first_load)
                     {
-                      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                      if (dump_enabled_p ())
                         {
                           dump_printf_loc (MSG_MISSED_OPTIMIZATION,
                                           vect_location, 
@@ -800,56 +799,14 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
                                           "interleaving chains in one node ");
                           dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
                                            stmt, 0);
+                          dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                         }
-
-                     vect_free_oprnd_info (&oprnds_info);
-                      return false;
+                     /* Mismatch.  */
+                     continue;
                     }
                 }
               else
                 prev_first_load = first_load;
-
-             /* In some cases a group of loads is just the same load
-                repeated N times.  Only analyze its cost once.  */
-              if (first_load == stmt && old_first_load != first_load)
-                {
-                  first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt));
-                  if (vect_supportable_dr_alignment (first_dr, false)
-                      == dr_unaligned_unsupported)
-                    {
-                      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-                        {
-                          dump_printf_loc (MSG_MISSED_OPTIMIZATION,
-                                          vect_location, 
-                                          "Build SLP failed: unsupported "
-                                          "unaligned load ");
-                          dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
-                                           stmt, 0);
-                        }
-
-                     vect_free_oprnd_info (&oprnds_info);
-                      return false;
-                    }
-
-                  /* Analyze costs (for the first stmt in the group).  */
-                  vect_model_load_cost (vinfo_for_stmt (stmt),
-                                        ncopies_for_cost, false, *node,
-                                       prologue_cost_vec, body_cost_vec);
-                }
-
-              /* Store the place of this load in the interleaving chain.  In
-                 case that permutation is needed we later decide if a specific
-                 permutation is supported.  */
-              load_place = vect_get_place_in_interleaving_chain (stmt,
-                                                                 first_load);
-              if (load_place != i)
-                permutation = true;
-
-              VEC_safe_push (int, heap, *load_permutation, load_place);
-
-              /* We stop the tree when we reach a group of loads.  */
-              stop_recursion = true;
-             continue;
            }
         } /* Grouped access.  */
       else
@@ -857,33 +814,36 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
          if (TREE_CODE_CLASS (rhs_code) == tcc_reference)
            {
              /* Not grouped load.  */
-             if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+             if (dump_enabled_p ())
                {
                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
                                   "Build SLP failed: not grouped load ");
                  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+                  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                }
 
              /* FORNOW: Not grouped loads are not supported.  */
-             vect_free_oprnd_info (&oprnds_info);
+             /* Fatal mismatch.  */
+             matches[0] = false;
              return false;
            }
 
          /* Not memory operation.  */
          if (TREE_CODE_CLASS (rhs_code) != tcc_binary
              && TREE_CODE_CLASS (rhs_code) != tcc_unary
-             && rhs_code != COND_EXPR
+             && TREE_CODE_CLASS (rhs_code) != tcc_expression
              && rhs_code != CALL_EXPR)
            {
-             if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+             if (dump_enabled_p ())
                {
                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                   "Build SLP failed: operation");
                  dump_printf (MSG_MISSED_OPTIMIZATION, " unsupported ");
                  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+                  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                }
-
-             vect_free_oprnd_info (&oprnds_info);
+             /* Fatal mismatch.  */
+             matches[0] = false;
              return false;
            }
 
@@ -895,84 +855,317 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
                first_cond_code = TREE_CODE (cond_expr);
               else if (first_cond_code != TREE_CODE (cond_expr))
                 {
-                  if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                  if (dump_enabled_p ())
                     {
                       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                       "Build SLP failed: different"
                                       " operation");
                       dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
                                        stmt, 0);
+                      dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                     }
-
-                 vect_free_oprnd_info (&oprnds_info);
-                  return false;
+                 /* Mismatch.  */
+                 continue;
                }
             }
+       }
 
-         /* Find the def-stmts.  */
-         if (!vect_get_and_check_slp_defs (loop_vinfo, bb_vinfo, *node, stmt,
-                                           ncopies_for_cost, (i == 0),
-                                           &oprnds_info, prologue_cost_vec,
-                                           body_cost_vec))
-           {
-             vect_free_oprnd_info (&oprnds_info);
-             return false;
-           }
+      matches[i] = true;
+    }
+
+  for (i = 0; i < group_size; ++i)
+    if (!matches[i])
+      return false;
+
+  /* If we allowed a two-operation SLP node verify the target can cope
+     with the permute we are going to use.  */
+  if (alt_stmt_code != ERROR_MARK
+      && TREE_CODE_CLASS (alt_stmt_code) != tcc_reference)
+    {
+      unsigned char *sel
+       = XALLOCAVEC (unsigned char, TYPE_VECTOR_SUBPARTS (vectype));
+      for (i = 0; i < TYPE_VECTOR_SUBPARTS (vectype); ++i)
+       {
+         sel[i] = i;
+         if (gimple_assign_rhs_code (stmts[i % group_size]) == alt_stmt_code)
+           sel[i] += TYPE_VECTOR_SUBPARTS (vectype);
        }
+      if (!can_vec_perm_p (TYPE_MODE (vectype), false, sel))
+       {
+         for (i = 0; i < group_size; ++i)
+           if (gimple_assign_rhs_code (stmts[i]) == alt_stmt_code)
+             {
+               matches[i] = false;
+               if (dump_enabled_p ())
+                 {
+                   dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                                    "Build SLP failed: different operation "
+                                    "in stmt ");
+                   dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
+                                     stmts[i], 0);
+                   dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                                    "original stmt ");
+                   dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
+                                     first_stmt, 0);
+                 }
+             }
+         return false;
+       }
+      *two_operators = true;
     }
 
-  /* Grouped loads were reached - stop the recursion.  */
-  if (stop_recursion)
+  return true;
+}
+
+/* Recursively build an SLP tree starting from NODE.
+   Fail (and return a value not equal to zero) if def-stmts are not
+   isomorphic, require data permutation or are of unsupported types of
+   operation.  Otherwise, return 0.
+   The value returned is the depth in the SLP tree where a mismatch
+   was found.  */
+
+static bool
+vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
+                     slp_tree *node, unsigned int group_size,
+                     unsigned int *max_nunits,
+                     vec<slp_tree> *loads,
+                     unsigned int vectorization_factor,
+                    bool *matches, unsigned *npermutes, unsigned *tree_size,
+                    unsigned max_tree_size)
+{
+  unsigned nops, i, this_tree_size = 0;
+  gimple stmt;
+
+  matches[0] = false;
+
+  stmt = SLP_TREE_SCALAR_STMTS (*node)[0];
+  if (is_gimple_call (stmt))
+    nops = gimple_call_num_args (stmt);
+  else if (is_gimple_assign (stmt))
     {
-      VEC_safe_push (slp_tree, heap, *loads, *node);
-      if (permutation)
-        {
-         gimple first_stmt = VEC_index (gimple, stmts, 0);
-          *loads_permuted = true;
-         (void) record_stmt_cost (body_cost_vec, group_size, vec_perm, 
-                                  vinfo_for_stmt (first_stmt), 0, vect_body);
-        }
-      else
-        {
-          /* We don't check here complex numbers chains, so we set
-             LOADS_PERMUTED for further check in
-             vect_supported_load_permutation_p.  */
-          if (rhs_code == REALPART_EXPR || rhs_code == IMAGPART_EXPR)
-            *loads_permuted = true;
-        }
+      nops = gimple_num_ops (stmt) - 1;
+      if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+       nops++;
+    }
+  else
+    return false;
+
+  bool two_operators = false;
+  if (!vect_build_slp_tree_1 (loop_vinfo, bb_vinfo,
+                             SLP_TREE_SCALAR_STMTS (*node), group_size, nops,
+                             max_nunits, vectorization_factor, matches,
+                             &two_operators))
+    return false;
+  SLP_TREE_TWO_OPERATORS (*node) = two_operators;
 
-      vect_free_oprnd_info (&oprnds_info);
+  /* If the SLP node is a load, terminate the recursion.  */
+  if (STMT_VINFO_GROUPED_ACCESS (vinfo_for_stmt (stmt))
+      && DR_IS_READ (STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt))))
+    {
+      loads->safe_push (*node);
       return true;
     }
 
+  /* Get at the operands, verifying they are compatible.  */
+  vec<slp_oprnd_info> oprnds_info = vect_create_oprnd_info (nops, group_size);
+  slp_oprnd_info oprnd_info;
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (*node), i, stmt)
+    {
+      switch (vect_get_and_check_slp_defs (loop_vinfo, bb_vinfo,
+                                          stmt, i, &oprnds_info))
+       {
+       case 0:
+         break;
+       case -1:
+         matches[0] = false;
+         vect_free_oprnd_info (oprnds_info);
+         return false;
+       case 1:
+         matches[i] = false;
+         break;
+       }
+    }
+  for (i = 0; i < group_size; ++i)
+    if (!matches[i])
+      {
+       vect_free_oprnd_info (oprnds_info);
+       return false;
+      }
+
+  stmt = SLP_TREE_SCALAR_STMTS (*node)[0];
+
   /* Create SLP_TREE nodes for the definition node/s.  */
-  FOR_EACH_VEC_ELT (slp_oprnd_info, oprnds_info, i, oprnd_info)
+  FOR_EACH_VEC_ELT (oprnds_info, i, oprnd_info)
     {
       slp_tree child;
+      unsigned old_nloads = loads->length ();
+      unsigned old_max_nunits = *max_nunits;
 
       if (oprnd_info->first_dt != vect_internal_def)
         continue;
 
+      if (++this_tree_size > max_tree_size)
+       {
+         vect_free_oprnd_info (oprnds_info);
+         return false;
+       }
+
       child = vect_create_new_slp_node (oprnd_info->def_stmts);
-      if (!child
-          || !vect_build_slp_tree (loop_vinfo, bb_vinfo, &child, group_size,
-                                  outside_cost, ncopies_for_cost,
-                                  max_nunits, load_permutation, loads,
-                                  vectorization_factor, loads_permuted,
-                                  prologue_cost_vec, body_cost_vec))
-        {
-         if (child)
-           oprnd_info->def_stmts = NULL;
+      if (!child)
+       {
+         vect_free_oprnd_info (oprnds_info);
+         return false;
+       }
+
+      if (vect_build_slp_tree (loop_vinfo, bb_vinfo, &child,
+                              group_size, max_nunits, loads,
+                              vectorization_factor, matches,
+                              npermutes, &this_tree_size, max_tree_size))
+       {
+         /* If we have all children of child built up from scalars then just
+            throw that away and build it up this node from scalars.  */
+         if (!SLP_TREE_CHILDREN (child).is_empty ())
+           {
+             unsigned int j;
+             slp_tree grandchild;
+
+             FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (child), j, grandchild)
+               if (grandchild != NULL)
+                 break;
+             if (!grandchild)
+               {
+                 /* Roll back.  */
+                 *max_nunits = old_max_nunits;
+                 loads->truncate (old_nloads);
+                 FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (child), j, grandchild)
+                     vect_free_slp_tree (grandchild);
+                 SLP_TREE_CHILDREN (child).truncate (0);
+
+                 dump_printf_loc (MSG_NOTE, vect_location,
+                                  "Building parent vector operands from "
+                                  "scalars instead\n");
+                 oprnd_info->def_stmts = vNULL;
+                 vect_free_slp_tree (child);
+                 SLP_TREE_CHILDREN (*node).quick_push (NULL);
+                 continue;
+               }
+           }
+
+         oprnd_info->def_stmts = vNULL;
+         SLP_TREE_CHILDREN (*node).quick_push (child);
+         continue;
+       }
+
+      /* If the SLP build failed fatally and we analyze a basic-block
+         simply treat nodes we fail to build as externally defined
+        (and thus build vectors from the scalar defs).
+        The cost model will reject outright expensive cases.
+        ???  This doesn't treat cases where permutation ultimatively
+        fails (or we don't try permutation below).  Ideally we'd
+        even compute a permutation that will end up with the maximum
+        SLP tree size...  */
+      if (bb_vinfo
+         && !matches[0]
+         /* ???  Rejecting patterns this way doesn't work.  We'd have to
+            do extra work to cancel the pattern so the uses see the
+            scalar version.  */
+         && !is_pattern_stmt_p (vinfo_for_stmt (stmt)))
+       {
+         unsigned int j;
+         slp_tree grandchild;
+
+         /* Roll back.  */
+         *max_nunits = old_max_nunits;
+         loads->truncate (old_nloads);
+         FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (child), j, grandchild)
+           vect_free_slp_tree (grandchild);
+         SLP_TREE_CHILDREN (child).truncate (0);
+
+         dump_printf_loc (MSG_NOTE, vect_location,
+                          "Building vector operands from scalars\n");
+         oprnd_info->def_stmts = vNULL;
          vect_free_slp_tree (child);
-         vect_free_oprnd_info (&oprnds_info);
-         return false;
+         SLP_TREE_CHILDREN (*node).quick_push (NULL);
+         continue;
        }
 
-      oprnd_info->def_stmts = NULL;
-      VEC_quick_push (slp_void_p, SLP_TREE_CHILDREN (*node), child);
+      /* If the SLP build for operand zero failed and operand zero
+        and one can be commutated try that for the scalar stmts
+        that failed the match.  */
+      if (i == 0
+         /* A first scalar stmt mismatch signals a fatal mismatch.  */
+         && matches[0]
+         /* ???  For COND_EXPRs we can swap the comparison operands
+            as well as the arms under some constraints.  */
+         && nops == 2
+         && oprnds_info[1]->first_dt == vect_internal_def
+         && is_gimple_assign (stmt)
+         && commutative_tree_code (gimple_assign_rhs_code (stmt))
+         && !SLP_TREE_TWO_OPERATORS (*node)
+         /* Do so only if the number of not successful permutes was nor more
+            than a cut-ff as re-trying the recursive match on
+            possibly each level of the tree would expose exponential
+            behavior.  */
+         && *npermutes < 4)
+       {
+         unsigned int j;
+         slp_tree grandchild;
+
+         /* Roll back.  */
+         *max_nunits = old_max_nunits;
+         loads->truncate (old_nloads);
+         FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (child), j, grandchild)
+           vect_free_slp_tree (grandchild);
+         SLP_TREE_CHILDREN (child).truncate (0);
+
+         /* Swap mismatched definition stmts.  */
+         dump_printf_loc (MSG_NOTE, vect_location,
+                          "Re-trying with swapped operands of stmts ");
+         for (j = 0; j < group_size; ++j)
+           if (!matches[j])
+             {
+               std::swap (oprnds_info[0]->def_stmts[j],
+                          oprnds_info[1]->def_stmts[j]);
+               dump_printf (MSG_NOTE, "%d ", j);
+             }
+         dump_printf (MSG_NOTE, "\n");
+         /* And try again with scratch 'matches' ... */
+         bool *tem = XALLOCAVEC (bool, group_size);
+         if (vect_build_slp_tree (loop_vinfo, bb_vinfo, &child,
+                                  group_size, max_nunits, loads,
+                                  vectorization_factor,
+                                  tem, npermutes, &this_tree_size,
+                                  max_tree_size))
+           {
+             /* ... so if successful we can apply the operand swapping
+                to the GIMPLE IL.  This is necessary because for example
+                vect_get_slp_defs uses operand indexes and thus expects
+                canonical operand order.  */
+             for (j = 0; j < group_size; ++j)
+               if (!matches[j])
+                 {
+                   gimple stmt = SLP_TREE_SCALAR_STMTS (*node)[j];
+                   swap_ssa_operands (stmt, gimple_assign_rhs1_ptr (stmt),
+                                      gimple_assign_rhs2_ptr (stmt));
+                 }
+             oprnd_info->def_stmts = vNULL;
+             SLP_TREE_CHILDREN (*node).quick_push (child);
+             continue;
+           }
+
+         ++*npermutes;
+       }
+
+      oprnd_info->def_stmts = vNULL;
+      vect_free_slp_tree (child);
+      vect_free_oprnd_info (oprnds_info);
+      return false;
     }
 
-  vect_free_oprnd_info (&oprnds_info);
+  if (tree_size)
+    *tree_size += this_tree_size;
+
+  vect_free_oprnd_info (oprnds_info);
   return true;
 }
 
@@ -983,21 +1176,21 @@ vect_print_slp_tree (int dump_kind, slp_tree node)
 {
   int i;
   gimple stmt;
-  slp_void_p child;
+  slp_tree child;
 
   if (!node)
     return;
 
   dump_printf (dump_kind, "node ");
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), i, stmt)
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt)
     {
       dump_printf (dump_kind, "\n\tstmt %d ", i);
       dump_gimple_stmt (dump_kind, TDF_SLIM, stmt, 0);
     }
   dump_printf (dump_kind, "\n");
 
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_print_slp_tree (dump_kind, (slp_tree) child);
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    vect_print_slp_tree (dump_kind, child);
 }
 
 
@@ -1011,17 +1204,17 @@ vect_mark_slp_stmts (slp_tree node, enum slp_vect_type mark, int j)
 {
   int i;
   gimple stmt;
-  slp_void_p child;
+  slp_tree child;
 
   if (!node)
     return;
 
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), i, stmt)
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt)
     if (j < 0 || i == j)
       STMT_SLP_TYPE (vinfo_for_stmt (stmt)) = mark;
 
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_mark_slp_stmts ((slp_tree) child, mark, j);
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    vect_mark_slp_stmts (child, mark, j);
 }
 
 
@@ -1033,12 +1226,12 @@ vect_mark_slp_stmts_relevant (slp_tree node)
   int i;
   gimple stmt;
   stmt_vec_info stmt_info;
-  slp_void_p child;
+  slp_tree child;
 
   if (!node)
     return;
 
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), i, stmt)
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt)
     {
       stmt_info = vinfo_for_stmt (stmt);
       gcc_assert (!STMT_VINFO_RELEVANT (stmt_info)
@@ -1046,134 +1239,121 @@ vect_mark_slp_stmts_relevant (slp_tree node)
       STMT_VINFO_RELEVANT (stmt_info) = vect_used_in_scope;
     }
 
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_mark_slp_stmts_relevant ((slp_tree) child);
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    vect_mark_slp_stmts_relevant (child);
 }
 
 
-/* Check if the permutation required by the SLP INSTANCE is supported.
-   Reorganize the SLP nodes stored in SLP_INSTANCE_LOADS if needed.  */
+/* Rearrange the statements of NODE according to PERMUTATION.  */
 
-static bool
-vect_supported_slp_permutation_p (slp_instance instance)
+static void
+vect_slp_rearrange_stmts (slp_tree node, unsigned int group_size,
+                          vec<unsigned> permutation)
 {
-  slp_tree node = VEC_index (slp_tree, SLP_INSTANCE_LOADS (instance), 0);
-  gimple stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (node), 0);
-  gimple first_load = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt));
-  VEC (slp_tree, heap) *sorted_loads = NULL;
-  int index;
-  slp_tree *tmp_loads = NULL;
-  int group_size = SLP_INSTANCE_GROUP_SIZE (instance), i, j;
-  slp_tree load;
-
-  /* FORNOW: The only supported loads permutation is loads from the same
-     location in all the loads in the node, when the data-refs in
-     nodes of LOADS constitute an interleaving chain.
-     Sort the nodes according to the order of accesses in the chain.  */
-  tmp_loads = (slp_tree *) xmalloc (sizeof (slp_tree) * group_size);
-  for (i = 0, j = 0;
-       VEC_iterate (int, SLP_INSTANCE_LOAD_PERMUTATION (instance), i, index)
-       && VEC_iterate (slp_tree, SLP_INSTANCE_LOADS (instance), j, load);
-       i += group_size, j++)
-    {
-      gimple scalar_stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (load), 0);
-      /* Check that the loads are all in the same interleaving chain.  */
-      if (GROUP_FIRST_ELEMENT (vinfo_for_stmt (scalar_stmt)) != first_load)
-        {
-          if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-            {
-              dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                              "Build SLP failed: unsupported data "
-                              "permutation ");
-              dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
-                               scalar_stmt, 0);
-            }
-
-          free (tmp_loads);
-          return false;
-        }
-
-      tmp_loads[index] = load;
-    }
+  gimple stmt;
+  vec<gimple> tmp_stmts;
+  unsigned int i;
+  slp_tree child;
 
-  sorted_loads = VEC_alloc (slp_tree, heap, group_size);
-  for (i = 0; i < group_size; i++)
-     VEC_safe_push (slp_tree, heap, sorted_loads, tmp_loads[i]);
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    vect_slp_rearrange_stmts (child, group_size, permutation);
 
-  VEC_free (slp_tree, heap, SLP_INSTANCE_LOADS (instance));
-  SLP_INSTANCE_LOADS (instance) = sorted_loads;
-  free (tmp_loads);
+  gcc_assert (group_size == SLP_TREE_SCALAR_STMTS (node).length ());
+  tmp_stmts.create (group_size);
+  tmp_stmts.quick_grow_cleared (group_size);
 
-  if (!vect_transform_slp_perm_load (stmt, NULL, NULL,
-                                     SLP_INSTANCE_UNROLLING_FACTOR (instance),
-                                     instance, true))
-    return false;
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt)
+    tmp_stmts[permutation[i]] = stmt;
 
-  return true;
+  SLP_TREE_SCALAR_STMTS (node).release ();
+  SLP_TREE_SCALAR_STMTS (node) = tmp_stmts;
 }
 
 
-/* Rearrange the statements of NODE according to PERMUTATION.  */
+/* Attempt to reorder stmts in a reduction chain so that we don't
+   require any load permutation.  Return true if that was possible,
+   otherwise return false.  */
 
-static void
-vect_slp_rearrange_stmts (slp_tree node, unsigned int group_size,
-                          VEC (int, heap) *permutation)
+static bool
+vect_attempt_slp_rearrange_stmts (slp_instance slp_instn)
 {
-  gimple stmt;
-  VEC (gimple, heap) *tmp_stmts;
-  unsigned int index, i;
-  slp_void_p child;
-
-  if (!node)
-    return;
-
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_slp_rearrange_stmts ((slp_tree) child, group_size, permutation);
-
-  gcc_assert (group_size == VEC_length (gimple, SLP_TREE_SCALAR_STMTS (node)));
-  tmp_stmts = VEC_alloc (gimple, heap, group_size);
+  unsigned int group_size = SLP_INSTANCE_GROUP_SIZE (slp_instn);
+  unsigned int i, j;
+  sbitmap load_index;
+  unsigned int lidx;
+  slp_tree node, load;
 
-  for (i = 0; i < group_size; i++)
-    VEC_safe_push (gimple, heap, tmp_stmts, NULL);
+  /* Compare all the permutation sequences to the first one.  We know
+     that at least one load is permuted.  */
+  node = SLP_INSTANCE_LOADS (slp_instn)[0];
+  if (!node->load_permutation.exists ())
+    return false;
+  for (i = 1; SLP_INSTANCE_LOADS (slp_instn).iterate (i, &load); ++i)
+    {
+      if (!load->load_permutation.exists ())
+       return false;
+      FOR_EACH_VEC_ELT (load->load_permutation, j, lidx)
+       if (lidx != node->load_permutation[j])
+         return false;
+    }
 
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), i, stmt)
+  /* Check that the loads in the first sequence are different and there
+     are no gaps between them.  */
+  load_index = sbitmap_alloc (group_size);
+  bitmap_clear (load_index);
+  FOR_EACH_VEC_ELT (node->load_permutation, i, lidx)
     {
-      index = VEC_index (int, permutation, i);
-      VEC_replace (gimple, tmp_stmts, index, stmt);
+      if (bitmap_bit_p (load_index, lidx))
+       {
+         sbitmap_free (load_index);
+         return false;
+       }
+      bitmap_set_bit (load_index, lidx);
     }
+  for (i = 0; i < group_size; i++)
+    if (!bitmap_bit_p (load_index, i))
+      {
+       sbitmap_free (load_index);
+       return false;
+      }
+  sbitmap_free (load_index);
 
-  VEC_free (gimple, heap, SLP_TREE_SCALAR_STMTS (node));
-  SLP_TREE_SCALAR_STMTS (node) = tmp_stmts;
-}
+  /* This permutation is valid for reduction.  Since the order of the
+     statements in the nodes is not important unless they are memory
+     accesses, we can rearrange the statements in all the nodes
+     according to the order of the loads.  */
+  vect_slp_rearrange_stmts (SLP_INSTANCE_TREE (slp_instn), group_size,
+                           node->load_permutation);
 
+  /* We are done, no actual permutations need to be generated.  */
+  FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
+    SLP_TREE_LOAD_PERMUTATION (node).release ();
+  return true;
+}
 
-/* Check if the required load permutation is supported.
-   LOAD_PERMUTATION contains a list of indices of the loads.
-   In SLP this permutation is relative to the order of grouped stores that are
-   the base of the SLP instance.  */
+/* Check if the required load permutations in the SLP instance
+   SLP_INSTN are supported.  */
 
 static bool
-vect_supported_load_permutation_p (slp_instance slp_instn, int group_size,
-                                   VEC (int, heap) *load_permutation)
+vect_supported_load_permutation_p (slp_instance slp_instn)
 {
-  int i = 0, j, prev = -1, next, k, number_of_groups;
-  bool supported, bad_permutation = false;
-  sbitmap load_index;
-  slp_tree node, other_complex_node;
-  gimple stmt, first = NULL, other_node_first, load, next_load, first_load;
-  unsigned complex_numbers = 0;
+  unsigned int group_size = SLP_INSTANCE_GROUP_SIZE (slp_instn);
+  unsigned int i, j, k, next;
+  slp_tree node;
+  gimple stmt, load, next_load, first_load;
   struct data_reference *dr;
-  bb_vec_info bb_vinfo;
 
-  /* FORNOW: permutations are only supported in SLP.  */
-  if (!slp_instn)
-    return false;
-
-  if (dump_kind_p (MSG_NOTE))
+  if (dump_enabled_p ())
     {
       dump_printf_loc (MSG_NOTE, vect_location, "Load permutation ");
-      FOR_EACH_VEC_ELT (int, load_permutation, i, next)
-        dump_printf (MSG_NOTE, "%d ", next);
+      FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
+       if (node->load_permutation.exists ())
+         FOR_EACH_VEC_ELT (node->load_permutation, j, next)
+           dump_printf (MSG_NOTE, "%d ", next);
+       else
+         for (k = 0; k < group_size; ++k)
+           dump_printf (MSG_NOTE, "%d ", k);
+      dump_printf (MSG_NOTE, "\n");
     }
 
   /* In case of reduction every load permutation is allowed, since the order
@@ -1184,316 +1364,294 @@ vect_supported_load_permutation_p (slp_instance slp_instn, int group_size,
      permutation).  */
 
   /* Check that all the load nodes are of the same size.  */
-  FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (slp_instn), i, node)
-    {
-      if (VEC_length (gimple, SLP_TREE_SCALAR_STMTS (node))
-          != (unsigned) group_size)
-        return false;
-
-      stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (node), 0);
-      if (is_gimple_assign (stmt) 
-          && (gimple_assign_rhs_code (stmt) == REALPART_EXPR
-              || gimple_assign_rhs_code (stmt) == IMAGPART_EXPR))
-        complex_numbers++;
-    }
-
-  /* Complex operands can be swapped as following:
-      real_c = real_b + real_a;
-      imag_c = imag_a + imag_b;
-     i.e., we have {real_b, imag_a} and {real_a, imag_b} instead of 
-     {real_a, imag_a} and {real_b, imag_b}.  We check here that if interleaving
-     chains are mixed, they match the above pattern.  */
-  if (complex_numbers)
-    {
-      FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (slp_instn), i, node)
-        {
-         FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), j, stmt)
-            {
-              if (j == 0)
-                first = stmt;
-              else
-                {
-                  if (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) != first)
-                    {
-                      if (complex_numbers != 2)
-                        return false;
-
-                      if (i == 0)
-                        k = 1;
-                      else
-                        k = 0;
-                      other_complex_node = VEC_index (slp_tree, 
-                                            SLP_INSTANCE_LOADS (slp_instn), k);
-                      other_node_first = VEC_index (gimple, 
-                                SLP_TREE_SCALAR_STMTS (other_complex_node), 0);
-
-                      if (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt))
-                          != other_node_first)
-                       return false;
-                    }
-                }
-            }
-        }
-    }
+  /* ???  Can't we assert this? */
+  FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
+    if (SLP_TREE_SCALAR_STMTS (node).length () != (unsigned) group_size)
+      return false;
 
-  /* We checked that this case ok, so there is no need to proceed with 
-     permutation tests.  */
-  if (complex_numbers == 2
-      && VEC_length (slp_tree, SLP_INSTANCE_LOADS (slp_instn)) == 2)
-    {
-      VEC_free (slp_tree, heap, SLP_INSTANCE_LOADS (slp_instn));
-      VEC_free (int, heap, SLP_INSTANCE_LOAD_PERMUTATION (slp_instn));
-      return true;
-    }
-                   
   node = SLP_INSTANCE_TREE (slp_instn);
-  stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (node), 0);
-  /* LOAD_PERMUTATION is a list of indices of all the loads of the SLP
-     instance, not all the loads belong to the same node or interleaving
-     group.  Hence, we need to divide them into groups according to
-     GROUP_SIZE.  */
-  number_of_groups = VEC_length (int, load_permutation) / group_size;
+  stmt = SLP_TREE_SCALAR_STMTS (node)[0];
 
   /* Reduction (there are no data-refs in the root).
-     In reduction chain the order of the loads is important.  */
+     In reduction chain the order of the loads is not important.  */
   if (!STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt))
       && !GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)))
     {
-      int first_group_load_index;
-
-      /* Compare all the permutation sequences to the first one.  */
-      for (i = 1; i < number_of_groups; i++)
-        {
-          k = 0;
-          for (j = i * group_size; j < i * group_size + group_size; j++)
-            {
-              next = VEC_index (int, load_permutation, j);
-              first_group_load_index = VEC_index (int, load_permutation, k);
-
-              if (next != first_group_load_index)
-                {
-                  bad_permutation = true;
-                  break;
-                }
-
-              k++;
-            }
-
-          if (bad_permutation)
-            break;
-        }
-
-      if (!bad_permutation)
-        {
-          /* Check that the loads in the first sequence are different and there
-             are no gaps between them.  */
-          load_index = sbitmap_alloc (group_size);
-          sbitmap_zero (load_index);
-          for (k = 0; k < group_size; k++)
-            {
-              first_group_load_index = VEC_index (int, load_permutation, k);
-              if (TEST_BIT (load_index, first_group_load_index))
-                {
-                  bad_permutation = true;
-                  break;
-                }
-
-              SET_BIT (load_index, first_group_load_index);
-            }
-
-          if (!bad_permutation)
-            for (k = 0; k < group_size; k++)
-              if (!TEST_BIT (load_index, k))
-                {
-                  bad_permutation = true;
-                  break;
-                }
+      if (vect_attempt_slp_rearrange_stmts (slp_instn))
+       return true;
 
-          sbitmap_free (load_index);
-        }
-
-      if (!bad_permutation)
-        {
-          /* This permutation is valid for reduction.  Since the order of the
-             statements in the nodes is not important unless they are memory
-             accesses, we can rearrange the statements in all the nodes 
-             according to the order of the loads.  */
-          vect_slp_rearrange_stmts (SLP_INSTANCE_TREE (slp_instn), group_size,
-                                    load_permutation);
-          VEC_free (int, heap, SLP_INSTANCE_LOAD_PERMUTATION (slp_instn));
-          return true;
-        }
+      /* Fallthru to general load permutation handling.  */
     }
 
   /* In basic block vectorization we allow any subchain of an interleaving
      chain.
      FORNOW: not supported in loop SLP because of realignment compications.  */
-  bb_vinfo = STMT_VINFO_BB_VINFO (vinfo_for_stmt (stmt));
-  bad_permutation = false;
-  /* Check that for every node in the instance the loads form a subchain.  */
-  if (bb_vinfo)
+  if (STMT_VINFO_BB_VINFO (vinfo_for_stmt (stmt)))
     {
-      FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (slp_instn), i, node)
+      /* Check whether the loads in an instance form a subchain and thus
+         no permutation is necessary.  */
+      FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
         {
+         if (!SLP_TREE_LOAD_PERMUTATION (node).exists ())
+           continue;
+         bool subchain_p = true;
           next_load = NULL;
-          first_load = NULL;
-          FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), j, load)
+          FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), j, load)
             {
-              if (!first_load)
-                first_load = GROUP_FIRST_ELEMENT (vinfo_for_stmt (load));
-              else if (first_load
-                         != GROUP_FIRST_ELEMENT (vinfo_for_stmt (load)))
-                {
-                  bad_permutation = true;
-                 break;
-               }
-
-              if (j != 0 && next_load != load)
-                {
-                  bad_permutation = true;
-                  break;
-                }
-
+              if (j != 0
+                 && (next_load != load
+                     || GROUP_GAP (vinfo_for_stmt (load)) != 1))
+               {
+                 subchain_p = false;
+                 break;
+               }
               next_load = GROUP_NEXT_ELEMENT (vinfo_for_stmt (load));
             }
-
-          if (bad_permutation)
-            break;
+         if (subchain_p)
+           SLP_TREE_LOAD_PERMUTATION (node).release ();
+         else
+           {
+             /* Verify the permutation can be generated.  */
+             vec<tree> tem;
+             if (!vect_transform_slp_perm_load (node, tem, NULL,
+                                                1, slp_instn, true))
+               {
+                 dump_printf_loc (MSG_MISSED_OPTIMIZATION,
+                                  vect_location,
+                                  "unsupported load permutation\n");
+                 return false;
+               }
+           }
         }
 
       /* Check that the alignment of the first load in every subchain, i.e.,
-         the first statement in every load node, is supported.  */
-      if (!bad_permutation)
-        {
-          FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (slp_instn), i, node)
-            {
-              first_load = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (node), 0);
-              if (first_load
-                    != GROUP_FIRST_ELEMENT (vinfo_for_stmt (first_load)))
-                {
-                  dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_load));
-                  if (vect_supportable_dr_alignment (dr, false)
-                      == dr_unaligned_unsupported)
-                    {
-                     if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-                       {
-                         dump_printf_loc (MSG_MISSED_OPTIMIZATION,
-                                          vect_location, 
-                                          "unsupported unaligned load ");
-                          dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
-                                           first_load, 0);
-                        }
-                     bad_permutation = true;
-                      break;
-                    }
-               }
-            }
+         the first statement in every load node, is supported.
+        ???  This belongs in alignment checking.  */
+      FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
+       {
+         first_load = SLP_TREE_SCALAR_STMTS (node)[0];
+         if (first_load != GROUP_FIRST_ELEMENT (vinfo_for_stmt (first_load)))
+           {
+             dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_load));
+             if (vect_supportable_dr_alignment (dr, false)
+                 == dr_unaligned_unsupported)
+               {
+                 if (dump_enabled_p ())
+                   {
+                     dump_printf_loc (MSG_MISSED_OPTIMIZATION,
+                                      vect_location,
+                                      "unsupported unaligned load ");
+                     dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
+                                       first_load, 0);
+                      dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
+                   }
+                 return false;
+               }
+           }
+       }
 
-          if (!bad_permutation)
-            {
-              VEC_free (int, heap, SLP_INSTANCE_LOAD_PERMUTATION (slp_instn));
-              return true;
-           }
-        }
+      return true;
     }
 
-  /* FORNOW: the only supported permutation is 0..01..1.. of length equal to
-     GROUP_SIZE and where each sequence of same drs is of GROUP_SIZE length as
-     well (unless it's reduction).  */
-  if (VEC_length (int, load_permutation)
-      != (unsigned int) (group_size * group_size))
-    return false;
+  /* For loop vectorization verify we can generate the permutation.  */
+  FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
+    if (node->load_permutation.exists ()
+       && !vect_transform_slp_perm_load
+             (node, vNULL, NULL,
+              SLP_INSTANCE_UNROLLING_FACTOR (slp_instn), slp_instn, true))
+      return false;
 
-  supported = true;
-  load_index = sbitmap_alloc (group_size);
-  sbitmap_zero (load_index);
-  for (j = 0; j < group_size; j++)
-    {
-      for (i = j * group_size, k = 0;
-           VEC_iterate (int, load_permutation, i, next) && k < group_size;
-           i++, k++)
-       {
-         if (i != j * group_size && next != prev)
-          {
-            supported = false;
-            break;
-          }
+  return true;
+}
 
-         prev = next;
-       }
 
-      if (TEST_BIT (load_index, prev))
-        {
-          supported = false;
-          break;
-        }
+/* Find the last store in SLP INSTANCE.  */
+
+static gimple
+vect_find_last_scalar_stmt_in_slp (slp_tree node)
+{
+  gimple last = NULL, stmt;
 
-      SET_BIT (load_index, prev);
+  for (int i = 0; SLP_TREE_SCALAR_STMTS (node).iterate (i, &stmt); i++)
+    {
+      stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
+      if (is_pattern_stmt_p (stmt_vinfo))
+       last = get_later_stmt (STMT_VINFO_RELATED_STMT (stmt_vinfo), last);
+      else
+       last = get_later_stmt (stmt, last);
     }
-  for (j = 0; j < group_size; j++)
-    if (!TEST_BIT (load_index, j))
-      return false;
 
-  sbitmap_free (load_index);
+  return last;
+}
 
-  if (supported && i == group_size * group_size
-      && vect_supported_slp_permutation_p (slp_instn))
-    return true;
+/* Compute the cost for the SLP node NODE in the SLP instance INSTANCE.  */
 
-  return false;
-}
+static void
+vect_analyze_slp_cost_1 (slp_instance instance, slp_tree node,
+                        stmt_vector_for_cost *prologue_cost_vec,
+                        stmt_vector_for_cost *body_cost_vec,
+                        unsigned ncopies_for_cost)
+{
+  unsigned i;
+  slp_tree child;
+  gimple stmt, s;
+  stmt_vec_info stmt_info;
+  tree lhs;
+  unsigned group_size = SLP_INSTANCE_GROUP_SIZE (instance);
 
+  /* Recurse down the SLP tree.  */
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    if (child)
+      vect_analyze_slp_cost_1 (instance, child, prologue_cost_vec,
+                              body_cost_vec, ncopies_for_cost);
 
-/* Find the first load in the loop that belongs to INSTANCE.
-   When loads are in several SLP nodes, there can be a case in which the first
-   load does not appear in the first SLP node to be transformed, causing
-   incorrect order of statements.  Since we generate all the loads together,
-   they must be inserted before the first load of the SLP instance and not
-   before the first load of the first node of the instance.  */
+  /* Look at the first scalar stmt to determine the cost.  */
+  stmt = SLP_TREE_SCALAR_STMTS (node)[0];
+  stmt_info = vinfo_for_stmt (stmt);
+  if (STMT_VINFO_GROUPED_ACCESS (stmt_info))
+    {
+      if (DR_IS_WRITE (STMT_VINFO_DATA_REF (stmt_info)))
+       vect_model_store_cost (stmt_info, ncopies_for_cost, false,
+                              vect_uninitialized_def,
+                              node, prologue_cost_vec, body_cost_vec);
+      else
+       {
+         int i;
+         gcc_checking_assert (DR_IS_READ (STMT_VINFO_DATA_REF (stmt_info)));
+         vect_model_load_cost (stmt_info, ncopies_for_cost, false,
+                               node, prologue_cost_vec, body_cost_vec);
+         /* If the load is permuted record the cost for the permutation.
+            ???  Loads from multiple chains are let through here only
+            for a single special case involving complex numbers where
+            in the end no permutation is necessary.  */
+         FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, s)
+           if ((STMT_VINFO_GROUP_FIRST_ELEMENT (vinfo_for_stmt (s))
+                == STMT_VINFO_GROUP_FIRST_ELEMENT (stmt_info))
+               && vect_get_place_in_interleaving_chain
+                    (s, STMT_VINFO_GROUP_FIRST_ELEMENT (stmt_info)) != i)
+             {
+               record_stmt_cost (body_cost_vec, group_size, vec_perm,
+                                 stmt_info, 0, vect_body);
+               break;
+             }
+       }
+    }
+  else
+    {
+      record_stmt_cost (body_cost_vec, ncopies_for_cost, vector_stmt,
+                       stmt_info, 0, vect_body);
+      if (SLP_TREE_TWO_OPERATORS (node))
+       {
+         record_stmt_cost (body_cost_vec, ncopies_for_cost, vector_stmt,
+                           stmt_info, 0, vect_body);
+         record_stmt_cost (body_cost_vec, ncopies_for_cost, vec_perm,
+                           stmt_info, 0, vect_body);
+       }
+    }
 
-static gimple
-vect_find_first_load_in_slp_instance (slp_instance instance)
-{
-  int i, j;
-  slp_tree load_node;
-  gimple first_load = NULL, load;
+  /* Scan operands and account for prologue cost of constants/externals.
+     ???  This over-estimates cost for multiple uses and should be
+     re-engineered.  */
+  lhs = gimple_get_lhs (stmt);
+  for (i = 0; i < gimple_num_ops (stmt); ++i)
+    {
+      tree def, op = gimple_op (stmt, i);
+      gimple def_stmt;
+      enum vect_def_type dt;
+      if (!op || op == lhs)
+       continue;
+      if (vect_is_simple_use (op, NULL, STMT_VINFO_LOOP_VINFO (stmt_info),
+                             STMT_VINFO_BB_VINFO (stmt_info),
+                             &def_stmt, &def, &dt))
+       {
+         /* Without looking at the actual initializer a vector of
+            constants can be implemented as load from the constant pool.
+            ???  We need to pass down stmt_info for a vector type
+            even if it points to the wrong stmt.  */
+         if (dt == vect_constant_def)
+           record_stmt_cost (prologue_cost_vec, 1, vector_load,
+                             stmt_info, 0, vect_prologue);
+         else if (dt == vect_external_def)
+           record_stmt_cost (prologue_cost_vec, 1, vec_construct,
+                             stmt_info, 0, vect_prologue);
+       }
+    }
+}
 
-  FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (instance), i, load_node)
-    FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (load_node), j, load)
-      first_load = get_earlier_stmt (load, first_load);
+/* Compute the cost for the SLP instance INSTANCE.  */
 
-  return first_load;
-}
+static void
+vect_analyze_slp_cost (slp_instance instance, void *data)
+{
+  stmt_vector_for_cost body_cost_vec, prologue_cost_vec;
+  unsigned ncopies_for_cost;
+  stmt_info_for_cost *si;
+  unsigned i;
 
+  /* Calculate the number of vector stmts to create based on the unrolling
+     factor (number of vectors is 1 if NUNITS >= GROUP_SIZE, and is
+     GROUP_SIZE / NUNITS otherwise.  */
+  unsigned group_size = SLP_INSTANCE_GROUP_SIZE (instance);
+  slp_tree node = SLP_INSTANCE_TREE (instance);
+  stmt_vec_info stmt_info = vinfo_for_stmt (SLP_TREE_SCALAR_STMTS (node)[0]);
+  /* Adjust the group_size by the vectorization factor which is always one
+     for basic-block vectorization.  */
+  if (STMT_VINFO_LOOP_VINFO (stmt_info))
+    group_size *= LOOP_VINFO_VECT_FACTOR (STMT_VINFO_LOOP_VINFO (stmt_info));
+  unsigned nunits = TYPE_VECTOR_SUBPARTS (STMT_VINFO_VECTYPE (stmt_info));
+  /* For reductions look at a reduction operand in case the reduction
+     operation is widening like DOT_PROD or SAD.  */
+  if (!STMT_VINFO_GROUPED_ACCESS (stmt_info))
+    {
+      gimple stmt = SLP_TREE_SCALAR_STMTS (node)[0];
+      switch (gimple_assign_rhs_code (stmt))
+       {
+       case DOT_PROD_EXPR:
+       case SAD_EXPR:
+         nunits = TYPE_VECTOR_SUBPARTS (get_vectype_for_scalar_type
+                               (TREE_TYPE (gimple_assign_rhs1 (stmt))));
+         break;
+       default:;
+       }
+    }
+  ncopies_for_cost = least_common_multiple (nunits, group_size) / nunits;
 
-/* Find the last store in SLP INSTANCE.  */
+  prologue_cost_vec.create (10);
+  body_cost_vec.create (10);
+  vect_analyze_slp_cost_1 (instance, SLP_INSTANCE_TREE (instance),
+                          &prologue_cost_vec, &body_cost_vec,
+                          ncopies_for_cost);
 
-static gimple
-vect_find_last_store_in_slp_instance (slp_instance instance)
-{
-  int i;
-  slp_tree node;
-  gimple last_store = NULL, store;
+  /* Record the prologue costs, which were delayed until we were
+     sure that SLP was successful.  */
+  FOR_EACH_VEC_ELT (prologue_cost_vec, i, si)
+    {
+      struct _stmt_vec_info *stmt_info
+       = si->stmt ? vinfo_for_stmt (si->stmt) : NULL;
+      (void) add_stmt_cost (data, si->count, si->kind, stmt_info,
+                           si->misalign, vect_prologue);
+    }
 
-  node = SLP_INSTANCE_TREE (instance);
-  for (i = 0;
-       VEC_iterate (gimple, SLP_TREE_SCALAR_STMTS (node), i, store);
-       i++)
-    last_store = get_later_stmt (store, last_store);
+  /* Record the instance's instructions in the target cost model.  */
+  FOR_EACH_VEC_ELT (body_cost_vec, i, si)
+    {
+      struct _stmt_vec_info *stmt_info
+       = si->stmt ? vinfo_for_stmt (si->stmt) : NULL;
+      (void) add_stmt_cost (data, si->count, si->kind, stmt_info,
+                           si->misalign, vect_body);
+    }
 
-  return last_store;
+  prologue_cost_vec.release ();
+  body_cost_vec.release ();
 }
 
-
 /* Analyze an SLP instance starting from a group of grouped stores.  Call
    vect_build_slp_tree to build a tree of packed stmts if possible.
    Return FALSE if it's impossible to SLP any stmt in the loop.  */
 
 static bool
 vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
-                           gimple stmt)
+                           gimple stmt, unsigned max_tree_size)
 {
   slp_instance new_instance;
   slp_tree node;
@@ -1502,15 +1660,11 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
   tree vectype, scalar_type = NULL_TREE;
   gimple next;
   unsigned int vectorization_factor = 0;
-  int outside_cost = 0, ncopies_for_cost, i;
+  int i;
   unsigned int max_nunits = 0;
-  VEC (int, heap) *load_permutation;
-  VEC (slp_tree, heap) *loads;
+  vec<slp_tree> loads;
   struct data_reference *dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt));
-  bool loads_permuted = false;
-  VEC (gimple, heap) *scalar_stmts;
-  stmt_vector_for_cost body_cost_vec, prologue_cost_vec;
-  stmt_info_for_cost *si;
+  vec<gimple> scalar_stmts;
 
   if (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)))
     {
@@ -1531,16 +1685,17 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
     {
       gcc_assert (loop_vinfo);
       vectype = STMT_VINFO_VECTYPE (vinfo_for_stmt (stmt));
-      group_size = VEC_length (gimple, LOOP_VINFO_REDUCTIONS (loop_vinfo));
+      group_size = LOOP_VINFO_REDUCTIONS (loop_vinfo).length ();
     }
 
   if (!vectype)
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         {
           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                           "Build SLP failed: unsupported data-type ");
           dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, scalar_type);
+          dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
         }
 
       return false;
@@ -1556,16 +1711,16 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
   unrolling_factor = least_common_multiple (nunits, group_size) / group_size;
   if (unrolling_factor != 1 && !loop_vinfo)
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
+      if (dump_enabled_p ())
+        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                         "Build SLP failed: unrolling required in basic"
-                        " block SLP");
+                        " block SLP\n");
 
       return false;
     }
 
   /* Create a node (a root of the SLP tree) for the packed grouped stores.  */
-  scalar_stmts = VEC_alloc (gimple, heap, group_size);
+  scalar_stmts.create (group_size);
   next = stmt;
   if (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)))
     {
@@ -1574,43 +1729,38 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
         {
          if (STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (next))
              && STMT_VINFO_RELATED_STMT (vinfo_for_stmt (next)))
-           VEC_safe_push (gimple, heap, scalar_stmts,
-                       STMT_VINFO_RELATED_STMT (vinfo_for_stmt (next)));
+           scalar_stmts.safe_push (
+                 STMT_VINFO_RELATED_STMT (vinfo_for_stmt (next)));
          else
-            VEC_safe_push (gimple, heap, scalar_stmts, next);
+            scalar_stmts.safe_push (next);
           next = GROUP_NEXT_ELEMENT (vinfo_for_stmt (next));
         }
+      /* Mark the first element of the reduction chain as reduction to properly
+        transform the node.  In the reduction analysis phase only the last
+        element of the chain is marked as reduction.  */
+      if (!STMT_VINFO_GROUPED_ACCESS (vinfo_for_stmt (stmt)))
+       STMT_VINFO_DEF_TYPE (vinfo_for_stmt (stmt)) = vect_reduction_def;
     }
   else
     {
       /* Collect reduction statements.  */
-      VEC (gimple, heap) *reductions = LOOP_VINFO_REDUCTIONS (loop_vinfo);
-      for (i = 0; VEC_iterate (gimple, reductions, i, next); i++)
-       VEC_safe_push (gimple, heap, scalar_stmts, next);
+      vec<gimple> reductions = LOOP_VINFO_REDUCTIONS (loop_vinfo);
+      for (i = 0; reductions.iterate (i, &next); i++)
+       scalar_stmts.safe_push (next);
     }
 
   node = vect_create_new_slp_node (scalar_stmts);
 
-  /* Calculate the number of vector stmts to create based on the unrolling
-     factor (number of vectors is 1 if NUNITS >= GROUP_SIZE, and is
-     GROUP_SIZE / NUNITS otherwise.  */
-  ncopies_for_cost = unrolling_factor * group_size / nunits;
-
-  load_permutation = VEC_alloc (int, heap, group_size * group_size);
-  loads = VEC_alloc (slp_tree, heap, group_size);
-  prologue_cost_vec = VEC_alloc (stmt_info_for_cost, heap, 10);
-  body_cost_vec = VEC_alloc (stmt_info_for_cost, heap, 10);
+  loads.create (group_size);
 
   /* Build the tree for the SLP instance.  */
+  bool *matches = XALLOCAVEC (bool, group_size);
+  unsigned npermutes = 0;
   if (vect_build_slp_tree (loop_vinfo, bb_vinfo, &node, group_size,
-                           &outside_cost, ncopies_for_cost,
-                          &max_nunits, &load_permutation, &loads,
-                          vectorization_factor, &loads_permuted,
-                          &prologue_cost_vec, &body_cost_vec))
+                          &max_nunits, &loads,
+                          vectorization_factor, matches, &npermutes, NULL,
+                          max_tree_size))
     {
-      void *data = (loop_vinfo ? LOOP_VINFO_TARGET_COST_DATA (loop_vinfo)
-                   : BB_VINFO_TARGET_COST_DATA (bb_vinfo));
-
       /* Calculate the unrolling factor based on the smallest type.  */
       if (max_nunits > nunits)
         unrolling_factor = least_common_multiple (max_nunits, group_size)
@@ -1618,15 +1768,12 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
 
       if (unrolling_factor != 1 && !loop_vinfo)
         {
-          if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
+          if (dump_enabled_p ())
+            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                             "Build SLP failed: unrolling required in basic"
-                            " block SLP");
+                            " block SLP\n");
          vect_free_slp_tree (node);
-         VEC_free (stmt_info_for_cost, heap, body_cost_vec);
-         VEC_free (stmt_info_for_cost, heap, prologue_cost_vec);
-         VEC_free (int, heap, load_permutation);
-         VEC_free (slp_tree, heap, loads);
+         loads.release ();
           return false;
         }
 
@@ -1635,72 +1782,77 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
       SLP_INSTANCE_TREE (new_instance) = node;
       SLP_INSTANCE_GROUP_SIZE (new_instance) = group_size;
       SLP_INSTANCE_UNROLLING_FACTOR (new_instance) = unrolling_factor;
-      SLP_INSTANCE_BODY_COST_VEC (new_instance) = body_cost_vec;
       SLP_INSTANCE_LOADS (new_instance) = loads;
-      SLP_INSTANCE_FIRST_LOAD_STMT (new_instance) = NULL;
-      SLP_INSTANCE_LOAD_PERMUTATION (new_instance) = load_permutation;
+
+      /* Compute the load permutation.  */
+      slp_tree load_node;
+      bool loads_permuted = false;
+      FOR_EACH_VEC_ELT (loads, i, load_node)
+       {
+         vec<unsigned> load_permutation;
+         int j;
+         gimple load, first_stmt;
+         bool this_load_permuted = false;
+         load_permutation.create (group_size);
+         first_stmt = GROUP_FIRST_ELEMENT
+             (vinfo_for_stmt (SLP_TREE_SCALAR_STMTS (load_node)[0]));
+         FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (load_node), j, load)
+           {
+             int load_place
+               = vect_get_place_in_interleaving_chain (load, first_stmt);
+             gcc_assert (load_place != -1);
+             if (load_place != j)
+               this_load_permuted = true;
+             load_permutation.safe_push (load_place);
+           }
+         if (!this_load_permuted
+             /* The load requires permutation when unrolling exposes
+                a gap either because the group is larger than the SLP
+                group-size or because there is a gap between the groups.  */
+             && (unrolling_factor == 1
+                 || (group_size == GROUP_SIZE (vinfo_for_stmt (first_stmt))
+                     && GROUP_GAP (vinfo_for_stmt (first_stmt)) == 0)))
+           {
+             load_permutation.release ();
+             continue;
+           }
+         SLP_TREE_LOAD_PERMUTATION (load_node) = load_permutation;
+         loads_permuted = true;
+       }
 
       if (loads_permuted)
         {
-          if (!vect_supported_load_permutation_p (new_instance, group_size,
-                                                  load_permutation))
+          if (!vect_supported_load_permutation_p (new_instance))
             {
-              if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+              if (dump_enabled_p ())
                 {
-                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
+                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                   "Build SLP failed: unsupported load "
                                   "permutation ");
                   dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+                  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
                 }
-
               vect_free_slp_instance (new_instance);
-             VEC_free (stmt_info_for_cost, heap, prologue_cost_vec);
               return false;
             }
-
-          SLP_INSTANCE_FIRST_LOAD_STMT (new_instance)
-             = vect_find_first_load_in_slp_instance (new_instance);
         }
-      else
-        VEC_free (int, heap, SLP_INSTANCE_LOAD_PERMUTATION (new_instance));
-
-      /* Record the prologue costs, which were delayed until we were
-        sure that SLP was successful.  Unlike the body costs, we know
-        the final values now regardless of the loop vectorization factor.  */
-      FOR_EACH_VEC_ELT (stmt_info_for_cost, prologue_cost_vec, i, si)
-       {
-         struct _stmt_vec_info *stmt_info
-           = si->stmt ? vinfo_for_stmt (si->stmt) : NULL;
-         (void) add_stmt_cost (data, si->count, si->kind, stmt_info,
-                               si->misalign, vect_prologue);
-       }
 
-      VEC_free (stmt_info_for_cost, heap, prologue_cost_vec);
 
       if (loop_vinfo)
-        VEC_safe_push (slp_instance, heap,
-                       LOOP_VINFO_SLP_INSTANCES (loop_vinfo),
-                      new_instance);
+       LOOP_VINFO_SLP_INSTANCES (loop_vinfo).safe_push (new_instance);
       else
-        VEC_safe_push (slp_instance, heap, BB_VINFO_SLP_INSTANCES (bb_vinfo),
-                       new_instance);
+        BB_VINFO_SLP_INSTANCES (bb_vinfo).safe_push (new_instance);
 
-      if (dump_kind_p (MSG_NOTE))
+      if (dump_enabled_p ())
        vect_print_slp_tree (MSG_NOTE, node);
 
       return true;
     }
-  else
-    {
-      VEC_free (stmt_info_for_cost, heap, body_cost_vec);
-      VEC_free (stmt_info_for_cost, heap, prologue_cost_vec);
-    }
 
   /* Failed to SLP.  */
   /* Free the allocated memory.  */
   vect_free_slp_tree (node);
-  VEC_free (int, heap, load_permutation);
-  VEC_free (slp_tree, heap, loads);
+  loads.release ();
 
   return false;
 }
@@ -1710,15 +1862,18 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
    trees of packed scalar stmts if SLP is possible.  */
 
 bool
-vect_analyze_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
+vect_analyze_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo,
+                 unsigned max_tree_size)
 {
   unsigned int i;
-  VEC (gimple, heap) *grouped_stores, *reductions = NULL, *reduc_chains = NULL;
+  vec<gimple> grouped_stores;
+  vec<gimple> reductions = vNULL;
+  vec<gimple> reduc_chains = vNULL;
   gimple first_element;
   bool ok = false;
 
-  if (dump_kind_p (MSG_NOTE))
-    dump_printf_loc (MSG_NOTE, vect_location, "=== vect_analyze_slp ===");
+  if (dump_enabled_p ())
+    dump_printf_loc (MSG_NOTE, vect_location, "=== vect_analyze_slp ===\n");
 
   if (loop_vinfo)
     {
@@ -1730,25 +1885,17 @@ vect_analyze_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
     grouped_stores = BB_VINFO_GROUPED_STORES (bb_vinfo);
 
   /* Find SLP sequences starting from groups of grouped stores.  */
-  FOR_EACH_VEC_ELT (gimple, grouped_stores, i, first_element)
-    if (vect_analyze_slp_instance (loop_vinfo, bb_vinfo, first_element))
+  FOR_EACH_VEC_ELT (grouped_stores, i, first_element)
+    if (vect_analyze_slp_instance (loop_vinfo, bb_vinfo, first_element,
+                                  max_tree_size))
       ok = true;
 
-  if (bb_vinfo && !ok)
-    {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                        "Failed to SLP the basic block.");
-
-      return false;
-    }
-
-  if (loop_vinfo
-      && VEC_length (gimple, LOOP_VINFO_REDUCTION_CHAINS (loop_vinfo)) > 0)
+  if (reduc_chains.length () > 0)
     {
       /* Find SLP sequences starting from reduction chains.  */
-      FOR_EACH_VEC_ELT (gimple, reduc_chains, i, first_element)
-        if (vect_analyze_slp_instance (loop_vinfo, bb_vinfo, first_element))
+      FOR_EACH_VEC_ELT (reduc_chains, i, first_element)
+        if (vect_analyze_slp_instance (loop_vinfo, bb_vinfo, first_element,
+                                      max_tree_size))
           ok = true;
         else
           return false;
@@ -1759,9 +1906,9 @@ vect_analyze_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
     }
 
   /* Find SLP sequences starting from groups of reductions.  */
-  if (loop_vinfo && VEC_length (gimple, LOOP_VINFO_REDUCTIONS (loop_vinfo)) > 1
-      && vect_analyze_slp_instance (loop_vinfo, bb_vinfo, 
-                                    VEC_index (gimple, reductions, 0)))
+  if (reductions.length () > 1
+      && vect_analyze_slp_instance (loop_vinfo, bb_vinfo, reductions[0],
+                                   max_tree_size))
     ok = true;
 
   return true;
@@ -1776,14 +1923,15 @@ bool
 vect_make_slp_decision (loop_vec_info loop_vinfo)
 {
   unsigned int i, unrolling_factor = 1;
-  VEC (slp_instance, heap) *slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
+  vec<slp_instance> slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
   slp_instance instance;
   int decided_to_slp = 0;
 
-  if (dump_kind_p (MSG_NOTE))
-    dump_printf_loc (MSG_NOTE, vect_location, "=== vect_make_slp_decision ===");
+  if (dump_enabled_p ())
+    dump_printf_loc (MSG_NOTE, vect_location, "=== vect_make_slp_decision ==="
+                     "\n");
 
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
+  FOR_EACH_VEC_ELT (slp_instances, i, instance)
     {
       /* FORNOW: SLP if you can.  */
       if (unrolling_factor < SLP_INSTANCE_UNROLLING_FACTOR (instance))
@@ -1798,9 +1946,9 @@ vect_make_slp_decision (loop_vec_info loop_vinfo)
 
   LOOP_VINFO_SLP_UNROLLING_FACTOR (loop_vinfo) = unrolling_factor;
 
-  if (decided_to_slp && dump_kind_p (MSG_OPTIMIZED_LOCATIONS))
-    dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
-                    "Decided to SLP %d instances. Unrolling factor %d",
+  if (decided_to_slp && dump_enabled_p ())
+    dump_printf_loc (MSG_NOTE, vect_location,
+                    "Decided to SLP %d instances. Unrolling factor %d\n",
                     decided_to_slp, unrolling_factor);
 
   return (decided_to_slp > 0);
@@ -1811,48 +1959,113 @@ vect_make_slp_decision (loop_vec_info loop_vinfo)
    can't be SLPed) in the tree rooted at NODE.  Mark such stmts as HYBRID.  */
 
 static void
-vect_detect_hybrid_slp_stmts (slp_tree node)
+vect_detect_hybrid_slp_stmts (slp_tree node, unsigned i, slp_vect_type stype)
 {
-  int i;
-  VEC (gimple, heap) *stmts = SLP_TREE_SCALAR_STMTS (node);
-  gimple stmt = VEC_index (gimple, stmts, 0);
+  gimple stmt = SLP_TREE_SCALAR_STMTS (node)[i];
   imm_use_iterator imm_iter;
   gimple use_stmt;
-  stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
-  slp_void_p child;
+  stmt_vec_info use_vinfo, stmt_vinfo = vinfo_for_stmt (stmt);
+  slp_tree child;
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
-  struct loop *loop = NULL;
-  bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_vinfo);
-  basic_block bb = NULL;
+  struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
+  int j;
+
+  /* Propagate hybrid down the SLP tree.  */
+  if (stype == hybrid)
+    ;
+  else if (HYBRID_SLP_STMT (stmt_vinfo))
+    stype = hybrid;
+  else
+    {
+      /* Check if a pure SLP stmt has uses in non-SLP stmts.  */
+      gcc_checking_assert (PURE_SLP_STMT (stmt_vinfo));
+      /* We always get the pattern stmt here, but for immediate
+        uses we have to use the LHS of the original stmt.  */
+      gcc_checking_assert (!STMT_VINFO_IN_PATTERN_P (stmt_vinfo));
+      if (STMT_VINFO_RELATED_STMT (stmt_vinfo))
+       stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
+      if (TREE_CODE (gimple_op (stmt, 0)) == SSA_NAME)
+       FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, gimple_op (stmt, 0))
+         {
+           if (!flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+             continue;
+           use_vinfo = vinfo_for_stmt (use_stmt);
+           if (STMT_VINFO_IN_PATTERN_P (use_vinfo)
+               && STMT_VINFO_RELATED_STMT (use_vinfo))
+             use_vinfo = vinfo_for_stmt (STMT_VINFO_RELATED_STMT (use_vinfo));
+           if (!STMT_SLP_TYPE (use_vinfo)
+               && (STMT_VINFO_RELEVANT (use_vinfo)
+                   || VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (use_vinfo)))
+               && !(gimple_code (use_stmt) == GIMPLE_PHI
+                    && STMT_VINFO_DEF_TYPE (use_vinfo) == vect_reduction_def))
+             {
+               if (dump_enabled_p ())
+                 {
+                   dump_printf_loc (MSG_NOTE, vect_location, "use of SLP "
+                                    "def in non-SLP stmt: ");
+                   dump_gimple_stmt (MSG_NOTE, TDF_SLIM, use_stmt, 0);
+                 }
+               stype = hybrid;
+             }
+         }
+    }
+
+  if (stype == hybrid
+      && !HYBRID_SLP_STMT (stmt_vinfo))
+    {
+      if (dump_enabled_p ())
+       {
+         dump_printf_loc (MSG_NOTE, vect_location, "marking hybrid: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
+       }
+      STMT_SLP_TYPE (stmt_vinfo) = hybrid;
+    }
 
-  if (!node)
-    return;
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), j, child)
+    if (child)
+      vect_detect_hybrid_slp_stmts (child, i, stype);
+}
 
-  if (loop_vinfo)
-    loop = LOOP_VINFO_LOOP (loop_vinfo);
-  else
-    bb = BB_VINFO_BB (bb_vinfo);
-
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), i, stmt)
-    if (PURE_SLP_STMT (vinfo_for_stmt (stmt))
-       && TREE_CODE (gimple_op (stmt, 0)) == SSA_NAME)
-      FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, gimple_op (stmt, 0))
-       if (gimple_bb (use_stmt)
-            && ((loop && flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
-                || bb == gimple_bb (use_stmt))
-           && (stmt_vinfo = vinfo_for_stmt (use_stmt))
-           && !STMT_SLP_TYPE (stmt_vinfo)
-            && (STMT_VINFO_RELEVANT (stmt_vinfo)
-                || VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (stmt_vinfo)))
-           && !(gimple_code (use_stmt) == GIMPLE_PHI
-                 && STMT_VINFO_DEF_TYPE (stmt_vinfo)
-                  == vect_reduction_def))
-         vect_mark_slp_stmts (node, hybrid, i);
-
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_detect_hybrid_slp_stmts ((slp_tree) child);
+/* Helpers for vect_detect_hybrid_slp walking pattern stmt uses.  */
+
+static tree
+vect_detect_hybrid_slp_1 (tree *tp, int *, void *data)
+{
+  walk_stmt_info *wi = (walk_stmt_info *)data;
+  struct loop *loopp = (struct loop *)wi->info;
+
+  if (wi->is_lhs)
+    return NULL_TREE;
+
+  if (TREE_CODE (*tp) == SSA_NAME
+      && !SSA_NAME_IS_DEFAULT_DEF (*tp))
+    {
+      gimple def_stmt = SSA_NAME_DEF_STMT (*tp);
+      if (flow_bb_inside_loop_p (loopp, gimple_bb (def_stmt))
+         && PURE_SLP_STMT (vinfo_for_stmt (def_stmt)))
+       {
+         if (dump_enabled_p ())
+           {
+             dump_printf_loc (MSG_NOTE, vect_location, "marking hybrid: ");
+             dump_gimple_stmt (MSG_NOTE, TDF_SLIM, def_stmt, 0);
+           }
+         STMT_SLP_TYPE (vinfo_for_stmt (def_stmt)) = hybrid;
+       }
+    }
+
+  return NULL_TREE;
 }
 
+static tree
+vect_detect_hybrid_slp_2 (gimple_stmt_iterator *gsi, bool *handled,
+                         walk_stmt_info *)
+{
+  /* If the stmt is in a SLP instance then this isn't a reason
+     to mark use definitions in other SLP instances as hybrid.  */
+  if (STMT_SLP_TYPE (vinfo_for_stmt (gsi_stmt (*gsi))) != loop_vect)
+    *handled = true;
+  return NULL_TREE;
+}
 
 /* Find stmts that must be both vectorized and SLPed.  */
 
@@ -1860,14 +2073,48 @@ void
 vect_detect_hybrid_slp (loop_vec_info loop_vinfo)
 {
   unsigned int i;
-  VEC (slp_instance, heap) *slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
+  vec<slp_instance> slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
   slp_instance instance;
 
-  if (dump_kind_p (MSG_NOTE))
-    dump_printf_loc (MSG_NOTE, vect_location, "=== vect_detect_hybrid_slp ===");
+  if (dump_enabled_p ())
+    dump_printf_loc (MSG_NOTE, vect_location, "=== vect_detect_hybrid_slp ==="
+                     "\n");
+
+  /* First walk all pattern stmt in the loop and mark defs of uses as
+     hybrid because immediate uses in them are not recorded.  */
+  for (i = 0; i < LOOP_VINFO_LOOP (loop_vinfo)->num_nodes; ++i)
+    {
+      basic_block bb = LOOP_VINFO_BBS (loop_vinfo)[i];
+      for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
+          gsi_next (&gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+         if (STMT_VINFO_IN_PATTERN_P (stmt_info))
+           {
+             walk_stmt_info wi;
+             memset (&wi, 0, sizeof (wi));
+             wi.info = LOOP_VINFO_LOOP (loop_vinfo);
+             gimple_stmt_iterator gsi2
+               = gsi_for_stmt (STMT_VINFO_RELATED_STMT (stmt_info));
+             walk_gimple_stmt (&gsi2, vect_detect_hybrid_slp_2,
+                               vect_detect_hybrid_slp_1, &wi);
+             walk_gimple_seq (STMT_VINFO_PATTERN_DEF_SEQ (stmt_info),
+                              vect_detect_hybrid_slp_2,
+                              vect_detect_hybrid_slp_1, &wi);
+           }
+       }
+    }
 
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
-    vect_detect_hybrid_slp_stmts (SLP_INSTANCE_TREE (instance));
+  /* Then walk the SLP instance trees marking stmts with uses in
+     non-SLP stmts as hybrid, also propagating hybrid down the
+     SLP tree, collecting the above info on-the-fly.  */
+  FOR_EACH_VEC_ELT (slp_instances, i, instance)
+    {
+      for (unsigned i = 0; i < SLP_INSTANCE_GROUP_SIZE (instance); ++i)
+       vect_detect_hybrid_slp_stmts (SLP_INSTANCE_TREE (instance),
+                                     i, pure_slp);
+    }
 }
 
 
@@ -1890,8 +2137,8 @@ new_bb_vec_info (basic_block bb)
       set_vinfo_for_stmt (stmt, new_stmt_vec_info (stmt, NULL, res));
     }
 
-  BB_VINFO_GROUPED_STORES (res) = VEC_alloc (gimple, heap, 10);
-  BB_VINFO_SLP_INSTANCES (res) = VEC_alloc (slp_instance, heap, 2);
+  BB_VINFO_GROUPED_STORES (res).create (10);
+  BB_VINFO_SLP_INSTANCES (res).create (2);
   BB_VINFO_TARGET_COST_DATA (res) = init_cost (NULL);
 
   bb->aux = res;
@@ -1905,7 +2152,7 @@ new_bb_vec_info (basic_block bb)
 static void
 destroy_bb_vec_info (bb_vec_info bb_vinfo)
 {
-  VEC (slp_instance, heap) *slp_instances;
+  vec<slp_instance> slp_instances;
   slp_instance instance;
   basic_block bb;
   gimple_stmt_iterator si;
@@ -1926,13 +2173,13 @@ destroy_bb_vec_info (bb_vec_info bb_vinfo)
         free_stmt_vec_info (stmt);
     }
 
-  free_data_refs (BB_VINFO_DATAREFS (bb_vinfo));
+  vect_destroy_datarefs (NULL, bb_vinfo);
   free_dependence_relations (BB_VINFO_DDRS (bb_vinfo));
-  VEC_free (gimple, heap, BB_VINFO_GROUPED_STORES (bb_vinfo));
+  BB_VINFO_GROUPED_STORES (bb_vinfo).release ();
   slp_instances = BB_VINFO_SLP_INSTANCES (bb_vinfo);
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
+  FOR_EACH_VEC_ELT (slp_instances, i, instance)
     vect_free_slp_instance (instance);
-  VEC_free (slp_instance, heap, BB_VINFO_SLP_INSTANCES (bb_vinfo));
+  BB_VINFO_SLP_INSTANCES (bb_vinfo).release ();
   destroy_cost_data (BB_VINFO_TARGET_COST_DATA (bb_vinfo));
   free (bb_vinfo);
   bb->aux = NULL;
@@ -1943,28 +2190,28 @@ destroy_bb_vec_info (bb_vec_info bb_vinfo)
    the subtree. Return TRUE if the operations are supported.  */
 
 static bool
-vect_slp_analyze_node_operations (bb_vec_info bb_vinfo, slp_tree node)
+vect_slp_analyze_node_operations (slp_tree node)
 {
   bool dummy;
   int i;
   gimple stmt;
-  slp_void_p child;
+  slp_tree child;
 
   if (!node)
     return true;
 
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    if (!vect_slp_analyze_node_operations (bb_vinfo, (slp_tree) child))
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    if (!vect_slp_analyze_node_operations (child))
       return false;
 
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), i, stmt)
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt)
     {
       stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
       gcc_assert (stmt_info);
-      gcc_assert (PURE_SLP_STMT (stmt_info));
+      gcc_assert (STMT_SLP_TYPE (stmt_info) != loop_vect);
 
       if (!vect_analyze_stmt (stmt, &dummy, node))
-        return false;
+       return false;
     }
 
   return true;
@@ -1974,73 +2221,89 @@ vect_slp_analyze_node_operations (bb_vec_info bb_vinfo, slp_tree node)
 /* Analyze statements in SLP instances of the basic block.  Return TRUE if the
    operations are supported. */
 
-static bool
-vect_slp_analyze_operations (bb_vec_info bb_vinfo)
+bool
+vect_slp_analyze_operations (vec<slp_instance> slp_instances, void *data)
 {
-  VEC (slp_instance, heap) *slp_instances = BB_VINFO_SLP_INSTANCES (bb_vinfo);
   slp_instance instance;
   int i;
 
-  for (i = 0; VEC_iterate (slp_instance, slp_instances, i, instance); )
+  if (dump_enabled_p ())
+    dump_printf_loc (MSG_NOTE, vect_location,
+                    "=== vect_slp_analyze_operations ===\n");
+
+  for (i = 0; slp_instances.iterate (i, &instance); )
     {
-      if (!vect_slp_analyze_node_operations (bb_vinfo,
-                                             SLP_INSTANCE_TREE (instance)))
+      if (!vect_slp_analyze_node_operations (SLP_INSTANCE_TREE (instance)))
         {
-         vect_free_slp_instance (instance);
-          VEC_ordered_remove (slp_instance, slp_instances, i);
+         dump_printf_loc (MSG_NOTE, vect_location,
+                          "removing SLP instance operations starting from: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM,
+                           SLP_TREE_SCALAR_STMTS
+                             (SLP_INSTANCE_TREE (instance))[0], 0);
+         vect_free_slp_instance (instance);
+          slp_instances.ordered_remove (i);
        }
       else
-        i++;
+       {
+         /* Compute the costs of the SLP instance.  */
+         vect_analyze_slp_cost (instance, data);
+         i++;
+       }
     }
 
-  if (!VEC_length (slp_instance, slp_instances))
+  if (!slp_instances.length ())
     return false;
 
   return true;
 }
 
-/* Check if vectorization of the basic block is profitable.  */
 
-static bool
-vect_bb_vectorization_profitable_p (bb_vec_info bb_vinfo)
+/* Compute the scalar cost of the SLP node NODE and its children
+   and return it.  Do not account defs that are marked in LIFE and
+   update LIFE according to uses of NODE.  */
+
+static unsigned
+vect_bb_slp_scalar_cost (basic_block bb,
+                        slp_tree node, vec<bool, va_heap> *life)
 {
-  VEC (slp_instance, heap) *slp_instances = BB_VINFO_SLP_INSTANCES (bb_vinfo);
-  slp_instance instance;
-  int i, j;
-  unsigned int vec_inside_cost = 0, vec_outside_cost = 0, scalar_cost = 0;
-  unsigned int vec_prologue_cost = 0, vec_epilogue_cost = 0;
-  unsigned int stmt_cost;
+  unsigned scalar_cost = 0;
+  unsigned i;
   gimple stmt;
-  gimple_stmt_iterator si;
-  basic_block bb = BB_VINFO_BB (bb_vinfo);
-  void *target_cost_data = BB_VINFO_TARGET_COST_DATA (bb_vinfo);
-  stmt_vec_info stmt_info = NULL;
-  stmt_vector_for_cost body_cost_vec;
-  stmt_info_for_cost *ci;
+  slp_tree child;
 
-  /* Calculate vector costs.  */
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt)
     {
-      body_cost_vec = SLP_INSTANCE_BODY_COST_VEC (instance);
+      unsigned stmt_cost;
+      ssa_op_iter op_iter;
+      def_operand_p def_p;
+      stmt_vec_info stmt_info;
+
+      if ((*life)[i])
+       continue;
 
-      FOR_EACH_VEC_ELT (stmt_info_for_cost, body_cost_vec, j, ci)
+      /* If there is a non-vectorized use of the defs then the scalar
+         stmt is kept live in which case we do not account it or any
+        required defs in the SLP children in the scalar cost.  This
+        way we make the vectorization more costly when compared to
+        the scalar cost.  */
+      FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, op_iter, SSA_OP_DEF)
        {
-         stmt_info = ci->stmt ? vinfo_for_stmt (ci->stmt) : NULL;
-         (void) add_stmt_cost (target_cost_data, ci->count, ci->kind,
-                               stmt_info, ci->misalign, vect_body);
+         imm_use_iterator use_iter;
+         gimple use_stmt;
+         FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, DEF_FROM_PTR (def_p))
+           if (!is_gimple_debug (use_stmt)
+               && (gimple_code (use_stmt) == GIMPLE_PHI
+                   || gimple_bb (use_stmt) != bb
+                   || !STMT_VINFO_VECTORIZABLE (vinfo_for_stmt (use_stmt))))
+             {
+               (*life)[i] = true;
+               BREAK_FROM_IMM_USE_STMT (use_iter);
+             }
        }
-    }
+      if ((*life)[i])
+       continue;
 
-  /* Calculate scalar cost.  */
-  for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
-    {
-      stmt = gsi_stmt (si);
       stmt_info = vinfo_for_stmt (stmt);
-
-      if (!stmt_info || !STMT_VINFO_VECTORIZABLE (stmt_info)
-          || !PURE_SLP_STMT (stmt_info))
-        continue;
-
       if (STMT_VINFO_DATA_REF (stmt_info))
         {
           if (DR_IS_READ (STMT_VINFO_DATA_REF (stmt_info)))
@@ -2054,20 +2317,48 @@ vect_bb_vectorization_profitable_p (bb_vec_info bb_vinfo)
       scalar_cost += stmt_cost;
     }
 
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    if (child)
+      scalar_cost += vect_bb_slp_scalar_cost (bb, child, life);
+
+  return scalar_cost;
+}
+
+/* Check if vectorization of the basic block is profitable.  */
+
+static bool
+vect_bb_vectorization_profitable_p (bb_vec_info bb_vinfo)
+{
+  vec<slp_instance> slp_instances = BB_VINFO_SLP_INSTANCES (bb_vinfo);
+  slp_instance instance;
+  int i;
+  unsigned int vec_inside_cost = 0, vec_outside_cost = 0, scalar_cost = 0;
+  unsigned int vec_prologue_cost = 0, vec_epilogue_cost = 0;
+
+  /* Calculate scalar cost.  */
+  FOR_EACH_VEC_ELT (slp_instances, i, instance)
+    {
+      auto_vec<bool, 20> life;
+      life.safe_grow_cleared (SLP_INSTANCE_GROUP_SIZE (instance));
+      scalar_cost += vect_bb_slp_scalar_cost (BB_VINFO_BB (bb_vinfo),
+                                             SLP_INSTANCE_TREE (instance),
+                                             &life);
+    }
+
   /* Complete the target-specific cost calculation.  */
   finish_cost (BB_VINFO_TARGET_COST_DATA (bb_vinfo), &vec_prologue_cost,
               &vec_inside_cost, &vec_epilogue_cost);
 
   vec_outside_cost = vec_prologue_cost + vec_epilogue_cost;
 
-  if (dump_kind_p (MSG_NOTE))
+  if (dump_enabled_p ())
     {
       dump_printf_loc (MSG_NOTE, vect_location, "Cost model analysis: \n");
       dump_printf (MSG_NOTE, "  Vector inside of basic block cost: %d\n",
                   vec_inside_cost);
       dump_printf (MSG_NOTE, "  Vector prologue cost: %d\n", vec_prologue_cost);
       dump_printf (MSG_NOTE, "  Vector epilogue cost: %d\n", vec_epilogue_cost);
-      dump_printf (MSG_NOTE, "  Scalar cost of basic block: %d", scalar_cost);
+      dump_printf (MSG_NOTE, "  Scalar cost of basic block: %d\n", scalar_cost);
     }
 
   /* Vectorization is profitable if its cost is less than the cost of scalar
@@ -2084,20 +2375,19 @@ static bb_vec_info
 vect_slp_analyze_bb_1 (basic_block bb)
 {
   bb_vec_info bb_vinfo;
-  VEC (ddr_p, heap) *ddrs;
-  VEC (slp_instance, heap) *slp_instances;
+  vec<slp_instance> slp_instances;
   slp_instance instance;
   int i;
   int min_vf = 2;
-  int max_vf = MAX_VECTORIZATION_FACTOR;
+  unsigned n_stmts = 0;
 
   bb_vinfo = new_bb_vec_info (bb);
   if (!bb_vinfo)
     return NULL;
 
-  if (!vect_analyze_data_refs (NULL, bb_vinfo, &min_vf))
+  if (!vect_analyze_data_refs (NULL, bb_vinfo, &min_vf, &n_stmts))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                         "not vectorized: unhandled data-ref in basic "
                         "block.\n");
@@ -2106,10 +2396,9 @@ vect_slp_analyze_bb_1 (basic_block bb)
       return NULL;
     }
 
-  ddrs = BB_VINFO_DDRS (bb_vinfo);
-  if (!VEC_length (ddr_p, ddrs))
+  if (BB_VINFO_DATAREFS (bb_vinfo).length () < 2)
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                         "not vectorized: not enough data-refs in "
                         "basic block.\n");
@@ -2118,23 +2407,22 @@ vect_slp_analyze_bb_1 (basic_block bb)
       return NULL;
     }
 
-  vect_pattern_recog (NULL, bb_vinfo);
+  if (!vect_analyze_data_ref_accesses (NULL, bb_vinfo))
+    {
+     if (dump_enabled_p ())
+       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                       "not vectorized: unhandled data access in "
+                       "basic block.\n");
 
-  if (!vect_analyze_data_ref_dependences (NULL, bb_vinfo, &max_vf)
-       || min_vf > max_vf)
-     {
-       if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                         "not vectorized: unhandled data dependence "
-                         "in basic block.\n");
+      destroy_bb_vec_info (bb_vinfo);
+      return NULL;
+    }
 
-       destroy_bb_vec_info (bb_vinfo);
-       return NULL;
-     }
+  vect_pattern_recog (NULL, bb_vinfo);
 
   if (!vect_analyze_data_refs_alignment (NULL, bb_vinfo))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                         "not vectorized: bad data alignment in basic "
                         "block.\n");
@@ -2143,25 +2431,18 @@ vect_slp_analyze_bb_1 (basic_block bb)
       return NULL;
     }
 
-  if (!vect_analyze_data_ref_accesses (NULL, bb_vinfo))
-    {
-     if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-       dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                       "not vectorized: unhandled data access in "
-                       "basic block.\n");
-
-      destroy_bb_vec_info (bb_vinfo);
-      return NULL;
-    }
-
   /* Check the SLP opportunities in the basic block, analyze and build SLP
      trees.  */
-  if (!vect_analyze_slp (NULL, bb_vinfo))
+  if (!vect_analyze_slp (NULL, bb_vinfo, n_stmts))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
-                        "not vectorized: failed to find SLP opportunities "
-                        "in basic block.\n");
+      if (dump_enabled_p ())
+       {
+         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                          "Failed to SLP the basic block.\n");
+         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
+                          "not vectorized: failed to find SLP opportunities "
+                          "in basic block.\n");
+       }
 
       destroy_bb_vec_info (bb_vinfo);
       return NULL;
@@ -2171,15 +2452,38 @@ vect_slp_analyze_bb_1 (basic_block bb)
 
   /* Mark all the statements that we want to vectorize as pure SLP and
      relevant.  */
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
+  FOR_EACH_VEC_ELT (slp_instances, i, instance)
     {
       vect_mark_slp_stmts (SLP_INSTANCE_TREE (instance), pure_slp, -1);
       vect_mark_slp_stmts_relevant (SLP_INSTANCE_TREE (instance));
     }
 
+  /* Mark all the statements that we do not want to vectorize.  */
+  for (gimple_stmt_iterator gsi = gsi_start_bb (BB_VINFO_BB (bb_vinfo));
+       !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      stmt_vec_info vinfo = vinfo_for_stmt (gsi_stmt (gsi));
+      if (STMT_SLP_TYPE (vinfo) != pure_slp)
+       STMT_VINFO_VECTORIZABLE (vinfo) = false;
+    }
+
+  /* Analyze dependences.  At this point all stmts not participating in
+     vectorization have to be marked.  Dependence analysis assumes
+     that we either vectorize all SLP instances or none at all.  */
+  if (!vect_slp_analyze_data_ref_dependences (bb_vinfo))
+     {
+       if (dump_enabled_p ())
+        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                         "not vectorized: unhandled data dependence "
+                         "in basic block.\n");
+
+       destroy_bb_vec_info (bb_vinfo);
+       return NULL;
+     }
+
   if (!vect_verify_datarefs_alignment (NULL, bb_vinfo))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                          "not vectorized: unsupported alignment in basic "
                          "block.\n");
@@ -2187,10 +2491,11 @@ vect_slp_analyze_bb_1 (basic_block bb)
       return NULL;
     }
 
-  if (!vect_slp_analyze_operations (bb_vinfo))
+  if (!vect_slp_analyze_operations (BB_VINFO_SLP_INSTANCES (bb_vinfo),
+                                   BB_VINFO_TARGET_COST_DATA (bb_vinfo)))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
+      if (dump_enabled_p ())
+        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                         "not vectorized: bad operation in basic block.\n");
 
       destroy_bb_vec_info (bb_vinfo);
@@ -2198,10 +2503,10 @@ vect_slp_analyze_bb_1 (basic_block bb)
     }
 
   /* Cost model: check if the vectorization is worthwhile.  */
-  if (flag_vect_cost_model
+  if (!unlimited_cost_model (NULL)
       && !vect_bb_vectorization_profitable_p (bb_vinfo))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                         "not vectorized: vectorization is not "
                         "profitable.\n");
@@ -2210,7 +2515,7 @@ vect_slp_analyze_bb_1 (basic_block bb)
       return NULL;
     }
 
-  if (dump_kind_p (MSG_NOTE))
+  if (dump_enabled_p ())
     dump_printf_loc (MSG_NOTE, vect_location,
                     "Basic block will be vectorized using SLP\n");
 
@@ -2226,7 +2531,7 @@ vect_slp_analyze_bb (basic_block bb)
   gimple_stmt_iterator gsi;
   unsigned int vector_sizes;
 
-  if (dump_kind_p (MSG_NOTE))
+  if (dump_enabled_p ())
     dump_printf_loc (MSG_NOTE, vect_location, "===vect_slp_analyze_bb===\n");
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -2240,7 +2545,7 @@ vect_slp_analyze_bb (basic_block bb)
 
   if (insns > PARAM_VALUE (PARAM_SLP_MAX_INSNS_IN_BB))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                         "not vectorized: too many instructions in "
                         "basic block.\n");
@@ -2267,7 +2572,7 @@ vect_slp_analyze_bb (basic_block bb)
 
       /* Try the next biggest vector size.  */
       current_vector_size = 1 << floor_log2 (vector_sizes);
-      if (dump_kind_p (MSG_NOTE))
+      if (dump_enabled_p ())
         dump_printf_loc (MSG_NOTE, vect_location,
                         "***** Re-trying analysis with "
                         "vector size %d\n", current_vector_size);
@@ -2275,45 +2580,6 @@ vect_slp_analyze_bb (basic_block bb)
 }
 
 
-/* SLP costs are calculated according to SLP instance unrolling factor (i.e.,
-   the number of created vector stmts depends on the unrolling factor).
-   However, the actual number of vector stmts for every SLP node depends on
-   VF which is set later in vect_analyze_operations ().  Hence, SLP costs
-   should be updated.  In this function we assume that the inside costs
-   calculated in vect_model_xxx_cost are linear in ncopies.  */
-
-void
-vect_update_slp_costs_according_to_vf (loop_vec_info loop_vinfo)
-{
-  unsigned int i, j, vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
-  VEC (slp_instance, heap) *slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
-  slp_instance instance;
-  stmt_vector_for_cost body_cost_vec;
-  stmt_info_for_cost *si;
-  void *data = LOOP_VINFO_TARGET_COST_DATA (loop_vinfo);
-
-  if (dump_kind_p (MSG_NOTE))
-    dump_printf_loc (MSG_NOTE, vect_location,
-                    "=== vect_update_slp_costs_according_to_vf ===");
-
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
-    {
-      /* We assume that costs are linear in ncopies.  */
-      int ncopies = vf / SLP_INSTANCE_UNROLLING_FACTOR (instance);
-
-      /* Record the instance's instructions in the target cost model.
-        This was delayed until here because the count of instructions
-        isn't known beforehand.  */
-      body_cost_vec = SLP_INSTANCE_BODY_COST_VEC (instance);
-
-      FOR_EACH_VEC_ELT (stmt_info_for_cost, body_cost_vec, j, si)
-       (void) add_stmt_cost (data, si->count * ncopies, si->kind,
-                             vinfo_for_stmt (si->stmt), si->misalign,
-                             vect_body);
-    }
-}
-
-
 /* For constant and loop invariant defs of SLP_NODE this function returns
    (vector) defs (VEC_OPRNDS) that will be used in the vectorized stmts.
    OP_NUM determines if we gather defs for operand 0 or operand 1 of the RHS of
@@ -2323,12 +2589,12 @@ vect_update_slp_costs_according_to_vf (loop_vec_info loop_vinfo)
 
 static void
 vect_get_constant_vectors (tree op, slp_tree slp_node,
-                           VEC (tree, heap) **vec_oprnds,
+                           vec<tree> *vec_oprnds,
                           unsigned int op_num, unsigned int number_of_vectors,
                            int reduc_index)
 {
-  VEC (gimple, heap) *stmts = SLP_TREE_SCALAR_STMTS (slp_node);
-  gimple stmt = VEC_index (gimple, stmts, 0);
+  vec<gimple> stmts = SLP_TREE_SCALAR_STMTS (slp_node);
+  gimple stmt = stmts[0];
   stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
   unsigned nunits;
   tree vec_cst;
@@ -2336,10 +2602,11 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
   unsigned j, number_of_places_left_in_vector;
   tree vector_type;
   tree vop;
-  int group_size = VEC_length (gimple, stmts);
+  int group_size = stmts.length ();
   unsigned int vec_num, i;
   unsigned number_of_copies = 1;
-  VEC (tree, heap) *voprnds = VEC_alloc (tree, heap, number_of_vectors);
+  vec<tree> voprnds;
+  voprnds.create (number_of_vectors);
   bool constant_p, is_store;
   tree neutral_op = NULL;
   enum tree_code code = gimple_expr_code (stmt);
@@ -2347,11 +2614,14 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
   struct loop *loop;
   gimple_seq ctor_seq = NULL;
 
+  vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
+  nunits = TYPE_VECTOR_SUBPARTS (vector_type);
+
   if (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
       && reduc_index != -1)
     {
-      op_num = reduc_index - 1;
-      op = gimple_op (stmt, reduc_index);
+      op_num = reduc_index;
+      op = gimple_op (stmt, op_num + 1);
       /* For additional copies (see the explanation of NUMBER_OF_COPIES below)
          we need either neutral operands or the original operands.  See
          get_initial_def_for_reduction() for details.  */
@@ -2359,6 +2629,7 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
         {
           case WIDEN_SUM_EXPR:
           case DOT_PROD_EXPR:
+         case SAD_EXPR:
           case PLUS_EXPR:
           case MINUS_EXPR:
           case BIT_IOR_EXPR:
@@ -2382,15 +2653,24 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
             neutral_op = build_int_cst (TREE_TYPE (op), -1);
             break;
 
-          case MAX_EXPR:
-          case MIN_EXPR:
-            def_stmt = SSA_NAME_DEF_STMT (op);
-            loop = (gimple_bb (stmt))->loop_father;
-            neutral_op = PHI_ARG_DEF_FROM_EDGE (def_stmt,
-                                                loop_preheader_edge (loop));
-            break;
+         /* For MIN/MAX we don't have an easy neutral operand but
+            the initial values can be used fine here.  Only for
+            a reduction chain we have to force a neutral element.  */
+         case MAX_EXPR:
+         case MIN_EXPR:
+           if (!GROUP_FIRST_ELEMENT (stmt_vinfo))
+             neutral_op = NULL;
+           else
+             {
+               def_stmt = SSA_NAME_DEF_STMT (op);
+               loop = (gimple_bb (stmt))->loop_father;
+               neutral_op = PHI_ARG_DEF_FROM_EDGE (def_stmt,
+                                                   loop_preheader_edge (loop));
+             }
+           break;
 
           default:
+           gcc_assert (!GROUP_FIRST_ELEMENT (stmt_vinfo));
             neutral_op = NULL;
         }
     }
@@ -2410,10 +2690,6 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
   else
     constant_p = false;
 
-  vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
-  gcc_assert (vector_type);
-  nunits = TYPE_VECTOR_SUBPARTS (vector_type);
-
   /* NUMBER_OF_COPIES is the number of times we need to use the same values in
      created vectors. It is greater than 1 if unrolling is performed.
 
@@ -2430,13 +2706,14 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
      (s1, s2, ..., s8).  We will create two vectors {s1, s2, s3, s4} and
      {s5, s6, s7, s8}.  */
 
-  number_of_copies = least_common_multiple (nunits, group_size) / group_size;
+  number_of_copies = nunits * number_of_vectors / group_size;
 
   number_of_places_left_in_vector = nunits;
   elts = XALLOCAVEC (tree, nunits);
+  bool place_after_defs = false;
   for (j = 0; j < number_of_copies; j++)
     {
-      for (i = group_size - 1; VEC_iterate (gimple, stmts, i, stmt); i--)
+      for (i = group_size - 1; stmts.iterate (i, &stmt); i--)
         {
           if (is_store)
             op = gimple_assign_rhs1 (stmt);
@@ -2473,7 +2750,7 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
                       the lhs, so make sure the scalar is the right type if
                       we are dealing with vectors of
                       long long/long/short/char.  */
-                   if (op_num == 1 && constant_p)
+                   if (op_num == 1 && TREE_CODE (op) == INTEGER_CST)
                      op = fold_convert (TREE_TYPE (vector_type), op);
                    break;
 
@@ -2504,9 +2781,10 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
 
           /* Create 'vect_ = {op0,op1,...,opn}'.  */
           number_of_places_left_in_vector--;
+         tree orig_op = op;
          if (!types_compatible_p (TREE_TYPE (vector_type), TREE_TYPE (op)))
            {
-             if (constant_p)
+             if (CONSTANT_CLASS_P (op))
                {
                  op = fold_unary (VIEW_CONVERT_EXPR,
                                   TREE_TYPE (vector_type), op);
@@ -2514,19 +2792,24 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
                }
              else
                {
-                 tree new_temp
-                   = make_ssa_name (TREE_TYPE (vector_type), NULL);
+                 tree new_temp = make_ssa_name (TREE_TYPE (vector_type));
                  gimple init_stmt;
-                 op = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (vector_type),
-                              op);               
+                 op = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (vector_type), op);
                  init_stmt
-                   = gimple_build_assign_with_ops (VIEW_CONVERT_EXPR,
-                                                   new_temp, op, NULL_TREE);
+                   = gimple_build_assign (new_temp, VIEW_CONVERT_EXPR, op);
                  gimple_seq_add_stmt (&ctor_seq, init_stmt);
                  op = new_temp;
                }
            }
          elts[number_of_places_left_in_vector] = op;
+         if (!CONSTANT_CLASS_P (op))
+           constant_p = false;
+         if (TREE_CODE (orig_op) == SSA_NAME
+             && !SSA_NAME_IS_DEFAULT_DEF (orig_op)
+             && STMT_VINFO_BB_VINFO (stmt_vinfo)
+             && (STMT_VINFO_BB_VINFO (stmt_vinfo)->bb
+                 == gimple_bb (SSA_NAME_DEF_STMT (orig_op))))
+           place_after_defs = true;
 
           if (number_of_places_left_in_vector == 0)
             {
@@ -2536,45 +2819,52 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
                vec_cst = build_vector (vector_type, elts);
              else
                {
-                 VEC(constructor_elt,gc) *v;
+                 vec<constructor_elt, va_gc> *v;
                  unsigned k;
-                 v = VEC_alloc (constructor_elt, gc, nunits);
+                 vec_alloc (v, nunits);
                  for (k = 0; k < nunits; ++k)
                    CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elts[k]);
                  vec_cst = build_constructor (vector_type, v);
                }
-              VEC_quick_push (tree, voprnds,
-                              vect_init_vector (stmt, vec_cst,
-                                               vector_type, NULL));
+             tree init;
+             gimple_stmt_iterator gsi;
+             if (place_after_defs)
+               {
+                 gsi = gsi_for_stmt
+                         (vect_find_last_scalar_stmt_in_slp (slp_node));
+                 init = vect_init_vector (stmt, vec_cst, vector_type, &gsi);
+               }
+             else
+               init = vect_init_vector (stmt, vec_cst, vector_type, NULL);
              if (ctor_seq != NULL)
                {
-                 gimple init_stmt
-                   = SSA_NAME_DEF_STMT (VEC_last (tree, voprnds));
-                 gimple_stmt_iterator gsi = gsi_for_stmt (init_stmt);
+                 gsi = gsi_for_stmt (SSA_NAME_DEF_STMT (init));
                  gsi_insert_seq_before_without_update (&gsi, ctor_seq,
                                                        GSI_SAME_STMT);
                  ctor_seq = NULL;
                }
+             voprnds.quick_push (init);
+             place_after_defs = false;
             }
         }
     }
 
   /* Since the vectors are created in the reverse order, we should invert
      them.  */
-  vec_num = VEC_length (tree, voprnds);
+  vec_num = voprnds.length ();
   for (j = vec_num; j != 0; j--)
     {
-      vop = VEC_index (tree, voprnds, j - 1);
-      VEC_quick_push (tree, *vec_oprnds, vop);
+      vop = voprnds[j - 1];
+      vec_oprnds->quick_push (vop);
     }
 
-  VEC_free (tree, heap, voprnds);
+  voprnds.release ();
 
   /* In case that VF is greater than the unrolling factor needed for the SLP
      group of stmts, NUMBER_OF_VECTORS to be created is greater than
      NUMBER_OF_SCALARS/NUNITS or NUNITS/NUMBER_OF_SCALARS, and hence we have
      to replicate the vectors.  */
-  while (number_of_vectors > VEC_length (tree, *vec_oprnds))
+  while (number_of_vectors > vec_oprnds->length ())
     {
       tree neutral_vec = NULL;
 
@@ -2583,12 +2873,12 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
           if (!neutral_vec)
            neutral_vec = build_vector_from_val (vector_type, neutral_op);
 
-          VEC_quick_push (tree, *vec_oprnds, neutral_vec);
+          vec_oprnds->quick_push (neutral_vec);
         }
       else
         {
-          for (i = 0; VEC_iterate (tree, *vec_oprnds, i, vop) && i < vec_num; i++)
-            VEC_quick_push (tree, *vec_oprnds, vop);
+          for (i = 0; vec_oprnds->iterate (i, &vop) && i < vec_num; i++)
+            vec_oprnds->quick_push (vop);
         }
     }
 }
@@ -2598,19 +2888,19 @@ vect_get_constant_vectors (tree op, slp_tree slp_node,
    vectorized def-stmts.  */
 
 static void
-vect_get_slp_vect_defs (slp_tree slp_node, VEC (tree,heap) **vec_oprnds)
+vect_get_slp_vect_defs (slp_tree slp_node, vec<tree> *vec_oprnds)
 {
   tree vec_oprnd;
   gimple vec_def_stmt;
   unsigned int i;
 
-  gcc_assert (SLP_TREE_VEC_STMTS (slp_node));
+  gcc_assert (SLP_TREE_VEC_STMTS (slp_node).exists ());
 
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_VEC_STMTS (slp_node), i, vec_def_stmt)
+  FOR_EACH_VEC_ELT (SLP_TREE_VEC_STMTS (slp_node), i, vec_def_stmt)
     {
       gcc_assert (vec_def_stmt);
       vec_oprnd = gimple_get_lhs (vec_def_stmt);
-      VEC_quick_push (tree, *vec_oprnds, vec_oprnd);
+      vec_oprnds->quick_push (vec_oprnd);
     }
 }
 
@@ -2623,20 +2913,20 @@ vect_get_slp_vect_defs (slp_tree slp_node, VEC (tree,heap) **vec_oprnds)
    vect_get_slp_vect_defs () to retrieve them.  */
 
 void
-vect_get_slp_defs (VEC (tree, heap) *ops, slp_tree slp_node,
-                   VEC (slp_void_p, heap) **vec_oprnds, int reduc_index)
+vect_get_slp_defs (vec<tree> ops, slp_tree slp_node,
+                  vec<vec<tree> > *vec_oprnds, int reduc_index)
 {
-  gimple first_stmt, first_def;
+  gimple first_stmt;
   int number_of_vects = 0, i;
   unsigned int child_index = 0;
   HOST_WIDE_INT lhs_size_unit, rhs_size_unit;
   slp_tree child = NULL;
-  VEC (tree, heap) *vec_defs;
-  tree oprnd, def_lhs;
+  vec<tree> vec_defs;
+  tree oprnd;
   bool vectorized_defs;
 
-  first_stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (slp_node), 0);
-  FOR_EACH_VEC_ELT (tree, ops, i, oprnd)
+  first_stmt = SLP_TREE_SCALAR_STMTS (slp_node)[0];
+  FOR_EACH_VEC_ELT (ops, i, oprnd)
     {
       /* For each operand we check if it has vectorized definitions in a child
         node or we need to create them (for invariants and constants).  We
@@ -2645,34 +2935,31 @@ vect_get_slp_defs (VEC (tree, heap) *ops, slp_tree slp_node,
         vect_get_constant_vectors (), and not advance CHILD_INDEX in order
         to check this child node for the next operand.  */
       vectorized_defs = false;
-      if (VEC_length (slp_void_p, SLP_TREE_CHILDREN (slp_node)) > child_index)
+      if (SLP_TREE_CHILDREN (slp_node).length () > child_index)
         {
-          child = (slp_tree) VEC_index (slp_void_p,
-                                       SLP_TREE_CHILDREN (slp_node),
-                                       child_index);
-          first_def = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (child), 0);
-
-         /* In the end of a pattern sequence we have a use of the original stmt,
-            so we need to compare OPRND with the original def.  */
-          if (is_pattern_stmt_p (vinfo_for_stmt (first_def))
-             && !STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (first_stmt))
-              && !is_pattern_stmt_p (vinfo_for_stmt (first_stmt)))
-            first_def = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (first_def));
-
-          if (is_gimple_call (first_def))
-            def_lhs = gimple_call_lhs (first_def);
-          else
-            def_lhs = gimple_assign_lhs (first_def);
+          child = SLP_TREE_CHILDREN (slp_node)[child_index];
 
-          if (operand_equal_p (oprnd, def_lhs, 0))
-            {
-              /* The number of vector defs is determined by the number of
-                 vector statements in the node from which we get those
-                statements.  */
-                 number_of_vects = SLP_TREE_NUMBER_OF_VEC_STMTS (child);
-                 vectorized_defs = true;
-             child_index++;
-            }
+         /* We have to check both pattern and original def, if available.  */
+         if (child)
+           {
+             gimple first_def = SLP_TREE_SCALAR_STMTS (child)[0];
+             gimple related
+               = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (first_def));
+
+             if (operand_equal_p (oprnd, gimple_get_lhs (first_def), 0)
+                 || (related
+                     && operand_equal_p (oprnd, gimple_get_lhs (related), 0)))
+               {
+                 /* The number of vector defs is determined by the number of
+                    vector statements in the node from which we get those
+                    statements.  */
+                 number_of_vects = SLP_TREE_NUMBER_OF_VEC_STMTS (child);
+                 vectorized_defs = true;
+                 child_index++;
+               }
+           }
+         else
+           child_index++;
         }
 
       if (!vectorized_defs)
@@ -2695,19 +2982,20 @@ vect_get_slp_defs (VEC (tree, heap) *ops, slp_tree slp_node,
         }
 
       /* Allocate memory for vectorized defs.  */
-      vec_defs = VEC_alloc (tree, heap, number_of_vects);
+      vec_defs = vNULL;
+      vec_defs.create (number_of_vects);
 
       /* For reduction defs we call vect_get_constant_vectors (), since we are
          looking for initial loop invariant values.  */
       if (vectorized_defs && reduc_index == -1)
         /* The defs are already vectorized.  */
-        vect_get_slp_vect_defs (child, &vec_defs);
+       vect_get_slp_vect_defs (child, &vec_defs);
       else
         /* Build vectors from scalar defs.  */
-        vect_get_constant_vectors (oprnd, slp_node, &vec_defs, i,
+       vect_get_constant_vectors (oprnd, slp_node, &vec_defs, i,
                                    number_of_vects, reduc_index);
 
-      VEC_quick_push (slp_void_p, *vec_oprnds, (slp_void_p) vec_defs);
+      vec_oprnds->quick_push (vec_defs);
 
       /* For reductions, we only need initial values.  */
       if (reduc_index != -1)
@@ -2726,15 +3014,14 @@ vect_get_slp_defs (VEC (tree, heap) *ops, slp_tree slp_node,
    the created stmts must be inserted.  */
 
 static inline void
-vect_create_mask_and_perm (gimple stmt, gimple next_scalar_stmt,
+vect_create_mask_and_perm (gimple stmt,
                            tree mask, int first_vec_indx, int second_vec_indx,
                            gimple_stmt_iterator *gsi, slp_tree node,
-                           tree vectype, VEC(tree,heap) *dr_chain,
+                           tree vectype, vec<tree> dr_chain,
                            int ncopies, int vect_stmts_counter)
 {
   tree perm_dest;
   gimple perm_stmt = NULL;
-  stmt_vec_info next_stmt_info;
   int i, stride;
   tree first_vec, second_vec, data_ref;
 
@@ -2742,34 +3029,29 @@ vect_create_mask_and_perm (gimple stmt, gimple next_scalar_stmt,
 
   /* Initialize the vect stmts of NODE to properly insert the generated
      stmts later.  */
-  for (i = VEC_length (gimple, SLP_TREE_VEC_STMTS (node));
+  for (i = SLP_TREE_VEC_STMTS (node).length ();
        i < (int) SLP_TREE_NUMBER_OF_VEC_STMTS (node); i++)
-    VEC_quick_push (gimple, SLP_TREE_VEC_STMTS (node), NULL);
+    SLP_TREE_VEC_STMTS (node).quick_push (NULL);
 
   perm_dest = vect_create_destination_var (gimple_assign_lhs (stmt), vectype);
   for (i = 0; i < ncopies; i++)
     {
-      first_vec = VEC_index (tree, dr_chain, first_vec_indx);
-      second_vec = VEC_index (tree, dr_chain, second_vec_indx);
+      first_vec = dr_chain[first_vec_indx];
+      second_vec = dr_chain[second_vec_indx];
 
       /* Generate the permute statement.  */
-      perm_stmt = gimple_build_assign_with_ops (VEC_PERM_EXPR, perm_dest,
-                                               first_vec, second_vec, mask);
+      perm_stmt = gimple_build_assign (perm_dest, VEC_PERM_EXPR,
+                                      first_vec, second_vec, mask);
       data_ref = make_ssa_name (perm_dest, perm_stmt);
       gimple_set_lhs (perm_stmt, data_ref);
       vect_finish_stmt_generation (stmt, perm_stmt, gsi);
 
       /* Store the vector statement in NODE.  */
-      VEC_replace (gimple, SLP_TREE_VEC_STMTS (node),
-                   stride * i + vect_stmts_counter, perm_stmt);
+      SLP_TREE_VEC_STMTS (node)[stride * i + vect_stmts_counter] = perm_stmt;
 
       first_vec_indx += stride;
       second_vec_indx += stride;
     }
-
-  /* Mark the scalar stmt as vectorized.  */
-  next_stmt_info = vinfo_for_stmt (next_scalar_stmt);
-  STMT_VINFO_VEC_STMT (next_stmt_info) = perm_stmt;
 }
 
 
@@ -2793,6 +3075,18 @@ vect_get_mask_element (gimple stmt, int first_mask_element, int m,
   /* Adjust the value in case it's a mask for second and third vectors.  */
   *current_mask_element -= mask_nunits * (*number_of_mask_fixes - 1);
 
+  if (*current_mask_element < 0)
+    {
+      if (dump_enabled_p ())
+       {
+         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                          "permutation requires past vector ");
+         dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+         dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
+       }
+      return false;
+    }
+
   if (*current_mask_element < mask_nunits)
     *needs_first_vector = true;
 
@@ -2800,30 +3094,32 @@ vect_get_mask_element (gimple stmt, int first_mask_element, int m,
      the next vector as well.  */
   if (only_one_vec && *current_mask_element >= mask_nunits)
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         {
-          dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, 
+          dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                           "permutation requires at least two vectors ");
           dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+          dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
         }
 
       return false;
     }
 
   /* The mask requires the next vector.  */
-  if (*current_mask_element >= mask_nunits * 2)
+  while (*current_mask_element >= mask_nunits * 2)
     {
       if (*needs_first_vector || *mask_fixed)
         {
           /* We either need the first vector too or have already moved to the
              next vector. In both cases, this permutation needs three
              vectors.  */
-          if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+          if (dump_enabled_p ())
             {
               dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                               "permutation requires at "
                               "least three vectors ");
               dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+              dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
             }
 
           return false;
@@ -2857,18 +3153,19 @@ vect_get_mask_element (gimple stmt, int first_mask_element, int m,
 
 /* Generate vector permute statements from a list of loads in DR_CHAIN.
    If ANALYZE_ONLY is TRUE, only check that it is possible to create valid
-   permute statements for SLP_NODE_INSTANCE.  */
+   permute statements for the SLP node NODE of the SLP instance
+   SLP_NODE_INSTANCE.  */
+
 bool
-vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
+vect_transform_slp_perm_load (slp_tree node, vec<tree> dr_chain,
                               gimple_stmt_iterator *gsi, int vf,
                               slp_instance slp_node_instance, bool analyze_only)
 {
+  gimple stmt = SLP_TREE_SCALAR_STMTS (node)[0];
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
   tree mask_element_type = NULL_TREE, mask_type;
-  int i, j, k, nunits, vec_index = 0, scalar_index;
-  slp_tree node;
+  int i, j, k, nunits, vec_index = 0;
   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;
   int index, unroll_factor, current_mask_element, ncopies;
@@ -2878,17 +3175,23 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
   int number_of_mask_fixes = 1;
   bool mask_fixed = false;
   bool needs_first_vector = false;
-  enum machine_mode mode;
+  machine_mode mode;
+
+  if (!STMT_VINFO_GROUPED_ACCESS (stmt_info))
+    return false;
+
+  stmt_info = vinfo_for_stmt (GROUP_FIRST_ELEMENT (stmt_info));
 
   mode = TYPE_MODE (vectype);
 
   if (!can_vec_perm_p (mode, false, NULL))
     {
-      if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+      if (dump_enabled_p ())
         {
           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                           "no vect permute for ");
           dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+          dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
         }
       return false;
     }
@@ -2904,8 +3207,10 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
 
   /* The number of vector stmts to generate based only on SLP_NODE_INSTANCE
      unrolling factor.  */
-  orig_vec_stmts_num = group_size *
-                SLP_INSTANCE_UNROLLING_FACTOR (slp_node_instance) / nunits;
+  orig_vec_stmts_num
+    = (STMT_VINFO_GROUP_SIZE (stmt_info)
+       * SLP_INSTANCE_UNROLLING_FACTOR (slp_node_instance)
+       + nunits - 1) / nunits;
   if (orig_vec_stmts_num == 1)
     only_one_vec = true;
 
@@ -2931,9 +3236,7 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
      we need the second and the third vectors: {b1,c1,a2,b2} and
      {c2,a3,b3,c3}.  */
 
-  FOR_EACH_VEC_ELT  (slp_tree, SLP_INSTANCE_LOADS (slp_node_instance), i, node)
-    {
-      scalar_index = 0;
+  {
       index = 0;
       vect_stmts_counter = 0;
       vec_index = 0;
@@ -2947,7 +3250,8 @@ 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;
+             i = SLP_TREE_LOAD_PERMUTATION (node)[k];
+              first_mask_element = i + j * STMT_VINFO_GROUP_SIZE (stmt_info);
               if (!vect_get_mask_element (stmt, first_mask_element, 0,
                                          nunits, only_one_vec, index,
                                          mask, &current_mask_element,
@@ -2955,16 +3259,16 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
                                          &number_of_mask_fixes, &mask_fixed,
                                          &needs_first_vector))
                return false;
+             gcc_assert (current_mask_element >= 0
+                         && current_mask_element < 2 * nunits);
              mask[index++] = current_mask_element;
 
               if (index == nunits)
                 {
-                 tree mask_vec, *mask_elts;
-                 int l;
-
+                 index = 0;
                  if (!can_vec_perm_p (mode, false, mask))
                    {
-                     if (dump_kind_p (MSG_MISSED_OPTIMIZATION))
+                     if (dump_enabled_p ())
                        {
                          dump_printf_loc (MSG_MISSED_OPTIMIZATION,
                                           vect_location, 
@@ -2977,24 +3281,23 @@ vect_transform_slp_perm_load (gimple stmt, VEC (tree, heap) *dr_chain,
                      return false;
                    }
 
-                 mask_elts = XALLOCAVEC (tree, nunits);
-                 for (l = 0; l < nunits; ++l)
-                   mask_elts[l] = build_int_cst (mask_element_type, mask[l]);
-                 mask_vec = build_vector (mask_type, mask_elts);
-                 index = 0;
-
                   if (!analyze_only)
                     {
-                      if (need_next_vector)
+                     int l;
+                     tree mask_vec, *mask_elts;
+                     mask_elts = XALLOCAVEC (tree, nunits);
+                     for (l = 0; l < nunits; ++l)
+                       mask_elts[l] = build_int_cst (mask_element_type,
+                                                     mask[l]);
+                     mask_vec = build_vector (mask_type, mask_elts);
+
+                     if (need_next_vector)
                         {
                           first_vec_index = second_vec_index;
                           second_vec_index = vec_index;
                         }
 
-                      next_scalar_stmt = VEC_index (gimple,
-                                SLP_TREE_SCALAR_STMTS (node), scalar_index++);
-
-                      vect_create_mask_and_perm (stmt, next_scalar_stmt,
+                      vect_create_mask_and_perm (stmt,
                                mask_vec, first_vec_index, second_vec_index,
                               gsi, node, vectype, dr_chain,
                               ncopies, vect_stmts_counter++);
@@ -3022,17 +3325,15 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance,
   unsigned int vec_stmts_size, nunits, group_size;
   tree vectype;
   int i;
-  slp_tree loads_node;
-  slp_void_p child;
+  slp_tree child;
 
   if (!node)
     return false;
 
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_schedule_slp_instance ((slp_tree) child, instance,
-                                vectorization_factor);
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    vect_schedule_slp_instance (child, instance, vectorization_factor);
 
-  stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (node), 0);
+  stmt = SLP_TREE_SCALAR_STMTS (node)[0];
   stmt_info = vinfo_for_stmt (stmt);
 
   /* VECTYPE is the type of the destination.  */
@@ -3044,57 +3345,32 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance,
      for the scalar stmts in each node of the SLP tree.  Number of vector
      elements in one vector iteration is the number of scalar elements in
      one scalar iteration (GROUP_SIZE) multiplied by VF divided by vector
-     size.  */
-  vec_stmts_size = (vectorization_factor * group_size) / nunits;
-
-  /* In case of load permutation we have to allocate vectorized statements for
-     all the nodes that participate in that permutation.  */
-  if (SLP_INSTANCE_LOAD_PERMUTATION (instance))
-    {
-      FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (instance), i, loads_node)
-        {
-          if (!SLP_TREE_VEC_STMTS (loads_node))
-            {
-              SLP_TREE_VEC_STMTS (loads_node) = VEC_alloc (gimple, heap,
-                                                           vec_stmts_size);
-              SLP_TREE_NUMBER_OF_VEC_STMTS (loads_node) = vec_stmts_size;
-            }
-        }
-    }
+     size.
+     Unless this is a SLP reduction in which case the number of vector
+     stmts is equal to the number of vector stmts of the children.  */
+  if (GROUP_FIRST_ELEMENT (stmt_info)
+      && !STMT_VINFO_GROUPED_ACCESS (stmt_info))
+    vec_stmts_size = SLP_TREE_NUMBER_OF_VEC_STMTS (SLP_TREE_CHILDREN (node)[0]);
+  else
+    vec_stmts_size = (vectorization_factor * group_size) / nunits;
 
-  if (!SLP_TREE_VEC_STMTS (node))
+  if (!SLP_TREE_VEC_STMTS (node).exists ())
     {
-      SLP_TREE_VEC_STMTS (node) = VEC_alloc (gimple, heap, vec_stmts_size);
+      SLP_TREE_VEC_STMTS (node).create (vec_stmts_size);
       SLP_TREE_NUMBER_OF_VEC_STMTS (node) = vec_stmts_size;
     }
 
-  if (dump_kind_p (MSG_NOTE))
+  if (dump_enabled_p ())
     {
       dump_printf_loc (MSG_NOTE,vect_location,
                       "------>vectorizing SLP node starting from: ");
       dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
+      dump_printf (MSG_NOTE, "\n");
     }
 
-  /* Loads should be inserted before the first load.  */
-  if (SLP_INSTANCE_FIRST_LOAD_STMT (instance)
-      && STMT_VINFO_GROUPED_ACCESS (stmt_info)
-      && !REFERENCE_CLASS_P (gimple_get_lhs (stmt))
-      && SLP_INSTANCE_LOAD_PERMUTATION (instance))
-    si = gsi_for_stmt (SLP_INSTANCE_FIRST_LOAD_STMT (instance));
-  else if (is_pattern_stmt_p (stmt_info))
-    si = gsi_for_stmt (STMT_VINFO_RELATED_STMT (stmt_info));
-  else
-    si = gsi_for_stmt (stmt);
-
-  /* Stores should be inserted just before the last store.  */
-  if (STMT_VINFO_GROUPED_ACCESS (stmt_info)
-      && REFERENCE_CLASS_P (gimple_get_lhs (stmt)))
-    { 
-      gimple last_store = vect_find_last_store_in_slp_instance (instance);
-      if (is_pattern_stmt_p (vinfo_for_stmt (last_store)))
-       last_store = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (last_store));
-      si = gsi_for_stmt (last_store);
-    }
+  /* Vectorized stmts go before the last scalar stmt which is where
+     all uses are ready.  */
+  si = gsi_for_stmt (vect_find_last_scalar_stmt_in_slp (node));
 
   /* Mark the first element of the reduction chain as reduction to properly
      transform the node.  In the analysis phase only the last element of the
@@ -3106,6 +3382,74 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance,
       STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type;
     }
 
+  /* Handle two-operation SLP nodes by vectorizing the group with
+     both operations and then performing a merge.  */
+  if (SLP_TREE_TWO_OPERATORS (node))
+    {
+      enum tree_code code0 = gimple_assign_rhs_code (stmt);
+      enum tree_code ocode;
+      gimple ostmt;
+      unsigned char *mask = XALLOCAVEC (unsigned char, group_size);
+      bool allsame = true;
+      FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, ostmt)
+       if (gimple_assign_rhs_code (ostmt) != code0)
+         {
+           mask[i] = 1;
+           allsame = false;
+           ocode = gimple_assign_rhs_code (ostmt);
+         }
+       else
+         mask[i] = 0;
+      if (!allsame)
+       {
+         vec<gimple> v0;
+         vec<gimple> v1;
+         unsigned j;
+         tree tmask = NULL_TREE;
+         vect_transform_stmt (stmt, &si, &grouped_store, node, instance);
+         v0 = SLP_TREE_VEC_STMTS (node).copy ();
+         SLP_TREE_VEC_STMTS (node).truncate (0);
+         gimple_assign_set_rhs_code (stmt, ocode);
+         vect_transform_stmt (stmt, &si, &grouped_store, node, instance);
+         gimple_assign_set_rhs_code (stmt, code0);
+         v1 = SLP_TREE_VEC_STMTS (node).copy ();
+         SLP_TREE_VEC_STMTS (node).truncate (0);
+         tree meltype = build_nonstandard_integer_type
+             (GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vectype))), 1);
+         tree mvectype = get_same_sized_vectype (meltype, vectype);
+         unsigned k = 0, l;
+         for (j = 0; j < v0.length (); ++j)
+           {
+             tree *melts = XALLOCAVEC (tree, TYPE_VECTOR_SUBPARTS (vectype));
+             for (l = 0; l < TYPE_VECTOR_SUBPARTS (vectype); ++l)
+               {
+                 if (k >= group_size)
+                   k = 0;
+                 melts[l] = build_int_cst
+                     (meltype, mask[k++] * TYPE_VECTOR_SUBPARTS (vectype) + l);
+               }
+             tmask = build_vector (mvectype, melts);
+
+             /* ???  Not all targets support a VEC_PERM_EXPR with a
+                constant mask that would translate to a vec_merge RTX
+                (with their vec_perm_const_ok).  We can either not
+                vectorize in that case or let veclower do its job.
+                Unfortunately that isn't too great and at least for
+                plus/minus we'd eventually like to match targets
+                vector addsub instructions.  */
+             gimple vstmt;
+             vstmt = gimple_build_assign (make_ssa_name (vectype),
+                                          VEC_PERM_EXPR,
+                                          gimple_assign_lhs (v0[j]),
+                                          gimple_assign_lhs (v1[j]), tmask);
+             vect_finish_stmt_generation (stmt, vstmt, &si);
+             SLP_TREE_VEC_STMTS (node).quick_push (vstmt);
+           }
+         v0.release ();
+         v1.release ();
+         return false;
+       }
+    }
   is_store = vect_transform_stmt (stmt, &si, &grouped_store, node, instance);
   return is_store;
 }
@@ -3121,17 +3465,17 @@ vect_remove_slp_scalar_calls (slp_tree node)
   gimple stmt, new_stmt;
   gimple_stmt_iterator gsi;
   int i;
-  slp_void_p child;
+  slp_tree child;
   tree lhs;
   stmt_vec_info stmt_info;
 
   if (!node)
     return;
 
-  FOR_EACH_VEC_ELT (slp_void_p, SLP_TREE_CHILDREN (node), i, child)
-    vect_remove_slp_scalar_calls ((slp_tree) child);
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    vect_remove_slp_scalar_calls (child);
 
-  FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), i, stmt)
+  FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_STMTS (node), i, stmt)
     {
       if (!is_gimple_call (stmt) || gimple_bb (stmt) == NULL)
        continue;
@@ -3156,7 +3500,7 @@ vect_remove_slp_scalar_calls (slp_tree node)
 bool
 vect_schedule_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
 {
-  VEC (slp_instance, heap) *slp_instances;
+  vec<slp_instance> slp_instances;
   slp_instance instance;
   unsigned int i, vf;
   bool is_store = false;
@@ -3172,26 +3516,34 @@ vect_schedule_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
       vf = 1;
     }
 
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
+  FOR_EACH_VEC_ELT (slp_instances, i, instance)
     {
       /* Schedule the tree of INSTANCE.  */
       is_store = vect_schedule_slp_instance (SLP_INSTANCE_TREE (instance),
                                              instance, vf);
-      if (dump_kind_p (MSG_NOTE))
+      if (dump_enabled_p ())
        dump_printf_loc (MSG_NOTE, vect_location,
-                         "vectorizing stmts using SLP.");
+                         "vectorizing stmts using SLP.\n");
     }
 
-  FOR_EACH_VEC_ELT (slp_instance, slp_instances, i, instance)
+  FOR_EACH_VEC_ELT (slp_instances, i, instance)
     {
       slp_tree root = SLP_INSTANCE_TREE (instance);
       gimple store;
       unsigned int j;
       gimple_stmt_iterator gsi;
 
-      vect_remove_slp_scalar_calls (root);
+      /* Remove scalar call stmts.  Do not do this for basic-block
+        vectorization as not all uses may be vectorized.
+        ???  Why should this be necessary?  DCE should be able to
+        remove the stmts itself.
+        ???  For BB vectorization we can as well remove scalar
+        stmts starting from the SLP tree root if they have no
+        uses.  */
+      if (loop_vinfo)
+       vect_remove_slp_scalar_calls (root);
 
-      for (j = 0; VEC_iterate (gimple, SLP_TREE_SCALAR_STMTS (root), j, store)
+      for (j = 0; SLP_TREE_SCALAR_STMTS (root).iterate (j, &store)
                   && j < SLP_INSTANCE_GROUP_SIZE (instance); j++)
         {
           if (!STMT_VINFO_DATA_REF (vinfo_for_stmt (store)))
@@ -3222,7 +3574,7 @@ vect_slp_transform_bb (basic_block bb)
 
   gcc_assert (bb_vinfo);
 
-  if (dump_kind_p (MSG_NOTE))
+  if (dump_enabled_p ())
     dump_printf_loc (MSG_NOTE, vect_location, "SLPing BB\n");
 
   for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
@@ -3230,11 +3582,12 @@ vect_slp_transform_bb (basic_block bb)
       gimple stmt = gsi_stmt (si);
       stmt_vec_info stmt_info;
 
-      if (dump_kind_p (MSG_NOTE))
+      if (dump_enabled_p ())
         {
           dump_printf_loc (MSG_NOTE, vect_location,
                            "------>SLPing statement: ");
           dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
+          dump_printf (MSG_NOTE, "\n");
         }
 
       stmt_info = vinfo_for_stmt (stmt);
@@ -3248,8 +3601,9 @@ vect_slp_transform_bb (basic_block bb)
         }
     }
 
-  if (dump_kind_p (MSG_OPTIMIZED_LOCATIONS))
-    dump_printf (MSG_OPTIMIZED_LOCATIONS, "BASIC BLOCK VECTORIZED\n");
+  if (dump_enabled_p ())
+    dump_printf_loc (MSG_NOTE, vect_location,
+                    "BASIC BLOCK VECTORIZED\n");
 
   destroy_bb_vec_info (bb_vinfo);
 }