PR rtl-optimization/31360
authorrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 Apr 2007 16:42:29 +0000 (16:42 +0000)
committerrakdver <rakdver@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 Apr 2007 16:42:29 +0000 (16:42 +0000)
* cfgloopanal.c (target_small_cost, target_pres_cost): Removed.
(target_reg_cost): New.
(init_set_costs): Initialize target_reg_cost.  Add comments
regarding the rationale of the costs.
(global_cost_for_size): Renamed to...
(estimate_reg_pressure_cost): ... and simplify.  Decrease importance
of register pressure.
* tree-ssa-loop-ivopts.c (ivopts_global_cost_for_size): Use
estimate_reg_pressure_cost.  Add number of ivs.
(determine_set_costs): Dump target_reg_cost.
* loop-invariant.c (gain_for_invariant):  Use
estimate_reg_pressure_cost.  Removed n_inv_uses argument.
(best_gain_for_invariant, find_invariants_to_move): Remove
n_inv_uses.
* cfgloop.h (target_small_cost, target_pres_cost): Removed.
(target_reg_cost): Declare.
(global_cost_for_size): Declaration removed.
(estimate_reg_pressure_cost): Declare.

* gcc.dg/loop-7.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@123919 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cfgloop.h
gcc/cfgloopanal.c
gcc/loop-invariant.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/loop-7.c [new file with mode: 0644]
gcc/tree-ssa-loop-ivopts.c

index 19525a3..55c0fa3 100644 (file)
@@ -1,3 +1,25 @@
+2007-04-17  Zdenek Dvorak  <dvorakz@suse.cz>
+
+       PR rtl-optimization/31360
+       * cfgloopanal.c (target_small_cost, target_pres_cost): Removed.
+       (target_reg_cost): New.
+       (init_set_costs): Initialize target_reg_cost.  Add comments
+       regarding the rationale of the costs.
+       (global_cost_for_size): Renamed to...
+       (estimate_reg_pressure_cost): ... and simplify.  Decrease importance
+       of register pressure.
+       * tree-ssa-loop-ivopts.c (ivopts_global_cost_for_size): Use
+       estimate_reg_pressure_cost.  Add number of ivs.
+       (determine_set_costs): Dump target_reg_cost.
+       * loop-invariant.c (gain_for_invariant):  Use
+       estimate_reg_pressure_cost.  Removed n_inv_uses argument.
+       (best_gain_for_invariant, find_invariants_to_move): Remove
+       n_inv_uses.
+       * cfgloop.h (target_small_cost, target_pres_cost): Removed.
+       (target_reg_cost): Declare.
+       (global_cost_for_size): Declaration removed.
+       (estimate_reg_pressure_cost): Declare.
+
 2007-04-17  Peter Bergner  <bergner@vnet.ibm.com>
 
        * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Force TDmode
index 15d5589..5216063 100644 (file)
@@ -562,18 +562,14 @@ fel_init (loop_iterator *li, loop_p *loop, unsigned flags)
 
 /* The properties of the target.  */
 
-extern unsigned target_avail_regs;     /* Number of available registers.  */
-extern unsigned target_res_regs;       /* Number of reserved registers.  */
-extern unsigned target_small_cost;     /* The cost for register when there
-                                          is a free one.  */
-extern unsigned target_pres_cost;      /* The cost for register when there are
-                                          not too many free ones.  */
-extern unsigned target_spill_cost;     /* The cost for register when we need
-                                          to spill.  */
+extern unsigned target_avail_regs;
+extern unsigned target_res_regs;
+extern unsigned target_reg_cost;
+extern unsigned target_spill_cost;
 
 /* Register pressure estimation for induction variable optimizations & loop
    invariant motion.  */
-extern unsigned global_cost_for_size (unsigned, unsigned, unsigned);
+extern unsigned estimate_reg_pressure_cost (unsigned, unsigned);
 extern void init_set_costs (void);
 
 /* Loop optimizer initialization.  */
index 4612ab8..7baa30a 100644 (file)
@@ -523,11 +523,13 @@ seq_cost (rtx seq)
 /* The properties of the target.  */
 
 unsigned target_avail_regs;    /* Number of available registers.  */
-unsigned target_res_regs;      /* Number of reserved registers.  */
-unsigned target_small_cost;    /* The cost for register when there is a free one.  */
-unsigned target_pres_cost;     /* The cost for register when there are not too many
-                                  free ones.  */
-unsigned target_spill_cost;    /* The cost for register when we need to spill.  */
+unsigned target_res_regs;      /* Number of registers reserved for temporary
+                                  expressions.  */
+unsigned target_reg_cost;      /* The cost for register when there still
+                                  is some reserve, but we are approaching
+                                  the number of available registers.  */
+unsigned target_spill_cost;    /* The cost for register when we need
+                                  to spill.  */
 
 /* Initialize the constants for computing set costs.  */
 
