]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-loop-prefetch.c
Merge from trunk.
[thirdparty/gcc.git] / gcc / tree-ssa-loop-prefetch.c
index dcc65e19abbc2374a140198d60dd6b13d6e96e21..32b9f8c216f71a6f3dbd18a37b927cc4c9cf9e41 100644 (file)
@@ -1,6 +1,5 @@
 /* Array prefetching.
-   Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2005-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -23,10 +22,20 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "stor-layout.h"
 #include "tm_p.h"
 #include "basic-block.h"
 #include "tree-pretty-print.h"
-#include "tree-flow.h"
+#include "gimple.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-ssa.h"
+#include "tree-ssa-loop-ivopts.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-ssa-loop.h"
+#include "tree-into-ssa.h"
 #include "cfgloop.h"
 #include "tree-pass.h"
 #include "insn-config.h"
@@ -286,7 +295,7 @@ dump_mem_details (FILE *file, tree base, tree step,
   fprintf (file, "(base ");
   print_generic_expr (file, base, TDF_SLIM);
   fprintf (file, ", step ");
-  if (cst_and_fits_in_hwi (step))
+  if (cst_fits_shwi_p (step))
     fprintf (file, HOST_WIDE_INT_PRINT_DEC, int_cst_value (step));
   else
     print_generic_expr (file, step, TDF_TREE);
@@ -327,7 +336,7 @@ find_or_create_group (struct mem_ref_group **groups, tree base, tree step)
 
       /* If step is an integer constant, keep the list of groups sorted
          by decreasing step.  */
-        if (cst_and_fits_in_hwi ((*groups)->step) && cst_and_fits_in_hwi (step)
+        if (cst_fits_shwi_p ((*groups)->step) && cst_fits_shwi_p (step)
             && int_cst_value ((*groups)->step) < int_cst_value (step))
        break;
     }
@@ -435,12 +444,12 @@ idx_analyze_ref (tree base, tree *index, void *data)
   step = iv.step;
 
   if (TREE_CODE (ibase) == POINTER_PLUS_EXPR
-      && cst_and_fits_in_hwi (TREE_OPERAND (ibase, 1)))
+      && cst_fits_shwi_p (TREE_OPERAND (ibase, 1)))
     {
       idelta = int_cst_value (TREE_OPERAND (ibase, 1));
       ibase = TREE_OPERAND (ibase, 0);
     }
-  if (cst_and_fits_in_hwi (ibase))
+  if (cst_fits_shwi_p (ibase))
     {
       idelta += int_cst_value (ibase);
       ibase = build_int_cst (TREE_TYPE (ibase), 0);
@@ -449,7 +458,7 @@ idx_analyze_ref (tree base, tree *index, void *data)
   if (TREE_CODE (base) == ARRAY_REF)
     {
       stepsize = array_ref_element_size (base);
-      if (!cst_and_fits_in_hwi (stepsize))
+      if (!cst_fits_shwi_p (stepsize))
        return false;
       imult = int_cst_value (stepsize);
       step = fold_build2 (MULT_EXPR, sizetype,
@@ -547,7 +556,7 @@ gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs,
 
   /* Limit non-constant step prefetching only to the innermost loops and 
      only when the step is loop invariant in the entire loop nest. */
-  if (!cst_and_fits_in_hwi (step))
+  if (!cst_fits_shwi_p (step))
     {
       if (loop->inner != NULL)
         {
@@ -556,7 +565,7 @@ gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs,
               fprintf (dump_file, "Memory expression %p\n",(void *) ref ); 
               print_generic_expr (dump_file, ref, TDF_TREE); 
               fprintf (dump_file,":");
-              dump_mem_details( dump_file, base, step, delta, write_p);              
+              dump_mem_details (dump_file, base, step, delta, write_p);
               fprintf (dump_file, 
                        "Ignoring %p, non-constant step prefetching is "
                        "limited to inner most loops \n", 
@@ -573,7 +582,7 @@ gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs,
                 fprintf (dump_file, "Memory expression %p\n",(void *) ref );
                 print_generic_expr (dump_file, ref, TDF_TREE);
                 fprintf (dump_file,":");
-                dump_mem_details(dump_file, base, step, delta, write_p);
+                dump_mem_details (dump_file, base, step, delta, write_p);
                 fprintf (dump_file, 
                          "Not prefetching, ignoring %p due to "
                          "loop variant step\n",
@@ -661,7 +670,7 @@ prune_ref_by_self_reuse (struct mem_ref *ref)
   bool backward;
 
   /* If the step size is non constant, we cannot calculate prefetch_mod.  */
-  if (!cst_and_fits_in_hwi (ref->group->step))
+  if (!cst_fits_shwi_p (ref->group->step))
     return;
 
   step = int_cst_value (ref->group->step);
@@ -771,7 +780,7 @@ prune_ref_by_group_reuse (struct mem_ref *ref, struct mem_ref *by,
   int align_unit;
 
   /* If the step is non constant we cannot calculate prefetch_before.  */
-  if (!cst_and_fits_in_hwi (ref->group->step)) {
+  if (!cst_fits_shwi_p (ref->group->step)) {
     return;
   }
 
@@ -1136,7 +1145,7 @@ issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead)
 
   for (ap = 0; ap < n_prefetches; ap++)
     {
-      if (cst_and_fits_in_hwi (ref->group->step))
+      if (cst_fits_shwi_p (ref->group->step))
         {
           /* Determine the address to prefetch.  */
           delta = (ahead + ap * ref->prefetch_mod) *
@@ -1229,13 +1238,13 @@ mark_nontemporal_store (struct mem_ref *ref)
 static void
 emit_mfence_after_loop (struct loop *loop)
 {
-  VEC (edge, heap) *exits = get_loop_exit_edges (loop);
+  vec<edge> exits = get_loop_exit_edges (loop);
   edge exit;
   gimple call;
   gimple_stmt_iterator bsi;
   unsigned i;
 
-  FOR_EACH_VEC_ELT (edge, exits, i, exit)
+  FOR_EACH_VEC_ELT (exits, i, exit)
     {
       call = gimple_build_call (FENCE_FOLLOWING_MOVNT, 0);
 
@@ -1249,7 +1258,7 @@ emit_mfence_after_loop (struct loop *loop)
       gsi_insert_before (&bsi, call, GSI_NEW_STMT);
     }
 
-  VEC_free (edge, heap, exits);
+  exits.release ();
   update_ssa (TODO_update_ssa_only_virtuals);
 }
 
@@ -1267,16 +1276,16 @@ may_use_storent_in_loop_p (struct loop *loop)
      is a suitable place for it at each of the loop exits.  */
   if (FENCE_FOLLOWING_MOVNT != NULL_TREE)
     {
-      VEC (edge, heap) *exits = get_loop_exit_edges (loop);
+      vec<edge> exits = get_loop_exit_edges (loop);
       unsigned i;
       edge exit;
 
-      FOR_EACH_VEC_ELT (edge, exits, i, exit)
+      FOR_EACH_VEC_ELT (exits, i, exit)
        if ((exit->flags & EDGE_ABNORMAL)
-           && exit->dest == EXIT_BLOCK_PTR)
+           && exit->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
          ret = false;
 
-      VEC_free (edge, heap, exits);
+      exits.release ();
     }
 
   return ret;
@@ -1450,8 +1459,8 @@ add_subscript_strides (tree access_fn, unsigned stride,
       if ((unsigned) loop_depth (aloop) <= min_depth)
        continue;
 
-      if (host_integerp (step, 0))
-       astep = tree_low_cst (step, 0);
+      if (tree_fits_shwi_p (step))
+       astep = tree_to_shwi (step);
       else
        astep = L1_CACHE_LINE_SIZE;
 
@@ -1471,7 +1480,7 @@ self_reuse_distance (data_reference_p dr, unsigned *loop_sizes, unsigned n,
 {
   tree stride, access_fn;
   HOST_WIDE_INT *strides, astride;
-  VEC (tree, heap) *access_fns;
+  vec<tree> access_fns;
   tree ref = DR_REF (dr);
   unsigned i, ret = ~0u;
 
@@ -1490,7 +1499,7 @@ self_reuse_distance (data_reference_p dr, unsigned *loop_sizes, unsigned n,
   strides = XCNEWVEC (HOST_WIDE_INT, n);
   access_fns = DR_ACCESS_FNS (dr);
 
-  FOR_EACH_VEC_ELT (tree, access_fns, i, access_fn)
+  FOR_EACH_VEC_ELT (access_fns, i, access_fn)
     {
       /* Keep track of the reference corresponding to the subscript, so that we
         know its stride.  */
@@ -1500,8 +1509,8 @@ self_reuse_distance (data_reference_p dr, unsigned *loop_sizes, unsigned n,
       if (TREE_CODE (ref) == ARRAY_REF)
        {
          stride = TYPE_SIZE_UNIT (TREE_TYPE (ref));
-         if (host_integerp (stride, 1))
-           astride = tree_low_cst (stride, 1);
+         if (tree_fits_uhwi_p (stride))
+           astride = tree_to_uhwi (stride);
          else
            astride = L1_CACHE_LINE_SIZE;
 
@@ -1541,11 +1550,11 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
                           bool no_other_refs)
 {
   struct loop *nest, *aloop;
-  VEC (data_reference_p, heap) *datarefs = NULL;
-  VEC (ddr_p, heap) *dependences = NULL;
+  vec<data_reference_p> datarefs = vNULL;
+  vec<ddr_p> dependences = vNULL;
   struct mem_ref_group *gr;
   struct mem_ref *ref, *refb;
-  VEC (loop_p, heap) *vloops = NULL;
+  vec<loop_p> vloops = vNULL;
   unsigned *loop_data_size;
   unsigned i, j, n;
   unsigned volume, dist, adist;
@@ -1574,7 +1583,7 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
      We use this to estimate whether the reference is evicted from the
      cache before its reuse.  */
   find_loop_nest (nest, &vloops);
-  n = VEC_length (loop_p, vloops);
+  n = vloops.length ();
   loop_data_size = XNEWVEC (unsigned, n);
   volume = volume_of_references (refs);
   i = n;
@@ -1586,7 +1595,7 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
       if (volume > L2_CACHE_SIZE_BYTES)
        continue;
 
-      aloop = VEC_index (loop_p, vloops, i);
+      aloop = vloops[i];
       vol = estimated_stmt_executions_int (aloop);
       if (vol == -1)
        vol = expected_loop_iterations (aloop);
@@ -1607,13 +1616,13 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
          {
            ref->reuse_distance = volume;
            dr->aux = ref;
-           VEC_safe_push (data_reference_p, heap, datarefs, dr);
+           datarefs.safe_push (dr);
          }
        else
          no_other_refs = false;
       }
 
-  FOR_EACH_VEC_ELT (data_reference_p, datarefs, i, dr)
+  FOR_EACH_VEC_ELT (datarefs, i, dr)
     {
       dist = self_reuse_distance (dr, loop_data_size, n, loop);
       ref = (struct mem_ref *) dr->aux;
@@ -1627,7 +1636,7 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
   if (!compute_all_dependences (datarefs, &dependences, vloops, true))
     return false;
 
-  FOR_EACH_VEC_ELT (ddr_p, dependences, i, dep)
+  FOR_EACH_VEC_ELT (dependences, i, dep)
     {
       if (DDR_ARE_DEPENDENT (dep) == chrec_known)
        continue;
@@ -1921,7 +1930,6 @@ fail:
 unsigned int
 tree_ssa_prefetch_arrays (void)
 {
-  loop_iterator li;
   struct loop *loop;
   bool unrolled = false;
   int todo_flags = 0;
@@ -1969,7 +1977,7 @@ tree_ssa_prefetch_arrays (void)
      here.  */
   gcc_assert ((PREFETCH_BLOCK & (PREFETCH_BLOCK - 1)) == 0);
 
-  FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
+  FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Processing loop %d:\n", loop->num);
@@ -1989,3 +1997,60 @@ tree_ssa_prefetch_arrays (void)
   free_original_copy_tables ();
   return todo_flags;
 }
+
+/* Prefetching.  */
+
+static unsigned int
+tree_ssa_loop_prefetch (void)
+{
+  if (number_of_loops (cfun) <= 1)
+    return 0;
+
+  return tree_ssa_prefetch_arrays ();
+}
+
+static bool
+gate_tree_ssa_loop_prefetch (void)
+{
+  return flag_prefetch_loop_arrays > 0;
+}
+
+namespace {
+
+const pass_data pass_data_loop_prefetch =
+{
+  GIMPLE_PASS, /* type */
+  "aprefetch", /* name */
+  OPTGROUP_LOOP, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_TREE_PREFETCH, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_loop_prefetch : public gimple_opt_pass
+{
+public:
+  pass_loop_prefetch (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_loop_prefetch, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_tree_ssa_loop_prefetch (); }
+  unsigned int execute () { return tree_ssa_loop_prefetch (); }
+
+}; // class pass_loop_prefetch
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_loop_prefetch (gcc::context *ctxt)
+{
+  return new pass_loop_prefetch (ctxt);
+}
+
+