This patch makes the shift code in simplify-rtx.c more like the CONST_INT
handling on mainline.  There we have:

        case LSHIFTRT:
        case ASHIFT:
        case ASHIFTRT:
          /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
             the value is in range.  We can't return any old value for
             out-of-range arguments because either the middle-end (via
             shift_truncation_mask) or the back-end might be relying on
             target-specific knowledge.  Nor can we rely on
             shift_truncation_mask, since the shift might not be part of an
             ashlM3, lshrM3 or ashrM3 instruction.  */
          if (SHIFT_COUNT_TRUNCATED)
            arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
          else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
            return 0;

          val = (code == ASHIFT
                 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
                 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);

          /* Sign-extend the result for arithmetic right shifts.  */
          if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
            val |= HOST_WIDE_INT_M1U << (width - arg1);
          break;

        case ROTATERT:
          if (arg1 < 0)
            return 0;

          arg1 %= width;
          val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
                 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
          break;

        case ROTATE:
          if (arg1 < 0)
            return 0;

          arg1 %= width;
          val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
                 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
          break;

The main points being:

- We don't care whether a shift (as opposed to rotate) amount appears
  negative if SHIFT_COUNT_TRUNCATED, since the macro means there's
  no such thing as a negative shift.

- !SHIFT_COUNT_TRUNCATED means that the target-independent code doesn't
  know how the target handles out-of-range shifts, so it shouldn't try
  to simplify them.

- With that change, the bitsize argument is redundant, since we already
  ensure that the argument is in [0, width), where width <= bitsize.

- We treat all nonnegative rotate amounts as being modulo the width,
  regardless of SHIFT_COUNT_TRUNCATED.  This goes back to the very
  early days of GCC so I don't think we should change it here.

Tested on powerpc64-linux-gnu and by comparing assembly code.  OK to install?

Thanks,
Richard


Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c  2013-11-04 09:07:28.343111332 +0000
+++ gcc/simplify-rtx.c  2013-11-04 21:08:24.937662430 +0000
@@ -3703,7 +3703,6 @@ simplify_const_binary_operation (enum rt
     {
       wide_int result;
       bool overflow;
-      unsigned int bitsize = GET_MODE_BITSIZE (mode);
       rtx_mode_t pop0 = std::make_pair (op0, mode);
       rtx_mode_t pop1 = std::make_pair (op1, mode); 
 
@@ -3785,36 +3784,46 @@ simplify_const_binary_operation (enum rt
        case LSHIFTRT:
        case ASHIFTRT:
        case ASHIFT:
-       case ROTATE:
-       case ROTATERT:
          {
            wide_int wop1 = pop1;
-           if (wi::neg_p (wop1))
-             return NULL_RTX;
-
            if (SHIFT_COUNT_TRUNCATED)
              wop1 = wi::umod_trunc (wop1, width);
+           else if (wi::geu_p (wop1, width))
+             return NULL_RTX;
 
            switch (code)
              {
              case LSHIFTRT:
-               result = wi::lrshift (pop0, wop1, bitsize);
+               result = wi::lrshift (pop0, wop1);
                break;
                
              case ASHIFTRT:
-               result = wi::arshift (pop0, wop1, bitsize);
+               result = wi::arshift (pop0, wop1);
                break;
                
              case ASHIFT:
-               result = wi::lshift (pop0, wop1, bitsize);
+               result = wi::lshift (pop0, wop1);
                break;
                
+             default:
+               gcc_unreachable ();
+             }
+           break;
+         }
+       case ROTATE:
+       case ROTATERT:
+         {
+           if (wi::neg_p (pop1))
+             return NULL_RTX;
+
+           switch (code)
+             {
              case ROTATE:
-               result = wi::lrotate (pop0, wop1);
+               result = wi::lrotate (pop0, pop1);
                break;
                
              case ROTATERT:
-               result = wi::rrotate (pop0, wop1);
+               result = wi::rrotate (pop0, pop1);
                break;
 
              default:

Reply via email to