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] PR middle-end/27959 reload bug


Hello,

this fixes PR 27959. Here my description from the PR:

On s390 we use a trick to make the literal pool base register
available "on demand". It is defined as eliminable register
which can be eliminated to itself with offset 0. When a reload round
finds a r13 (literal pool base) it asks the back end whether it can
be eliminated and the back end says no. So reload throws any pseudos
out of r13 and marks it as bad_spill_regs_global hence it won't be
used as a reload register.

In the example there is no literal pool reference when entering reload.
So the initial elimination step marks r13 as eliminable and therefore free
to be used in reloads and it actually is used in a reload. In the second 
round reload forces a constant into the literal pool what creates a 
literal pool reference. When update_eliminables is called r13 is marked 
as cant_eliminate and the respective bit in bad_spill_regs_global is set. 
So far so good.

Unfortunately reload seems to think that registers which were once good to
be used in reloads will be good for future reloads as well - thats my
impression at least. The bitmap used_spill_regs is not reset between the
reload rounds. used_spill_regs is used in finish_spills to recalculate the
spill_regs array which then contains r13 since it was used as reload reg in the
first round.

The following patch deletes all registers which are recognized by
update_eliminables as eliminable_previous but cant_eliminate now from the
used_spill_regs bitmap and fixes the testcase.


Bootstrapped on i686, s390 and s390x with gcc 4.1.
No testsuite regressions

I've diffed the code generated for the cc1 executable on i686 and s390x and 
it showed no changes (except the part modified by the patch).

Ok for mainline and gcc 4.1? (given the mainline bootstrap is fine as well)

Bye,

-Andreas-


2006-06-13  Andreas Krebbel  <krebbel1@de.ibm.com>

	PR middle-end/27959
	* reload1.c (reload): Remove registers returned by update_eliminables
	from used_spill_regs.


2006-06-13  Andreas Krebbel  <krebbel1@de.ibm.com>

	PR middle-end/27959
	* gcc.dg/pr27959.c: New testcase.


Index: gcc/reload1.c
===================================================================
*** gcc/reload1.c.orig	2006-06-12 18:52:04.000000000 +0200
--- gcc/reload1.c	2006-06-12 18:52:24.000000000 +0200
*************** reload (rtx first, int global)
*** 987,992 ****
--- 987,994 ----
  	HARD_REG_SET to_spill;
  	CLEAR_HARD_REG_SET (to_spill);
  	update_eliminables (&to_spill);
+ 	AND_COMPL_HARD_REG_SET(used_spill_regs, to_spill);
+ 
  	for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	  if (TEST_HARD_REG_BIT (to_spill, i))
  	    {
Index: gcc/testsuite/gcc.dg/pr27959.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/pr27959.c	2006-06-12 18:52:24.000000000 +0200
***************
*** 0 ****
--- 1,93 ----
+ /* PR middle-end/27959 */
+ /* { dg-do run } */
+ /* { dg-options "-O2" } */
+ /* { dg-options "-O2 -mtune=z990" { target s390*-*-* } } */
+ 
+ extern void abort (void);
+ 
+ struct B
+ {
+   unsigned int b1, b2, b3;
+   char b4;
+ };
+ 
+ struct C
+ {
+   char c1;
+ };
+ 
+ struct D
+ {
+   char *d1;
+   struct C **d2;
+   unsigned int d3;
+ };
+ 
+ void
+ __attribute__((noinline))
+ foo (void *x, struct B *y, unsigned int *z)
+ {
+   if (x)
+     abort ();
+   if (y->b1 != 7 || y->b2 != 5 || y->b3 != 3 || y->b4)
+     abort ();
+   if (*z != 2)
+     abort ();
+ }
+ 
+ int
+ __attribute__((noinline))
+ baz (unsigned int *x, unsigned int y)
+ {
+   asm volatile ("" : : "r" (&x), "r" (&y) : "memory");
+   return *x + y;
+ }
+ 
+ inline int bar (unsigned int *x, unsigned int y)
+ {
+   if (y < *x)
+     return 0;
+   return baz (x, y);
+ }
+ 
+ unsigned int *
+ __attribute__((noinline))
+ test (struct D *x, unsigned int *y)
+ {
+   struct B b;
+   unsigned int c;
+ 
+   bar (y, x->d3);
+   if ((*(x->d2))->c1)
+     c = ((unsigned char) x->d1[0]
+ 	 + ((unsigned char) x->d1[1] << 8)
+ 	 + ((unsigned char) x->d1[2] << 16)
+ 	 + ((short) x->d1[3] << 24));
+   else
+     {
+       int d;
+       ((char *) &d)[0] = x->d1[0];
+       ((char *) &d)[1] = x->d1[1];
+       ((char *) &d)[2] = x->d1[2];
+       ((char *) &d)[3] = x->d1[3];
+       c = d;
+     }
+   b.b4 = 0;
+   b.b1 = c / 10000L % 10000;
+   b.b2 = c / 100 % 100;
+   b.b3 = c % 100;
+   foo (0, &b, y);
+   return y;
+ }
+ 
+ int
+ main (void)
+ {
+   unsigned int x = 900070503;
+   unsigned int y = 2;
+   struct C c = { 0 }, *cptr = &c;
+   struct D d = { (char *) &x, &cptr, 0 };
+   if (test (&d, &y) != &y)
+     abort ();
+   return 0;
+ }


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