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]

[PATCH] Don't caller-save pseudos across calls that may throw (PR rtl-optimization/23478) (take 2)


On Mon, Aug 22, 2005 at 08:46:37AM -0700, Richard Henderson wrote:
> On Mon, Aug 22, 2005 at 11:28:22AM -0400, Jakub Jelinek wrote:
> > 	PR rtl-optimization/23478
> > 	* regs.h (reg_info): Add throw_calls_crossed.
> > 	(REG_N_THROWING_CALLS_CROSSED): Define.
> > 	* flow.c (allocate_reg_life_data): Initialize
> > 	REG_N_THROWING_CALLS_CROSSED.
> > 	(propagate_one_insn, attempt_auto_inc): Update
> > 	REG_N_THROWING_CALLS_CROSSED.
> > 	* global.c (global_alloc): Don't allocate pseudos across
> > 	calls that may throw.
> > 	* g++.dg/opt/pr23478.C: New test.
> 
> Ok everywhere.  This looks pretty safe.

Unfortunately, it seems this was a too big hammer.  The patch didn't
avoid putting pseudos live across calls that may throw only into call used
registers, but into any registers, so forced them all into memory.
This has apparently caused other latent bugs to pop up on ia64.

But we really don't need to force such pseudos into memory, all we need is
to force them not to be in call used registers (as the unwinder should
take care of restoring the call used registers during EH).

The following patch (on top of the already committed patch) does that.
Reverts the global.c change and just avoids caller save for pseudos that
ever live across calls that might throw.

I have bootstrapped/regtested it on HEAD/i386-linux, tested on 3.4/x86_64 that
the testcase passes (it fails there without the original 23478 patch)
and tested on HEAD/ia64 that the ada bootstrap problem is gone.

Ok for HEAD?  Ok to commit these 2 patches merged together to 4.0/3.4
(the first patch has been approved for 4.0/3.4, but I haven't applied it yet
as it caused problems on HEAD/ia64).

2005-08-31  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/23478
	* local-alloc.c (struct qty): Add n_throwing_calls_crossed field.
	(alloc_qty): Initialize it.
	(update_equiv_regs): Clear REG_N_THROWING_CALLS_CROSSED.
	(combine_regs): Combine also n_throwing_calls_crossed fields.
	(find_free_reg): Don't attempt to caller-save pseudos crossing
	calls that might throw.
	* global.c (struct allocno): Add throwing_calls_crossed field.
	(global_alloc): Revert 2005-08-22 change.  Initialize
	throwing_calls_crossed.
	(find_reg): Don't attempt to caller-save pseudos crossing calls that
	might throw.

--- gcc/local-alloc.c.jj	2005-07-07 13:04:10.000000000 +0200
+++ gcc/local-alloc.c	2005-08-31 08:38:06.000000000 +0200
@@ -123,6 +123,11 @@ struct qty
 
   int n_calls_crossed;
 
+  /* Number of times a reg tied to given qty lives across a CALL_INSN
+     that might throw.  */
+
+  int n_throwing_calls_crossed;
+
   /* The register number of one pseudo register whose reg_qty value is Q.
      This register should be the head of the chain
      maintained in reg_next_in_qty.  */
@@ -324,6 +329,7 @@ alloc_qty (int regno, enum machine_mode 
   qty[qtyno].mode = mode;
   qty[qtyno].birth = birth;
   qty[qtyno].n_calls_crossed = REG_N_CALLS_CROSSED (regno);
+  qty[qtyno].n_throwing_calls_crossed = REG_N_THROWING_CALLS_CROSSED (regno);
   qty[qtyno].min_class = reg_preferred_class (regno);
   qty[qtyno].alternate_class = reg_alternate_class (regno);
   qty[qtyno].n_refs = REG_N_REFS (regno);
@@ -1170,6 +1176,7 @@ update_equiv_regs (void)
 
 		      REG_BASIC_BLOCK (regno) = bb->index;
 		      REG_N_CALLS_CROSSED (regno) = 0;
+		      REG_N_THROWING_CALLS_CROSSED (regno) = 0;
 		      REG_LIVE_LENGTH (regno) = 2;
 
 		      if (insn == BB_HEAD (bb))
@@ -2011,6 +2018,8 @@ combine_regs (rtx usedreg, rtx setreg, i
 
       /* Update info about quantity SQTY.  */
       qty[sqty].n_calls_crossed += REG_N_CALLS_CROSSED (sreg);
+      qty[sqty].n_throwing_calls_crossed
+	+= REG_N_THROWING_CALLS_CROSSED (sreg);
       qty[sqty].n_refs += REG_N_REFS (sreg);
       qty[sqty].freq += REG_FREQ (sreg);
       if (usize < ssize)
@@ -2315,12 +2324,14 @@ find_free_reg (enum reg_class class, enu
 
   /* We need not check to see if the current function has nonlocal
      labels because we don't put any pseudos that are live over calls in
-     registers in that case.  */
+     registers in that case.  Avoid putting pseudos crossing calls that
+     might throw into call used registers.  */
 
   if (! accept_call_clobbered
       && flag_caller_saves
       && ! just_try_suggested
       && qty[qtyno].n_calls_crossed != 0
+      && qty[qtyno].n_throwing_calls_crossed == 0
       && CALLER_SAVE_PROFITABLE (qty[qtyno].n_refs,
 				 qty[qtyno].n_calls_crossed))
     {
--- gcc/global.c.jj	2005-08-27 10:12:45.000000000 +0200
+++ gcc/global.c	2005-08-31 08:32:48.000000000 +0200
@@ -97,6 +97,9 @@ struct allocno
   /* Number of calls crossed by each allocno.  */
   int calls_crossed;
 
+  /* Number of calls that might throw crossed by each allocno.  */
+  int throwing_calls_crossed;
+
   /* Number of refs to each allocno.  */
   int n_refs;
 
@@ -465,9 +468,7 @@ global_alloc (FILE *file)
 	/* Don't allocate pseudos that cross calls,
 	   if this function receives a nonlocal goto.  */
 	&& (! current_function_has_nonlocal_label
-	    || REG_N_CALLS_CROSSED (i) == 0)
-	/* Don't allocate pseudos that cross calls that may throw.  */
-	&& REG_N_THROWING_CALLS_CROSSED (i) == 0)
+	    || REG_N_CALLS_CROSSED (i) == 0))
       {
 	if (reg_renumber[i] < 0
 	    && reg_may_share[i] && reg_allocno[reg_may_share[i]] >= 0)
@@ -488,6 +489,8 @@ global_alloc (FILE *file)
 	allocno[num].reg = i;
 	allocno[num].size = PSEUDO_REGNO_SIZE (i);
 	allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
+	allocno[num].throwing_calls_crossed
+	  += REG_N_THROWING_CALLS_CROSSED (i);
 	allocno[num].n_refs += REG_N_REFS (i);
 	allocno[num].freq += REG_FREQ (i);
 	if (allocno[num].live_length < REG_LIVE_LENGTH (i))
@@ -1207,9 +1210,11 @@ find_reg (int num, HARD_REG_SET losers, 
     {
       /* Did not find a register.  If it would be profitable to
 	 allocate a call-clobbered register and save and restore it
-	 around calls, do that.  */
+	 around calls, do that.  Don't do this if it crosses any calls
+	 that might throw.  */
       if (! accept_call_clobbered
 	  && allocno[num].calls_crossed != 0
+	  && allocno[num].throwing_calls_crossed == 0
 	  && CALLER_SAVE_PROFITABLE (allocno[num].n_refs,
 				     allocno[num].calls_crossed))
 	{


	Jakub


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