diff mbox

[wide-int] Tweak handling of rtx shifts

Message ID 87k3gljhjg.fsf@talisman.default
State New
Headers show

Commit Message

Richard Sandiford Nov. 6, 2013, 10:23 p.m. UTC
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
diff mbox

Patch

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: