[PATCH] S/390: Fix shifts and setmems predicates

Andreas Krebbel krebbel1@de.ibm.com
Thu Aug 25 08:15:00 GMT 2005


Hi,

debugging the potential reload problem with my patch omitting ANDs
applied to a shift count operand I found that even without the patch
we had a bug when eliminable regs appear within the shift count operand.

The problem occurs whenever a local stack address is used as a shift 
count operand and an immediate value is added:

return a << ((unsigned long)&f + 3);

is expanded and later on combined to:

(set (reg/i:DI 2 %r2 [ <result> ])
        (ashift:DI (reg:DI 2 %r2 [ a ])
            (plus:SI (subreg:SI (reg/f:DI 32 %ap) 4)
                (const_int 3 [0x3]))))

reload eliminates the argument pointer (32) to stack pointer + offset:

(set (reg/i:DI 2 %r2 [ <result> ])
        (ashift:DI (reg:DI 2 %r2 [ a ])
            (plus:SI (subreg:SI (plus:DI (reg/f:DI 15 %r15)
                                         (const_int 160 [0xa0])) 4)
                (const_int 3 [0x3]))))

Now the shift count operand is not even a general_operand anymore.

As Ulrich suggested avoiding eliminable registers to fix the new failures
(with eliminables within an AND) also helps in this case. 

The attached patch modifies the shift_count_operand and the setmem_operand 
to take care of this.

Bootstrapped and testsuite run without regressions on s390 and s390x.

OK for mainline?

Bye,

-Andreas-


2005-08-25  Andreas Krebbel  <krebbel1@de.ibm.com>

	* config/s390/predicates.md ("shift_count_operand", "setmem_operand"):
	Reject operands containing eliminable registers.
	* testsuite/gcc.dg/20050825-1.c: New testcase.


Index: gcc/config/s390/predicates.md
===================================================================
--- gcc/config/s390/predicates.md.orig	2005-08-24 13:09:28.000000000 +0200
+++ gcc/config/s390/predicates.md	2005-08-24 13:58:54.000000000 +0200
@@ -107,6 +107,10 @@
   if (op && GET_CODE (op) != REG)
     return false;
 
+  if (op && REGNO (op) < FIRST_PSEUDO_REGISTER
+      && !GENERAL_REGNO_P (REGNO (op)))
+    return false;
+
   /* Unfortunately we have to reject constants that are invalid
      for an address, or else reload will get confused.  */
   if (!DISP_IN_RANGE (offset))
@@ -147,6 +151,10 @@
   if (op && GET_CODE (op) != REG)
     return false;
 
+  if (op && REGNO (op) < FIRST_PSEUDO_REGISTER
+      && !GENERAL_REGNO_P (REGNO (op)))
+    return false;
+
   /* Unfortunately we have to reject constants that are invalid
      for an address, or else reload will get confused.  */
   if (!DISP_IN_RANGE (offset))
Index: gcc/testsuite/gcc.dg/20050824-1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.dg/20050824-1.c	2005-08-24 13:26:34.000000000 +0200
@@ -0,0 +1,30 @@
+/* Make sure that the S/390 specific shift_count_operand
+   predicate work properly.  */
+
+/* { dg-do compile { target s390*-*-* } } */
+/* { dg-options "-O3" } */
+
+unsigned long long
+f (unsigned long long a, unsigned long b)
+{
+  asm ("" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 
+                "r8", "r9", "r10", "r11", "r12", "r13", "r14");
+
+  return a << ((b + 3) & 63);
+}
+
+unsigned long long
+g (unsigned long long a, char **b , int c, int d, int e, int f)
+{
+  char buffer [4096];
+
+  *b = &buffer[0];
+
+  return a << ((unsigned long)&f & 63);
+}
+
+unsigned long long
+h (unsigned long long a, int b, int c, int d, int e, int f)
+{
+  return a << ((unsigned long)&f + 3);
+}



More information about the Gcc-patches mailing list