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:
parent
faf28b3a89
commit
a154b43a81
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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, ®s_needed,
|
||||
new_regs, regs_used, n_inv_uses) > 0)
|
||||
while (best_gain_for_invariant (&inv, ®s_needed, new_regs, regs_used) > 0)
|
||||
{
|
||||
set_move_mark (inv->invno);
|
||||
new_regs += regs_needed;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue