Commit a154b43a by Zdenek Dvorak Committed by Zdenek Dvorak

re PR rtl-optimization/31360 (RTL loop invariant is not aggressive enough)

	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.

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

From-SVN: r123919
parent faf28b3a
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> 2007-04-17 Peter Bergner <bergner@vnet.ibm.com>
* config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Force TDmode * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Force TDmode
......
...@@ -562,18 +562,14 @@ fel_init (loop_iterator *li, loop_p *loop, unsigned flags) ...@@ -562,18 +562,14 @@ fel_init (loop_iterator *li, loop_p *loop, unsigned flags)
/* The properties of the target. */ /* The properties of the target. */
extern unsigned target_avail_regs; /* Number of available registers. */ extern unsigned target_avail_regs;
extern unsigned target_res_regs; /* Number of reserved registers. */ extern unsigned target_res_regs;
extern unsigned target_small_cost; /* The cost for register when there extern unsigned target_reg_cost;
is a free one. */ extern unsigned target_spill_cost;
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. */
/* Register pressure estimation for induction variable optimizations & loop /* Register pressure estimation for induction variable optimizations & loop
invariant motion. */ 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); extern void init_set_costs (void);
/* Loop optimizer initialization. */ /* Loop optimizer initialization. */
......
...@@ -523,11 +523,13 @@ seq_cost (rtx seq) ...@@ -523,11 +523,13 @@ seq_cost (rtx seq)
/* The properties of the target. */ /* The properties of the target. */
unsigned target_avail_regs; /* Number of available registers. */ unsigned target_avail_regs; /* Number of available registers. */
unsigned target_res_regs; /* Number of reserved registers. */ unsigned target_res_regs; /* Number of registers reserved for temporary
unsigned target_small_cost; /* The cost for register when there is a free one. */ expressions. */
unsigned target_pres_cost; /* The cost for register when there are not too many unsigned target_reg_cost; /* The cost for register when there still
free ones. */ is some reserve, but we are approaching
unsigned target_spill_cost; /* The cost for register when we need to spill. */ 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. */ /* Initialize the constants for computing set costs. */
...@@ -548,14 +550,20 @@ init_set_costs (void) ...@@ -548,14 +550,20 @@ init_set_costs (void)
target_res_regs = 3; 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 (); start_sequence ();
emit_move_insn (reg1, reg2); emit_move_insn (reg1, reg2);
seq = get_insns (); seq = get_insns ();
end_sequence (); end_sequence ();
target_small_cost = seq_cost (seq); target_reg_cost = seq_cost (seq);
target_pres_cost = 2 * target_small_cost;
start_sequence (); start_sequence ();
emit_move_insn (mem, reg1); emit_move_insn (mem, reg1);
...@@ -565,27 +573,26 @@ init_set_costs (void) ...@@ -565,27 +573,26 @@ init_set_costs (void)
target_spill_cost = seq_cost (seq); target_spill_cost = seq_cost (seq);
} }
/* Calculates cost for having SIZE new loop global variables. REGS_USED is the /* Estimates cost of increased register pressure caused by making N_NEW new
number of global registers used in loop. N_USES is the number of relevant registers live around the loop. N_OLD is the number of registers live
variable uses. */ around the loop. */
unsigned 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 regs_needed = n_new + n_old;
unsigned cost = 0;
/* If we have enough registers, we should use them and not restrict
the transformations unnecessarily. */
if (regs_needed + target_res_regs <= target_avail_regs) if (regs_needed + target_res_regs <= target_avail_regs)
cost += target_small_cost * size; return 0;
else if (regs_needed <= target_avail_regs)
cost += target_pres_cost * size; /* If we are close to running out of registers, try to preserve them. */
else if (regs_needed <= target_avail_regs)
{ return target_reg_cost * n_new;
cost += target_pres_cost * size;
cost += target_spill_cost * n_uses * (regs_needed - target_avail_regs) / regs_needed; /* If we run out of registers, it is very expensive to add another one. */
} return target_spill_cost * n_new;
return cost;
} }
/* Sets EDGE_LOOP_EXIT flag for all loop exits. */ /* Sets EDGE_LOOP_EXIT flag for all loop exits. */
......
...@@ -983,37 +983,34 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed) ...@@ -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 /* 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 of registers used in the loop, NEW_REGS is the number of new variables
invariants, NEW_REGS is the number of new variables already added due to already added due to the invariant motion. The number of registers needed
the invariant motion. The number of registers needed for it is stored in for it is stored in *REGS_NEEDED. */
*REGS_NEEDED. */
static int static int
gain_for_invariant (struct invariant *inv, unsigned *regs_needed, 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; int comp_cost, size_cost;
get_inv_cost (inv, &comp_cost, regs_needed); get_inv_cost (inv, &comp_cost, regs_needed);
actual_stamp++; actual_stamp++;
size_cost = (global_cost_for_size (new_regs + *regs_needed, size_cost = (estimate_reg_pressure_cost (new_regs + *regs_needed, regs_used)
regs_used, n_inv_uses) - estimate_reg_pressure_cost (new_regs, regs_used));
- global_cost_for_size (new_regs, regs_used, n_inv_uses));
return comp_cost - size_cost; return comp_cost - size_cost;
} }
/* Finds invariant with best gain for moving. Returns the gain, stores /* Finds invariant with best gain for moving. Returns the gain, stores
the invariant in *BEST and number of registers needed for it to the invariant in *BEST and number of registers needed for it to
*REGS_NEEDED. REGS_USED is the number of registers used in *REGS_NEEDED. REGS_USED is the number of registers used in the loop.
the loop, N_INV_USES is the number of uses of invariants. NEW_REGS NEW_REGS is the number of new variables already added due to invariant
is the number of new variables already added due to invariant motion. */ motion. */
static int static int
best_gain_for_invariant (struct invariant **best, unsigned *regs_needed, best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
unsigned new_regs, unsigned regs_used, unsigned new_regs, unsigned regs_used)
unsigned n_inv_uses)
{ {
struct invariant *inv; struct invariant *inv;
int gain = 0, again; int gain = 0, again;
...@@ -1028,8 +1025,7 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed, ...@@ -1028,8 +1025,7 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
if (inv->eqto != inv->invno) if (inv->eqto != inv->invno)
continue; continue;
again = gain_for_invariant (inv, &aregs_needed, again = gain_for_invariant (inv, &aregs_needed, new_regs, regs_used);
new_regs, regs_used, n_inv_uses);
if (again > gain) if (again > gain)
{ {
gain = again; gain = again;
...@@ -1070,19 +1066,16 @@ set_move_mark (unsigned invno) ...@@ -1070,19 +1066,16 @@ set_move_mark (unsigned invno)
static void static void
find_invariants_to_move (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; struct invariant *inv = NULL;
unsigned int n_regs = DF_REG_SIZE (df); unsigned int n_regs = DF_REG_SIZE (df);
if (!VEC_length (invariant_p, invariants)) if (!VEC_length (invariant_p, invariants))
return; return;
/* Now something slightly more involved. First estimate the number of used /* We do not really do a good job in estimating number of registers used;
registers. */ we put some initial bound here to stand for induction variables etc.
n_inv_uses = 0; that we do not detect. */
/* 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. */
regs_used = 2; regs_used = 2;
for (i = 0; i < n_regs; i++) for (i = 0; i < n_regs; i++)
...@@ -1094,15 +1087,8 @@ find_invariants_to_move (void) ...@@ -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; new_regs = 0;
while (best_gain_for_invariant (&inv, &regs_needed, while (best_gain_for_invariant (&inv, &regs_needed, new_regs, regs_used) > 0)
new_regs, regs_used, n_inv_uses) > 0)
{ {
set_move_mark (inv->invno); set_move_mark (inv->invno);
new_regs += regs_needed; new_regs += regs_needed;
......
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> 2007-04-17 Mark Mitchell <mark@codesourcery.com>
* gcc.misc-tests/linkage.exp: Do not run on remote hosts. * gcc.misc-tests/linkage.exp: Do not run on remote hosts.
/* 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" } } */
...@@ -3908,7 +3908,9 @@ determine_iv_costs (struct ivopts_data *data) ...@@ -3908,7 +3908,9 @@ determine_iv_costs (struct ivopts_data *data)
static unsigned static unsigned
ivopts_global_cost_for_size (struct ivopts_data *data, unsigned size) 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. */ /* For each size of the induction variable set determine the penalty. */
...@@ -3945,8 +3947,7 @@ determine_set_costs (struct ivopts_data *data) ...@@ -3945,8 +3947,7 @@ determine_set_costs (struct ivopts_data *data)
{ {
fprintf (dump_file, "Global costs:\n"); fprintf (dump_file, "Global costs:\n");
fprintf (dump_file, " target_avail_regs %d\n", target_avail_regs); 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_reg_cost %d\n", target_reg_cost);
fprintf (dump_file, " target_pres_cost %d\n", target_pres_cost);
fprintf (dump_file, " target_spill_cost %d\n", target_spill_cost); fprintf (dump_file, " target_spill_cost %d\n", target_spill_cost);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment