OSDN Git Service

* cse.c: (struct cse_basic_block_data): Remove LAST field.
[pf3gnuchains/gcc-fork.git] / gcc / tree-vect-transform.c
index 19097fd..53380b2 100644 (file)
@@ -46,15 +46,15 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "real.h"
 
 /* Utility functions for the code transformation.  */
-static bool vect_transform_stmt (tree, block_stmt_iterator *);
+static bool vect_transform_stmt (tree, block_stmt_iterator *, bool *);
 static tree vect_create_destination_var (tree, tree);
 static tree vect_create_data_ref_ptr 
-  (tree, block_stmt_iterator *, tree, tree *, tree *, bool); 
+  (tree, block_stmt_iterator *, tree, tree *, tree *, bool, tree); 
 static tree vect_create_addr_base_for_vector_ref (tree, tree *, tree);
 static tree vect_setup_realignment (tree, block_stmt_iterator *, tree *);
 static tree vect_get_new_vect_var (tree, enum vect_var_kind, const char *);
 static tree vect_get_vec_def_for_operand (tree, tree, tree *);
-static tree vect_init_vector (tree, tree);
+static tree vect_init_vector (tree, tree, tree);
 static void vect_finish_stmt_generation 
   (tree stmt, tree vec_stmt, block_stmt_iterator *bsi);
 static bool vect_is_simple_cond (tree, loop_vec_info); 
@@ -70,9 +70,6 @@ static void vect_update_ivs_after_vectorizer (loop_vec_info, tree, edge);
 static tree vect_gen_niters_for_prolog_loop (loop_vec_info, tree);
 static void vect_update_init_of_dr (struct data_reference *, tree niters);
 static void vect_update_inits_of_drs (loop_vec_info, tree);
-static void vect_do_peeling_for_alignment (loop_vec_info, struct loops *);
-static void vect_do_peeling_for_loop_bound 
-  (loop_vec_info, tree *, struct loops *);
 static int vect_min_worthwhile_factor (enum tree_code);
 
 
@@ -140,15 +137,12 @@ vect_create_addr_base_for_vector_ref (tree stmt,
   struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
   tree data_ref_base = unshare_expr (DR_BASE_ADDRESS (dr));
   tree base_name = build_fold_indirect_ref (data_ref_base);
-  tree ref = DR_REF (dr);
-  tree scalar_type = TREE_TYPE (ref);
-  tree scalar_ptr_type = build_pointer_type (scalar_type);
   tree vec_stmt;
-  tree new_temp;
   tree addr_base, addr_expr;
   tree dest, new_stmt;
   tree base_offset = unshare_expr (DR_OFFSET (dr));
   tree init = unshare_expr (DR_INIT (dr));
+  tree vect_ptr_type, addr_expr2;
 
   /* Create base_offset */
   base_offset = size_binop (PLUS_EXPR, base_offset, init);
@@ -160,9 +154,19 @@ vect_create_addr_base_for_vector_ref (tree stmt,
   if (offset)
     {
       tree tmp = create_tmp_var (TREE_TYPE (base_offset), "offset");
+      tree step; 
+
+      /* For interleaved access step we divide STEP by the size of the
+        interleaving group.  */
+      if (DR_GROUP_SIZE (stmt_info))
+       step = fold_build2 (TRUNC_DIV_EXPR, TREE_TYPE (offset), DR_STEP (dr),
+                           build_int_cst (TREE_TYPE (offset),
+                                          DR_GROUP_SIZE (stmt_info)));
+      else
+       step = DR_STEP (dr);
+
       add_referenced_var (tmp);
-      offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset), offset,
-                           DR_STEP (dr));
+      offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset), offset, step);
       base_offset = fold_build2 (PLUS_EXPR, TREE_TYPE (base_offset),
                                 base_offset, offset);
       base_offset = force_gimple_operand (base_offset, &new_stmt, false, tmp);  
@@ -173,21 +177,25 @@ vect_create_addr_base_for_vector_ref (tree stmt,
   addr_base = fold_build2 (PLUS_EXPR, TREE_TYPE (data_ref_base), data_ref_base,
                           base_offset);
 
+  vect_ptr_type = build_pointer_type (STMT_VINFO_VECTYPE (stmt_info));
+
   /* addr_expr = addr_base */
-  addr_expr = vect_get_new_vect_var (scalar_ptr_type, vect_pointer_var,
+  addr_expr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var,
                                      get_name (base_name));
   add_referenced_var (addr_expr);
-  vec_stmt = build2 (MODIFY_EXPR, void_type_node, addr_expr, addr_base);
-  new_temp = make_ssa_name (addr_expr, vec_stmt);
-  TREE_OPERAND (vec_stmt, 0) = new_temp;
-  append_to_statement_list_force (vec_stmt, new_stmt_list);
+  vec_stmt = fold_convert (vect_ptr_type, addr_base);
+  addr_expr2 = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var,
+                                     get_name (base_name));
+  add_referenced_var (addr_expr2);
+  vec_stmt = force_gimple_operand (vec_stmt, &new_stmt, false, addr_expr2);
+  append_to_statement_list_force (new_stmt, new_stmt_list);
 
   if (vect_print_dump_info (REPORT_DETAILS))
     {
       fprintf (vect_dump, "created ");
       print_generic_expr (vect_dump, vec_stmt, TDF_SLIM);
     }
-  return new_temp;
+  return vec_stmt;
 }
 
 
@@ -202,12 +210,14 @@ vect_create_addr_base_for_vector_ref (tree stmt,
 
    Input:
    1. STMT: a stmt that references memory. Expected to be of the form
-         MODIFY_EXPR <name, data-ref> or MODIFY_EXPR <data-ref, name>.
+         GIMPLE_MODIFY_STMT <name, data-ref> or
+        GIMPLE_MODIFY_STMT <data-ref, name>.
    2. BSI: block_stmt_iterator where new stmts can be added.
    3. OFFSET (optional): an offset to be added to the initial address accessed
         by the data-ref in STMT.
    4. ONLY_INIT: indicate if vp is to be updated in the loop, or remain
         pointing to the initial address.
+   5. TYPE: if not NULL indicates the required type of the data-ref
 
    Output:
    1. Declare a new ptr to vector_type, and have it point to the base of the
@@ -235,7 +245,7 @@ static tree
 vect_create_data_ref_ptr (tree stmt,
                          block_stmt_iterator *bsi ATTRIBUTE_UNUSED,
                          tree offset, tree *initial_address, tree *ptr_incr,
-                         bool only_init)
+                         bool only_init, tree type)
 {
   tree base_name;
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
@@ -272,13 +282,14 @@ vect_create_data_ref_ptr (tree stmt,
     }
 
   /** (1) Create the new vector-pointer variable:  **/
-
-  vect_ptr_type = build_pointer_type (vectype);
+  if (type)  
+    vect_ptr_type = build_pointer_type (type);
+  else
+    vect_ptr_type = build_pointer_type (vectype);
   vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var,
                                     get_name (base_name));
   add_referenced_var (vect_ptr);
-  
-  
+
   /** (2) Add aliasing information to the new vector-pointer:
           (The points-to info (DR_PTR_INFO) may be defined later.)  **/
   
@@ -307,9 +318,9 @@ vect_create_data_ref_ptr (tree stmt,
 
   /* Create: p = (vectype *) initial_base  */
   vec_stmt = fold_convert (vect_ptr_type, new_temp);
-  vec_stmt = build2 (MODIFY_EXPR, void_type_node, vect_ptr, vec_stmt);
+  vec_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vect_ptr, vec_stmt);
   vect_ptr_init = make_ssa_name (vect_ptr, vec_stmt);
-  TREE_OPERAND (vec_stmt, 0) = vect_ptr_init;
+  GIMPLE_STMT_OPERAND (vec_stmt, 0) = vect_ptr_init;
   new_bb = bsi_insert_on_edge_immediate (pe, vec_stmt);
   gcc_assert (!new_bb);
 
@@ -358,7 +369,7 @@ vect_create_data_ref_ptr (tree stmt,
 /* Function bump_vector_ptr
 
    Increment a pointer (to a vector type) by vector-size. Connect the new 
-   increment stmt to the exising def-use update-chain of the pointer.
+   increment stmt to the existing def-use update-chain of the pointer.
 
    The pointer def-use update-chain before this function:
                         DATAREF_PTR = phi (p_0, p_2)
@@ -400,10 +411,10 @@ bump_vector_ptr (tree dataref_ptr, tree ptr_incr, block_stmt_iterator *bsi,
   use_operand_p use_p;
   tree new_dataref_ptr;
 
-  incr_stmt = build2 (MODIFY_EXPR, void_type_node, ptr_var,
+  incr_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, ptr_var,
                 build2 (PLUS_EXPR, vptr_type, dataref_ptr, update));
   new_dataref_ptr = make_ssa_name (ptr_var, incr_stmt);
-  TREE_OPERAND (incr_stmt, 0) = new_dataref_ptr;
+  GIMPLE_STMT_OPERAND (incr_stmt, 0) = new_dataref_ptr;
   vect_finish_stmt_generation (stmt, incr_stmt, bsi);
 
   /* Update the vector-pointer's cross-iteration increment.  */
@@ -460,25 +471,24 @@ vect_create_destination_var (tree scalar_dest, tree vectype)
    used in the vectorization of STMT.  */
 
 static tree
-vect_init_vector (tree stmt, tree vector_var)
+vect_init_vector (tree stmt, tree vector_var, tree vector_type)
 {
   stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
   tree new_var;
   tree init_stmt;
-  tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo); 
   tree vec_oprnd;
   edge pe;
   tree new_temp;
   basic_block new_bb;
  
-  new_var = vect_get_new_vect_var (vectype, vect_simple_var, "cst_");
+  new_var = vect_get_new_vect_var (vector_type, vect_simple_var, "cst_");
   add_referenced_var (new_var); 
  
-  init_stmt = build2 (MODIFY_EXPR, vectype, new_var, vector_var);
+  init_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, new_var, vector_var);
   new_temp = make_ssa_name (new_var, init_stmt);
-  TREE_OPERAND (init_stmt, 0) = new_temp;
+  GIMPLE_STMT_OPERAND (init_stmt, 0) = new_temp;
 
   pe = loop_preheader_edge (loop);
   new_bb = bsi_insert_on_edge_immediate (pe, init_stmt);
@@ -490,7 +500,7 @@ vect_init_vector (tree stmt, tree vector_var)
       print_generic_expr (vect_dump, init_stmt, TDF_SLIM);
     }
 
-  vec_oprnd = TREE_OPERAND (init_stmt, 0);
+  vec_oprnd = GIMPLE_STMT_OPERAND (init_stmt, 0);
   return vec_oprnd;
 }
 
@@ -525,6 +535,7 @@ vect_get_vec_def_for_operand (tree op, tree stmt, tree *scalar_def)
   int i;
   enum vect_def_type dt;
   bool is_simple_use;
+  tree vector_type;
 
   if (vect_print_dump_info (REPORT_DETAILS))
     {
@@ -564,8 +575,10 @@ vect_get_vec_def_for_operand (tree op, tree stmt, tree *scalar_def)
           {
             t = tree_cons (NULL_TREE, op, t);
           }
-        vec_cst = build_vector (vectype, t);
-        return vect_init_vector (stmt, vec_cst);
+        vector_type = get_vectype_for_scalar_type (TREE_TYPE (op));
+        vec_cst = build_vector (vector_type, t);
+
+        return vect_init_vector (stmt, vec_cst, vector_type);
       }
 
     /* Case 2: operand is defined outside the loop - loop invariant.  */
@@ -584,8 +597,9 @@ vect_get_vec_def_for_operand (tree op, tree stmt, tree *scalar_def)
           }
 
        /* FIXME: use build_constructor directly.  */
-        vec_inv = build_constructor_from_list (vectype, t);
-        return vect_init_vector (stmt, vec_inv);
+       vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
+        vec_inv = build_constructor_from_list (vector_type, t);
+        return vect_init_vector (stmt, vec_inv, vector_type);
       }
 
     /* Case 3: operand is defined inside the loop.  */
@@ -598,7 +612,7 @@ vect_get_vec_def_for_operand (tree op, tree stmt, tree *scalar_def)
         def_stmt_info = vinfo_for_stmt (def_stmt);
         vec_stmt = STMT_VINFO_VEC_STMT (def_stmt_info);
         gcc_assert (vec_stmt);
-        vec_oprnd = TREE_OPERAND (vec_stmt, 0);
+        vec_oprnd = GIMPLE_STMT_OPERAND (vec_stmt, 0);
         return vec_oprnd;
       }
 
@@ -645,7 +659,7 @@ vect_get_vec_def_for_operand (tree op, tree stmt, tree *scalar_def)
    stmts operating on wider types we need to create 'VF/nunits' "copies" of the
    vector stmt (each computing a vector of 'nunits' results, and together
    computing 'VF' results in each iteration).  This function is called when 
-   vectorizing such a stmt (e.g. vectorizing S2 in the illusration below, in 
+   vectorizing such a stmt (e.g. vectorizing S2 in the illustration below, in
    which VF=16 and nuniti=4, so the number of copies required is 4):
 
    scalar stmt:         vectorized into:        STMT_VINFO_RELATED_STMT
@@ -699,7 +713,7 @@ vect_get_vec_def_for_stmt_copy (enum vect_def_type dt, tree vec_oprnd)
   gcc_assert (def_stmt_info);
   vec_stmt_for_operand = STMT_VINFO_RELATED_STMT (def_stmt_info);
   gcc_assert (vec_stmt_for_operand);
-  vec_oprnd = TREE_OPERAND (vec_stmt_for_operand, 0);
+  vec_oprnd = GIMPLE_STMT_OPERAND (vec_stmt_for_operand, 0);
 
   return vec_oprnd;
 }
@@ -789,12 +803,13 @@ get_initial_def_for_reduction (tree stmt, tree init_val, tree *scalar_def)
   tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
   int nunits = GET_MODE_NUNITS (TYPE_MODE (vectype));
   int nelements;
-  enum tree_code code = TREE_CODE (TREE_OPERAND (stmt, 1));
+  enum tree_code code = TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1));
   tree type = TREE_TYPE (init_val);
   tree def;
   tree vec, t = NULL_TREE;
   bool need_epilog_adjust;
   int i;
+  tree vector_type;
 
   gcc_assert (INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type));
 
@@ -842,18 +857,19 @@ get_initial_def_for_reduction (tree stmt, tree init_val, tree *scalar_def)
       nelements += 1;
     }
   gcc_assert (nelements == nunits);
-  
+
+  vector_type = get_vectype_for_scalar_type (TREE_TYPE (def));
   if (TREE_CODE (init_val) == INTEGER_CST || TREE_CODE (init_val) == REAL_CST)
-    vec = build_vector (vectype, t);
+    vec = build_vector (vector_type, t);
   else
-    vec = build_constructor_from_list (vectype, t);
+    vec = build_constructor_from_list (vector_type, t);
     
   if (!need_epilog_adjust)
     *scalar_def = NULL_TREE;
   else
     *scalar_def = init_val;
 
-  return vect_init_vector (stmt, vec);
+  return vect_init_vector (stmt, vec, vector_type);
 }
 
 
@@ -925,7 +941,7 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
   tree epilog_stmt;
   tree new_scalar_dest, exit_phi;
   tree bitsize, bitpos, bytesize; 
-  enum tree_code code = TREE_CODE (TREE_OPERAND (stmt, 1));
+  enum tree_code code = TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1));
   tree scalar_initial_def;
   tree vec_initial_def;
   tree orig_name;
@@ -935,7 +951,7 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
   tree reduction_op;
   tree orig_stmt;
   tree use_stmt;
-  tree operation = TREE_OPERAND (stmt, 1);
+  tree operation = GIMPLE_STMT_OPERAND (stmt, 1);
   int op_type;
   
   op_type = TREE_CODE_LENGTH (TREE_CODE (operation));
@@ -995,9 +1011,9 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
   /* 2.1 Create new loop-exit-phi to preserve loop-closed form:
         v_out1 = phi <v_loop>  */
 
-  exit_bb = loop->single_exit->dest;
+  exit_bb = single_exit (loop)->dest;
   new_phi = create_phi_node (SSA_NAME_VAR (vect_def), exit_bb);
-  SET_PHI_ARG_DEF (new_phi, loop->single_exit->dest_idx, vect_def);
+  SET_PHI_ARG_DEF (new_phi, single_exit (loop)->dest_idx, vect_def);
   exit_bsi = bsi_start (exit_bb);
 
   /* 2.2 Get the relevant tree-code to use in the epilog for schemes 2,3 
@@ -1022,8 +1038,8 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
       gcc_assert (STMT_VINFO_IN_PATTERN_P (stmt_vinfo));
       gcc_assert (STMT_VINFO_RELATED_STMT (stmt_vinfo) == stmt);
     }
-  code = TREE_CODE (TREE_OPERAND (orig_stmt, 1));
-  scalar_dest = TREE_OPERAND (orig_stmt, 0);
+  code = TREE_CODE (GIMPLE_STMT_OPERAND (orig_stmt, 1));
+  scalar_dest = GIMPLE_STMT_OPERAND (orig_stmt, 0);
   scalar_type = TREE_TYPE (scalar_dest);
   new_scalar_dest = vect_create_destination_var (scalar_dest, NULL);
   bitsize = TYPE_SIZE (scalar_type);
@@ -1041,10 +1057,10 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
        fprintf (vect_dump, "Reduce using direct vector reduction.");
 
       vec_dest = vect_create_destination_var (scalar_dest, vectype);
-      epilog_stmt = build2 (MODIFY_EXPR, vectype, vec_dest,
+      epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
                        build1 (reduc_code, vectype,  PHI_RESULT (new_phi)));
       new_temp = make_ssa_name (vec_dest, epilog_stmt);
-      TREE_OPERAND (epilog_stmt, 0) = new_temp;
+      GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_temp;
       bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
 
       extract_scalar_result = true;
@@ -1099,16 +1115,20 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
            {
              tree bitpos = size_int (bit_offset);
 
-             epilog_stmt = build2 (MODIFY_EXPR, vectype, vec_dest,
-             build2 (shift_code, vectype, new_temp, bitpos));
+             epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                                   vec_dest,
+                                   build2 (shift_code, vectype,
+                                           new_temp, bitpos));
              new_name = make_ssa_name (vec_dest, epilog_stmt);
-             TREE_OPERAND (epilog_stmt, 0) = new_name;
+             GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_name;
              bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
 
-             epilog_stmt = build2 (MODIFY_EXPR, vectype, vec_dest,
-             build2 (code, vectype, new_name, new_temp));
+             epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                                   vec_dest,
+                                   build2 (code, vectype,
+                                           new_name, new_temp));
              new_temp = make_ssa_name (vec_dest, epilog_stmt);
-             TREE_OPERAND (epilog_stmt, 0) = new_temp;
+             GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_temp;
              bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
            }
 
@@ -1136,9 +1156,10 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
          rhs = build3 (BIT_FIELD_REF, scalar_type, vec_temp, bitsize,
                         bitsize_zero_node);
          BIT_FIELD_REF_UNSIGNED (rhs) = TYPE_UNSIGNED (scalar_type);
-         epilog_stmt = build2 (MODIFY_EXPR, scalar_type, new_scalar_dest, rhs);
+         epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                               new_scalar_dest, rhs);
          new_temp = make_ssa_name (new_scalar_dest, epilog_stmt);
-         TREE_OPERAND (epilog_stmt, 0) = new_temp;
+         GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_temp;
          bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
              
          for (bit_offset = element_bitsize;
@@ -1150,16 +1171,17 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
                                 bitpos);
                
              BIT_FIELD_REF_UNSIGNED (rhs) = TYPE_UNSIGNED (scalar_type);
-             epilog_stmt = build2 (MODIFY_EXPR, scalar_type, new_scalar_dest,
-                                   rhs);       
+             epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                                   new_scalar_dest, rhs);      
              new_name = make_ssa_name (new_scalar_dest, epilog_stmt);
-             TREE_OPERAND (epilog_stmt, 0) = new_name;
+             GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_name;
              bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
 
-             epilog_stmt = build2 (MODIFY_EXPR, scalar_type, new_scalar_dest,
+             epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                               new_scalar_dest,
                                build2 (code, scalar_type, new_name, new_temp));
              new_temp = make_ssa_name (new_scalar_dest, epilog_stmt);
-             TREE_OPERAND (epilog_stmt, 0) = new_temp;
+             GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_temp;
              bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
            }
 
@@ -1186,9 +1208,10 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
 
       rhs = build3 (BIT_FIELD_REF, scalar_type, new_temp, bitsize, bitpos);
       BIT_FIELD_REF_UNSIGNED (rhs) = TYPE_UNSIGNED (scalar_type);
-      epilog_stmt = build2 (MODIFY_EXPR, scalar_type, new_scalar_dest, rhs);
+      epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                           new_scalar_dest, rhs);
       new_temp = make_ssa_name (new_scalar_dest, epilog_stmt);
-      TREE_OPERAND (epilog_stmt, 0) = new_temp; 
+      GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_temp; 
       bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
     }
 
@@ -1201,10 +1224,11 @@ vect_create_epilog_for_reduction (tree vect_def, tree stmt,
   
   if (scalar_initial_def)
     {
-      epilog_stmt = build2 (MODIFY_EXPR, scalar_type, new_scalar_dest,
+      epilog_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                     new_scalar_dest,
                       build2 (code, scalar_type, new_temp, scalar_initial_def));
       new_temp = make_ssa_name (new_scalar_dest, epilog_stmt);
-      TREE_OPERAND (epilog_stmt, 0) = new_temp;
+      GIMPLE_STMT_OPERAND (epilog_stmt, 0) = new_temp;
       bsi_insert_after (&exit_bsi, epilog_stmt, BSI_NEW_STMT);
     }
 
@@ -1340,14 +1364,14 @@ vectorizable_reduction (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
         inside the loop body. The last operand is the reduction variable,
         which is defined by the loop-header-phi.  */
 
-  gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR);
+  gcc_assert (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
 
-  operation = TREE_OPERAND (stmt, 1);
+  operation = GIMPLE_STMT_OPERAND (stmt, 1);
   code = TREE_CODE (operation);
   op_type = TREE_CODE_LENGTH (code);
   if (op_type != binary_op && op_type != ternary_op)
     return false;
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   scalar_type = TREE_TYPE (scalar_dest);
 
   /* All uses but the last are expected to be defined in the loop.
@@ -1445,7 +1469,7 @@ vectorizable_reduction (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
     {
       /* This is a reduction pattern: get the vectype from the type of the
          reduction variable, and get the tree-code from orig_stmt.  */
-      orig_code = TREE_CODE (TREE_OPERAND (orig_stmt, 1));
+      orig_code = TREE_CODE (GIMPLE_STMT_OPERAND (orig_stmt, 1));
       vectype = get_vectype_for_scalar_type (TREE_TYPE (def));
       vec_mode = TYPE_MODE (vectype);
     }
@@ -1521,7 +1545,7 @@ vectorizable_reduction (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
                                                                                 
           /* Get the vector def for the reduction variable from the vectorized
              reduction operation generated in the previous iteration (j-1)  */
-          reduc_def = TREE_OPERAND (new_stmt ,0);
+          reduc_def = GIMPLE_STMT_OPERAND (new_stmt ,0);
         }
                                                                                 
       /* Arguments are ready. create the new vector stmt.  */
@@ -1531,9 +1555,9 @@ vectorizable_reduction (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
       else
         expr = build3 (code, vectype, loop_vec_def0, loop_vec_def1, 
                                                                reduc_def);
-      new_stmt = build2 (MODIFY_EXPR, void_type_node, vec_dest, expr);
+      new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest, expr);
       new_temp = make_ssa_name (vec_dest, new_stmt);
-      TREE_OPERAND (new_stmt, 0) = new_temp;
+      GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
       vect_finish_stmt_generation (stmt, new_stmt, bsi);
                                                                                 
       if (j == 0)
@@ -1549,6 +1573,152 @@ vectorizable_reduction (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   return true;
 }
 