@@ -548,14 +550,20 @@ init_set_costs (void)
 
   target_res_regs = 3;
 
-  /* These are really just heuristic values.  */
+  /* Set up the costs for using extra registers:
+
+     1) If not many free registers remain, we should prefer having an
+       additional move to decreasing the number of available registers.
+       (TARGET_REG_COST).
+     2) If no registers are available, we need to spill, which may require
+       storing the old value to memory and loading it back
+       (TARGET_SPILL_COST).  */
 
   start_sequence ();
   emit_move_insn (reg1, reg2);
   seq = get_insns ();
   end_sequence ();
-  target_small_cost = seq_cost (seq);
-  target_pres_cost = 2 * target_small_cost;
+  target_reg_cost = seq_cost (seq);
 
   start_sequence ();
   emit_move_insn (mem, reg1);
@@ -565,27 +573,26 @@ init_set_costs (void)
   target_spill_cost = seq_cost (seq);
 }
 
-/* Calculates cost for having SIZE new loop global variables.  REGS_USED is the
-   number of global registers used in loop.  N_USES is the number of relevant
-   variable uses.  */
+/* Estimates cost of increased register pressure caused by making N_NEW new
+   registers live around the loop.  N_OLD is the number of registers live
+   around the loop.  */
 
 unsigned
-global_cost_for_size (unsigned size, unsigned regs_used, unsigned n_uses)
+estimate_reg_pressure_cost (unsigned n_new, unsigned n_old)
 {
-  unsigned regs_needed = regs_used + size;
-  unsigned cost = 0;
+  unsigned regs_needed = n_new + n_old;
 
+  /* If we have enough registers, we should use them and not restrict
+     the transformations unnecessarily.  */
   if (regs_needed + target_res_regs <= target_avail_regs)
-    cost += target_small_cost * size;
-  else if (regs_needed <= target_avail_regs)
-    cost += target_pres_cost * size;
-  else
-    {
-      cost += target_pres_cost * size;
-      cost += target_spill_cost * n_uses * (regs_needed - target_avail_regs) / regs_needed;
-    }
-
-  return cost;
+    return 0;
+
+  /* If we are close to running out of registers, try to preserve them.  */
+  if (regs_needed <= target_avail_regs)
+    return target_reg_cost * n_new;
+  
+  /* If we run out of registers, it is very expensive to add another one.  */
+  return target_spill_cost * n_new;
 }
 
 /* Sets EDGE_LOOP_EXIT flag for all loop exits.  */
index 4c6e8bc..304e424 100644 (file)
@@ -983,37 +983,34 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
 }
 
 /* Calculates gain for eliminating invariant INV.  REGS_USED is the number
-   of registers used in the loop, N_INV_USES is the number of uses of
-   invariants, NEW_REGS is the number of new variables already added due to
-   the invariant motion.  The number of registers needed for it is stored in
-   *REGS_NEEDED.  */
+   of registers used in the loop, NEW_REGS is the number of new variables
+   already added due to the invariant motion.  The number of registers needed
+   for it is stored in *REGS_NEEDED.  */
 
 static int
 gain_for_invariant (struct invariant *inv, unsigned *regs_needed,
-                   unsigned new_regs, unsigned regs_used, unsigned n_inv_uses)
+                   unsigned new_regs, unsigned regs_used)
 {
   int comp_cost, size_cost;
 
   get_inv_cost (inv, &comp_cost, regs_needed);
   actual_stamp++;
 
-  size_cost = (global_cost_for_size (new_regs + *regs_needed,
-                                    regs_used, n_inv_uses)
-              - global_cost_for_size (new_regs, regs_used, n_inv_uses));
+  size_cost = (estimate_reg_pressure_cost (new_regs + *regs_needed, regs_used)
+              - estimate_reg_pressure_cost (new_regs, regs_used));
 
   return comp_cost - size_cost;
 }
 
 /* Finds invariant with best gain for moving.  Returns the gain, stores
    the invariant in *BEST and number of registers needed for it to
-   *REGS_NEEDED.  REGS_USED is the number of registers used in
-   the loop, N_INV_USES is the number of uses of invariants.  NEW_REGS
-   is the number of new variables already added due to invariant motion.  */
+   *REGS_NEEDED.  REGS_USED is the number of registers used in the loop.
+   NEW_REGS is the number of new variables already added due to invariant
+   motion.  */
 
 static int
 best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
