Hi!

The following testcase is miscompiled on s390-linux (31-bit).
r202393 changed:
@@ -11946,11 +11949,11 @@                                                       
                                                                   
          if (op1 == const0_rtx && (code == LT || code == GE)                   
                                                                   
              && HWI_COMPUTABLE_MODE_P (mode))                                  
                                                                   
            {                                                                   
                                                                   
+             unsigned HOST_WIDE_INT sign                                       
                                                                   
+               = (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1);  
                                                                   
              op0 = simplify_gen_binary (AND, tmode,                            
                                                                   
                                         gen_lowpart (tmode, op0),              
                                                                   
-                                        GEN_INT ((unsigned HOST_WIDE_INT) 1    
                                                                   
-                                                 << (GET_MODE_BITSIZE (mode)   
                                                                   
-                                                     - 1)));                   
                                                                   
+                                        gen_int_mode (sign, mode));            
                                                                   
              code = (code == LT) ? NE : EQ;                                    
                                                                   
              break;                                                            
                                                                   
            }                                                                   
                                                                   
This code creates AND of a paradoxical subreg where the bits above
mode are undefined, so of course the mask has to check just the single
sign bit rather than that bit + all bits above it.
In this particular testcase, mode is QImode and tmode is SImode,
previously and with my patch we were masking with 128, current 4.9 branch
and trunk masks with -128.

Bootstrapped/regtested on x86_64-linux, i686-linux and s390{,x}-linux.  Ok
for trunk/4.9?

2014-07-03  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/61673
        * combine.c (simplify_comparison): Test just mode's sign bit
        in tmode rather than the sign bit and any bits above it.

        * gcc.c-torture/execute/pr61673.c: New test.

--- gcc/combine.c.jj    2014-03-28 20:49:52.892077022 +0100
+++ gcc/combine.c       2014-07-02 16:56:02.260456040 +0200
@@ -11987,7 +11987,7 @@ simplify_comparison (enum rtx_code code,
                = (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1);
              op0 = simplify_gen_binary (AND, tmode,
                                         gen_lowpart (tmode, op0),
-                                        gen_int_mode (sign, mode));
+                                        gen_int_mode (sign, tmode));
              code = (code == LT) ? NE : EQ;
              break;
            }
--- gcc/testsuite/gcc.c-torture/execute/pr61673.c.jj    2014-07-02 
17:17:01.398908630 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr61673.c       2014-07-02 
17:12:36.000000000 +0200
@@ -0,0 +1,50 @@
+/* PR rtl-optimization/61673 */
+
+char e;
+
+__attribute__((noinline, noclone)) void
+bar (char x)
+{
+  if (x != 0x54 && x != (char) 0x87)
+    __builtin_abort ();
+}
+
+__attribute__((noinline, noclone)) void
+foo (const char *x)
+{
+  char d = x[0];
+  int c = d;
+  if ((c >= 0 && c <= 0x7f) == 0)
+    e = d;
+  bar (d);
+}
+
+__attribute__((noinline, noclone)) void
+baz (const char *x)
+{
+  char d = x[0];
+  int c = d;
+  if ((c >= 0 && c <= 0x7f) == 0)
+    e = d;
+}
+
+int
+main ()
+{
+  const char c[] = { 0x54, 0x87 };
+  e = 0x21;
+  foo (c);
+  if (e != 0x21)
+    __builtin_abort ();
+  foo (c + 1);
+  if (e != (char) 0x87)
+    __builtin_abort ();
+  e = 0x21;
+  baz (c);
+  if (e != 0x21)
+    __builtin_abort ();
+  baz (c + 1);
+  if (e != (char) 0x87)
+    __builtin_abort ();
+  return 0;
+}

        Jakub

Reply via email to