+/* Checks if CALL can be vectorized in type VECTYPE.  Returns
+   true if the target has a vectorized version of the function,
+   or false if the function cannot be vectorized.  */
+
+bool
+vectorizable_function (tree call, tree vectype)
+{
+  tree fndecl = get_callee_fndecl (call);
+
+  /* We only handle functions that do not read or clobber memory -- i.e.
+     const or novops ones.  */
+  if (!(call_expr_flags (call) & (ECF_CONST | ECF_NOVOPS)))
+    return false;
+
+  if (!fndecl
+      || TREE_CODE (fndecl) != FUNCTION_DECL
+      || !DECL_BUILT_IN (fndecl))
+    return false;
+
+  if (targetm.vectorize.builtin_vectorized_function (DECL_FUNCTION_CODE (fndecl), vectype))
+    return true;
+
+  return false;
+}
+
+/* Returns an expression that performs a call to vectorized version
+   of FNDECL in type VECTYPE, with the arguments given by ARGS.
+   If extra statements need to be generated, they are inserted
+   before BSI.  */
+
+static tree
+build_vectorized_function_call (tree fndecl,
+                               tree vectype, tree args)
+{
+  tree vfndecl;
+  enum built_in_function code = DECL_FUNCTION_CODE (fndecl);
+
+  /* The target specific builtin should be available.  */
+  vfndecl = targetm.vectorize.builtin_vectorized_function (code, vectype);
+  gcc_assert (vfndecl != NULL_TREE);
+
+  return build_function_call_expr (vfndecl, args);
+}
+
+/* Function vectorizable_call.
+
+   Check if STMT performs a function call that can be vectorized. 
+   If VEC_STMT is also passed, vectorize the STMT: create a vectorized 
+   stmt to replace it, put it in VEC_STMT, and insert it at BSI.
+   Return FALSE if not a vectorizable STMT, TRUE otherwise.  */
+
+bool
+vectorizable_call (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
+{
+  tree vec_dest;
+  tree scalar_dest;
+  tree operation;
+  tree op, args, type;
+  tree vec_oprnd, vargs, *pvargs_end;
+  stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+  tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+  loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
+  tree fndecl, rhs, new_temp, def, def_stmt;
+  enum vect_def_type dt;
+
+  /* Is STMT a vectorizable call?   */
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
+    return false;
+
+  if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) != SSA_NAME)
+    return false;
+
+  operation = GIMPLE_STMT_OPERAND (stmt, 1);
+  if (TREE_CODE (operation) != CALL_EXPR)
+    return false;
+   
+  /* For now, we only vectorize functions if a target specific builtin
+     is available.  TODO -- in some cases, it might be profitable to
+     insert the calls for pieces of the vector, in order to be able
+     to vectorize other operations in the loop.  */
+  if (!vectorizable_function (operation, vectype))
+    {
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump, "function is not vectorizable.");
+
+      return false;
+    }
+  gcc_assert (!stmt_references_memory_p (stmt));
+
+  for (args = TREE_OPERAND (operation, 1); args; args = TREE_CHAIN (args))
+    {
+      op = TREE_VALUE (args);
+
+      if (!vect_is_simple_use (op, loop_vinfo, &def_stmt, &def, &dt))
+       {
+         if (vect_print_dump_info (REPORT_DETAILS))
+           fprintf (vect_dump, "use not simple.");
+         return false;
+       }
+    }
+
+  if (!vec_stmt) /* transformation not required.  */
+    {
+      STMT_VINFO_TYPE (stmt_info) = call_vec_info_type;
+      return true;
+    }
+
+  /** Transform.  **/
+
+  if (vect_print_dump_info (REPORT_DETAILS))
+    fprintf (vect_dump, "transform operation.");
+
+  /* Handle def.  */
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
+  vec_dest = vect_create_destination_var (scalar_dest, vectype);
+
+  /* Handle uses.  */
+  vargs = NULL_TREE;
+  pvargs_end = &vargs;
+  for (args = TREE_OPERAND (operation, 1); args; args = TREE_CHAIN (args))
+    {
+      op = TREE_VALUE (args);
+      vec_oprnd = vect_get_vec_def_for_operand (op, stmt, NULL);
+         
+      *pvargs_end = tree_cons (NULL_TREE, vec_oprnd, NULL_TREE);
+      pvargs_end = &TREE_CHAIN (*pvargs_end);
+    }
+
+  fndecl = get_callee_fndecl (operation);
+  rhs = build_vectorized_function_call (fndecl, vectype, vargs);
+  *vec_stmt = build2 (GIMPLE_MODIFY_STMT, vectype, vec_dest, rhs);
+  new_temp = make_ssa_name (vec_dest, *vec_stmt);
+  GIMPLE_STMT_OPERAND (*vec_stmt, 0) = new_temp;
+
+  vect_finish_stmt_generation (stmt, *vec_stmt, bsi);
+
+  /* The call in STMT might prevent it from being removed in dce.  We however
+     cannot remove it here, due to the way the ssa name it defines is mapped
+     to the new definition.  So just replace rhs of the statement with something
+     harmless.  */
+  type = TREE_TYPE (scalar_dest);
+  GIMPLE_STMT_OPERAND (stmt, 1) = fold_convert (type, integer_zero_node);
+
+  return true;
+}
+
 
 /* Function vectorizable_assignment.
 
@@ -1583,14 +1753,14 @@ vectorizable_assignment (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
 
   gcc_assert (STMT_VINFO_DEF_TYPE (stmt_info) == vect_loop_def);
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
 
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   if (TREE_CODE (scalar_dest) != SSA_NAME)
     return false;
 
-  op = TREE_OPERAND (stmt, 1);
+  op = GIMPLE_STMT_OPERAND (stmt, 1);
   if (!vect_is_simple_use (op, loop_vinfo, &def_stmt, &def, &dt))
     {
       if (vect_print_dump_info (REPORT_DETAILS))
@@ -1612,13 +1782,13 @@ vectorizable_assignment (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   vec_dest = vect_create_destination_var (scalar_dest, vectype);
 
   /* Handle use.  */
-  op = TREE_OPERAND (stmt, 1);
+  op = GIMPLE_STMT_OPERAND (stmt, 1);
   vec_oprnd = vect_get_vec_def_for_operand (op, stmt, NULL);
 
   /* Arguments are ready. create the new vector stmt.  */
-  *vec_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, vec_oprnd);
+  *vec_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest, vec_oprnd);
   new_temp = make_ssa_name (vec_dest, *vec_stmt);
-  TREE_OPERAND (*vec_stmt, 0) = new_temp;
+  GIMPLE_STMT_OPERAND (*vec_stmt, 0) = new_temp;
   vect_finish_stmt_generation (stmt, *vec_stmt, bsi);
   
   return true;
@@ -1703,19 +1873,19 @@ vectorizable_operation (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
       return false;
     }
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
 
-  if (TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
+  if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) != SSA_NAME)
     return false;
 
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   vectype_out = get_vectype_for_scalar_type (TREE_TYPE (scalar_dest));
   nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
   if (nunits_out != nunits_in)
     return false;
 
-  operation = TREE_OPERAND (stmt, 1);
+  operation = GIMPLE_STMT_OPERAND (stmt, 1);
   code = TREE_CODE (operation);
   optab = optab_for_tree_code (code, vectype);
 
@@ -1901,13 +2071,13 @@ vectorizable_operation (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
       /* Arguments are ready. create the new vector stmt.  */
                                                                                 
       if (op_type == binary_op)
-        new_stmt = build2 (MODIFY_EXPR, void_type_node, vec_dest,
+        new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
                     build2 (code, vectype, vec_oprnd0, vec_oprnd1));
       else
-        new_stmt = build2 (MODIFY_EXPR, void_type_node, vec_dest,
+        new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
                     build1 (code, vectype, vec_oprnd0));
       new_temp = make_ssa_name (vec_dest, new_stmt);
-      TREE_OPERAND (new_stmt, 0) = new_temp;
+      GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
       vect_finish_stmt_generation (stmt, new_stmt, bsi);
                                                                                 
       if (j == 0)
@@ -1972,13 +2142,13 @@ vectorizable_type_demotion (tree stmt, block_stmt_iterator *bsi,
       return false;
     }
                                                                                 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
                                                                                 
-  if (TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
+  if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) != SSA_NAME)
     return false;
                                                                                 
-  operation = TREE_OPERAND (stmt, 1);
+  operation = GIMPLE_STMT_OPERAND (stmt, 1);
   code = TREE_CODE (operation);
   if (code != NOP_EXPR && code != CONVERT_EXPR)
     return false;
@@ -1987,7 +2157,7 @@ vectorizable_type_demotion (tree stmt, block_stmt_iterator *bsi,
   vectype_in = get_vectype_for_scalar_type (TREE_TYPE (op0));
   nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
                                                                                 
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   scalar_type = TREE_TYPE (scalar_dest);
   vectype_out = get_vectype_for_scalar_type (scalar_type);
   nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
@@ -2054,9 +2224,9 @@ vectorizable_type_demotion (tree stmt, block_stmt_iterator *bsi,
                                                                                 
       /* Arguments are ready. Create the new vector stmt.  */
       expr = build2 (code, vectype_out, vec_oprnd0, vec_oprnd1);
-      new_stmt = build2 (MODIFY_EXPR, void_type_node, vec_dest, expr);
+      new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest, expr);
       new_temp = make_ssa_name (vec_dest, new_stmt);
-      TREE_OPERAND (new_stmt, 0) = new_temp;
+      GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
       vect_finish_stmt_generation (stmt, new_stmt, bsi);
                                                                                 
       if (j == 0)
@@ -2112,9 +2282,9 @@ vect_gen_widened_results_half (enum tree_code code, tree vectype, tree decl,
       else  
         expr = build1 (code, vectype, vec_oprnd0); 
     } 
-  new_stmt = build2 (MODIFY_EXPR, void_type_node, vec_dest, expr); 
+  new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest, expr);
   new_temp = make_ssa_name (vec_dest, new_stmt); 
-  TREE_OPERAND (new_stmt, 0) = new_temp; 
+  GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp; 
   vect_finish_stmt_generation (stmt, new_stmt, bsi); 
 
   if (code == CALL_EXPR)
@@ -2179,13 +2349,13 @@ vectorizable_type_promotion (tree stmt, block_stmt_iterator *bsi,
       return false;
     }
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
 
-  if (TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
+  if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) != SSA_NAME)
     return false;
 
-  operation = TREE_OPERAND (stmt, 1);
+  operation = GIMPLE_STMT_OPERAND (stmt, 1);
   code = TREE_CODE (operation);
   if (code != NOP_EXPR && code != WIDEN_MULT_EXPR)
     return false;
