This fixes a regression present on the mainline and 7 branch for IA-64 whereby 
the combiner wrongly infers that some bits are zero after a rotate operation 
because nonzero_bits says so for WORD_REGISTER_OPERATIONS machines.

As discussed in the audit trail, WORD_REGISTER_OPERATIONS is ambiguous because 
it isn't fully clear which operations are covered.  But it seems sensible to 
say that rotate operations are not, since neither defining nor leveraging what 
happens for the upper bits of a register when the lower bits are rotated seems 
straightforward.  So the attached patch just implements that.

There are two versions of the patch: one for the 7 branch which only does that 
and one for the mainline which additionally handles ROTATERT in nonzero_bits1 
(the RTL operation is already handled in the twin num_sign_bit_copies1).

Tested on IA-64/Linux and SPARC64/Linux, applied on mainline and 7 branch.


2018-01-12  Eric Botcazou  <ebotca...@adacore.com>

        PR rtl-optimization/83565
        * rtlanal.c (nonzero_bits1): On WORD_REGISTER_OPERATIONS machines, do
        not extend the result to a larger mode for rotate operations.
        (num_sign_bit_copies1): Likewise.


2018-01-12  Eric Botcazou  <ebotca...@adacore.com>

        * gcc.c-torture/execute/20180112-1.c: New test.

