Patch to fix register allocation bug

Richard Sandiford rsandifo@redhat.com
Mon Nov 18 02:46:00 GMT 2002


This patch fixes a bug (seen on sh5) in which pseudos with
overlapping lifetimes were allocated to the same hard register.

One of the pseudos was SFmode and the other was DFmode.
The SFmode register was allocated during local-alloc but
the other was left to global-alloc.  When its turn came,
there were no suitable registers free, and we hit this
code in global.c:find_reg():

  /* If we haven't succeeded yet,
     see if some hard reg that conflicts with us
     was utilized poorly by local-alloc.
     If so, kick out the regs that were put there by local-alloc
     so we can use it instead.  */
  if (best_reg < 0 && !retrying
      /* Let's not bother with multi-reg allocnos.  */
      && allocno[num].size == 1)
    {

This code "kicked out" another SFmode pseudo and replaced it by our
DFmode one.  But on this target, DFmode values take two registers.
The pseudo allocated to the second register wasn't kicked out.

It's clear that the code was written for pseudos that need only
one hard register, but checking allocno[num].size isn't enough,
because it gives the register's size in words.  In this case
words are 64 bits wide, but 64-bit values could still need
more than one register.

Patch tested on sh64-elf.  Fixes the attached test case.
OK to install?


	* global.c (find_reg): Check HARD_REGNO_NREGS before kicking
	out another register.

Index: global.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/global.c,v
retrieving revision 1.86
diff -c -d -p -F^[(a-zA-Z0-9_^#] -r1.86 global.c
*** global.c	4 Nov 2002 16:57:01 -0000	1.86
--- global.c	12 Nov 2002 12:48:01 -0000
*************** #endif
*** 1192,1197 ****
--- 1192,1202 ----
  	      /* Don't use a reg no good for this pseudo.  */
  	      && ! TEST_HARD_REG_BIT (used2, regno)
  	      && HARD_REGNO_MODE_OK (regno, mode)
+ 	      /* The code below assumes that we need only a single
+ 		 register, but the check of allocno[num].size above
+ 		 was not enough.  Sometimes we need more than one
+ 		 register for a single-word value.  */
+ 	      && HARD_REGNO_NREGS (regno, mode) == 1
  	      && (allocno[num].calls_crossed == 0
  		  || accept_call_clobbered
  		  || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
*** /dev/null	Tue Nov 14 21:44:43 2000
--- testsuite/gcc.c-torture/execute/20021112-2.c	Tue Nov 12 12:32:43 2002
***************
*** 0 ****
--- 1,58 ----
+ /* Macros to emit "L Nxx R" for each octal number xx between 000 and 037.  */
+ #define OP1(L, N, R, I, J) L N##I##J R
+ #define OP2(L, N, R, I) \
+     OP1(L, N, R, 0, I), OP1(L, N, R, 1, I), \
+     OP1(L, N, R, 2, I), OP1(L, N, R, 3, I)
+ #define OP(L, N, R) \
+     OP2(L, N, R, 0), OP2(L, N, R, 1), OP2(L, N, R, 2), OP2(L, N, R, 3), \
+     OP2(L, N, R, 4), OP2(L, N, R, 5), OP2(L, N, R, 6), OP2(L, N, R, 7)
+ 
+ /* Declare 32 unique variables with prefix N.  */
+ #define DECLARE(N) OP (, N,)
+ 
+ /* Copy 32 variables with prefix N from the array at ADDR.
+    Leave ADDR pointing to the end of the array.  */
+ #define COPYIN(N, ADDR) OP (, N, = *(ADDR++))
+ 
+ /* Likewise, but copy the other way.  */
+ #define COPYOUT(N, ADDR) OP (*(ADDR++) =, N,)
+ 
+ /* Add the contents of the array at ADDR to 32 variables with prefix N.
+    Leave ADDR pointing to the end of the array.  */
+ #define ADD(N, ADDR) OP (, N, += *(ADDR++))
+ 
+ volatile double gd[32];
+ volatile float gf[32];
+ 
+ void foo (int n)
+ {
+   double DECLARE(d);
+   float DECLARE(f);
+   volatile double *pd;
+   volatile float *pf;
+   int i;
+ 
+   pd = gd; COPYIN (d, pd);
+   for (i = 0; i < n; i++)
+     {
+       pf = gf; COPYIN (f, pf);
+       pd = gd; ADD (d, pd);
+       pd = gd; ADD (d, pd);
+       pd = gd; ADD (d, pd);
+       pf = gf; COPYOUT (f, pf);
+     }
+   pd = gd; COPYOUT (d, pd);
+ }
+ 
+ int main ()
+ {
+   int i;
+ 
+   for (i = 0; i < 32; i++)
+     gd[i] = i, gf[i] = i;
+   foo (1);
+   for (i = 0; i < 32; i++)
+     if (gd[i] != i * 4 || gf[i] != i)
+       abort ();
+   exit (0);
+ }



More information about the Gcc-patches mailing list