This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [patch] for PR 31676
- From: Zdenek Dvorak <rakdver at kam dot mff dot cuni dot cz>
- To: Mark Mitchell <mark at codesourcery dot com>
- Cc: Zdenek Dvorak <rakdver at atrey dot karlin dot mff dot cuni dot cz>, Eric Botcazou <ebotcazou at libertysurf dot fr>, gcc-patches at gcc dot gnu dot org
- Date: Wed, 2 May 2007 21:37:02 +0200
- Subject: Re: [patch] for PR 31676
- References: <20070427075335.GA30884@atrey.karlin.mff.cuni.cz> <200704281229.22533.ebotcazou@libertysurf.fr> <46363F2A.6010401@codesourcery.com> <20070430193924.GA8506@atrey.karlin.mff.cuni.cz> <4636488D.803@codesourcery.com>
Hello,
here is the patch, bootstrapped & regtested on i686 and ppc-linux.
Zdenek
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.
PR rtl-optimization/31676
* df-scan.c (record_nonlocal_goto_receiver_defs): New function.
(df_refs_record): Call it.
Index: cfgloopanal.c
===================================================================
*** cfgloopanal.c (revision 124303)
--- cfgloopanal.c (working copy)
*************** seq_cost (rtx seq)
*** 502,512 ****
/* 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. */
/* Initialize the constants for computing set costs. */
--- 502,514 ----
/* The properties of the target. */
unsigned target_avail_regs; /* Number of available registers. */
! 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. */
*************** init_set_costs (void)
*** 527,540 ****
target_res_regs = 3;
! /* These are really just heuristic values. */
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;
start_sequence ();
emit_move_insn (mem, reg1);
--- 529,548 ----
target_res_regs = 3;
! /* 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_reg_cost = seq_cost (seq);
start_sequence ();
emit_move_insn (mem, reg1);
*************** init_set_costs (void)
*** 544,570 ****
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. */
unsigned
! global_cost_for_size (unsigned size, unsigned regs_used, unsigned n_uses)
{
! unsigned regs_needed = regs_used + size;
! unsigned cost = 0;
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;
}
/* Sets EDGE_LOOP_EXIT flag for all exits of LOOPS. */
--- 552,577 ----
target_spill_cost = seq_cost (seq);
}
! /* 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
! estimate_reg_pressure_cost (unsigned n_new, unsigned n_old)
{
! 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)
! 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 exits of LOOPS. */
Index: testsuite/gcc.dg/loop-7.c
===================================================================
*** testsuite/gcc.dg/loop-7.c (revision 0)
--- testsuite/gcc.dg/loop-7.c (revision 0)
***************
*** 0 ****
--- 1,15 ----
+ /* PR rtl-optimization/31360 */
+
+ /* { dg-do compile { target { powerpc*-*-* } } } */
+ /* { dg-options "-O1 -dL" } */
+
+ 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" } } */
+
Index: df-scan.c
===================================================================
*** df-scan.c (revision 124303)
--- df-scan.c (working copy)
*************** df_bb_refs_record (struct dataflow *dflo
*** 1760,1765 ****
--- 1760,1791 ----
}
}
+ /* Records the implicit definitions at targets of nonlocal gotos in BLOCKS. */
+
+ static void
+ record_nonlocal_goto_receiver_defs (struct dataflow *dflow, bitmap blocks)
+ {
+ rtx x;
+ basic_block bb;
+
+ /* See expand_builtin_setjmp_receiver; hard_frame_pointer_rtx is used in
+ the nonlocal goto receiver, and needs to be considered defined
+ implicitly. */
+ if (!(dflow->flags & DF_HARD_REGS))
+ return;
+
+ for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
+ {
+ bb = BLOCK_FOR_INSN (XEXP (x, 0));
+ if (!bitmap_bit_p (blocks, bb->index))
+ continue;
+
+ df_ref_record (dflow, hard_frame_pointer_rtx, &hard_frame_pointer_rtx,
+ bb, NULL,
+ DF_REF_REG_DEF, DF_REF_ARTIFICIAL | DF_REF_AT_TOP,
+ false);
+ }
+ }
/* Record all the refs in the basic blocks specified by BLOCKS. */
*************** df_refs_record (struct dataflow *dflow,
*** 1780,1785 ****
--- 1806,1814 ----
if (bitmap_bit_p (blocks, ENTRY_BLOCK))
df_record_entry_block_defs (dflow);
+
+ if (current_function_has_nonlocal_label)
+ record_nonlocal_goto_receiver_defs (dflow, blocks);
}
Index: tree-ssa-loop-ivopts.c
===================================================================
*** tree-ssa-loop-ivopts.c (revision 124303)
--- tree-ssa-loop-ivopts.c (working copy)
*************** if (dump_file && (dump_flags & TDF_DETAI
*** 4401,4407 ****
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));
}
/* For each size of the induction variable set determine the penalty. */
--- 4401,4409 ----
static unsigned
ivopts_global_cost_for_size (struct ivopts_data *data, unsigned size)
{
! /* 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. */
*************** determine_set_costs (struct ivopts_data
*** 4438,4445 ****
{
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_spill_cost %d\n", target_spill_cost);
}
--- 4440,4446 ----
{
fprintf (dump_file, "Global costs:\n");
fprintf (dump_file, " target_avail_regs %d\n", target_avail_regs);
! fprintf (dump_file, " target_reg_cost %d\n", target_reg_cost);
fprintf (dump_file, " target_spill_cost %d\n", target_spill_cost);
}
Index: loop-invariant.c
===================================================================
*** loop-invariant.c (revision 124303)
--- loop-invariant.c (working copy)
*************** get_inv_cost (struct invariant *inv, int
*** 983,1019 ****
}
/* 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. */
static int
gain_for_invariant (struct invariant *inv, unsigned *regs_needed,
! unsigned new_regs, unsigned regs_used, unsigned n_inv_uses)
{
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));
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. */
static int
best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
! unsigned new_regs, unsigned regs_used,
! unsigned n_inv_uses)
{
struct invariant *inv;
int gain = 0, again;
--- 983,1016 ----
}
/* Calculates gain for eliminating invariant INV. REGS_USED is the number
! 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)
{
int comp_cost, size_cost;
get_inv_cost (inv, &comp_cost, regs_needed);
actual_stamp++;
! 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.
! 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)
{
struct invariant *inv;
int gain = 0, again;
*************** best_gain_for_invariant (struct invarian
*** 1028,1035 ****
if (inv->eqto != inv->invno)
continue;
! again = gain_for_invariant (inv, &aregs_needed,
! new_regs, regs_used, n_inv_uses);
if (again > gain)
{
gain = again;
--- 1025,1031 ----
if (inv->eqto != inv->invno)
continue;
! again = gain_for_invariant (inv, &aregs_needed, new_regs, regs_used);
if (again > gain)
{
gain = again;
*************** set_move_mark (unsigned invno)
*** 1070,1088 ****
static void
find_invariants_to_move (void)
{
! unsigned i, regs_used, n_inv_uses, 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. */
regs_used = 2;
for (i = 0; i < n_regs; i++)
--- 1066,1081 ----
static void
find_invariants_to_move (void)
{
! 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;
! /* 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++)
*************** find_invariants_to_move (void)
*** 1094,1108 ****
}
}
- 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)
{
set_move_mark (inv->invno);
new_regs += regs_needed;
--- 1087,1094 ----
}
}
new_regs = 0;
! while (best_gain_for_invariant (&inv, ®s_needed, new_regs, regs_used) > 0)
{
set_move_mark (inv->invno);
new_regs += regs_needed;
Index: cfgloop.h
===================================================================
*** cfgloop.h (revision 124303)
--- cfgloop.h (working copy)
*************** simple_loop_desc (struct loop *loop)
*** 367,384 ****
/* 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. */
/* Register pressure estimation for induction variable optimizations & loop
invariant motion. */
! extern unsigned global_cost_for_size (unsigned, unsigned, unsigned);
extern void init_set_costs (void);
/* Loop optimizer initialization. */
--- 367,380 ----
/* The properties of the target. */
! 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 estimate_reg_pressure_cost (unsigned, unsigned);
extern void init_set_costs (void);
/* Loop optimizer initialization. */