OSDN Git Service

* gcc.dg/march.c: Ignore a note for some targets.
[pf3gnuchains/gcc-fork.git] / gcc / tree-vect-loop-manip.c
index 5771c51..89b4574 100644 (file)
@@ -34,7 +34,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "cfglayout.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "tree-scalar-evolution.h"
 #include "tree-vectorizer.h"
 #include "langhooks.h"
@@ -1107,6 +1106,34 @@ set_prologue_iterations (basic_block bb_before_first_loop,
 }
 
 
+/* Remove dead assignments from loop NEW_LOOP.  */
+
+static void
+remove_dead_stmts_from_loop (struct loop *new_loop)
+{
+  basic_block *bbs = get_loop_body (new_loop);
+  unsigned i;
+  for (i = 0; i < new_loop->num_nodes; ++i)
+    {
+      gimple_stmt_iterator gsi;
+      for (gsi = gsi_start_bb (bbs[i]); !gsi_end_p (gsi);)
+       {
+         gimple stmt = gsi_stmt (gsi);
+         if (is_gimple_assign (stmt)
+             && TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME
+             && has_zero_uses (gimple_assign_lhs (stmt)))
+           {
+             gsi_remove (&gsi, true);
+             release_defs (stmt);
+           }
+         else
+           gsi_next (&gsi);
+       }
+    }
+  free (bbs);
+}
+
+
 /* Function slpeel_tree_peel_loop_to_edge.
 
    Peel the first (last) iterations of LOOP into a new prolog (epilog) loop
@@ -1415,11 +1442,18 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop,
   if (update_first_loop_count)
     slpeel_make_loop_iterate_ntimes (first_loop, first_niters);
 
-  adjust_vec_debug_stmts ();
-
   BITMAP_FREE (definitions);
   delete_update_ssa ();
 
+  /* Remove all pattern statements from the loop copy.  They will confuse
+     the expander if DCE is disabled.
+     ???  The pattern recognizer should be split into an analysis and
+     a transformation phase that is then run only on the loop that is
+     going to be transformed.  */
+  remove_dead_stmts_from_loop (new_loop);
+
+  adjust_vec_debug_stmts ();
+
   return new_loop;
 }
 
