OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-loop-prefetch.c
index 48fafb1..264d97b 100644 (file)
@@ -1,18 +1,19 @@
 /* Array prefetching.
 /* Array prefetching.
-   Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
-   
+   Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
+
 This file is part of GCC.
 This file is part of GCC.
-   
+
 GCC is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
 Free Software Foundation; either version 3, or (at your option) any
 later version.
 GCC is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
 Free Software Foundation; either version 3, or (at your option) any
 later version.
-   
+
 GCC is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 GCC is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
-   
+
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
@@ -22,30 +23,30 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
 #include "tm_p.h"
 #include "tm_p.h"
-#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
 #include "basic-block.h"
 #include "output.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
 #include "tree-flow.h"
 #include "tree-dump.h"
 #include "timevar.h"
 #include "cfgloop.h"
 #include "tree-flow.h"
 #include "tree-dump.h"
 #include "timevar.h"
 #include "cfgloop.h"
-#include "varray.h"
-#include "expr.h"
 #include "tree-pass.h"
 #include "tree-pass.h"
-#include "ggc.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "hashtab.h"
 #include "tree-chrec.h"
 #include "tree-scalar-evolution.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "hashtab.h"
 #include "tree-chrec.h"
 #include "tree-scalar-evolution.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "params.h"
 #include "langhooks.h"
 #include "tree-inline.h"
 #include "tree-data-ref.h"
 #include "params.h"
 #include "langhooks.h"
 #include "tree-inline.h"
 #include "tree-data-ref.h"
+
+
+/* FIXME: Needed for optabs, but this should all be moved to a TBD interface
+   between the GIMPLE and RTL worlds.  */
+#include "expr.h"
 #include "optabs.h"
 
 /* This pass inserts prefetch instructions to optimize cache usage during
 #include "optabs.h"
 
 /* This pass inserts prefetch instructions to optimize cache usage during
@@ -79,7 +80,7 @@ along with GCC; see the file COPYING3.  If not see
        (2) has PREFETCH_MOD 64
        (3) has PREFETCH_MOD 4
        (4) has PREFETCH_MOD 1.  We do not set PREFETCH_BEFORE here, since
        (2) has PREFETCH_MOD 64
        (3) has PREFETCH_MOD 4
        (4) has PREFETCH_MOD 1.  We do not set PREFETCH_BEFORE here, since
-           the cache line accessed by (4) is the same with probability only
+           the cache line accessed by (5) is the same with probability only
           7/32.
        (5) has PREFETCH_MOD 1 as well.
 
           7/32.
        (5) has PREFETCH_MOD 1 as well.
 
@@ -99,16 +100,43 @@ along with GCC; see the file COPYING3.  If not see
       while still within this bound (starting with those with lowest
       prefetch_mod, since they are responsible for most of the cache
       misses).
       while still within this bound (starting with those with lowest
       prefetch_mod, since they are responsible for most of the cache
       misses).
-      
+
    5) We unroll and peel loops so that we are able to satisfy PREFETCH_MOD
       and PREFETCH_BEFORE requirements (within some bounds), and to avoid
       prefetching nonaccessed memory.
       TODO -- actually implement peeling.
    5) We unroll and peel loops so that we are able to satisfy PREFETCH_MOD
       and PREFETCH_BEFORE requirements (within some bounds), and to avoid
       prefetching nonaccessed memory.
       TODO -- actually implement peeling.
-      
+
    6) We actually emit the prefetch instructions.  ??? Perhaps emit the
       prefetch instructions with guards in cases where 5) was not sufficient
       to satisfy the constraints?
 
    6) We actually emit the prefetch instructions.  ??? Perhaps emit the
       prefetch instructions with guards in cases where 5) was not sufficient
       to satisfy the constraints?
 
+   A cost model is implemented to determine whether or not prefetching is
+   profitable for a given loop.  The cost model has three heuristics:
+
+   1. Function trip_count_to_ahead_ratio_too_small_p implements a
+      heuristic that determines whether or not the loop has too few
+      iterations (compared to ahead).  Prefetching is not likely to be
+      beneficial if the trip count to ahead ratio is below a certain
+      minimum.
+
+   2. Function mem_ref_count_reasonable_p implements a heuristic that
+      determines whether the given loop has enough CPU ops that can be
+      overlapped with cache missing memory ops.  If not, the loop
+      won't benefit from prefetching.  In the implementation,
+      prefetching is not considered beneficial if the ratio between
+      the instruction count and the mem ref count is below a certain
+      minimum.
+
+   3. Function insn_to_prefetch_ratio_too_small_p implements a
+      heuristic that disables prefetching in a loop if the prefetching
+      cost is above a certain limit.  The relative prefetching cost is
+      estimated by taking the ratio between the prefetch count and the
+      total intruction count (this models the I-cache cost).
+
+   The limits used in these heuristics are defined as parameters with
+   reasonable default values. Machine-specific default values will be
+   added later.
+
    Some other TODO:
       -- write and use more general reuse analysis (that could be also used
         in other cache aimed loop optimizations)
    Some other TODO:
       -- write and use more general reuse analysis (that could be also used
         in other cache aimed loop optimizations)
@@ -183,12 +211,24 @@ along with GCC; see the file COPYING3.  If not see
 #define FENCE_FOLLOWING_MOVNT NULL_TREE
 #endif
 
 #define FENCE_FOLLOWING_MOVNT NULL_TREE
 #endif
 
+/* It is not profitable to prefetch when the trip count is not at
+   least TRIP_COUNT_TO_AHEAD_RATIO times the prefetch ahead distance.
+   For example, in a loop with a prefetch ahead distance of 10,
+   supposing that TRIP_COUNT_TO_AHEAD_RATIO is equal to 4, it is
+   profitable to prefetch when the trip count is greater or equal to
+   40.  In that case, 30 out of the 40 iterations will benefit from
+   prefetching.  */
+
+#ifndef TRIP_COUNT_TO_AHEAD_RATIO
+#define TRIP_COUNT_TO_AHEAD_RATIO 4
+#endif
+
 /* The group of references between that reuse may occur.  */
 
 struct mem_ref_group
 {
   tree base;                   /* Base of the reference.  */
 /* The group of references between that reuse may occur.  */
 
 struct mem_ref_group
 {
   tree base;                   /* Base of the reference.  */
-  HOST_WIDE_INT step;          /* Step of the reference.  */
+  tree step;                   /* Step of the reference.  */
   struct mem_ref *refs;                /* References in the group.  */
   struct mem_ref_group *next;  /* Next group of references.  */
 };
   struct mem_ref *refs;                /* References in the group.  */
   struct mem_ref_group *next;  /* Next group of references.  */
 };
@@ -197,11 +237,30 @@ struct mem_ref_group
 
 #define PREFETCH_ALL           (~(unsigned HOST_WIDE_INT) 0)
 
 
 #define PREFETCH_ALL           (~(unsigned HOST_WIDE_INT) 0)
 