-- 
Eric Botcazou
Index: rtlanal.c
===================================================================
--- rtlanal.c	(revision 256562)
+++ rtlanal.c	(working copy)
@@ -4429,7 +4429,7 @@ nonzero_bits1 (const_rtx x, scalar_int_m
 {
   unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
   unsigned HOST_WIDE_INT inner_nz;
-  enum rtx_code code;
+  enum rtx_code code = GET_CODE (x);
   machine_mode inner_mode;
   unsigned int inner_width;
   scalar_int_mode xmode;
@@ -4465,16 +4465,16 @@ nonzero_bits1 (const_rtx x, scalar_int_m
     return nonzero;
 
   /* If MODE is wider than X, but both are a single word for both the host
-     and target machines, we can compute this from which bits of the
-     object might be nonzero in its own mode, taking into account the fact
-     that on many CISC machines, accessing an object in a wider mode
-     causes the high-order bits to become undefined.  So they are
-     not known to be zero.  */
-
-  if (!WORD_REGISTER_OPERATIONS
-      && mode_width > xmode_width
+     and target machines, we can compute this from which bits of the object
+     might be nonzero in its own mode, taking into account the fact that, on
+     CISC machines, accessing an object in a wider mode generally causes the
+     high-order bits to become undefined, so they are not known to be zero.
+     We extend this reasoning to RISC machines for rotate operations since the
+     semantics of the operations in the larger mode is not well defined.  */
+  if (mode_width > xmode_width
       && xmode_width <= BITS_PER_WORD
-      && xmode_width <= HOST_BITS_PER_WIDE_INT)
+      && xmode_width <= HOST_BITS_PER_WIDE_INT
+      && (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT))
     {
       nonzero &= cached_nonzero_bits (x, xmode,
 				      known_x, known_mode, known_ret);
@@ -4484,7 +4484,6 @@ nonzero_bits1 (const_rtx x, scalar_int_m
 
   /* Please keep nonzero_bits_binary_arith_p above in sync with
      the code in the switch below.  */
-  code = GET_CODE (x);
   switch (code)
     {
     case REG:
@@ -4760,10 +4759,11 @@ nonzero_bits1 (const_rtx x, scalar_int_m
 	}
       break;
 
+    case ASHIFT:
     case ASHIFTRT:
     case LSHIFTRT:
-    case ASHIFT:
     case ROTATE:
+    case ROTATERT:
       /* The nonzero bits are in two classes: any bits within MODE
 	 that aren't in xmode are always significant.  The rest of the
 	 nonzero bits are those that are significant in the operand of
@@ -4786,10 +4786,17 @@ nonzero_bits1 (const_rtx x, scalar_int_m
 	  if (mode_width > xmode_width)
 	    outer = (op_nonzero & nonzero & ~mode_mask);
 
-	  if (code == LSHIFTRT)
-	    inner >>= count;
-	  else if (code == ASHIFTRT)
+	  switch (code)
 	    {
+	    case ASHIFT:
+	      inner <<= count;
+	      break;
+
+	    case LSHIFTRT:
+	      inner >>= count;
+	      break;
+
+	    case ASHIFTRT:
 	      inner >>= count;
 
 	      /* If the sign bit may have been nonzero before the shift, we
@@ -4798,13 +4805,23 @@ nonzero_bits1 (const_rtx x, scalar_int_m
 	      if (inner & (HOST_WIDE_INT_1U << (xmode_width - 1 - count)))
 		inner |= (((HOST_WIDE_INT_1U << count) - 1)
 			  << (xmode_width - count));
+	      break;
+
+	    case ROTATE:
+	      inner = (inner << (count % xmode_width)
+		       | (inner >> (xmode_width - (count % xmode_width))))
+		      & mode_mask;
+	      break;
+
+	    case ROTATERT:
+	      inner = (inner >> (count % xmode_width)
+		       | (inner << (xmode_width - (count % xmode_width))))
+		      & mode_mask;
+	      break;
+
+	    default:
+	      gcc_unreachable ();
 	    }
-	  else if (code == ASHIFT)
-	    inner <<= count;
-	  else
-	    inner = ((inner << (count % xmode_width)
-		      | (inner >> (xmode_width - (count % xmode_width))))
-		     & mode_mask);
 
 	  nonzero &= (outer | inner);
 	}
@@ -4992,8 +5009,10 @@ num_sign_bit_copies1 (const_rtx x, scala
     {
       /* If this machine does not do all register operations on the entire
 	 register and MODE is wider than the mode of X, we can say nothing
-	 at all about the high-order bits.  */
-      if (!WORD_REGISTER_OPERATIONS)
+	 at all about the high-order bits.  We extend this reasoning to every
+	 machine for rotate operations since the semantics of the operations
+	 in the larger mode is not well defined.  */
+      if (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT)
 	return 1;
 
       /* Likewise on machines that do, if the mode of the object is smaller
Index: rtlanal.c
===================================================================
--- rtlanal.c	(revision 255413)
+++ rtlanal.c	(working copy)
@@ -4312,7 +4312,7 @@ nonzero_bits1 (const_rtx x, machine_mode
 {
   unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
   unsigned HOST_WIDE_INT inner_nz;
-  enum rtx_code code;
+  enum rtx_code code = GET_CODE (x);
   machine_mode inner_mode;
   unsigned int mode_width = GET_MODE_PRECISION (mode);
 
@@ -4335,18 +4335,18 @@ nonzero_bits1 (const_rtx x, machine_mode
     return nonzero;
 
   /* If MODE is wider than X, but both are a single word for both the host
-     and target machines, we can compute this from which bits of the
-     object might be nonzero in its own mode, taking into account the fact
-     that on many CISC machines, accessing an object in a wider mode
-     causes the high-order bits to become undefined.  So they are
-     not known to be zero.  */
-
-  if (!WORD_REGISTER_OPERATIONS
-      && GET_MODE (x) != VOIDmode
+     and target machines, we can compute this from which bits of the object
+     might be nonzero in its own mode, taking into account the fact that, on
+     CISC machines, accessing an object in a wider mode generally causes the
+     high-order bits to become undefined, so they are not known to be zero.
+     We extend this reasoning to RISC machines for rotate operations since the
+     semantics of the operations in the larger mode is not well defined.  */
+  if (GET_MODE (x) != VOIDmode
       && GET_MODE (x) != mode
       && GET_MODE_PRECISION (GET_MODE (x)) <= BITS_PER_WORD
       && GET_MODE_PRECISION (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
-      && GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (GET_MODE (x)))
+      && GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (GET_MODE (x))
+      && (!WORD_REGISTER_OPERATIONS || code == ROTATE))
     {
       nonzero &= cached_nonzero_bits (x, GET_MODE (x),
 				      known_x, known_mode, known_ret);
@@ -4356,7 +4356,6 @@ nonzero_bits1 (const_rtx x, machine_mode
 
   /* Please keep nonzero_bits_binary_arith_p above in sync with
      the code in the switch below.  */
-  code = GET_CODE (x);
   switch (code)
     {
     case REG:
@@ -4873,8 +4872,10 @@ num_sign_bit_copies1 (const_rtx x, machi
     {
       /* If this machine does not do all register operations on the entire
 	 register and MODE is wider than the mode of X, we can say nothing
-	 at all about the high-order bits.  */
-      if (!WORD_REGISTER_OPERATIONS)
+	 at all about the high-order bits.  We extend this reasoning to every
+	 machine for rotate operations since the semantics of the operations
+	 in the larger mode is not well defined.  */
+      if (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT)
 	return 1;
 
       /* Likewise on machines that do, if the mode of the object is smaller
/* PR rtl-optimization/83565 */
/* Testcase by Sergei Trofimovich <sly...@inbox.ru> */

extern void abort (void);

typedef unsigned int u32;

u32 bug (u32 * result) __attribute__((noinline));
u32 bug (u32 * result)
{
  volatile u32 ss = 0xFFFFffff;
  volatile u32 d  = 0xEEEEeeee;
  u32 tt = d & 0x00800000;
  u32 r  = tt << 8;

  r = (r >> 31) | (r <<  1);

  u32 u = r^ss;
  u32 off = u >> 1;

  *result = tt;
  return off;
}

int main(void)
{
  u32 l;
  u32 off = bug(&l);
  if (off != 0x7fffffff)
    abort ();
  return 0;
}

Reply via email to