@@ -2196,7 +2366,7 @@ vectorizable_type_promotion (tree stmt, block_stmt_iterator *bsi,
   ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits_in;
   gcc_assert (ncopies >= 1);
 
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   vectype_out = get_vectype_for_scalar_type (TREE_TYPE (scalar_dest));
   nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
   if (nunits_out != nunits_in / 2) /* FORNOW */
@@ -2292,6 +2462,164 @@ vectorizable_type_promotion (tree stmt, block_stmt_iterator *bsi,
 }
 
 
+/* Function vect_strided_store_supported.
+
+   Returns TRUE is INTERLEAVE_HIGH and INTERLEAVE_LOW operations are supported,
+   and FALSE otherwise.  */
+
+static bool
+vect_strided_store_supported (tree vectype)
+{
+  optab interleave_high_optab, interleave_low_optab;
+  int mode;
+
+  mode = (int) TYPE_MODE (vectype);
+      
+  /* Check that the operation is supported.  */
+  interleave_high_optab = optab_for_tree_code (VEC_INTERLEAVE_HIGH_EXPR, 
+                                              vectype);
+  interleave_low_optab = optab_for_tree_code (VEC_INTERLEAVE_LOW_EXPR, 
+                                             vectype);
+  if (!interleave_high_optab || !interleave_low_optab)
+    {
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump, "no optab for interleave.");
+      return false;
+    }
+
+  if (interleave_high_optab->handlers[(int) mode].insn_code 
+      == CODE_FOR_nothing
+      || interleave_low_optab->handlers[(int) mode].insn_code 
+      == CODE_FOR_nothing)
+    {
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump, "interleave op not supported by target.");
+      return false;
+    }
+  return true;
+}
+
+
+/* Function vect_permute_store_chain.
+
+   Given a chain of interleaved stores in DR_CHAIN of LENGTH that must be
+   a power of 2, generate interleave_high/low stmts to reorder the data 
+   correctly for the stores. Return the final references for stores in
+   RESULT_CHAIN.
+
+   E.g., LENGTH is 4 and the scalar type is short, i.e., VF is 8.
+   The input is 4 vectors each containing 8 elements. We assign a number to each
+   element, the input sequence is:
+
+   1st vec:   0  1  2  3  4  5  6  7
+   2nd vec:   8  9 10 11 12 13 14 15
+   3rd vec:  16 17 18 19 20 21 22 23 
+   4th vec:  24 25 26 27 28 29 30 31
+
+   The output sequence should be:
+
+   1st vec:  0  8 16 24  1  9 17 25
+   2nd vec:  2 10 18 26  3 11 19 27
+   3rd vec:  4 12 20 28  5 13 21 30
+   4th vec:  6 14 22 30  7 15 23 31
+
+   i.e., we interleave the contents of the four vectors in their order.
+
+   We use interleave_high/low instructions to create such output. The input of 
+   each interleave_high/low operation is two vectors:
+   1st vec    2nd vec 
+   0 1 2 3    4 5 6 7 
+   the even elements of the result vector are obtained left-to-right from the 
+   high/low elements of the first vector. The odd elements of the result are 
+   obtained left-to-right from the high/low elements of the second vector.
+   The output of interleave_high will be:   0 4 1 5
+   and of interleave_low:                   2 6 3 7
+
+   
+   The permutation is done in log LENGTH stages. In each stage interleave_high
+   and interleave_low stmts are created for each pair of vectors in DR_CHAIN, 
+   where the first argument is taken from the first half of DR_CHAIN and the 
+   second argument from it's second half. 
+   In our example, 
+
+   I1: interleave_high (1st vec, 3rd vec)
+   I2: interleave_low (1st vec, 3rd vec)
+   I3: interleave_high (2nd vec, 4th vec)
+   I4: interleave_low (2nd vec, 4th vec)
+
+   The output for the first stage is:
+
+   I1:  0 16  1 17  2 18  3 19
+   I2:  4 20  5 21  6 22  7 23
+   I3:  8 24  9 25 10 26 11 27
+   I4: 12 28 13 29 14 30 15 31
+
+   The output of the second stage, i.e. the final result is:
+
+   I1:  0  8 16 24  1  9 17 25
+   I2:  2 10 18 26  3 11 19 27
+   I3:  4 12 20 28  5 13 21 30
+   I4:  6 14 22 30  7 15 23 31.  */
+static bool
+vect_permute_store_chain (VEC(tree,heap) *dr_chain, 
+                         unsigned int length, 
+                         tree stmt, 
+                         block_stmt_iterator *bsi,
+                         VEC(tree,heap) **result_chain)
+{
+  tree perm_dest, perm_stmt, vect1, vect2, high, low;
+  tree vectype = STMT_VINFO_VECTYPE (vinfo_for_stmt (stmt));
+  tree scalar_dest;
+  int i;
+  unsigned int j;
+  VEC(tree,heap) *first, *second;
+  
+  scalar_dest = TREE_OPERAND (stmt, 0);
+  first = VEC_alloc (tree, heap, length/2);
+  second = VEC_alloc (tree, heap, length/2);
+
+  /* Check that the operation is supported.  */
+  if (!vect_strided_store_supported (vectype))
+    return false;
+
+  *result_chain = VEC_copy (tree, heap, dr_chain);
+
+  for (i = 0; i < exact_log2 (length); i++)
+    {
+      for (j = 0; j < length/2; j++)
+       {
+         vect1 = VEC_index (tree, dr_chain, j);
+         vect2 = VEC_index (tree, dr_chain, j+length/2);
+
+         /* high = interleave_high (vect1, vect2);  */
+         perm_dest = create_tmp_var (vectype, "vect_inter_high");
+         add_referenced_var (perm_dest);
+         perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, perm_dest,
+                             build2 (VEC_INTERLEAVE_HIGH_EXPR, vectype, vect1, 
+                                     vect2));
+         high = make_ssa_name (perm_dest, perm_stmt);
+         GIMPLE_STMT_OPERAND (perm_stmt, 0) = high;
+         vect_finish_stmt_generation (stmt, perm_stmt, bsi);
+         VEC_replace (tree, *result_chain, 2*j, high);
+
+         /* low = interleave_low (vect1, vect2);  */
+         perm_dest = create_tmp_var (vectype, "vect_inter_low");
+         add_referenced_var (perm_dest);
+         perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, perm_dest,
+                             build2 (VEC_INTERLEAVE_LOW_EXPR, vectype, vect1, 
+                                     vect2));
+         low = make_ssa_name (perm_dest, perm_stmt);
+         GIMPLE_STMT_OPERAND (perm_stmt, 0) = low;
+         vect_finish_stmt_generation (stmt, perm_stmt, bsi);
+         VEC_replace (tree, *result_chain, 2*j+1, low);
+       }
+      dr_chain = VEC_copy (tree, heap, *result_chain);
+    }
+  return true;
+}
+
+
 /* Function vectorizable_store.
 
    Check if STMT defines a non scalar data-ref (array/pointer/structure) that 
@@ -2308,7 +2636,7 @@ vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   tree op;
   tree vec_oprnd = NULL_TREE;
   stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
-  struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
+  struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info), *first_dr = NULL;
   tree vectype = STMT_VINFO_VECTYPE (stmt_info);
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
   enum machine_mode vec_mode;
@@ -2318,25 +2646,29 @@ vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   def_operand_p def_p;
   tree def, def_stmt;
   enum vect_def_type dt;
-  stmt_vec_info prev_stmt_info;
+  stmt_vec_info prev_stmt_info = NULL;
   tree dataref_ptr = NULL_TREE;
   int nunits = TYPE_VECTOR_SUBPARTS (vectype);
   int ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits;
   int j;
-
+  tree next_stmt, first_stmt;
+  bool strided_store = false;
+  unsigned int group_size, i;
+  VEC(tree,heap) *dr_chain = NULL, *oprnds = NULL, *result_chain = NULL;
   gcc_assert (ncopies >= 1);
 
   /* Is vectorizable store? */
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
 
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   if (TREE_CODE (scalar_dest) != ARRAY_REF
-      && TREE_CODE (scalar_dest) != INDIRECT_REF)
+      && TREE_CODE (scalar_dest) != INDIRECT_REF
+      && !DR_GROUP_FIRST_DR (stmt_info))
     return false;
 
-  op = TREE_OPERAND (stmt, 1);
+  op = GIMPLE_STMT_OPERAND (stmt, 1);
   if (!vect_is_simple_use (op, loop_vinfo, &def_stmt, &def, &dt))
     {
       if (vect_print_dump_info (REPORT_DETAILS))
@@ -2353,6 +2685,12 @@ vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   if (!STMT_VINFO_DATA_REF (stmt_info))
     return false;
 
+  if (DR_GROUP_FIRST_DR (stmt_info))
+    {
+      strided_store = true;
+      if (!vect_strided_store_supported (vectype))
+       return false;      
+    }
 
   if (!vec_stmt) /* transformation not required.  */
     {
@@ -2365,7 +2703,34 @@ vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   if (vect_print_dump_info (REPORT_DETAILS))
     fprintf (vect_dump, "transform store. ncopies = %d",ncopies);
 
-  alignment_support_cheme = vect_supportable_dr_alignment (dr);
+  if (strided_store)
+    {
+      first_stmt = DR_GROUP_FIRST_DR (stmt_info);
+      first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt));
+      group_size = DR_GROUP_SIZE (vinfo_for_stmt (first_stmt));
+
+      DR_GROUP_STORE_COUNT (vinfo_for_stmt (first_stmt))++;
+
+      /* We vectorize all the stmts of the interleaving group when we
+        reach the last stmt in the group.  */
+      if (DR_GROUP_STORE_COUNT (vinfo_for_stmt (first_stmt)) 
+         < DR_GROUP_SIZE (vinfo_for_stmt (first_stmt)))
+       {
+         *vec_stmt = NULL_TREE;
+         return true;
+       }
+    }
+  else 
+    {
+      first_stmt = stmt;
+      first_dr = dr;
+      group_size = 1;
+    }
+  
+  dr_chain = VEC_alloc (tree, heap, group_size);
+  oprnds = VEC_alloc (tree, heap, group_size);
+
+  alignment_support_cheme = vect_supportable_dr_alignment (first_dr);
   gcc_assert (alignment_support_cheme);
   gcc_assert (alignment_support_cheme == dr_aligned);  /* FORNOW */
 
@@ -2375,6 +2740,39 @@ vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
      vector stmt by a factor VF/nunits.  For more details see documentation in 
      vect_get_vec_def_for_copy_stmt.  */
 
+  /* In case of interleaving (non-unit strided access):
+
+        S1:  &base + 2 = x2
+        S2:  &base = x0
+        S3:  &base + 1 = x1
+        S4:  &base + 3 = x3
+
+     We create vectorized storess starting from base address (the access of the
+     first stmt in the chain (S2 in the above example), when the last store stmt
+     of the chain (S4) is reached:
+
+        VS1: &base = vx2
+       VS2: &base + vec_size*1 = vx0
+       VS3: &base + vec_size*2 = vx1
+       VS4: &base + vec_size*3 = vx3
+
+     Then permutation statements are generated:
+
+        VS5: vx5 = VEC_INTERLEAVE_HIGH_EXPR < vx0, vx3 >
+        VS6: vx6 = VEC_INTERLEAVE_LOW_EXPR < vx0, vx3 >
+       ...
+       
+     And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
+     (the order of the data-refs in the output of vect_permute_store_chain
+     corresponds to the order of scalar stmts in the interleaving chain - see
+     the documentation of vect_permute_store_chain()).
+
+     In case of both multiple types and interleaving, above vector stores and
+     permutation stmts are created for every copy. The result vector stmts are
+     put in STMT_VINFO_VEC_STMT for the first copy and in the corresponding
+     STMT_VINFO_RELATED_STMT for the next copies.     
+  */
+
   prev_stmt_info = NULL;
   for (j = 0; j < ncopies; j++)
     {
@@ -2383,52 +2781,113 @@ vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
 
       if (j == 0)
        {
-         vec_oprnd = vect_get_vec_def_for_operand (op, stmt, NULL);
-         dataref_ptr = vect_create_data_ref_ptr (stmt, bsi, NULL_TREE, &dummy, 
-                                                 &ptr_incr, false);
+         /* For interleaved stores we collect vectorized defs for all the 
+            stores in the group in DR_CHAIN and OPRNDS. DR_CHAIN is then used
+            as an input to vect_permute_store_chain(), and OPRNDS as an input
+            to vect_get_vec_def_for_stmt_copy() for the next copy.
+            If the store is not strided, GROUP_SIZE is 1, and DR_CHAIN and
+            OPRNDS are of size 1.
+         */
+         next_stmt = first_stmt;         
+         for (i = 0; i < group_size; i++)
+           {
+             /* Since gaps are not supported for interleaved stores, GROUP_SIZE
+                is the exact number of stmts in the chain. Therefore, NEXT_STMT
+                can't be NULL_TREE.  In case that there is no interleaving, 
+                GROUP_SIZE is 1, and only one iteration of the loop will be 
+                executed.
+             */
+             gcc_assert (next_stmt);
+             op = GIMPLE_STMT_OPERAND (next_stmt, 1);
+             vec_oprnd = vect_get_vec_def_for_operand (op, next_stmt, NULL);
+             VEC_quick_push(tree, dr_chain, vec_oprnd); 
+             VEC_quick_push(tree, oprnds, vec_oprnd); 
+             next_stmt = DR_GROUP_NEXT_DR (vinfo_for_stmt (next_stmt));
+           }
+         dataref_ptr = vect_create_data_ref_ptr (first_stmt, bsi, NULL_TREE, 
+                                                 &dummy, &ptr_incr, false,
+                                                 TREE_TYPE (vec_oprnd));
        }
       else 
        {
-         vec_oprnd = vect_get_vec_def_for_stmt_copy (dt, vec_oprnd);
+         /* For interleaved stores we created vectorized defs for all the 
+            defs stored in OPRNDS in the previous iteration (previous copy). 
+            DR_CHAIN is then used as an input to vect_permute_store_chain(), 
+            and OPRNDS as an input to vect_get_vec_def_for_stmt_copy() for the 
+            next copy.
+            If the store is not strided, GROUP_SIZE is 1, and DR_CHAIN and
+            OPRNDS are of size 1.
+         */
+         for (i = 0; i < group_size; i++)
+           {
+             vec_oprnd = vect_get_vec_def_for_stmt_copy (dt, 
+                                                  VEC_index (tree, oprnds, i));
+             VEC_replace(tree, dr_chain, i, vec_oprnd);
+             VEC_replace(tree, oprnds, i, vec_oprnd);
+           }
          dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, bsi, stmt);
        }
 
-      /* Arguments are ready. create the new vector stmt.  */
-      data_ref = build_fold_indirect_ref (dataref_ptr);
-      new_stmt = build2 (MODIFY_EXPR, vectype, data_ref, vec_oprnd);
-      vect_finish_stmt_generation (stmt, new_stmt, bsi);
+      if (strided_store)
+       {
+         result_chain = VEC_alloc (tree, heap, group_size);     
+         /* Permute.  */
+         if (!vect_permute_store_chain (dr_chain, group_size, stmt, bsi, 
+                                        &result_chain))
+           return false;
+       }
 
-     /* Set the V_MAY_DEFS for the vector pointer. If this virtual def has a 
-       use outside the loop and a loop peel is performed then the def may be 
-       renamed by the peel.  Mark it for renaming so the later use will also 
-       be renamed.  */
-      copy_virtual_operands (new_stmt, stmt);
-      if (j == 0)
+      next_stmt = first_stmt;
+      for (i = 0; i < group_size; i++)
        {
-         /* The original store is deleted so the same SSA_NAMEs can be used.  
-          */
-         FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_VMAYDEF)
+         /* For strided stores vectorized defs are interleaved in 
+            vect_permute_store_chain().  */
+         if (strided_store)
+           vec_oprnd = VEC_index(tree, result_chain, i);
+
+         data_ref = build_fold_indirect_ref (dataref_ptr);
+         /* Arguments are ready. Create the new vector stmt.  */
+         new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, data_ref, 
+                            vec_oprnd);
+         vect_finish_stmt_generation (stmt, new_stmt, bsi);
+
+         /* Set the V_MAY_DEFS for the vector pointer. If this virtual def has a 
+            use outside the loop and a loop peel is performed then the def may be 
+            renamed by the peel.  Mark it for renaming so the later use will also 
+            be renamed.  */
+         copy_virtual_operands (new_stmt, next_stmt);
+         if (j == 0)
            {
-             SSA_NAME_DEF_STMT (def) = new_stmt;
-             mark_sym_for_renaming (SSA_NAME_VAR (def));
+             /* The original store is deleted so the same SSA_NAMEs can be used.  
+              */
+             FOR_EACH_SSA_TREE_OPERAND (def, next_stmt, iter, SSA_OP_VMAYDEF)
+               {
+                 SSA_NAME_DEF_STMT (def) = new_stmt;
+                 mark_sym_for_renaming (SSA_NAME_VAR (def));
+               }
+             
+             STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt =  new_stmt;
            }
-
-         STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt =  new_stmt;
-       }
-      else
-       {
-         /* Create new names for all the definitions created by COPY and
-            add replacement mappings for each new name.  */
-          FOR_EACH_SSA_DEF_OPERAND (def_p, new_stmt, iter, SSA_OP_VMAYDEF)
+         else
            {
-             create_new_def_for (DEF_FROM_PTR (def_p), new_stmt, def_p);
-             mark_sym_for_renaming (SSA_NAME_VAR (DEF_FROM_PTR (def_p)));
+             /* Create new names for all the definitions created by COPY and
+                add replacement mappings for each new name.  */
+             FOR_EACH_SSA_DEF_OPERAND (def_p, new_stmt, iter, SSA_OP_VMAYDEF)
+               {
+                 create_new_def_for (DEF_FROM_PTR (def_p), new_stmt, def_p);
+                 mark_sym_for_renaming (SSA_NAME_VAR (DEF_FROM_PTR (def_p)));
+               }
+             
+             STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
            }
 
-         STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
+         prev_stmt_info = vinfo_for_stmt (new_stmt);
+                 next_stmt = DR_GROUP_NEXT_DR (vinfo_for_stmt (next_stmt));
+         if (!next_stmt)
+           break;
+         /* Bump the vector pointer.  */
+         dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, bsi, stmt);
        }
-
-      prev_stmt_info = vinfo_for_stmt (new_stmt);
     }
 
   return true;
@@ -2471,8 +2930,7 @@ vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
    Output:
    REALIGNMENT_TOKEN - the result of a call to the builtin_mask_for_load
                        target hook, if defined.
-   Return value - the result of the loop-header phi node.
-*/
+   Return value - the result of the loop-header phi node.  */
 
 static tree
 vect_setup_realignment (tree stmt, block_stmt_iterator *bsi,
@@ -2498,14 +2956,15 @@ vect_setup_realignment (tree stmt, block_stmt_iterator *bsi,
 
   /* 1. Create msq_init = *(floor(p1)) in the loop preheader  */
   vec_dest = vect_create_destination_var (scalar_dest, vectype);
-  ptr = vect_create_data_ref_ptr (stmt, bsi, NULL_TREE, &init_addr, &inc, true);
+  ptr = vect_create_data_ref_ptr (stmt, bsi, NULL_TREE, &init_addr, &inc, true,
+                                 NULL_TREE);
   data_ref = build1 (ALIGN_INDIRECT_REF, vectype, ptr);
-  new_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, data_ref);
+  new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest, data_ref);
   new_temp = make_ssa_name (vec_dest, new_stmt);
-  TREE_OPERAND (new_stmt, 0) = new_temp;
+  GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
   new_bb = bsi_insert_on_edge_immediate (pe, new_stmt);
   gcc_assert (!new_bb);
-  msq_init = TREE_OPERAND (new_stmt, 0);
+  msq_init = GIMPLE_STMT_OPERAND (new_stmt, 0);
   copy_virtual_operands (new_stmt, stmt);
   update_vuses_to_preheader (new_stmt, loop);
 
@@ -2515,16 +2974,17 @@ vect_setup_realignment (tree stmt, block_stmt_iterator *bsi,
       tree builtin_decl;
       tree params = build_tree_list (NULL_TREE, init_addr);
 
-      vec_dest = vect_create_destination_var (scalar_dest, 
-                                                       TREE_TYPE (new_stmt));
       builtin_decl = targetm.vectorize.builtin_mask_for_load ();
       new_stmt = build_function_call_expr (builtin_decl, params);
-      new_stmt = build2 (MODIFY_EXPR, void_type_node, vec_dest, new_stmt);
+      vec_dest = vect_create_destination_var (scalar_dest, 
+                                             TREE_TYPE (new_stmt));
+      new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
+                        new_stmt);
       new_temp = make_ssa_name (vec_dest, new_stmt);
-      TREE_OPERAND (new_stmt, 0) = new_temp;
+      GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
       new_bb = bsi_insert_on_edge_immediate (pe, new_stmt);
       gcc_assert (!new_bb);
-      *realignment_token = TREE_OPERAND (new_stmt, 0);
+      *realignment_token = GIMPLE_STMT_OPERAND (new_stmt, 0);
 
       /* The result of the CALL_EXPR to this builtin is determined from
          the value of the parameter and no global variables are touched
@@ -2545,6 +3005,268 @@ vect_setup_realignment (tree stmt, block_stmt_iterator *bsi,
 }
 
 
+/* Function vect_strided_load_supported.
+
+   Returns TRUE is EXTRACT_EVEN and EXTRACT_ODD operations are supported,
+   and FALSE otherwise.  */
+
+static bool
+vect_strided_load_supported (tree vectype)
+{
+  optab perm_even_optab, perm_odd_optab;
+  int mode;
+
+  mode = (int) TYPE_MODE (vectype);
+
+  perm_even_optab = optab_for_tree_code (VEC_EXTRACT_EVEN_EXPR, vectype);
+  if (!perm_even_optab)
+    {
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump, "no optab for perm_even.");
+      return false;
+    }
+
+  if (perm_even_optab->handlers[mode].insn_code == CODE_FOR_nothing)
+    {
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump, "perm_even op not supported by target.");
+      return false;
+    }
+
+  perm_odd_optab = optab_for_tree_code (VEC_EXTRACT_ODD_EXPR, vectype);
+  if (!perm_odd_optab)
+    {
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump, "no optab for perm_odd.");
+      return false;
+    }
+
+  if (perm_odd_optab->handlers[mode].insn_code == CODE_FOR_nothing)
+    {
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump, "perm_odd op not supported by target.");
+      return false;
+    }
+  return true;
+}
+
+
+/* Function vect_permute_load_chain.
+
+   Given a chain of interleaved loads in DR_CHAIN of LENGTH that must be
+   a power of 2, generate extract_even/odd stmts to reorder the input data 
+   correctly. Return the final references for loads in RESULT_CHAIN.
+
+   E.g., LENGTH is 4 and the scalar type is short, i.e., VF is 8.
+   The input is 4 vectors each containing 8 elements. We assign a number to each
+   element, the input sequence is:
+
+   1st vec:   0  1  2  3  4  5  6  7
+   2nd vec:   8  9 10 11 12 13 14 15
+   3rd vec:  16 17 18 19 20 21 22 23 
+   4th vec:  24 25 26 27 28 29 30 31
+
+   The output sequence should be:
+
+   1st vec:  0 4  8 12 16 20 24 28
+   2nd vec:  1 5  9 13 17 21 25 29
+   3rd vec:  2 6 10 14 18 22 26 30 
+   4th vec:  3 7 11 15 19 23 27 31
+
+   i.e., the first output vector should contain the first elements of each
+   interleaving group, etc.
+
+   We use extract_even/odd instructions to create such output. The input of each
+   extract_even/odd operation is two vectors
+   1st vec    2nd vec 
+   0 1 2 3    4 5 6 7 
+
+   and the output is the vector of extracted even/odd elements. The output of 
+   extract_even will be:   0 2 4 6
+   and of extract_odd:     1 3 5 7
+
+   
+   The permutation is done in log LENGTH stages. In each stage extract_even and
+   extract_odd stmts are created for each pair of vectors in DR_CHAIN in their 
+   order. In our example, 
+
+   E1: extract_even (1st vec, 2nd vec)
+   E2: extract_odd (1st vec, 2nd vec)
+   E3: extract_even (3rd vec, 4th vec)
+   E4: extract_odd (3rd vec, 4th vec)
+
+   The output for the first stage will be:
+
+   E1:  0  2  4  6  8 10 12 14
+   E2:  1  3  5  7  9 11 13 15
+   E3: 16 18 20 22 24 26 28 30 
+   E4: 17 19 21 23 25 27 29 31
+
+   In order to proceed and create the correct sequence for the next stage (or
+   for the correct output, if the second stage is the last one, as in our 
+   example), we first put the output of extract_even operation and then the 
+   output of extract_odd in RESULT_CHAIN (which is then copied to DR_CHAIN).
+   The input for the second stage is:
+
+   1st vec (E1):  0  2  4  6  8 10 12 14
+   2nd vec (E3): 16 18 20 22 24 26 28 30  
+   3rd vec (E2):  1  3  5  7  9 11 13 15    
+   4th vec (E4): 17 19 21 23 25 27 29 31
+
+   The output of the second stage:
+
+   E1: 0 4  8 12 16 20 24 28
+   E2: 2 6 10 14 18 22 26 30
+   E3: 1 5  9 13 17 21 25 29
+   E4: 3 7 11 15 19 23 27 31
+
+   And RESULT_CHAIN after reordering:
+
+   1st vec (E1):  0 4  8 12 16 20 24 28
+   2nd vec (E3):  1 5  9 13 17 21 25 29
+   3rd vec (E2):  2 6 10 14 18 22 26 30 
+   4th vec (E4):  3 7 11 15 19 23 27 31.  */
+
+static bool
+vect_permute_load_chain (VEC(tree,heap) *dr_chain, 
+                        unsigned int length, 
+                        tree stmt, 
+                        block_stmt_iterator *bsi,
+                        VEC(tree,heap) **result_chain)
+{
+  tree perm_dest, perm_stmt, data_ref, first_vect, second_vect;
+  tree vectype = STMT_VINFO_VECTYPE (vinfo_for_stmt (stmt));
+  int i;
+  unsigned int j;
+
+  /* Check that the operation is supported.  */
+  if (!vect_strided_load_supported (vectype))
+    return false;
+
+  *result_chain = VEC_copy (tree, heap, dr_chain);
+  for (i = 0; i < exact_log2 (length); i++)
+    {
+      for (j = 0; j < length; j +=2)
+       {
+         first_vect = VEC_index (tree, dr_chain, j);
+         second_vect = VEC_index (tree, dr_chain, j+1);
+
+         /* data_ref = permute_even (first_data_ref, second_data_ref);  */
+         perm_dest = create_tmp_var (vectype, "vect_perm_even");
+         add_referenced_var (perm_dest);
+        
+         perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, perm_dest,
+                             build2 (VEC_EXTRACT_EVEN_EXPR, vectype, 
+                                     first_vect, second_vect));
+
+         data_ref = make_ssa_name (perm_dest, perm_stmt);
+         GIMPLE_STMT_OPERAND (perm_stmt, 0) = data_ref;
+         vect_finish_stmt_generation (stmt, perm_stmt, bsi);
+         mark_new_vars_to_rename (perm_stmt);
+
+         VEC_replace (tree, *result_chain, j/2, data_ref);           
+             
+         /* data_ref = permute_odd (first_data_ref, second_data_ref);  */
+         perm_dest = create_tmp_var (vectype, "vect_perm_odd");
+         add_referenced_var (perm_dest);
+
+         perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, perm_dest,
+                             build2 (VEC_EXTRACT_ODD_EXPR, vectype, 
+                                     first_vect, second_vect));
+         data_ref = make_ssa_name (perm_dest, perm_stmt);
+         GIMPLE_STMT_OPERAND (perm_stmt, 0) = data_ref;
+         vect_finish_stmt_generation (stmt, perm_stmt, bsi);
+         mark_new_vars_to_rename (perm_stmt);
+
+         VEC_replace (tree, *result_chain, j/2+length/2, data_ref);
+       }
+      dr_chain = VEC_copy (tree, heap, *result_chain);
+    }
+  return true;
+}
+
+
+/* Function vect_transform_strided_load.
+
+   Given a chain of input interleaved data-refs (in DR_CHAIN), build statements
+   to perform their permutation and ascribe the result vectorized statements to
+   the scalar statements.
+*/
+
+static bool
+vect_transform_strided_load (tree stmt, VEC(tree,heap) *dr_chain, int size,
+                            block_stmt_iterator *bsi)
+{
+  stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+  tree first_stmt = DR_GROUP_FIRST_DR (stmt_info);
+  tree next_stmt, new_stmt;
+  VEC(tree,heap) *result_chain = NULL;
+  unsigned int i, gap_count;
+  tree tmp_data_ref;
+
+  /* DR_CHAIN contains input data-refs that are a part of the interleaving. 
+     RESULT_CHAIN is the output of vect_permute_load_chain, it contains permuted 
+     vectors, that are ready for vector computation.  */
+  result_chain = VEC_alloc (tree, heap, size);
+  /* Permute.  */
+  if (!vect_permute_load_chain (dr_chain, size, stmt, bsi, &result_chain))
+    return false;
+
+  /* Put a permuted data-ref in the VECTORIZED_STMT field.  
+     Since we scan the chain starting from it's first node, their order 
+     corresponds the order of data-refs in RESULT_CHAIN.  */
+  next_stmt = first_stmt;
+  gap_count = 1;
+  for (i = 0; VEC_iterate(tree, result_chain, i, tmp_data_ref); i++)
+    {
+      if (!next_stmt)
+       break;
+
+      /* Skip the gaps. Loads created for the gaps will be removed by dead
+       code elimination pass later.
+       DR_GROUP_GAP is the number of steps in elements from the previous
+       access (if there is no gap DR_GROUP_GAP is 1). We skip loads that
+       correspond to the gaps.
+      */
+      if (gap_count < DR_GROUP_GAP (vinfo_for_stmt (next_stmt)))
+      {
+        gap_count++;
+        continue;
+      }
+
+      while (next_stmt)
+        {
+         new_stmt = SSA_NAME_DEF_STMT (tmp_data_ref);
+         /* We assume that if VEC_STMT is not NULL, this is a case of multiple
+            copies, and we put the new vector statement in the first available
+            RELATED_STMT.  */
+         if (!STMT_VINFO_VEC_STMT (vinfo_for_stmt (next_stmt)))
+           STMT_VINFO_VEC_STMT (vinfo_for_stmt (next_stmt)) = new_stmt;
+         else
+            {
+             tree prev_stmt = STMT_VINFO_VEC_STMT (vinfo_for_stmt (next_stmt));
+             tree rel_stmt = STMT_VINFO_RELATED_STMT (
+                                                      vinfo_for_stmt (prev_stmt));
+             while (rel_stmt)
+               {
+                 prev_stmt = rel_stmt;
+                 rel_stmt = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (rel_stmt));
+               }
+             STMT_VINFO_RELATED_STMT (vinfo_for_stmt (prev_stmt)) = new_stmt;
+            }
+         next_stmt = DR_GROUP_NEXT_DR (vinfo_for_stmt (next_stmt));
+         gap_count = 1;
+         /* If NEXT_STMT accesses the same DR as the previous statement,
+            put the same TMP_DATA_REF as its vectorized statement; otherwise
+            get the next data-ref from RESULT_CHAIN.  */
+         if (!next_stmt || !DR_GROUP_SAME_DR_STMT (vinfo_for_stmt (next_stmt)))
+           break;
+        }
+    }
+  return true;
+}
+
+
 /* vectorizable_load.
 
    Check if STMT reads a non scalar data-ref (array/pointer/structure) that 
@@ -2564,22 +3286,25 @@ vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   stmt_vec_info prev_stmt_info; 
   loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
-  struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
+  struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info), *first_dr;
   tree vectype = STMT_VINFO_VECTYPE (stmt_info);
   tree new_temp;
   int mode;
-  tree new_stmt;
+  tree new_stmt = NULL_TREE;
   tree dummy;
   enum dr_alignment_support alignment_support_cheme;
   tree dataref_ptr = NULL_TREE;
   tree ptr_incr;
   int nunits = TYPE_VECTOR_SUBPARTS (vectype);
   int ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits;
-  int j;
+  int i, j, group_size;
   tree msq = NULL_TREE, lsq;
   tree offset = NULL_TREE;
   tree realignment_token = NULL_TREE;
   tree phi_stmt = NULL_TREE;
+  VEC(tree,heap) *dr_chain = NULL;
+  bool strided_load = false;
+  tree first_stmt;
 
   /* Is vectorizable load? */
   if (!STMT_VINFO_RELEVANT_P (stmt_info))
@@ -2595,15 +3320,17 @@ vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
       return false;
     }
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
 
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   if (TREE_CODE (scalar_dest) != SSA_NAME)
     return false;
 
-  op = TREE_OPERAND (stmt, 1);
-  if (TREE_CODE (op) != ARRAY_REF && TREE_CODE (op) != INDIRECT_REF)
+  op = GIMPLE_STMT_OPERAND (stmt, 1);
+  if (TREE_CODE (op) != ARRAY_REF 
+      && TREE_CODE (op) != INDIRECT_REF
+      && !DR_GROUP_FIRST_DR (stmt_info))
     return false;
 
   if (!STMT_VINFO_DATA_REF (stmt_info))
@@ -2620,6 +3347,16 @@ vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
       return false;
     }
 
+  /* Check if the load is a part of an interleaving chain.  */
+  if (DR_GROUP_FIRST_DR (stmt_info))
+    {
+      strided_load = true;
+
+      /* Check if interleaving is supported.  */
+      if (!vect_strided_load_supported (vectype))
+       return false;
+    }
+
   if (!vec_stmt) /* transformation not required.  */
     {
       STMT_VINFO_TYPE (stmt_info) = load_vec_info_type;
@@ -2631,9 +3368,30 @@ vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   if (vect_print_dump_info (REPORT_DETAILS))
     fprintf (vect_dump, "transform load.");
 
-  alignment_support_cheme = vect_supportable_dr_alignment (dr);
+  if (strided_load)
+    {
+      first_stmt = DR_GROUP_FIRST_DR (stmt_info);
+      /* Check if the chain of loads is already vectorized.  */
+      if (STMT_VINFO_VEC_STMT (vinfo_for_stmt (first_stmt)))
+       {
+         *vec_stmt = STMT_VINFO_VEC_STMT (stmt_info);
+         return true;
+       }
+      first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt));
+      group_size = DR_GROUP_SIZE (vinfo_for_stmt (first_stmt));
+      dr_chain = VEC_alloc (tree, heap, group_size);
+    }
+  else
+    {
+      first_stmt = stmt;
+      first_dr = dr;
+      group_size = 1;
+    }
+
+  alignment_support_cheme = vect_supportable_dr_alignment (first_dr);
   gcc_assert (alignment_support_cheme);
 
+
   /* In case the vectorization factor (VF) is bigger than the number
      of elements that we can fit in a vectype (nunits), we have to generate
      more than one vector stmt - i.e - we need to "unroll" the
@@ -2669,6 +3427,39 @@ vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
      information we recorded in RELATED_STMT field is used to vectorize 
      stmt S2.  */
 
+  /* In case of interleaving (non-unit strided access):
+
+     S1:  x2 = &base + 2
+     S2:  x0 = &base
+     S3:  x1 = &base + 1
+     S4:  x3 = &base + 3
+
+     Vectorized loads are created in the order of memory accesses 
+     starting from the access of the first stmt of the chain:
+
+     VS1: vx0 = &base
+     VS2: vx1 = &base + vec_size*1
+     VS3: vx3 = &base + vec_size*2
+     VS4: vx4 = &base + vec_size*3
+
+     Then permutation statements are generated:
+
+     VS5: vx5 = VEC_EXTRACT_EVEN_EXPR < vx0, vx1 >
+     VS6: vx6 = VEC_EXTRACT_ODD_EXPR < vx0, vx1 >
+       ...
+
+     And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
+     (the order of the data-refs in the output of vect_permute_load_chain
+     corresponds to the order of scalar stmts in the interleaving chain - see
+     the documentation of vect_permute_load_chain()).
+     The generation of permutation stmts and recording them in
+     STMT_VINFO_VEC_STMT is done in vect_transform_strided_load().
+
+     In case of both multiple types and interleaving, the vector loads and 
+     permutation stmts above are created for every copy. The result vector stmts
+     are put in STMT_VINFO_VEC_STMT for the first copy and in the corresponding
+     STMT_VINFO_RELATED_STMT for the next copies.  */
+
   /* If the data reference is aligned (dr_aligned) or potentially unaligned
      on a target that supports unaligned accesses (dr_unaligned_supported)
      we generate the following code:
@@ -2696,12 +3487,11 @@ vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
            vec_dest = realign_load (msq, lsq, realignment_token)
            indx = indx + 1;
            msq = lsq;
-         }
-  */
+         }   */
 
   if (alignment_support_cheme == dr_unaligned_software_pipeline)
     {
-      msq = vect_setup_realignment (stmt, bsi, &realignment_token);
+      msq = vect_setup_realignment (first_stmt, bsi, &realignment_token);
       phi_stmt = SSA_NAME_DEF_STMT (msq);
       offset = size_int (TYPE_VECTOR_SUBPARTS (vectype) - 1);
     }
@@ -2711,69 +3501,88 @@ vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
     { 
       /* 1. Create the vector pointer update chain.  */
       if (j == 0)
-        dataref_ptr = vect_create_data_ref_ptr (stmt, bsi, offset,
-                                                &dummy, &ptr_incr, false);
+        dataref_ptr = vect_create_data_ref_ptr (first_stmt, bsi, offset, &dummy,
+                                                &ptr_incr, false, NULL_TREE);
       else
         dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, bsi, stmt);
 
-      /* 2. Create the vector-load in the loop.  */
-      switch (alignment_support_cheme)
-      {
-      case dr_aligned:
-        gcc_assert (aligned_access_p (dr));
-        data_ref = build_fold_indirect_ref (dataref_ptr);
-        break;
-      case dr_unaligned_supported:
-        {
-          int mis = DR_MISALIGNMENT (dr);
-          tree tmis = (mis == -1 ? size_zero_node : size_int (mis));
-
-          gcc_assert (!aligned_access_p (dr));
-          tmis = size_binop (MULT_EXPR, tmis, size_int(BITS_PER_UNIT));
-          data_ref =
-                build2 (MISALIGNED_INDIRECT_REF, vectype, dataref_ptr, tmis);
-          break;
-        }
-      case dr_unaligned_software_pipeline:
-        gcc_assert (!aligned_access_p (dr));
-        data_ref = build1 (ALIGN_INDIRECT_REF, vectype, dataref_ptr);
-        break;
-      default:
-        gcc_unreachable ();
-      }
-      vec_dest = vect_create_destination_var (scalar_dest, vectype);
-      new_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, data_ref);
-      new_temp = make_ssa_name (vec_dest, new_stmt);
-      TREE_OPERAND (new_stmt, 0) = new_temp;
-      vect_finish_stmt_generation (stmt, new_stmt, bsi);
-      copy_virtual_operands (new_stmt, stmt);
-      mark_new_vars_to_rename (new_stmt);
-
-      /* 3. Handle explicit realignment if necessary/supported.  */
-      if (alignment_support_cheme == dr_unaligned_software_pipeline)
-        {
-          /* Create in loop: 
-             <vec_dest = realign_load (msq, lsq, realignment_token)>  */
-          lsq = TREE_OPERAND (new_stmt, 0);
-          if (!realignment_token)
-            realignment_token = dataref_ptr;
-          vec_dest = vect_create_destination_var (scalar_dest, vectype);
-          new_stmt =
-            build3 (REALIGN_LOAD_EXPR, vectype, msq, lsq, realignment_token);
-          new_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, new_stmt);
-          new_temp = make_ssa_name (vec_dest, new_stmt);
-          TREE_OPERAND (new_stmt, 0) = new_temp;
-          vect_finish_stmt_generation (stmt, new_stmt, bsi);
-          if (j == ncopies - 1)
-            add_phi_arg (phi_stmt, lsq, loop_latch_edge (loop));
-          msq = lsq;
-        }
+      for (i = 0; i < group_size; i++)
+       {
+         /* 2. Create the vector-load in the loop.  */
+         switch (alignment_support_cheme)
+           {
+           case dr_aligned:
+             gcc_assert (aligned_access_p (first_dr));
+             data_ref = build_fold_indirect_ref (dataref_ptr);
+             break;
+           case dr_unaligned_supported:
+             {
+               int mis = DR_MISALIGNMENT (first_dr);
+               tree tmis = (mis == -1 ? size_zero_node : size_int (mis));
+
+               gcc_assert (!aligned_access_p (first_dr));
+               tmis = size_binop (MULT_EXPR, tmis, size_int(BITS_PER_UNIT));
+               data_ref =
+                 build2 (MISALIGNED_INDIRECT_REF, vectype, dataref_ptr, tmis);
+               break;
+             }
+           case dr_unaligned_software_pipeline:
+             gcc_assert (!aligned_access_p (first_dr));
+             data_ref = build1 (ALIGN_INDIRECT_REF, vectype, dataref_ptr);
+             break;
+           default:
+             gcc_unreachable ();
+           }
+         vec_dest = vect_create_destination_var (scalar_dest, vectype);
+         new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
+                            data_ref);
+         new_temp = make_ssa_name (vec_dest, new_stmt);
+         GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
+         vect_finish_stmt_generation (stmt, new_stmt, bsi);
+         copy_virtual_operands (new_stmt, stmt);
+         mark_new_vars_to_rename (new_stmt);
+
+         /* 3. Handle explicit realignment if necessary/supported.  */
+         if (alignment_support_cheme == dr_unaligned_software_pipeline)
+           {
+             /* Create in loop: 
+                <vec_dest = realign_load (msq, lsq, realignment_token)>  */
+             lsq = GIMPLE_STMT_OPERAND (new_stmt, 0);
+             if (!realignment_token)
+               realignment_token = dataref_ptr;
+             vec_dest = vect_create_destination_var (scalar_dest, vectype);
+             new_stmt =
+               build3 (REALIGN_LOAD_EXPR, vectype, msq, lsq, realignment_token);
+             new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
+                                new_stmt);
+             new_temp = make_ssa_name (vec_dest, new_stmt);
+             GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
+             vect_finish_stmt_generation (stmt, new_stmt, bsi);
+             if (i == group_size - 1 && j == ncopies - 1)
+               add_phi_arg (phi_stmt, lsq, loop_latch_edge (loop));
+             msq = lsq;
+           }
+         if (strided_load)
+           VEC_quick_push (tree, dr_chain, new_temp);
+         if (i < group_size - 1)
+           dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, bsi, stmt);     
+       }
 
