* 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
+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
/* 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. */
/* 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. */
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);
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. */
}
/* 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;
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;
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++)
}
}
- 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;
+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.
--- /dev/null
+/* 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" } } */
+
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. */
{
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);
}