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
This commit is contained in:
Zdenek Dvorak 2007-04-17 18:42:29 +02:00 committed by Zdenek Dvorak
parent faf28b3a89
commit a154b43a81
7 changed files with 98 additions and 65 deletions

View 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

View 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. */

View 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 0;
return cost;
/* 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. */

View 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;

View 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.

View File

@ -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" } } */

View 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);
}