@@ -1517,7 +1551,7 @@ vect_generate_tmps_on_preheader (loop_vec_info loop_vinfo,
   edge pe;
   basic_block new_bb;
   gimple_seq stmts;
-  tree ni_name;
+  tree ni_name, ni_minus_gap_name;
   tree var;
   tree ratio_name;
   tree ratio_mult_vf_name;
@@ -1534,9 +1568,39 @@ vect_generate_tmps_on_preheader (loop_vec_info loop_vinfo,
   ni_name = vect_build_loop_niters (loop_vinfo, cond_expr_stmt_list);
   log_vf = build_int_cst (TREE_TYPE (ni), exact_log2 (vf));
 
+  /* If epilogue loop is required because of data accesses with gaps, we
+     subtract one iteration from the total number of iterations here for
+     correct calculation of RATIO.  */
+  if (LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo))
+    {
+      ni_minus_gap_name = fold_build2 (MINUS_EXPR, TREE_TYPE (ni_name),
+                                      ni_name,
+                                      build_one_cst (TREE_TYPE (ni_name)));
+      if (!is_gimple_val (ni_minus_gap_name))
+       {
+         var = create_tmp_var (TREE_TYPE (ni), "ni_gap");
+          add_referenced_var (var);
+
+          stmts = NULL;
+          ni_minus_gap_name = force_gimple_operand (ni_minus_gap_name, &stmts,
+                                                   true, var);
+          if (cond_expr_stmt_list)
+            gimple_seq_add_seq (&cond_expr_stmt_list, stmts);
+          else
+            {
+              pe = loop_preheader_edge (loop);
+              new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
+              gcc_assert (!new_bb);
+            }
+        }
+    }
+  else
+    ni_minus_gap_name = ni_name;
+
   /* Create: ratio = ni >> log2(vf) */
 
-  ratio_name = fold_build2 (RSHIFT_EXPR, TREE_TYPE (ni_name), ni_name, log_vf);
+  ratio_name = fold_build2 (RSHIFT_EXPR, TREE_TYPE (ni_minus_gap_name),
+                           ni_minus_gap_name, log_vf);
   if (!is_gimple_val (ratio_name))
     {
       var = create_tmp_var (TREE_TYPE (ni), "bnd");
@@ -1993,8 +2057,11 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters,
   else
     {
       gimple_seq new_stmts = NULL;
+      bool negative = tree_int_cst_compare (DR_STEP (dr), size_zero_node) < 0;
+      tree offset = negative
+         ? size_int (-TYPE_VECTOR_SUBPARTS (vectype) + 1) : NULL_TREE;
       tree start_addr = vect_create_addr_base_for_vector_ref (dr_stmt,
-                                               &new_stmts, NULL_TREE, loop);
+                                               &new_stmts, offset, loop);
       tree ptr_type = TREE_TYPE (start_addr);
       tree size = TYPE_SIZE (ptr_type);
       tree type = lang_hooks.types.type_for_size (tree_low_cst (size, 1), 1);
@@ -2019,7 +2086,10 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters,
         fold_build2 (RSHIFT_EXPR, type, byte_misalign, elem_size_log);
 
       /* Create:  (niters_type) (nelements - elem_misalign)&(nelements - 1)  */
-      iters = fold_build2 (MINUS_EXPR, type, nelements_tree, elem_misalign);
+      if (negative)
+       iters = fold_build2 (MINUS_EXPR, type, elem_misalign, nelements_tree);
+      else
+       iters = fold_build2 (MINUS_EXPR, type, nelements_tree, elem_misalign);
       iters = fold_build2 (BIT_AND_EXPR, type, iters, nelements_minus_1);
       iters = fold_convert (niters_type, iters);
     }
@@ -2236,11 +2306,17 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
       tree addr_tmp, addr_tmp_name;
       tree or_tmp, new_or_tmp_name;
       gimple addr_stmt, or_stmt;
+      stmt_vec_info stmt_vinfo = vinfo_for_stmt (ref_stmt);
+      tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
+      bool negative = tree_int_cst_compare
+       (DR_STEP (STMT_VINFO_DATA_REF (stmt_vinfo)), size_zero_node) < 0;
+      tree offset = negative
+       ? size_int (-TYPE_VECTOR_SUBPARTS (vectype) + 1) : NULL_TREE;
 
       /* create: addr_tmp = (int)(address_of_first_vector) */
       addr_base =
        vect_create_addr_base_for_vector_ref (ref_stmt, &new_stmt_list,
-                                             NULL_TREE, loop);
+                                             offset, loop);
       if (new_stmt_list != NULL)
        gimple_seq_add_seq (cond_expr_stmt_list, new_stmt_list);
 
@@ -2307,27 +2383,27 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
 
    Input:
      DR: The data reference.
-     VECT_FACTOR: vectorization factor.
+     LENGTH_FACTOR: segment length to consider.
 
    Return an expression whose value is the size of segment which will be
    accessed by DR.  */
 
 static tree
-vect_vfa_segment_size (struct data_reference *dr, tree vect_factor)
+vect_vfa_segment_size (struct data_reference *dr, tree length_factor)
 {
-  tree segment_length = fold_build2 (MULT_EXPR, integer_type_node,
-                                    DR_STEP (dr), vect_factor);
-
+  tree segment_length;
+  segment_length = size_binop (MULT_EXPR,
+                              fold_convert (sizetype, DR_STEP (dr)),
+                              fold_convert (sizetype, length_factor));
   if (vect_supportable_dr_alignment (dr, false)
         == dr_explicit_realign_optimized)
     {
       tree vector_size = TYPE_SIZE_UNIT
                          (STMT_VINFO_VECTYPE (vinfo_for_stmt (DR_STMT (dr))));
 
-      segment_length = fold_build2 (PLUS_EXPR, integer_type_node,
-                                   segment_length, vector_size);
+      segment_length = size_binop (PLUS_EXPR, segment_length, vector_size);
     }
-  return fold_convert (sizetype, segment_length);
+  return segment_length;
 }
 
 