-                        unsigned new_regs, unsigned regs_used,
-                        unsigned n_inv_uses)
+                        unsigned new_regs, unsigned regs_used)
 {
   struct invariant *inv;
   int gain = 0, again;
@@ -1028,8 +1025,7 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
       if (inv->eqto != inv->invno)
        continue;
 
-      again = gain_for_invariant (inv, &aregs_needed,
-                                 new_regs, regs_used, n_inv_uses);
+      again = gain_for_invariant (inv, &aregs_needed, new_regs, regs_used);
       if (again > gain)
        {
          gain = again;
@@ -1070,19 +1066,16 @@ set_move_mark (unsigned invno)
 static void
 find_invariants_to_move (void)
 {
-  unsigned i, regs_used, n_inv_uses, regs_needed = 0, new_regs;
+  unsigned i, regs_used, regs_needed = 0, new_regs;
   struct invariant *inv = NULL;
   unsigned int n_regs = DF_REG_SIZE (df);
 
   if (!VEC_length (invariant_p, invariants))
     return;
 
-  /* Now something slightly more involved.  First estimate the number of used
-     registers.  */
-  n_inv_uses = 0;
-
-  /* We do not really do a good job in this estimation; put some initial bound
-     here to stand for induction variables etc. that we do not detect.  */
+  /* We do not really do a good job in estimating number of registers used;
+     we put some initial bound here to stand for induction variables etc.
+     that we do not detect.  */
   regs_used = 2;
 
   for (i = 0; i < n_regs; i++)
@@ -1094,15 +1087,8 @@ find_invariants_to_move (void)
        }
     }
 
-  for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
-    {
-      if (inv->def)
-       n_inv_uses += inv->def->n_uses;
-    }
-
   new_regs = 0;
-  while (best_gain_for_invariant (&inv, &regs_needed,
-                                 new_regs, regs_used, n_inv_uses) > 0)
+  while (best_gain_for_invariant (&inv, &regs_needed, new_regs, regs_used) > 0)
     {
       set_move_mark (inv->invno);
       new_regs += regs_needed;
index f04e498..36592ab 100644 (file)
@@ -1,3 +1,8 @@
+2007-04-17  Zdenek Dvorak  <dvorakz@suse.cz>
+
+       PR rtl-optimization/31360
+       * gcc.dg/loop-7.c: New test.
+
 2007-04-17  Mark Mitchell  <mark@codesourcery.com>
 
        * gcc.misc-tests/linkage.exp: Do not run on remote hosts.
diff --git a/gcc/testsuite/gcc.dg/loop-7.c b/gcc/testsuite/gcc.dg/loop-7.c
new file mode 100644 (file)
index 0000000..0457add
--- /dev/null
@@ -0,0 +1,16 @@
+/* PR rtl-optimization/31360  */
+
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-options "-O1 -fdump-rtl-loop2_invariant" } */
+
+void f(int *a)
+{
+  int i;
+  for (i = 0;i<100;i++)
+    a[i] = 0;
+}
+
+/* Load of 0 is moved out of the loop.  */
+/* { dg-final { scan-rtl-dump-times "Decided" 1 "loop2_invariant" } } */
+/* { dg-final { cleanup-rtl-dump "loop2_invariant" } } */
+
index 6e952af..d26608b 100644 (file)
@@ -3908,7 +3908,9 @@ determine_iv_costs (struct ivopts_data *data)
 static unsigned
 ivopts_global_cost_for_size (struct ivopts_data *data, unsigned size)
 {
-  return global_cost_for_size (size, data->regs_used, n_iv_uses (data));
+  /* We add size to the cost, so that we prefer eliminating ivs
+     if possible.  */
+  return size + estimate_reg_pressure_cost (size, data->regs_used);
 }
 
 /* For each size of the induction variable set determine the penalty.  */
@@ -3945,8 +3947,7 @@ determine_set_costs (struct ivopts_data *data)
     {
       fprintf (dump_file, "Global costs:\n");
       fprintf (dump_file, "  target_avail_regs %d\n", target_avail_regs);
-      fprintf (dump_file, "  target_small_cost %d\n", target_small_cost);
-      fprintf (dump_file, "  target_pres_cost %d\n", target_pres_cost);
+      fprintf (dump_file, "  target_reg_cost %d\n", target_reg_cost);
       fprintf (dump_file, "  target_spill_cost %d\n", target_spill_cost);
     }