This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] for PR 31676


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, &regs_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, &regs_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.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]