From 25153338ebbedbe0f614bc9b994fa72c6fb38699 Mon Sep 17 00:00:00 2001 From: rakdver Date: Tue, 17 Apr 2007 16:42:29 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@123919 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 22 +++++++++++++++++ gcc/cfgloop.h | 14 ++++------- gcc/cfgloopanal.c | 55 ++++++++++++++++++++++++------------------- gcc/loop-invariant.c | 46 +++++++++++++----------------------- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gcc.dg/loop-7.c | 16 +++++++++++++ gcc/tree-ssa-loop-ivopts.c | 7 +++--- 7 files changed, 99 insertions(+), 66 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/loop-7.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 19525a3..55c0fa3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2007-04-17 Zdenek Dvorak + + 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 * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Force TDmode diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 15d5589..5216063 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -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. */ diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c index 4612ab8..7baa30a 100644 --- a/gcc/cfgloopanal.c +++ b/gcc/cfgloopanal.c @@ -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. */ diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c index 4c6e8bc..304e424 100644 --- a/gcc/loop-invariant.c +++ b/gcc/loop-invariant.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f04e498..36592ab 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-04-17 Zdenek Dvorak + + PR rtl-optimization/31360 + * gcc.dg/loop-7.c: New test. + 2007-04-17 Mark Mitchell * 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 index 0000000..0457add --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-7.c @@ -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" } } */ + diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 6e952af..d26608b 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -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); } -- 2.7.4