@@ -2361,12 +2437,12 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo,
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
   VEC (ddr_p, heap) * may_alias_ddrs =
     LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
-  tree vect_factor =
-    build_int_cst (integer_type_node, LOOP_VINFO_VECT_FACTOR (loop_vinfo));
+  int vect_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
+  tree scalar_loop_iters = LOOP_VINFO_NITERS (loop_vinfo);
 
   ddr_p ddr;
   unsigned int i;
-  tree part_cond_expr;
+  tree part_cond_expr, length_factor;
 
   /* Create expression
      ((store_ptr_0 + store_segment_length_0) < load_ptr_0)
@@ -2387,10 +2463,11 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo,
       tree addr_base_a, addr_base_b;
       tree segment_length_a, segment_length_b;
       gimple stmt_a, stmt_b;
+      tree seg_a_min, seg_a_max, seg_b_min, seg_b_max;
 
       dr_a = DDR_A (ddr);
       stmt_a = DR_STMT (DDR_A (ddr));
-      dr_group_first_a = DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_a));
+      dr_group_first_a = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_a));
       if (dr_group_first_a)
         {
          stmt_a = dr_group_first_a;
@@ -2399,7 +2476,7 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo,
 
       dr_b = DDR_B (ddr);
       stmt_b = DR_STMT (DDR_B (ddr));
-      dr_group_first_b = DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_b));
+      dr_group_first_b = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_b));
       if (dr_group_first_b)
         {
          stmt_b = dr_group_first_b;
@@ -2413,8 +2490,12 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo,
         vect_create_addr_base_for_vector_ref (stmt_b, cond_expr_stmt_list,
                                              NULL_TREE, loop);
 
-      segment_length_a = vect_vfa_segment_size (dr_a, vect_factor);
-      segment_length_b = vect_vfa_segment_size (dr_b, vect_factor);
+      if (!operand_equal_p (DR_STEP (dr_a), DR_STEP (dr_b), 0))
+       length_factor = scalar_loop_iters;
+      else
+       length_factor = size_int (vect_factor);
+      segment_length_a = vect_vfa_segment_size (dr_a, length_factor);
+      segment_length_b = vect_vfa_segment_size (dr_b, length_factor);
 
       if (vect_print_dump_info (REPORT_DR_DETAILS))
        {
@@ -2425,19 +2506,22 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo,
          print_generic_expr (vect_dump, DR_REF (dr_b), TDF_SLIM);
        }
 
+      seg_a_min = addr_base_a;
+      seg_a_max = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr_base_a), 
+                              addr_base_a, segment_length_a);
+      if (tree_int_cst_compare (DR_STEP (dr_a), size_zero_node) < 0)
+       seg_a_min = seg_a_max, seg_a_max = addr_base_a;
+
+      seg_b_min = addr_base_b;
+      seg_b_max = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr_base_b),
+                              addr_base_b, segment_length_b);
+      if (tree_int_cst_compare (DR_STEP (dr_b), size_zero_node) < 0)
+       seg_b_min = seg_b_max, seg_b_max = addr_base_b;
 
       part_cond_expr =
        fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
-         fold_build2 (LT_EXPR, boolean_type_node,
-           fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr_base_a),
-             addr_base_a,
-             segment_length_a),
-           addr_base_b),
-         fold_build2 (LT_EXPR, boolean_type_node,
-           fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr_base_b),
-             addr_base_b,
-             segment_length_b),
-           addr_base_a));
+         fold_build2 (LT_EXPR, boolean_type_node, seg_a_max, seg_b_min),
+         fold_build2 (LT_EXPR, boolean_type_node, seg_b_max, seg_a_min));
 
       if (*cond_expr)
        *cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,