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]

REG_N_REFS vs regmove



After combine, REG_N_REFS is supposed to only be an approximation, and
inaccuracies in the reference count must be tolerated.

However two values for REG_N_REFS are special.

A value of zero will direct the register allocators to ignore the register.

A value of two means the register is set and used only once -- the
register allocators & reload handle this case specially.

We must never set REG_N_REFS to either of those values except when those
two special cases are true.

--

The regmove class tries to keep REG_N_REFS up to date as changes are
made.  However, since the starting value may be inaccurate, the final
value can also be inaccurate.

But regmove makes no attempt to ensure that it does not incorrectly
set REG_N_REFS to either of the special values.


Consider:

  Before flow we have a register X.  It is set once and referenced
  7 times.  REG_N_REFS is 8.

  Then pretend that due to combine's operations we end up with one
  set and 15 references to register X.  REG_N_REFS will still be
  8.

  Now pretend that regmove comes along and eliminates 6 references
  to register X.  REG_N_REFS will be set to the value 2, even though
  there's more than one set & use left in the RTL chain.

The net result is the allocators will perform invalid transformations
on the RTL and we either get incorrect code or the compiler core dumps.


This is in fact what happens on the PA when compiling spec92 after
applying rth's latest loop patch.  It also is likely the root cause
of a bug reported by someone else on this list (sorry, I don't have
the name handy).


regmove is not a pass I've spent a lot of time studying, so I'd like
Jim and/or Joern to look at this patch and comment on it.  It may be
the case that it's overly conservative -- I just don't know.

One could also argue that we should just fix the bloody reference
counts to be accurate.  Doing so might even help register allocation.


	* regmove.c (optimize_reg_copy_1): Make sure REG_N_REFS is
	at least 3 after decrementing it due to removing a reference.
	(optimize_reg_copy_2, fixup_match_2): Likewise.
	(regmove_optimize, fixup_match_1): Likewise.


Index: regmove.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/./gcc/regmove.c,v
retrieving revision 1.27
diff -c -3 -p -r1.27 regmove.c
*** regmove.c	1998/06/22 05:46:32	1.27
--- regmove.c	1998/06/26 05:34:05
*************** optimize_reg_copy_1 (insn, dest, src)
*** 294,299 ****
--- 294,305 ----
  			REG_N_REFS (sregno) -= loop_depth;
  		      if (dregno >= FIRST_PSEUDO_REGISTER)
  			REG_N_REFS (dregno) += loop_depth;
+ 
+ 		      /* REG_N_REFS is only an approximation after combine
+ 			 has finished.  We must not let its value decrease to
+ 			 two since that value has special meaning.  */
+ 		      if (REG_N_REFS (sregno) <= 2)
+ 			REG_N_REFS (sregno) = 3;
  		    }
  		  else
  		    {
*************** optimize_reg_copy_2 (insn, dest, src)
*** 444,449 ****
--- 450,461 ----
  		       no great harm is done.  */
  		    REG_N_REFS (dregno) -= loop_depth;
  		    REG_N_REFS (sregno) += loop_depth;
+ 
+ 		    /* REG_N_REFS is only an approximation after combine
+ 		       has finished.  We must not let its value decrease to
+ 		       two since that value has special meaning.  */
+ 		    if (REG_N_REFS (sregno) <= 2)
+ 		      REG_N_REFS (dregno) = 3;
  		  }
  
  
*************** fixup_match_2 (insn, dst, src, offset, r
*** 776,781 ****
--- 788,799 ----
  	      REG_N_REFS (REGNO (dst)) += loop_depth;
  	      REG_N_REFS (REGNO (src)) -= loop_depth;
  
+ 	      /* REG_N_REFS is only an approximation after combine
+ 		 has finished.  We must not let its value decrease to
+ 		 two since that value has special meaning.  */
+ 	      if (REG_N_REFS (REGNO (src)) <= 2)
+ 		REG_N_REFS (REGNO (src)) = 3;
+ 
  	      if (regmove_dump_file)
  		fprintf (regmove_dump_file,
  			 "Fixed operand of insn %d.\n",
*************** regmove_optimize (f, nregs, regmove_dump
*** 1299,1304 ****
--- 1317,1328 ----
  		  REG_N_REFS (dstno) += 2 * loop_depth;
  		  REG_N_REFS (srcno) -= 2 * loop_depth;
  
+ 		  /* REG_N_REFS is only an approximation after combine
+ 		     has finished.  We must not let its value decrease to
+ 		     two since that value has special meaning.  */
+ 		  if (REG_N_REFS (srcno) <= 2)
+ 		    REG_N_REFS (srcno) = 3;
+ 
                    /* If that was the only time src was set,
                       and src was not live at the start of the
                       function, we know that we have no more
*************** fixup_match_1 (insn, set, src, src_subre
*** 1744,1749 ****
--- 1768,1779 ----
  	      REG_N_REFS (REGNO (src)) -= true_loop_depth;
  	      REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
  	      insn_const = 0;
+ 
+ 	      /* REG_N_REFS is only an approximation after combine
+ 		 has finished.  We must not let its value decrease to
+ 		 two since that value has special meaning.  */
+ 	      if (REG_N_REFS (REGNO (src)) <= 2)
+ 		REG_N_REFS (REGNO (src)) = 3;
  	    }
  	}
      }
*************** fixup_match_1 (insn, set, src, src_subre
*** 1855,1860 ****
--- 1885,1896 ----
  
    REG_N_REFS (REGNO (src)) += 2 * true_loop_depth;
    REG_N_REFS (REGNO (dst)) -= 2 * true_loop_depth;
+ 
+   /* REG_N_REFS is only an approximation after combine
+      has finished.  We must not let its value decrease to
+      two since that value has special meaning.  */
+   if (REG_N_REFS (REGNO (dst)) <= 2)
+     REG_N_REFS (REGNO (dst)) = 3;
  
    /* If that was the only time dst was set,
       and dst was not live at the start of the










Jeff Law (law@cygnus.com)
Cygnus Solutions		EGCS GNU Compiler System
http://www.cygnus.com		http://www.cygnus.com/egcs



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