simplify-rtx.c (simplify_subreg): Simplify truncations of shifts of sign or zero...
authorRoger Sayle <roger@eyesopen.com>
Fri, 7 Jan 2005 00:47:13 +0000 (00:47 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Fri, 7 Jan 2005 00:47:13 +0000 (00:47 +0000)
* simplify-rtx.c (simplify_subreg): Simplify truncations of shifts
of sign or zero extended values.

From-SVN: r93022

gcc/ChangeLog
gcc/simplify-rtx.c

index 44ef9c7cb30253b8e8aeb35cb10db97d66092e09..965fe599e17785792455bd9aebdfb73ddd5e7051 100644 (file)
@@ -1,3 +1,8 @@
+2005-01-06  Roger Sayle  <roger@eyesopen.com>
+
+       * simplify-rtx.c (simplify_subreg): Simplify truncations of shifts
+       of sign or zero extended values.
+
 2005-01-06  Geoffrey Keating  <geoffk@apple.com>
 
        * c-cppbuiltin.c (builtin_define_float_constants): Set __*_EPSILON__
index 6e208aa9d9a6a4e269827a7421c83f374a76313f..0aa1e9576aa09124c74ea37a8dee7d5fcccab404 100644 (file)
@@ -3829,6 +3829,55 @@ simplify_subreg (enum machine_mode outermode, rtx op,
        return CONST0_RTX (outermode);
     }
 
+  /* Simplify (subreg:QI (lshiftrt:SI (sign_extend:SI (x:QI)) C), 0) into
+     to (ashiftrt:QI (x:QI) C), where C is a suitable small constant and
+     the outer subreg is effectively a truncation to the original mode.  */
+  if ((GET_CODE (op) == LSHIFTRT
+       || GET_CODE (op) == ASHIFTRT)
+      && SCALAR_INT_MODE_P (outermode)
+      /* Ensure that OUTERMODE is at least twice as wide as the INNERMODE
+        to avoid the possibility that an outer LSHIFTRT shifts by more
+        than the sign extension's sign_bit_copies and introduces zeros
+        into the high bits of the result.  */
+      && (2 * GET_MODE_BITSIZE (outermode)) <= GET_MODE_BITSIZE (innermode)
+      && GET_CODE (XEXP (op, 1)) == CONST_INT
+      && GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
+      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
+      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
+      && subreg_lsb_1 (outermode, innermode, byte) == 0)
+    return simplify_gen_binary (ASHIFTRT, outermode,
+                               XEXP (XEXP (op, 0), 0), XEXP (op, 1));
+
+  /* Likewise (subreg:QI (lshiftrt:SI (zero_extend:SI (x:QI)) C), 0) into
+     to (lshiftrt:QI (x:QI) C), where C is a suitable small constant and
+     the outer subreg is effectively a truncation to the original mode.  */
+  if ((GET_CODE (op) == LSHIFTRT
+       || GET_CODE (op) == ASHIFTRT)
+      && SCALAR_INT_MODE_P (outermode)
+      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
+      && GET_CODE (XEXP (op, 1)) == CONST_INT
+      && GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
+      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
+      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
+      && subreg_lsb_1 (outermode, innermode, byte) == 0)
+    return simplify_gen_binary (LSHIFTRT, outermode,
+                               XEXP (XEXP (op, 0), 0), XEXP (op, 1));
+
+  /* Likewise (subreg:QI (ashift:SI (zero_extend:SI (x:QI)) C), 0) into
+     to (ashift:QI (x:QI) C), where C is a suitable small constant and
+     the outer subreg is effectively a truncation to the original mode.  */
+  if (GET_CODE (op) == ASHIFT
+      && SCALAR_INT_MODE_P (outermode)
+      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
+      && GET_CODE (XEXP (op, 1)) == CONST_INT
+      && (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
+         || GET_CODE (XEXP (op, 0)) == SIGN_EXTEND)
+      && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
+      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
+      && subreg_lsb_1 (outermode, innermode, byte) == 0)
+    return simplify_gen_binary (ASHIFT, outermode,
+                               XEXP (XEXP (op, 0), 0), XEXP (op, 1));
+
   return NULL_RTX;
 }