+/* Do not generate a prefetch if the unroll factor is significantly less
+   than what is required by the prefetch.  This is to avoid redundant
+   prefetches.  For example, when prefetch_mod is 16 and unroll_factor is
+   2, prefetching requires unrolling the loop 16 times, but
+   the loop is actually unrolled twice.  In this case (ratio = 8),
+   prefetching is not likely to be beneficial.  */
+
+#ifndef PREFETCH_MOD_TO_UNROLL_FACTOR_RATIO
+#define PREFETCH_MOD_TO_UNROLL_FACTOR_RATIO 4
+#endif
+
+/* Some of the prefetch computations have quadratic complexity.  We want to
+   avoid huge compile times and, therefore, want to limit the amount of
+   memory references per loop where we consider prefetching.  */
+
+#ifndef PREFETCH_MAX_MEM_REFS_PER_LOOP
+#define PREFETCH_MAX_MEM_REFS_PER_LOOP 200
+#endif
+
 /* The memory reference.  */
 
 struct mem_ref
 {
 /* The memory reference.  */
 
 struct mem_ref
 {
-  tree stmt;                   /* Statement in that the reference appears.  */
+  gimple stmt;                 /* Statement in that the reference appears.  */
   tree mem;                    /* The reference.  */
   HOST_WIDE_INT delta;         /* Constant offset of the reference.  */
   struct mem_ref_group *group; /* The group of references it belongs to.  */
   tree mem;                    /* The reference.  */
   HOST_WIDE_INT delta;         /* Constant offset of the reference.  */
   struct mem_ref_group *group; /* The group of references it belongs to.  */
@@ -232,7 +291,10 @@ dump_mem_ref (FILE *file, struct mem_ref *ref)
   fprintf (file, "  group %p (base ", (void *) ref->group);
   print_generic_expr (file, ref->group->base, TDF_SLIM);
   fprintf (file, ", step ");
   fprintf (file, "  group %p (base ", (void *) ref->group);
   print_generic_expr (file, ref->group->base, TDF_SLIM);
   fprintf (file, ", step ");
-  fprintf (file, HOST_WIDE_INT_PRINT_DEC, ref->group->step);
+  if (cst_and_fits_in_hwi (ref->group->step))
+    fprintf (file, HOST_WIDE_INT_PRINT_DEC, int_cst_value (ref->group->step));
+  else
+    print_generic_expr (file, ref->group->step, TDF_TREE);
   fprintf (file, ")\n");
 
   fprintf (file, "  delta ");
   fprintf (file, ")\n");
 
   fprintf (file, "  delta ");
@@ -248,19 +310,20 @@ dump_mem_ref (FILE *file, struct mem_ref *ref)
    exist.  */
 
 static struct mem_ref_group *
    exist.  */
 
 static struct mem_ref_group *
-find_or_create_group (struct mem_ref_group **groups, tree base,
-                     HOST_WIDE_INT step)
+find_or_create_group (struct mem_ref_group **groups, tree base, tree step)
 {
   struct mem_ref_group *group;
 
   for (; *groups; groups = &(*groups)->next)
     {
 {
   struct mem_ref_group *group;
 
   for (; *groups; groups = &(*groups)->next)
     {
-      if ((*groups)->step == step
+      if (operand_equal_p ((*groups)->step, step, 0)
          && operand_equal_p ((*groups)->base, base, 0))
        return *groups;
 
          && operand_equal_p ((*groups)->base, base, 0))
        return *groups;
 
-      /* Keep the list of groups sorted by decreasing step.  */
-      if ((*groups)->step < 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)
+            && int_cst_value ((*groups)->step) < int_cst_value (step))
        break;
     }
 
        break;
     }
 
@@ -278,7 +341,7 @@ find_or_create_group (struct mem_ref_group **groups, tree base,
    WRITE_P.  The reference occurs in statement STMT.  */
 
 static void
    WRITE_P.  The reference occurs in statement STMT.  */
 
 static void
-record_ref (struct mem_ref_group *group, tree stmt, tree mem,
+record_ref (struct mem_ref_group *group, gimple stmt, tree mem,
            HOST_WIDE_INT delta, bool write_p)
 {
   struct mem_ref **aref;
            HOST_WIDE_INT delta, bool write_p)
 {
   struct mem_ref **aref;
@@ -344,8 +407,8 @@ release_mem_refs (struct mem_ref_group *groups)
 struct ar_data
 {
   struct loop *loop;                   /* Loop of the reference.  */
 struct ar_data
 {
   struct loop *loop;                   /* Loop of the reference.  */
-  tree stmt;                           /* Statement of the reference.  */
-  HOST_WIDE_INT *step;                 /* Step of the memory reference.  */
+  gimple stmt;                         /* Statement of the reference.  */
+  tree *step;                          /* Step of the memory reference.  */
   HOST_WIDE_INT *delta;                        /* Offset of the memory reference.  */
 };
 
   HOST_WIDE_INT *delta;                        /* Offset of the memory reference.  */
 };
 
@@ -357,22 +420,15 @@ idx_analyze_ref (tree base, tree *index, void *data)
 {
   struct ar_data *ar_data = (struct ar_data *) data;
   tree ibase, step, stepsize;
 {
   struct ar_data *ar_data = (struct ar_data *) data;
   tree ibase, step, stepsize;
-  HOST_WIDE_INT istep, idelta = 0, imult = 1;
+  HOST_WIDE_INT idelta = 0, imult = 1;
   affine_iv iv;
 
   affine_iv iv;
 
-  if (TREE_CODE (base) == MISALIGNED_INDIRECT_REF
-      || TREE_CODE (base) == ALIGN_INDIRECT_REF)
-    return false;
-
-  if (!simple_iv (ar_data->loop, ar_data->stmt, *index, &iv, false))
+  if (!simple_iv (ar_data->loop, loop_containing_stmt (ar_data->stmt),
+                 *index, &iv, true))
     return false;
   ibase = iv.base;
   step = iv.step;
 
     return false;
   ibase = iv.base;
   step = iv.step;
 
-  if (!cst_and_fits_in_hwi (step))
-    return false;
-  istep = int_cst_value (step);
-
   if (TREE_CODE (ibase) == POINTER_PLUS_EXPR
       && cst_and_fits_in_hwi (TREE_OPERAND (ibase, 1)))
     {
   if (TREE_CODE (ibase) == POINTER_PLUS_EXPR
       && cst_and_fits_in_hwi (TREE_OPERAND (ibase, 1)))
     {
@@ -391,12 +447,18 @@ idx_analyze_ref (tree base, tree *index, void *data)
       if (!cst_and_fits_in_hwi (stepsize))
        return false;
       imult = int_cst_value (stepsize);
       if (!cst_and_fits_in_hwi (stepsize))
        return false;
       imult = int_cst_value (stepsize);
-
-      istep *= imult;
+      step = fold_build2 (MULT_EXPR, sizetype,
+                         fold_convert (sizetype, step),
+                         fold_convert (sizetype, stepsize));
       idelta *= imult;
     }
 
       idelta *= imult;
     }
 
-  *ar_data->step += istep;
+  if (*ar_data->step == NULL_TREE)
+    *ar_data->step = step;
+  else
+    *ar_data->step = fold_build2 (PLUS_EXPR, sizetype,
+                                 fold_convert (sizetype, *ar_data->step),
+                                 fold_convert (sizetype, step));
   *ar_data->delta += idelta;
   *index = ibase;
 
   *ar_data->delta += idelta;
   *index = ibase;
 
@@ -410,21 +472,29 @@ idx_analyze_ref (tree base, tree *index, void *data)
 
 static bool
 analyze_ref (struct loop *loop, tree *ref_p, tree *base,
 
 static bool
 analyze_ref (struct loop *loop, tree *ref_p, tree *base,
-            HOST_WIDE_INT *step, HOST_WIDE_INT *delta,
-            tree stmt)
+            tree *step, HOST_WIDE_INT *delta,
+            gimple stmt)
 {
   struct ar_data ar_data;
   tree off;
   HOST_WIDE_INT bit_offset;
   tree ref = *ref_p;
 
 {
   struct ar_data ar_data;
   tree off;
   HOST_WIDE_INT bit_offset;
   tree ref = *ref_p;
 
-  *step = 0;
+  *step = NULL_TREE;
   *delta = 0;
 
   *delta = 0;
 
-  /* First strip off the component references.  Ignore bitfields.  */
-  if (TREE_CODE (ref) == COMPONENT_REF
-      && DECL_NONADDRESSABLE_P (TREE_OPERAND (ref, 1)))
-    ref = TREE_OPERAND (ref, 0);
+  /* First strip off the component references.  Ignore bitfields.
+     Also strip off the real and imagine parts of a complex, so that
+     they can have the same base.  */
+  if (TREE_CODE (ref) == REALPART_EXPR
+      || TREE_CODE (ref) == IMAGPART_EXPR
+      || (TREE_CODE (ref) == COMPONENT_REF
+          && DECL_NONADDRESSABLE_P (TREE_OPERAND (ref, 1))))
+    {
+      if (TREE_CODE (ref) == IMAGPART_EXPR)
+        *delta += int_size_in_bytes (TREE_TYPE (ref));
+      ref = TREE_OPERAND (ref, 0);
+    }
 
   *ref_p = ref;
 
 
   *ref_p = ref;
 
@@ -433,7 +503,7 @@ analyze_ref (struct loop *loop, tree *ref_p, tree *base,
       off = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1));
       bit_offset = TREE_INT_CST_LOW (off);
       gcc_assert (bit_offset % BITS_PER_UNIT == 0);
       off = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1));
       bit_offset = TREE_INT_CST_LOW (off);
       gcc_assert (bit_offset % BITS_PER_UNIT == 0);
-      
+
       *delta += bit_offset / BITS_PER_UNIT;
     }
 
       *delta += bit_offset / BITS_PER_UNIT;
     }
 
@@ -451,14 +521,28 @@ analyze_ref (struct loop *loop, tree *ref_p, tree *base,
 
 static bool
 gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs,
 
 static bool
 gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs,
-                             tree ref, bool write_p, tree stmt)
+                             tree ref, bool write_p, gimple stmt)
 {
 {
-  tree base;
-  HOST_WIDE_INT step, delta;
+  tree base, step;
+  HOST_WIDE_INT delta;
   struct mem_ref_group *agrp;
 
   struct mem_ref_group *agrp;
 
+  if (get_base_address (ref) == NULL)
+    return false;
+
   if (!analyze_ref (loop, &ref, &base, &step, &delta, stmt))
     return false;
   if (!analyze_ref (loop, &ref, &base, &step, &delta, stmt))
     return false;
+  /* If analyze_ref fails the default is a NULL_TREE.  We can stop here.  */
+  if (step == NULL_TREE)
+    return false;
+
+  /* Stop if the address of BASE could not be taken.  */
+  if (may_be_nonaddressable_p (base))
+    return false;
+
+  /* Limit non-constant step prefetching only to the innermost loops.  */
+  if (!cst_and_fits_in_hwi (step) && loop->inner != NULL)
+    return false;
 
   /* Now we know that REF = &BASE + STEP * iter + DELTA, where DELTA and STEP
      are integer constants.  */
 
   /* Now we know that REF = &BASE + STEP * iter + DELTA, where DELTA and STEP
      are integer constants.  */
@@ -472,16 +556,18 @@ gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs,
    true if there are no other memory references inside the loop.  */
 
 static struct mem_ref_group *
    true if there are no other memory references inside the loop.  */
 
 static struct mem_ref_group *
-gather_memory_references (struct loop *loop, bool *no_other_refs)
+gather_memory_references (struct loop *loop, bool *no_other_refs, unsigned *ref_count)
 {
   basic_block *body = get_loop_body_in_dom_order (loop);
   basic_block bb;
   unsigned i;
 {
   basic_block *body = get_loop_body_in_dom_order (loop);
   basic_block bb;
   unsigned i;
-  block_stmt_iterator bsi;
-  tree stmt, lhs, rhs, call;
+  gimple_stmt_iterator bsi;
+  gimple stmt;
+  tree lhs, rhs;
   struct mem_ref_group *refs = NULL;
 
   *no_other_refs = true;
   struct mem_ref_group *refs = NULL;
 
   *no_other_refs = true;
+  *ref_count = 0;
 
   /* Scan the loop body in order, so that the former references precede the
      later ones.  */
 
   /* Scan the loop body in order, so that the former references precede the
      later ones.  */
@@ -491,29 +577,34 @@ gather_memory_references (struct loop *loop, bool *no_other_refs)
       if (bb->loop_father != loop)
        continue;
 
       if (bb->loop_father != loop)
        continue;
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
        {
        {
-         stmt = bsi_stmt (bsi);
-         call = get_call_expr_in (stmt);
-         if (call && !(call_expr_flags (call) & ECF_CONST))
-           *no_other_refs = false;
+         stmt = gsi_stmt (bsi);
 
 
-         if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
+         if (gimple_code (stmt) != GIMPLE_ASSIGN)
            {
            {
-             if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+             if (gimple_vuse (stmt)
+                 || (is_gimple_call (stmt)
+                     && !(gimple_call_flags (stmt) & ECF_CONST)))
                *no_other_refs = false;
              continue;
            }
 
                *no_other_refs = false;
              continue;
            }
 
-         lhs = GIMPLE_STMT_OPERAND (stmt, 0);
-         rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+         lhs = gimple_assign_lhs (stmt);
+         rhs = gimple_assign_rhs1 (stmt);
 
          if (REFERENCE_CLASS_P (rhs))
 
          if (REFERENCE_CLASS_P (rhs))
+           {
            *no_other_refs &= gather_memory_references_ref (loop, &refs,
                                                            rhs, false, stmt);
            *no_other_refs &= gather_memory_references_ref (loop, &refs,
                                                            rhs, false, stmt);
+           *ref_count += 1;
+           }
          if (REFERENCE_CLASS_P (lhs))
          if (REFERENCE_CLASS_P (lhs))
+           {
            *no_other_refs &= gather_memory_references_ref (loop, &refs,
                                                            lhs, true, stmt);
            *no_other_refs &= gather_memory_references_ref (loop, &refs,
                                                            lhs, true, stmt);
+           *ref_count += 1;
+           }
        }
     }
   free (body);
        }
     }
   free (body);
@@ -526,8 +617,16 @@ gather_memory_references (struct loop *loop, bool *no_other_refs)
 static void
 prune_ref_by_self_reuse (struct mem_ref *ref)
 {
 static void
 prune_ref_by_self_reuse (struct mem_ref *ref)
 {
-  HOST_WIDE_INT step = ref->group->step;
-  bool backward = step < 0;
+  HOST_WIDE_INT step;
+  bool backward;
+
+  /* If the step size is non constant, we cannot calculate prefetch_mod.  */
+  if (!cst_and_fits_in_hwi (ref->group->step))
+    return;
+
+  step = int_cst_value (ref->group->step);
+
+  backward = step < 0;
 
   if (step == 0)
     {
 
   if (step == 0)
     {
@@ -565,6 +664,54 @@ ddown (HOST_WIDE_INT x, unsigned HOST_WIDE_INT by)
     return (x + by - 1) / by;
 }
 
     return (x + by - 1) / by;
 }
 
+/* Given a CACHE_LINE_SIZE and two inductive memory references
+   with a common STEP greater than CACHE_LINE_SIZE and an address
+   difference DELTA, compute the probability that they will fall
+   in different cache lines.  Return true if the computed miss rate
+   is not greater than the ACCEPTABLE_MISS_RATE.  DISTINCT_ITERS is the
+   number of distinct iterations after which the pattern repeats itself.
+   ALIGN_UNIT is the unit of alignment in bytes.  */
+
+static bool
+is_miss_rate_acceptable (unsigned HOST_WIDE_INT cache_line_size,
+                  HOST_WIDE_INT step, HOST_WIDE_INT delta,
+                  unsigned HOST_WIDE_INT distinct_iters,
+                  int align_unit)
+{
+  unsigned align, iter;
+  int total_positions, miss_positions, max_allowed_miss_positions;
+  int address1, address2, cache_line1, cache_line2;
+
+  /* It always misses if delta is greater than or equal to the cache
+     line size.  */
+  if (delta >= (HOST_WIDE_INT) cache_line_size)
+    return false;
+
+  miss_positions = 0;
+  total_positions = (cache_line_size / align_unit) * distinct_iters;
+  max_allowed_miss_positions = (ACCEPTABLE_MISS_RATE * total_positions) / 1000;
+
+  /* Iterate through all possible alignments of the first
+     memory reference within its cache line.  */
+  for (align = 0; align < cache_line_size; align += align_unit)
+
+    /* Iterate through all distinct iterations.  */
+    for (iter = 0; iter < distinct_iters; iter++)
+      {
+       address1 = align + step * iter;
+       address2 = address1 + delta;
+       cache_line1 = address1 / cache_line_size;
+       cache_line2 = address2 / cache_line_size;
+       if (cache_line1 != cache_line2)
+         {
+           miss_positions += 1;
+            if (miss_positions > max_allowed_miss_positions)
+             return false;
+          }
+      }
+  return true;
+}
+
 /* Prune the prefetch candidate REF using the reuse with BY.
    If BY_IS_BEFORE is true, BY is before REF in the loop.  */
 
 /* Prune the prefetch candidate REF using the reuse with BY.
    If BY_IS_BEFORE is true, BY is before REF in the loop.  */
 
@@ -572,12 +719,26 @@ static void
 prune_ref_by_group_reuse (struct mem_ref *ref, struct mem_ref *by,
                          bool by_is_before)
 {
 prune_ref_by_group_reuse (struct mem_ref *ref, struct mem_ref *by,
                          bool by_is_before)
 {
-  HOST_WIDE_INT step = ref->group->step;
-  bool backward = step < 0;
+  HOST_WIDE_INT step;
+  bool backward;
   HOST_WIDE_INT delta_r = ref->delta, delta_b = by->delta;
   HOST_WIDE_INT delta = delta_b - delta_r;
   HOST_WIDE_INT hit_from;
   unsigned HOST_WIDE_INT prefetch_before, prefetch_block;
   HOST_WIDE_INT delta_r = ref->delta, delta_b = by->delta;
   HOST_WIDE_INT delta = delta_b - delta_r;
   HOST_WIDE_INT hit_from;
   unsigned HOST_WIDE_INT prefetch_before, prefetch_block;
+  HOST_WIDE_INT reduced_step;
+  unsigned HOST_WIDE_INT reduced_prefetch_block;
+  tree ref_type;
+  int align_unit;
+
+  /* If the step is non constant we cannot calculate prefetch_before.  */
+  if (!cst_and_fits_in_hwi (ref->group->step)) {
+    return;
+  }
+
+  step = int_cst_value (ref->group->step);
+
+  backward = step < 0;
+
 
   if (delta == 0)
     {
 
   if (delta == 0)
     {
@@ -585,7 +746,7 @@ prune_ref_by_group_reuse (struct mem_ref *ref, struct mem_ref *by,
         former.  */
       if (by_is_before)
        ref->prefetch_before = 0;
         former.  */
       if (by_is_before)
        ref->prefetch_before = 0;
-      
+
       return;
     }
 
       return;
     }
 
@@ -633,32 +794,41 @@ prune_ref_by_group_reuse (struct mem_ref *ref, struct mem_ref *by,
       hit_from = ddown (delta_b, PREFETCH_BLOCK) * PREFETCH_BLOCK;
       prefetch_before = (hit_from - delta_r + step - 1) / step;
 
       hit_from = ddown (delta_b, PREFETCH_BLOCK) * PREFETCH_BLOCK;
       prefetch_before = (hit_from - delta_r + step - 1) / step;
 
+      /* Do not reduce prefetch_before if we meet beyond cache size.  */
+      if (prefetch_before > absu_hwi (L2_CACHE_SIZE_BYTES / step))
+        prefetch_before = PREFETCH_ALL;
       if (prefetch_before < ref->prefetch_before)
        ref->prefetch_before = prefetch_before;
 
       return;
     }
 
       if (prefetch_before < ref->prefetch_before)
        ref->prefetch_before = prefetch_before;
 
       return;
     }
 
-  /* A more complicated case.  First let us ensure that size of cache line
-     and step are coprime (here we assume that PREFETCH_BLOCK is a power
-     of two.  */
+  /* A more complicated case with step > prefetch_block.  First reduce
+     the ratio between the step and the cache line size to its simplest
+     terms.  The resulting denominator will then represent the number of
+     distinct iterations after which each address will go back to its
+     initial location within the cache line.  This computation assumes
+     that PREFETCH_BLOCK is a power of two.  */
   prefetch_block = PREFETCH_BLOCK;
   prefetch_block = PREFETCH_BLOCK;
-  while ((step & 1) == 0
-        && prefetch_block > 1)
+  reduced_prefetch_block = prefetch_block;
+  reduced_step = step;
+  while ((reduced_step & 1) == 0
+        && reduced_prefetch_block > 1)
     {
     {
-      step >>= 1;
-      prefetch_block >>= 1;
-      delta >>= 1;
+      reduced_step >>= 1;
+      reduced_prefetch_block >>= 1;
     }
 
     }
 
-  /* Now step > prefetch_block, and step and prefetch_block are coprime.
-     Determine the probability that the accesses hit the same cache line.  */
-
   prefetch_before = delta / step;
   delta %= step;
   prefetch_before = delta / step;
   delta %= step;
-  if ((unsigned HOST_WIDE_INT) delta
-      <= (prefetch_block * ACCEPTABLE_MISS_RATE / 1000))
+  ref_type = TREE_TYPE (ref->mem);
+  align_unit = TYPE_ALIGN (ref_type) / 8;
+  if (is_miss_rate_acceptable (prefetch_block, step, delta,
+                              reduced_prefetch_block, align_unit))
     {
     {
+      /* Do not reduce prefetch_before if we meet beyond cache size.  */
+      if (prefetch_before > L2_CACHE_SIZE_BYTES / PREFETCH_BLOCK)
+        prefetch_before = PREFETCH_ALL;
       if (prefetch_before < ref->prefetch_before)
        ref->prefetch_before = prefetch_before;
 
       if (prefetch_before < ref->prefetch_before)
        ref->prefetch_before = prefetch_before;
 
@@ -668,8 +838,8 @@ prune_ref_by_group_reuse (struct mem_ref *ref, struct mem_ref *by,
   /* Try also the following iteration.  */
   prefetch_before++;
   delta = step - delta;
   /* Try also the following iteration.  */
   prefetch_before++;
   delta = step - delta;
-  if ((unsigned HOST_WIDE_INT) delta
-      <= (prefetch_block * ACCEPTABLE_MISS_RATE / 1000))
+  if (is_miss_rate_acceptable (prefetch_block, step, delta,
+                              reduced_prefetch_block, align_unit))
     {
       if (prefetch_before < ref->prefetch_before)
        ref->prefetch_before = prefetch_before;
     {
       if (prefetch_before < ref->prefetch_before)
        ref->prefetch_before = prefetch_before;
@@ -772,11 +942,20 @@ should_issue_prefetch_p (struct mem_ref *ref)
   /* For now do not issue prefetches for only first few of the
      iterations.  */
   if (ref->prefetch_before != PREFETCH_ALL)
   /* For now do not issue prefetches for only first few of the
      iterations.  */
   if (ref->prefetch_before != PREFETCH_ALL)
-    return false;
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+        fprintf (dump_file, "Ignoring %p due to prefetch_before\n",
+                (void *) ref);
+      return false;
+    }
 
   /* Do not prefetch nontemporal stores.  */
   if (ref->storent_p)
 
   /* Do not prefetch nontemporal stores.  */
   if (ref->storent_p)
-    return false;
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+        fprintf (dump_file, "Ignoring nontemporal store %p\n", (void *) ref);
+      return false;
+    }
 
   return true;
 }
 
   return true;
 }
@@ -818,6 +997,12 @@ schedule_prefetches (struct mem_ref_group *groups, unsigned unroll_factor,
        if (!should_issue_prefetch_p (ref))
          continue;
 
        if (!should_issue_prefetch_p (ref))
          continue;
 
+        /* The loop is far from being sufficiently unrolled for this
+           prefetch.  Do not generate prefetch to avoid many redudant
+           prefetches.  */
+        if (ref->prefetch_mod / unroll_factor > PREFETCH_MOD_TO_UNROLL_FACTOR_RATIO)
+          continue;
+
        /* If we need to prefetch the reference each PREFETCH_MOD iterations,
           and we unroll the loop UNROLL_FACTOR times, we need to insert
           ceil (UNROLL_FACTOR / PREFETCH_MOD) instructions in each
        /* If we need to prefetch the reference each PREFETCH_MOD iterations,
           and we unroll the loop UNROLL_FACTOR times, we need to insert
           ceil (UNROLL_FACTOR / PREFETCH_MOD) instructions in each
@@ -842,20 +1027,42 @@ schedule_prefetches (struct mem_ref_group *groups, unsigned unroll_factor,
   return any;
 }
 
   return any;
 }
 
-/* Determine whether there is any reference suitable for prefetching
-   in GROUPS.  */
+/* Return TRUE if no prefetch is going to be generated in the given
+   GROUPS.  */
 
 static bool
 
 static bool
-anything_to_prefetch_p (struct mem_ref_group *groups)
+nothing_to_prefetch_p (struct mem_ref_group *groups)
 {
   struct mem_ref *ref;
 
   for (; groups; groups = groups->next)
     for (ref = groups->refs; ref; ref = ref->next)
       if (should_issue_prefetch_p (ref))
 {
   struct mem_ref *ref;
 
   for (; groups; groups = groups->next)
     for (ref = groups->refs; ref; ref = ref->next)
       if (should_issue_prefetch_p (ref))
-       return true;
+       return false;
 
 
-  return false;
+  return true;
+}
+
+/* Estimate the number of prefetches in the given GROUPS.
+   UNROLL_FACTOR is the factor by which LOOP was unrolled.  */
+
+static int
+estimate_prefetch_count (struct mem_ref_group *groups, unsigned unroll_factor)
+{
+  struct mem_ref *ref;
+  unsigned n_prefetches;
+  int prefetch_count = 0;
+
+  for (; groups; groups = groups->next)
+    for (ref = groups->refs; ref; ref = ref->next)
+      if (should_issue_prefetch_p (ref))
+       {
+         n_prefetches = ((unroll_factor + ref->prefetch_mod - 1)
+                         / ref->prefetch_mod);
+         prefetch_count += n_prefetches;
+       }
+
+  return prefetch_count;
 }
 
 /* Issue prefetches for the reference REF into loop as decided before.
 }
 
 /* Issue prefetches for the reference REF into loop as decided before.
@@ -866,8 +1073,9 @@ static void
 issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead)
 {
   HOST_WIDE_INT delta;
 issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead)
 {
   HOST_WIDE_INT delta;
-  tree addr, addr_base, prefetch, write_p, local;
-  block_stmt_iterator bsi;
+  tree addr, addr_base, write_p, local, forward;
+  gimple prefetch;
+  gimple_stmt_iterator bsi;
   unsigned n_prefetches, ap;
   bool nontemporal = ref->reuse_distance >= L2_CACHE_SIZE_BYTES;
 
   unsigned n_prefetches, ap;
   bool nontemporal = ref->reuse_distance >= L2_CACHE_SIZE_BYTES;
 
@@ -876,29 +1084,42 @@ issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead)
             nontemporal ? " nontemporal" : "",
             (void *) ref);
 
             nontemporal ? " nontemporal" : "",
             (void *) ref);
 
-  bsi = bsi_for_stmt (ref->stmt);
+  bsi = gsi_for_stmt (ref->stmt);
 
   n_prefetches = ((unroll_factor + ref->prefetch_mod - 1)
                  / ref->prefetch_mod);
   addr_base = build_fold_addr_expr_with_type (ref->mem, ptr_type_node);
 
   n_prefetches = ((unroll_factor + ref->prefetch_mod - 1)
                  / ref->prefetch_mod);
   addr_base = build_fold_addr_expr_with_type (ref->mem, ptr_type_node);
-  addr_base = force_gimple_operand_bsi (&bsi, unshare_expr (addr_base),
-                                       true, NULL, true, BSI_SAME_STMT);
+  addr_base = force_gimple_operand_gsi (&bsi, unshare_expr (addr_base),
+                                       true, NULL, true, GSI_SAME_STMT);
   write_p = ref->write_p ? integer_one_node : integer_zero_node;
   write_p = ref->write_p ? integer_one_node : integer_zero_node;
-  local = build_int_cst (integer_type_node, nontemporal ? 0 : 3);
+  local = nontemporal ? integer_zero_node : integer_three_node;
 
   for (ap = 0; ap < n_prefetches; ap++)
     {
 
   for (ap = 0; ap < n_prefetches; ap++)
     {
-      /* Determine the address to prefetch.  */
-      delta = (ahead + ap * ref->prefetch_mod) * ref->group->step;
-      addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
-                         addr_base, size_int (delta));
-      addr = force_gimple_operand_bsi (&bsi, unshare_expr (addr), true, NULL,
-                                      true, BSI_SAME_STMT);
-
+      if (cst_and_fits_in_hwi (ref->group->step))
+        {
+          /* Determine the address to prefetch.  */
+          delta = (ahead + ap * ref->prefetch_mod) *
+                  int_cst_value (ref->group->step);
+          addr = fold_build_pointer_plus_hwi (addr_base, delta);
+          addr = force_gimple_operand_gsi (&bsi, unshare_expr (addr), true, NULL,
+                                           true, GSI_SAME_STMT);
+        }
+      else
+        {
+          /* The step size is non-constant but loop-invariant.  We use the
+             heuristic to simply prefetch ahead iterations ahead.  */
+          forward = fold_build2 (MULT_EXPR, sizetype,
+                                 fold_convert (sizetype, ref->group->step),
+                                 fold_convert (sizetype, size_int (ahead)));
+          addr = fold_build_pointer_plus (addr_base, forward);
+          addr = force_gimple_operand_gsi (&bsi, unshare_expr (addr), true,
+                                          NULL, true, GSI_SAME_STMT);
+      }
       /* Create the prefetch instruction.  */
       /* Create the prefetch instruction.  */
-      prefetch = build_call_expr (built_in_decls[BUILT_IN_PREFETCH],
-                                 3, addr, write_p, local);
-      bsi_insert_before (&bsi, prefetch, BSI_SAME_STMT);
+      prefetch = gimple_build_call (builtin_decl_explicit (BUILT_IN_PREFETCH),
+                                   3, addr, write_p, local);
+      gsi_insert_before (&bsi, prefetch, GSI_SAME_STMT);
     }
 }
 
     }
 }
 
@@ -940,7 +1161,7 @@ nontemporal_store_p (struct mem_ref *ref)
   if (mode == BLKmode)
     return false;
 
   if (mode == BLKmode)
     return false;
 
-  code = optab_handler (storent_optab, mode)->insn_code;
+  code = optab_handler (storent_optab, mode);
   return code != CODE_FOR_nothing;
 }
 
   return code != CODE_FOR_nothing;
 }
 
@@ -957,7 +1178,7 @@ mark_nontemporal_store (struct mem_ref *ref)
     fprintf (dump_file, "Marked reference %p as a nontemporal store.\n",
             (void *) ref);
 
     fprintf (dump_file, "Marked reference %p as a nontemporal store.\n",
             (void *) ref);
 
-  MOVE_NONTEMPORAL (ref->stmt) = true;
+  gimple_assign_set_nontemporal_move (ref->stmt, true);
   ref->storent_p = true;
 
   return true;
   ref->storent_p = true;
 
   return true;
@@ -970,22 +1191,22 @@ emit_mfence_after_loop (struct loop *loop)
 {
   VEC (edge, heap) *exits = get_loop_exit_edges (loop);
   edge exit;
 {
   VEC (edge, heap) *exits = get_loop_exit_edges (loop);
   edge exit;
-  tree call;
-  block_stmt_iterator bsi;
+  gimple call;
+  gimple_stmt_iterator bsi;
   unsigned i;
 
   unsigned i;
 
-  for (i = 0; VEC_iterate (edge, exits, i, exit); i++)
+  FOR_EACH_VEC_ELT (edge, exits, i, exit)
     {
     {
-      call = build_function_call_expr (FENCE_FOLLOWING_MOVNT, NULL_TREE);
+      call = gimple_build_call (FENCE_FOLLOWING_MOVNT, 0);
 
       if (!single_pred_p (exit->dest)
          /* If possible, we prefer not to insert the fence on other paths
             in cfg.  */
          && !(exit->flags & EDGE_ABNORMAL))
        split_loop_exit_edge (exit);
 
       if (!single_pred_p (exit->dest)
          /* If possible, we prefer not to insert the fence on other paths
             in cfg.  */
          && !(exit->flags & EDGE_ABNORMAL))
        split_loop_exit_edge (exit);
-      bsi = bsi_after_labels (exit->dest);
+      bsi = gsi_after_labels (exit->dest);
 
 
-      bsi_insert_before (&bsi, call, BSI_NEW_STMT);
+      gsi_insert_before (&bsi, call, GSI_NEW_STMT);
       mark_virtual_ops_for_renaming (call);
     }
 
       mark_virtual_ops_for_renaming (call);
     }
 
@@ -1011,7 +1232,7 @@ may_use_storent_in_loop_p (struct loop *loop)
       unsigned i;
       edge exit;
 
       unsigned i;
       edge exit;
 
-      for (i = 0; VEC_iterate (edge, exits, i, exit); i++)
+      FOR_EACH_VEC_ELT (edge, exits, i, exit)
        if ((exit->flags & EDGE_ABNORMAL)
            && exit->dest == EXIT_BLOCK_PTR)
          ret = false;
        if ((exit->flags & EDGE_ABNORMAL)
            && exit->dest == EXIT_BLOCK_PTR)
          ret = false;
@@ -1230,13 +1451,13 @@ self_reuse_distance (data_reference_p dr, unsigned *loop_sizes, unsigned n,
   strides = XCNEWVEC (HOST_WIDE_INT, n);
   access_fns = DR_ACCESS_FNS (dr);
 
   strides = XCNEWVEC (HOST_WIDE_INT, n);
   access_fns = DR_ACCESS_FNS (dr);
 
-  for (i = 0; VEC_iterate (tree, access_fns, i, access_fn); i++)
+  FOR_EACH_VEC_ELT (tree, access_fns, i, access_fn)
     {
       /* Keep track of the reference corresponding to the subscript, so that we
         know its stride.  */
       while (handled_component_p (ref) && TREE_CODE (ref) != ARRAY_REF)
        ref = TREE_OPERAND (ref, 0);
     {
       /* Keep track of the reference corresponding to the subscript, so that we
         know its stride.  */
       while (handled_component_p (ref) && TREE_CODE (ref) != ARRAY_REF)
        ref = TREE_OPERAND (ref, 0);
-      
+
       if (TREE_CODE (ref) == ARRAY_REF)
        {
          stride = TYPE_SIZE_UNIT (TREE_TYPE (ref));
       if (TREE_CODE (ref) == ARRAY_REF)
        {
          stride = TYPE_SIZE_UNIT (TREE_TYPE (ref));
@@ -1327,7 +1548,7 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
        continue;
 
       aloop = VEC_index (loop_p, vloops, i);
        continue;
 
       aloop = VEC_index (loop_p, vloops, i);
-      vol = estimated_loop_iterations_int (aloop, false);
+      vol = max_stmt_executions_int (aloop, false);
       if (vol < 0)
        vol = expected_loop_iterations (aloop);
       volume *= vol;
       if (vol < 0)
        vol = expected_loop_iterations (aloop);
       volume *= vol;
@@ -1340,7 +1561,8 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
   for (gr = refs; gr; gr = gr->next)
     for (ref = gr->refs; ref; ref = ref->next)
       {
   for (gr = refs; gr; gr = gr->next)
     for (ref = gr->refs; ref; ref = ref->next)
       {
-       dr = create_data_ref (nest, ref->mem, ref->stmt, !ref->write_p);
+       dr = create_data_ref (nest, loop_containing_stmt (ref->stmt),
+                             ref->mem, ref->stmt, !ref->write_p);
 
        if (dr)
          {
 
        if (dr)
          {
@@ -1352,10 +1574,10 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
          no_other_refs = false;
       }
 
          no_other_refs = false;
       }
 
-  for (i = 0; VEC_iterate (data_reference_p, datarefs, i, dr); i++)
+  FOR_EACH_VEC_ELT (data_reference_p, datarefs, i, dr)
     {
       dist = self_reuse_distance (dr, loop_data_size, n, loop);
     {
       dist = self_reuse_distance (dr, loop_data_size, n, loop);
-      ref = dr->aux;
+      ref = (struct mem_ref *) dr->aux;
       if (ref->reuse_distance > dist)
        ref->reuse_distance = dist;
 
       if (ref->reuse_distance > dist)
        ref->reuse_distance = dist;
 
@@ -1365,13 +1587,13 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
 
   compute_all_dependences (datarefs, &dependences, vloops, true);
 
 
   compute_all_dependences (datarefs, &dependences, vloops, true);
 
-  for (i = 0; VEC_iterate (ddr_p, dependences, i, dep); i++)
+  FOR_EACH_VEC_ELT (ddr_p, dependences, i, dep)
     {
       if (DDR_ARE_DEPENDENT (dep) == chrec_known)
        continue;
 
     {
       if (DDR_ARE_DEPENDENT (dep) == chrec_known)
        continue;
 
-      ref = DDR_A (dep)->aux;
-      refb = DDR_B (dep)->aux;
+      ref = (struct mem_ref *) DDR_A (dep)->aux;
+      refb = (struct mem_ref *) DDR_B (dep)->aux;
 
       if (DDR_ARE_DEPENDENT (dep) == chrec_dont_know
          || DDR_NUM_DIST_VECTS (dep) == 0)
 
       if (DDR_ARE_DEPENDENT (dep) == chrec_dont_know
          || DDR_NUM_DIST_VECTS (dep) == 0)
@@ -1379,7 +1601,7 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
          /* If the dependence cannot be analyzed, assume that there might be
             a reuse.  */
          dist = 0;
          /* If the dependence cannot be analyzed, assume that there might be
             a reuse.  */
          dist = 0;
-      
+
          ref->independent_p = false;
          refb->independent_p = false;
        }
          ref->independent_p = false;
          refb->independent_p = false;
        }
@@ -1444,6 +1666,112 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
     }
 }
 
     }
 }
 
+/* Determine whether or not the trip count to ahead ratio is too small based
+   on prefitablility consideration.
+   AHEAD: the iteration ahead distance,
+   EST_NITER: the estimated trip count.  */
+
+static bool
+trip_count_to_ahead_ratio_too_small_p (unsigned ahead, HOST_WIDE_INT est_niter)
+{
+  /* Assume trip count to ahead ratio is big enough if the trip count could not
+     be estimated at compile time.  */
+  if (est_niter < 0)
+    return false;
+
+  if (est_niter < (HOST_WIDE_INT) (TRIP_COUNT_TO_AHEAD_RATIO * ahead))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file,
+                "Not prefetching -- loop estimated to roll only %d times\n",
+                (int) est_niter);
+      return true;
+    }
+
+  return false;
+}
+
+/* Determine whether or not the number of memory references in the loop is
+   reasonable based on the profitablity and compilation time considerations.
+   NINSNS: estimated number of instructions in the loop,
+   MEM_REF_COUNT: total number of memory references in the loop.  */
+
+static bool
+mem_ref_count_reasonable_p (unsigned ninsns, unsigned mem_ref_count)
+{
+  int insn_to_mem_ratio;
+
+  if (mem_ref_count == 0)
+    return false;
+
+  /* Miss rate computation (is_miss_rate_acceptable) and dependence analysis
+     (compute_all_dependences) have high costs based on quadratic complexity.
+     To avoid huge compilation time, we give up prefetching if mem_ref_count
+     is too large.  */
+  if (mem_ref_count > PREFETCH_MAX_MEM_REFS_PER_LOOP)
+    return false;
+
+  /* Prefetching improves performance by overlapping cache missing
+     memory accesses with CPU operations.  If the loop does not have
+     enough CPU operations to overlap with memory operations, prefetching
+     won't give a significant benefit.  One approximate way of checking
+     this is to require the ratio of instructions to memory references to
+     be above a certain limit.  This approximation works well in practice.
+     TODO: Implement a more precise computation by estimating the time
+     for each CPU or memory op in the loop. Time estimates for memory ops
+     should account for cache misses.  */
+  insn_to_mem_ratio = ninsns / mem_ref_count;
+
+  if (insn_to_mem_ratio < PREFETCH_MIN_INSN_TO_MEM_RATIO)
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+        fprintf (dump_file,
+                "Not prefetching -- instruction to memory reference ratio (%d) too small\n",
+                insn_to_mem_ratio);
+      return false;
+    }
+
+  return true;
+}
+
+/* Determine whether or not the instruction to prefetch ratio in the loop is
+   too small based on the profitablity consideration.
+   NINSNS: estimated number of instructions in the loop,
+   PREFETCH_COUNT: an estimate of the number of prefetches,
+   UNROLL_FACTOR:  the factor to unroll the loop if prefetching.  */
+
+static bool
+insn_to_prefetch_ratio_too_small_p (unsigned ninsns, unsigned prefetch_count,
+                                     unsigned unroll_factor)
+{
+  int insn_to_prefetch_ratio;
+
+  /* Prefetching most likely causes performance degradation when the instruction
+     to prefetch ratio is too small.  Too many prefetch instructions in a loop
+     may reduce the I-cache performance.
+     (unroll_factor * ninsns) is used to estimate the number of instructions in
+     the unrolled loop.  This implementation is a bit simplistic -- the number
+     of issued prefetch instructions is also affected by unrolling.  So,
+     prefetch_mod and the unroll factor should be taken into account when
+     determining prefetch_count.  Also, the number of insns of the unrolled
+     loop will usually be significantly smaller than the number of insns of the
+     original loop * unroll_factor (at least the induction variable increases
+     and the exit branches will get eliminated), so it might be better to use
+     tree_estimate_loop_size + estimated_unrolled_size.  */
+  insn_to_prefetch_ratio = (unroll_factor * ninsns) / prefetch_count;
+  if (insn_to_prefetch_ratio < MIN_INSN_TO_PREFETCH_RATIO)
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+        fprintf (dump_file,
+                "Not prefetching -- instruction to prefetch ratio (%d) too small\n",
+                insn_to_prefetch_ratio);
+      return true;
+    }
+
+  return false;
+}
+
+
 /* Issue prefetch instructions for array references in LOOP.  Returns
    true if the LOOP was unrolled.  */
 
 /* Issue prefetch instructions for array references in LOOP.  Returns
    true if the LOOP was unrolled.  */
 
@@ -1455,53 +1783,73 @@ loop_prefetch_arrays (struct loop *loop)
   HOST_WIDE_INT est_niter;
   struct tree_niter_desc desc;
   bool unrolled = false, no_other_refs;
   HOST_WIDE_INT est_niter;
   struct tree_niter_desc desc;
   bool unrolled = false, no_other_refs;
+  unsigned prefetch_count;
+  unsigned mem_ref_count;
 
 
-  if (!maybe_hot_bb_p (loop->header))
+  if (optimize_loop_nest_for_size_p (loop))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "  ignored (cold area)\n");
       return false;
     }
 
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "  ignored (cold area)\n");
       return false;
     }
 
+  /* FIXME: the time should be weighted by the probabilities of the blocks in
+     the loop body.  */
+  time = tree_num_loop_insns (loop, &eni_time_weights);
+  if (time == 0)
+    return false;
+
+  ahead = (PREFETCH_LATENCY + time - 1) / time;
+  est_niter = max_stmt_executions_int (loop, false);
+
+  /* Prefetching is not likely to be profitable if the trip count to ahead
+     ratio is too small.  */
+  if (trip_count_to_ahead_ratio_too_small_p (ahead, est_niter))
+    return false;
+
+  ninsns = tree_num_loop_insns (loop, &eni_size_weights);
+
   /* Step 1: gather the memory references.  */
   /* Step 1: gather the memory references.  */
-  refs = gather_memory_references (loop, &no_other_refs);
+  refs = gather_memory_references (loop, &no_other_refs, &mem_ref_count);
+
+  /* Give up prefetching if the number of memory references in the
+     loop is not reasonable based on profitablity and compilation time
+     considerations.  */
+  if (!mem_ref_count_reasonable_p (ninsns, mem_ref_count))
+    goto fail;
 
   /* Step 2: estimate the reuse effects.  */
   prune_by_reuse (refs);
 
 
   /* Step 2: estimate the reuse effects.  */
   prune_by_reuse (refs);
 
-  if (!anything_to_prefetch_p (refs))
+  if (nothing_to_prefetch_p (refs))
     goto fail;
 
   determine_loop_nest_reuse (loop, refs, no_other_refs);
 
     goto fail;
 
   determine_loop_nest_reuse (loop, refs, no_other_refs);
 
-  /* Step 3: determine the ahead and unroll factor.  */
+  /* Step 3: determine unroll factor.  */
+  unroll_factor = determine_unroll_factor (loop, refs, ninsns, &desc,
+                                          est_niter);
 
 
-  /* FIXME: the time should be weighted by the probabilities of the blocks in
-     the loop body.  */
-  time = tree_num_loop_insns (loop, &eni_time_weights);
-  ahead = (PREFETCH_LATENCY + time - 1) / time;
-  est_niter = estimated_loop_iterations_int (loop, false);
+  /* Estimate prefetch count for the unrolled loop.  */
+  prefetch_count = estimate_prefetch_count (refs, unroll_factor);
+  if (prefetch_count == 0)
+    goto fail;
 
 
-  /* The prefetches will run for AHEAD iterations of the original loop.  Unless
-     the loop rolls at least AHEAD times, prefetching the references does not
-     make sense.  */
-  if (est_niter >= 0 && est_niter <= (HOST_WIDE_INT) ahead)
-    {
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       fprintf (dump_file,
-                "Not prefetching -- loop estimated to roll only %d times\n",
-                (int) est_niter);
-      goto fail;
-    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Ahead %d, unroll factor %d, trip count "
+            HOST_WIDE_INT_PRINT_DEC "\n"
+            "insn count %d, mem ref count %d, prefetch count %d\n",
+            ahead, unroll_factor, est_niter,
+            ninsns, mem_ref_count, prefetch_count);
+
+  /* Prefetching is not likely to be profitable if the instruction to prefetch
+     ratio is too small.  */
+  if (insn_to_prefetch_ratio_too_small_p (ninsns, prefetch_count,
+                                         unroll_factor))
+    goto fail;
 
   mark_nontemporal_stores (loop, refs);
 
 
   mark_nontemporal_stores (loop, refs);
 
-  ninsns = tree_num_loop_insns (loop, &eni_size_weights);
-  unroll_factor = determine_unroll_factor (loop, refs, ninsns, &desc,
-                                          est_niter);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Ahead %d, unroll factor %d\n", ahead, unroll_factor);
-
   /* Step 4: what to prefetch?  */
   if (!schedule_prefetches (refs, unroll_factor, ahead))
     goto fail;
   /* Step 4: what to prefetch?  */
   if (!schedule_prefetches (refs, unroll_factor, ahead))
     goto fail;
@@ -1552,22 +1900,24 @@ tree_ssa_prefetch_arrays (void)
               L1_CACHE_SIZE_BYTES / L1_CACHE_LINE_SIZE, L1_CACHE_SIZE);
       fprintf (dump_file, "    L1 cache line size: %d\n", L1_CACHE_LINE_SIZE);
       fprintf (dump_file, "    L2 cache size: %d kB\n", L2_CACHE_SIZE);
               L1_CACHE_SIZE_BYTES / L1_CACHE_LINE_SIZE, L1_CACHE_SIZE);
       fprintf (dump_file, "    L1 cache line size: %d\n", L1_CACHE_LINE_SIZE);
       fprintf (dump_file, "    L2 cache size: %d kB\n", L2_CACHE_SIZE);
+      fprintf (dump_file, "    min insn-to-prefetch ratio: %d \n",
+              MIN_INSN_TO_PREFETCH_RATIO);
+      fprintf (dump_file, "    min insn-to-mem ratio: %d \n",
+              PREFETCH_MIN_INSN_TO_MEM_RATIO);
       fprintf (dump_file, "\n");
     }
 
   initialize_original_copy_tables ();
 
       fprintf (dump_file, "\n");
     }
 
   initialize_original_copy_tables ();
 
-  if (!built_in_decls[BUILT_IN_PREFETCH])
+  if (!builtin_decl_explicit_p (BUILT_IN_PREFETCH))
     {
     {
-      tree type = build_function_type (void_type_node,
-                                      tree_cons (NULL_TREE,
-                                                 const_ptr_type_node,
-                                                 NULL_TREE));
+      tree type = build_function_type_list (void_type_node,
+                                           const_ptr_type_node, NULL_TREE);
       tree decl = add_builtin_function ("__builtin_prefetch", type,
                                        BUILT_IN_PREFETCH, BUILT_IN_NORMAL,
                                        NULL, NULL_TREE);
       DECL_IS_NOVOPS (decl) = true;
       tree decl = add_builtin_function ("__builtin_prefetch", type,
                                        BUILT_IN_PREFETCH, BUILT_IN_NORMAL,
                                        NULL, NULL_TREE);
       DECL_IS_NOVOPS (decl) = true;
-      built_in_decls[BUILT_IN_PREFETCH] = decl;
+      set_builtin_decl (BUILT_IN_PREFETCH, decl, false);
     }
 
   /* We assume that size of cache line is a power of two, so verify this
     }
 
   /* We assume that size of cache line is a power of two, so verify this