-      if (j == 0)
-        STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
+      if (strided_load)
+       {
+         if (!vect_transform_strided_load (stmt, dr_chain, group_size, bsi))
+           return false;         
+         *vec_stmt = STMT_VINFO_VEC_STMT (stmt_info);
+         dr_chain = VEC_alloc (tree, heap, group_size);
+       }
       else
-        STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
-      prev_stmt_info = vinfo_for_stmt (new_stmt);
+       {
+         if (j == 0)
+           STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
+         else
+           STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
+         prev_stmt_info = vinfo_for_stmt (new_stmt);
+       }
     }
 
   return true;
@@ -2803,13 +3612,13 @@ vectorizable_live_operation (tree stmt,
   if (!STMT_VINFO_LIVE_P (stmt_info))
     return false;
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
 
-  if (TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
+  if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) != SSA_NAME)
     return false;
 
-  operation = TREE_OPERAND (stmt, 1);
+  operation = GIMPLE_STMT_OPERAND (stmt, 1);
   code = TREE_CODE (operation);
 
   op_type = TREE_CODE_LENGTH (code);
@@ -2925,10 +3734,10 @@ vectorizable_condition (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
       return false;
     }
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
     return false;
 
-  op = TREE_OPERAND (stmt, 1);
+  op = GIMPLE_STMT_OPERAND (stmt, 1);
 
   if (TREE_CODE (op) != COND_EXPR)
     return false;
@@ -2979,7 +3788,7 @@ vectorizable_condition (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   /* Transform */
 
   /* Handle def.  */
-  scalar_dest = TREE_OPERAND (stmt, 0);
+  scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
   vec_dest = vect_create_destination_var (scalar_dest, vectype);
 
   /* Handle cond expr.  */
@@ -2996,9 +3805,10 @@ vectorizable_condition (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
   vec_cond_expr = build3 (VEC_COND_EXPR, vectype, 
                          vec_compare, vec_then_clause, vec_else_clause);
 
-  *vec_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, vec_cond_expr);
+  *vec_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
+                     vec_cond_expr);
   new_temp = make_ssa_name (vec_dest, *vec_stmt);
-  TREE_OPERAND (*vec_stmt, 0) = new_temp;
+  GIMPLE_STMT_OPERAND (*vec_stmt, 0) = new_temp;
   vect_finish_stmt_generation (stmt, *vec_stmt, bsi);
   
   return true;
@@ -3009,7 +3819,7 @@ vectorizable_condition (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt)
    Create a vectorized stmt to replace STMT, and insert it at BSI.  */
 
 bool
-vect_transform_stmt (tree stmt, block_stmt_iterator *bsi)
+vect_transform_stmt (tree stmt, block_stmt_iterator *bsi, bool *strided_store)
 {
   bool is_store = false;
   tree vec_stmt = NULL_TREE;
@@ -3049,7 +3859,18 @@ vect_transform_stmt (tree stmt, block_stmt_iterator *bsi)
       case store_vec_info_type:
        done = vectorizable_store (stmt, bsi, &vec_stmt);
        gcc_assert (done);
-       is_store = true;
+       if (DR_GROUP_FIRST_DR (stmt_info))
+         {
+           /* In case of interleaving, the whole chain is vectorized when the
+              last store in the chain is reached. Store stmts before the last
+              one are skipped, and there vec_stmt_info shouldn't be freed
+              meanwhile.  */
+           *strided_store = true;
+           if (STMT_VINFO_VEC_STMT (stmt_info))
+             is_store = true;
+         }
+       else
+         is_store = true;
        break;
 
       case condition_vec_info_type:
@@ -3057,31 +3878,39 @@ vect_transform_stmt (tree stmt, block_stmt_iterator *bsi)
        gcc_assert (done);
        break;
 
+      case call_vec_info_type:
+       done = vectorizable_call (stmt, bsi, &vec_stmt);
+       break;
+
       default:
        if (vect_print_dump_info (REPORT_DETAILS))
          fprintf (vect_dump, "stmt not supported.");
        gcc_unreachable ();
       }
 
-      gcc_assert (vec_stmt);
-      STMT_VINFO_VEC_STMT (stmt_info) = vec_stmt;
-      orig_stmt_in_pattern = STMT_VINFO_RELATED_STMT (stmt_info);
-      if (orig_stmt_in_pattern)
-        {
-          stmt_vec_info stmt_vinfo = vinfo_for_stmt (orig_stmt_in_pattern);
-          if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
-            {
-              gcc_assert (STMT_VINFO_RELATED_STMT (stmt_vinfo) == stmt);
-
-              /* STMT was inserted by the vectorizer to replace a computation 
-                 idiom.  ORIG_STMT_IN_PATTERN is a stmt in the original
-                 sequence that computed this idiom.  We need to record a pointer
-                 to VEC_STMT in the stmt_info of ORIG_STMT_IN_PATTERN.  See more
-                 detail in the documentation of vect_pattern_recog.  */
-
-              STMT_VINFO_VEC_STMT (stmt_vinfo) = vec_stmt;
-            }
-        }
+      gcc_assert (vec_stmt || *strided_store);
+      if (vec_stmt)
+       {
+         STMT_VINFO_VEC_STMT (stmt_info) = vec_stmt;
+         orig_stmt_in_pattern = STMT_VINFO_RELATED_STMT (stmt_info);
+         if (orig_stmt_in_pattern)
+           {
+             stmt_vec_info stmt_vinfo = vinfo_for_stmt (orig_stmt_in_pattern);
+             if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
+               {
+                 gcc_assert (STMT_VINFO_RELATED_STMT (stmt_vinfo) == stmt);
+                 
+                 /* STMT was inserted by the vectorizer to replace a 
+                    computation idiom.  ORIG_STMT_IN_PATTERN is a stmt in the 
+                    original sequence that computed this idiom.  We need to 
+                    record a pointer to VEC_STMT in the stmt_info of 
+                    ORIG_STMT_IN_PATTERN.  See more details in the 
+                    documentation of vect_pattern_recog.  */
+
+                 STMT_VINFO_VEC_STMT (stmt_vinfo) = vec_stmt;
+               }
+           }
+       }
     }
 
   if (STMT_VINFO_LIVE_P (stmt_info))
@@ -3165,29 +3994,33 @@ vect_generate_tmps_on_preheader (loop_vec_info loop_vinfo,
 
   /* Create: ratio = ni >> log2(vf) */
 
-  var = create_tmp_var (TREE_TYPE (ni), "bnd");
-  add_referenced_var (var);
-  ratio_name = make_ssa_name (var, NULL_TREE);
-  stmt = build2 (MODIFY_EXPR, void_type_node, ratio_name,
-          build2 (RSHIFT_EXPR, TREE_TYPE (ni_name), ni_name, log_vf));
-  SSA_NAME_DEF_STMT (ratio_name) = stmt;
+  ratio_name = fold_build2 (RSHIFT_EXPR, TREE_TYPE (ni_name), ni_name, log_vf);
+  if (!is_gimple_val (ratio_name))
+    {
+      var = create_tmp_var (TREE_TYPE (ni), "bnd");
+      add_referenced_var (var);
 
-  pe = loop_preheader_edge (loop);
-  new_bb = bsi_insert_on_edge_immediate (pe, stmt);
-  gcc_assert (!new_bb);
+      ratio_name = force_gimple_operand (ratio_name, &stmt, true, var);
+      pe = loop_preheader_edge (loop);
+      new_bb = bsi_insert_on_edge_immediate (pe, stmt);
+      gcc_assert (!new_bb);
+    }
        
   /* Create: ratio_mult_vf = ratio << log2 (vf).  */
 
-  var = create_tmp_var (TREE_TYPE (ni), "ratio_mult_vf");
-  add_referenced_var (var);
-  ratio_mult_vf_name = make_ssa_name (var, NULL_TREE);
-  stmt = build2 (MODIFY_EXPR, void_type_node, ratio_mult_vf_name,
-          build2 (LSHIFT_EXPR, TREE_TYPE (ratio_name), ratio_name, log_vf));
-  SSA_NAME_DEF_STMT (ratio_mult_vf_name) = stmt;
+  ratio_mult_vf_name = fold_build2 (LSHIFT_EXPR, TREE_TYPE (ratio_name),
+                                   ratio_name, log_vf);
+  if (!is_gimple_val (ratio_mult_vf_name))
+    {
+      var = create_tmp_var (TREE_TYPE (ni), "ratio_mult_vf");
+      add_referenced_var (var);
 
-  pe = loop_preheader_edge (loop);
-  new_bb = bsi_insert_on_edge_immediate (pe, stmt);
-  gcc_assert (!new_bb);
+      ratio_mult_vf_name = force_gimple_operand (ratio_mult_vf_name, &stmt,
+                                                true, var);
+      pe = loop_preheader_edge (loop);
+      new_bb = bsi_insert_on_edge_immediate (pe, stmt);
+      gcc_assert (!new_bb);
+    }
 
   *ni_name_ptr = ni_name;
   *ratio_mult_vf_name_ptr = ratio_mult_vf_name;
@@ -3319,7 +4152,7 @@ vect_update_ivs_after_vectorizer (loop_vec_info loop_vinfo, tree niters,
                                  edge update_e)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
-  basic_block exit_bb = loop->single_exit->dest;
+  basic_block exit_bb = single_exit (loop)->dest;
   tree phi, phi1;
   basic_block update_bb = update_e->dest;
 
@@ -3375,9 +4208,12 @@ vect_update_ivs_after_vectorizer (loop_vec_info loop_vinfo, tree niters,
       init_expr = unshare_expr (initial_condition_in_loop_num (access_fn, 
                                                               loop->num));
 
-      ni = build2 (PLUS_EXPR, TREE_TYPE (init_expr),
-                 build2 (MULT_EXPR, TREE_TYPE (niters),
-                      niters, step_expr), init_expr);
+      ni = fold_build2 (PLUS_EXPR, TREE_TYPE (init_expr),
+                       fold_build2 (MULT_EXPR, TREE_TYPE (init_expr),
+                                    fold_convert (TREE_TYPE (init_expr), 
+                                                  niters), 
+                                    step_expr),
+                       init_expr);
 
       var = create_tmp_var (TREE_TYPE (init_expr), "tmp");
       add_referenced_var (var);
@@ -3406,8 +4242,7 @@ vect_update_ivs_after_vectorizer (loop_vec_info loop_vinfo, tree niters,
    NITERS / VECTORIZATION_FACTOR times (this value is placed into RATIO).  */
 
 static void 
-vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio,
-                               struct loops *loops)
+vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio)
 {
   tree ni_name, ratio_mult_vf_name;
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -3430,7 +4265,7 @@ vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio,
                                   &ratio_mult_vf_name, ratio);
 
   loop_num  = loop->num; 
-  new_loop = slpeel_tree_peel_loop_to_edge (loop, loops, loop->single_exit,
+  new_loop = slpeel_tree_peel_loop_to_edge (loop, single_exit (loop),
                                            ratio_mult_vf_name, ni_name, false);
   gcc_assert (new_loop);
   gcc_assert (loop_num == loop->num);
@@ -3445,7 +4280,7 @@ vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio,
      is on the path where the LOOP IVs are used and need to be updated.  */
 
   preheader = loop_preheader_edge (new_loop)->src;
-  if (EDGE_PRED (preheader, 0)->src == loop->single_exit->dest)
+  if (EDGE_PRED (preheader, 0)->src == single_exit (loop)->dest)
     update_e = EDGE_PRED (preheader, 0);
   else
     update_e = EDGE_PRED (preheader, 1);
@@ -3479,7 +4314,14 @@ vect_do_peeling_for_loop_bound (loop_vec_info loop_vinfo, tree *ratio,
    prolog_niters = min ( LOOP_NITERS , (VF - addr_mis/elem_size)&(VF-1) )
    
    (elem_size = element type size; an element is the scalar element 
-       whose type is the inner type of the vectype)  */
+       whose type is the inner type of the vectype)  
+
+   For interleaving,
+
+   prolog_niters = min ( LOOP_NITERS , 
+                        (VF/group_size - addr_mis/elem_size)&(VF/group_size-1) )
+        where group_size is the size of the interleaved group.
+*/
 
 static tree 
 vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters)
@@ -3496,18 +4338,29 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters)
   tree vectype = STMT_VINFO_VECTYPE (stmt_info);
   int vectype_align = TYPE_ALIGN (vectype) / BITS_PER_UNIT;
   tree niters_type = TREE_TYPE (loop_niters);
+  int group_size = 1;
+  int element_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (DR_REF (dr))));
+
+  if (DR_GROUP_FIRST_DR (stmt_info))
+    {
+      /* For interleaved access element size must be multiplied by the size of
+        the interleaved group.  */
+      group_size = DR_GROUP_SIZE (vinfo_for_stmt (
+                                              DR_GROUP_FIRST_DR (stmt_info)));
+      element_size *= group_size;
+    }
 
   pe = loop_preheader_edge (loop); 
 
   if (LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo) > 0)
     {
       int byte_misalign = LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo);
-      int element_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (DR_REF (dr))));
       int elem_misalign = byte_misalign / element_size;
 
       if (vect_print_dump_info (REPORT_DETAILS))
         fprintf (vect_dump, "known alignment = %d.", byte_misalign);
-      iters = build_int_cst (niters_type, (vf - elem_misalign)&(vf-1));
+      iters = build_int_cst (niters_type, 
+                            (vf - elem_misalign)&(vf/group_size-1));
     }
   else
     {
@@ -3530,15 +4383,15 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters)
   
       /* Create:  byte_misalign = addr & (vectype_size - 1)  */
       byte_misalign = 
-        build2 (BIT_AND_EXPR, type, start_addr, vectype_size_minus_1);
+        fold_build2 (BIT_AND_EXPR, type, start_addr, vectype_size_minus_1);
   
       /* Create:  elem_misalign = byte_misalign / element_size  */
       elem_misalign =
-        build2 (RSHIFT_EXPR, type, byte_misalign, elem_size_log);
+        fold_build2 (RSHIFT_EXPR, type, byte_misalign, elem_size_log);
 
       /* Create:  (niters_type) (VF - elem_misalign)&(VF - 1)  */
-      iters = build2 (MINUS_EXPR, type, vf_tree, elem_misalign);
-      iters = build2 (BIT_AND_EXPR, type, iters, vf_minus_1);
+      iters = fold_build2 (MINUS_EXPR, type, vf_tree, elem_misalign);
+      iters = fold_build2 (BIT_AND_EXPR, type, iters, vf_minus_1);
       iters = fold_convert (niters_type, iters);
     }
 
@@ -3547,7 +4400,7 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters)
      greater than vf; since the misalignment ('iters') is at most vf, there's
      no need to generate the MIN_EXPR in this case.  */
   if (TREE_CODE (loop_niters) != INTEGER_CST)
-    iters = build2 (MIN_EXPR, niters_type, iters, loop_niters);
+    iters = fold_build2 (MIN_EXPR, niters_type, iters, loop_niters);
 
   if (vect_print_dump_info (REPORT_DETAILS))
     {
@@ -3620,7 +4473,7 @@ vect_update_inits_of_drs (loop_vec_info loop_vinfo, tree niters)
    peeling is recorded in LOOP_VINFO_UNALIGNED_DR.  */
 
 static void
-vect_do_peeling_for_alignment (loop_vec_info loop_vinfo, struct loops *loops)
+vect_do_peeling_for_alignment (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
   tree niters_of_prolog_loop, ni_name;
@@ -3637,7 +4490,7 @@ vect_do_peeling_for_alignment (loop_vec_info loop_vinfo, struct loops *loops)
   
   /* Peel the prolog loop and iterate it niters_of_prolog_loop.  */
   new_loop = 
-       slpeel_tree_peel_loop_to_edge (loop, loops, loop_preheader_edge (loop), 
+       slpeel_tree_peel_loop_to_edge (loop, loop_preheader_edge (loop), 
                                       niters_of_prolog_loop, ni_name, true); 
   gcc_assert (new_loop);
 #ifdef ENABLE_CHECKING
@@ -3732,7 +4585,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
       add_referenced_var (addr_tmp);
       addr_tmp_name = make_ssa_name (addr_tmp, NULL_TREE);
       addr_stmt = fold_convert (int_ptrsize_type, addr_base);
-      addr_stmt = build2 (MODIFY_EXPR, void_type_node,
+      addr_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
                           addr_tmp_name, addr_stmt);
       SSA_NAME_DEF_STMT (addr_tmp_name) = addr_stmt;
       append_to_statement_list_force (addr_stmt, cond_expr_stmt_list);
@@ -3746,7 +4599,8 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
           or_tmp = create_tmp_var (int_ptrsize_type, tmp_name);
           add_referenced_var (or_tmp);
           new_or_tmp_name = make_ssa_name (or_tmp, NULL_TREE);
-          or_stmt = build2 (MODIFY_EXPR, void_type_node, new_or_tmp_name,
+          or_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
+                           new_or_tmp_name,
                             build2 (BIT_IOR_EXPR, int_ptrsize_type,
                                    or_tmp_name,
                                     addr_tmp_name));
@@ -3766,7 +4620,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
   add_referenced_var (and_tmp);
   and_tmp_name = make_ssa_name (and_tmp, NULL_TREE);
 
-  and_stmt = build2 (MODIFY_EXPR, void_type_node,
+  and_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
                      and_tmp_name,
                      build2 (BIT_AND_EXPR, int_ptrsize_type,
                              or_tmp_name, mask_cst));
@@ -3788,8 +4642,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
    stmts in the loop, and update the loop exit condition.  */
 
 void
-vect_transform_loop (loop_vec_info loop_vinfo, 
-                    struct loops *loops ATTRIBUTE_UNUSED)
+vect_transform_loop (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
   basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
@@ -3800,6 +4653,7 @@ vect_transform_loop (loop_vec_info loop_vinfo,
   int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
   bitmap_iterator bi;
   unsigned int j;
+  bool strided_store;
 
   if (vect_print_dump_info (REPORT_DETAILS))
     fprintf (vect_dump, "=== vec_transform_loop ===");
@@ -3825,7 +4679,7 @@ vect_transform_loop (loop_vec_info loop_vinfo,
       cond_expr = vect_create_cond_for_align_checks (loop_vinfo,
                                                      &cond_expr_stmt_list);
       initialize_original_copy_tables ();
-      nloop = loop_version (loops, loop, cond_expr, &condition_bb, true);
+      nloop = loop_version (loop, cond_expr, &condition_bb, true);
       free_original_copy_tables();
 
       /** Loop versioning violates an assumption we try to maintain during 
@@ -3836,11 +4690,10 @@ vect_transform_loop (loop_vec_info loop_vinfo,
         here by adding a new (empty) block on the exit-edge of the loop,
         with the proper loop-exit phis to maintain loop-closed-form.  **/
       
-      merge_bb = loop->single_exit->dest;
+      merge_bb = single_exit (loop)->dest;
       gcc_assert (EDGE_COUNT (merge_bb->preds) == 2);
-      new_exit_bb = split_edge (loop->single_exit);
-      add_bb_to_loop (new_exit_bb, loop->outer);
-      new_exit_e = loop->single_exit;
+      new_exit_bb = split_edge (single_exit (loop));
+      new_exit_e = single_exit (loop);
       e = EDGE_SUCC (new_exit_bb, 0);
 
       for (orig_phi = phi_nodes (merge_bb); orig_phi; 
@@ -3868,7 +4721,7 @@ vect_transform_loop (loop_vec_info loop_vinfo,
      Only one data ref with unknown store is allowed.  */
 
   if (LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo))
-    vect_do_peeling_for_alignment (loop_vinfo, loops);
+    vect_do_peeling_for_alignment (loop_vinfo);
   
   /* If the loop has a symbolic number of iterations 'n' (i.e. it's not a
      compile time constant), or it is a constant that doesn't divide by the
@@ -3881,7 +4734,7 @@ vect_transform_loop (loop_vec_info loop_vinfo,
   if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
       || (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)
           && LOOP_VINFO_INT_NITERS (loop_vinfo) % vectorization_factor != 0))
-    vect_do_peeling_for_loop_bound (loop_vinfo, &ratio, loops);
+    vect_do_peeling_for_loop_bound (loop_vinfo, &ratio);
   else
     ratio = build_int_cst (TREE_TYPE (LOOP_VINFO_NITERS (loop_vinfo)),
                LOOP_VINFO_INT_NITERS (loop_vinfo) / vectorization_factor);
@@ -3891,8 +4744,7 @@ vect_transform_loop (loop_vec_info loop_vinfo,
 
   gcc_assert (EDGE_COUNT (loop->header->preds) == 2);
 
-  loop_split_edge_with (loop_preheader_edge (loop), NULL);
-
+  split_edge (loop_preheader_edge (loop));
 
   /* FORNOW: the vectorizer supports only loops which body consist
      of one basic block (header + empty latch). When the vectorizer will 
@@ -3932,17 +4784,53 @@ vect_transform_loop (loop_vec_info loop_vinfo,
          if (vect_print_dump_info (REPORT_DETAILS))
            fprintf (vect_dump, "transform statement.");
 
-         is_store = vect_transform_stmt (stmt, &si);
-         if (is_store)
-           {
-             /* Free the attached stmt_vec_info and remove the stmt.  */
-             stmt_ann_t ann = stmt_ann (stmt);
-             free (stmt_info);
-             set_stmt_info (ann, NULL);
-             bsi_remove (&si, true);
-             continue;
+         strided_store = false;
+         is_store = vect_transform_stmt (stmt, &si, &strided_store);
+          if (is_store)
+            {
+             stmt_ann_t ann;
+             if (DR_GROUP_FIRST_DR (stmt_info))
+               {
+                 /* Interleaving. If IS_STORE is TRUE, the vectorization of the
+                    interleaving chain was completed - free all the stores in
+                    the chain.  */
+                 tree next = DR_GROUP_FIRST_DR (stmt_info);
+                 tree tmp;
+                 stmt_vec_info next_stmt_info;
+
+                 while (next)
+                   {
+                     next_stmt_info = vinfo_for_stmt (next);
+                     /* Free the attached stmt_vec_info and remove the stmt.  */
+                     ann = stmt_ann (next);
+                     tmp = DR_GROUP_NEXT_DR (next_stmt_info);
+                     free (next_stmt_info);
+                     set_stmt_info (ann, NULL);
+                     next = tmp;
+                   }
+                 bsi_remove (&si, true);
+                 continue;
+               }
+             else
+               {
+                 /* Free the attached stmt_vec_info and remove the stmt.  */
+                 ann = stmt_ann (stmt);
+                 free (stmt_info);
+                 set_stmt_info (ann, NULL);
+                 bsi_remove (&si, true);
+                 continue;
+               }
            }
-
+         else
+           {
+             if (strided_store)
+               {
+                 /* This is case of skipped interleaved store. We don't free
+                    its stmt_vec_info.  */
+                 bsi_remove (&si, true);
+                 continue;
+               }
+            }
          bsi_next (&si);
        }                       /* stmts in BB */
     }                          /* BBs in loop */