commit 2cdd04f4de73db87b1f27d801922ff409ca7b3a8
Author: Jiong Wang <jiong.wang@arm.com>
Date: Tue Jul 29 14:57:01 2014 +0100
commit
@@ -2599,6 +2599,126 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
XEXP (op0, 1));
}
+ /* If we have
+
+ (ior (lshiftrt A imm1) (and (ashiftrt (A imm2)) mask))
+
+ where imm1 = imm2 + 1
+ mask = ((1 << imm1) - 1) << (mode_size (A) - imm1)
+
+ then we may simplify this into
+
+ (ashiftrt A imm1).
+
+ For example:
+
+ (ior:DI (lshiftrt:DI (reg:DI 79 [ data ])
+ (const_int 14 [0xe]))
+ (and:DI (ashiftrt:DI (reg:DI 79 [ data ])
+ (const_int 13 [0xd]))
+ (const_int -1125899906842624 [0xfffc000000000000]))).
+
+ is actually:
+
+ (ashiftrt:DI (reg:DI 79 [ data ]) (const_int 14 [0xe])).
+
+ There is another form:
+
+ (ior (lshiftrt A imm1)
+ (ashift (subreg (sign_extend A) high_offset) imm2)
+
+ where imm1 + imm2 == mode_size (A) could be simplified into
+
+ (ashiftrt A imm1). */
+
+ if (GET_CODE (op1) == LSHIFTRT)
+ {
+ opleft = op1;
+ opright = op0;
+ }
+ else
+ {
+ opright = op1;
+ opleft = op0;
+ }
+
+ if (GET_CODE (opleft) == LSHIFTRT
+ && GET_CODE (opright) == ASHIFT
+ && CONST_INT_P (XEXP (opleft, 1))
+ && CONST_INT_P (XEXP (opright, 1))
+ && (INTVAL (XEXP (opleft, 1)) + INTVAL (XEXP (opright, 1)))
+ == GET_MODE_SIZE (GET_MODE (XEXP (opleft, 0)))
+ && GET_CODE (XEXP (opright, 0)) == SUBREG
+ && GET_CODE (XEXP (XEXP (opright, 0), 0)) == SIGN_EXTEND
+ && (SUBREG_BYTE (XEXP (opright, 0))
+ == subreg_highpart_offset (GET_MODE (XEXP (opright, 0)),
+ GET_MODE (XEXP (XEXP (opright, 0),
+ 0))))
+ && rtx_equal_p (XEXP (opleft, 0), XEXP (XEXP (XEXP (opright, 0), 0),
+ 0))
+ && !side_effects_p (XEXP (opleft, 0))
+ && have_insn_for (ASHIFTRT, mode))
+ return simplify_gen_binary (ASHIFTRT, mode, XEXP (opleft, 0),
+ XEXP (opleft, 1));
+
+ if (GET_CODE (opleft) == LSHIFTRT
+ && GET_CODE (opright) == AND
+ && CONST_INT_P (XEXP (opleft, 1))
+ && CONST_INT_P (XEXP (opright, 1))
+ && GET_CODE (XEXP (opright, 0)) == ASHIFTRT
+ && CONST_INT_P (XEXP (XEXP (opright, 0), 1))
+ && rtx_equal_p (XEXP (opleft, 0), XEXP (XEXP (opright, 0), 0))
+ && !side_effects_p (XEXP (opleft, 0))
+ && have_insn_for (ASHIFTRT, mode))
+ {
+ int lshiftrt_imm = INTVAL (XEXP (opleft, 1));
+ HOST_WIDE_INT mask_nonzero_part, and_mask = INTVAL (XEXP (opright, 1));
+ int ashiftrt_imm, t_zero, l_one;
+
+ if (width < HOST_BITS_PER_WIDE_INT)
+ and_mask &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+
+ if (!and_mask)
+ return opleft;
+
+ ashiftrt_imm = INTVAL (XEXP (XEXP (opright, 0), 1));
+#if GCC_VERSION >= 3004
+ t_zero = (width <= HOST_BITS_PER_INT
+ ? __builtin_ctz (and_mask)
+ : (width <= HOST_BITS_PER_LONG
+ ? __builtin_ctzl (and_mask)
+ : __builtin_ctzll (and_mask)));
+#else
+ t_zero = 0;
+ while (((~and_mask) >> t_zero) & 1)
+ ++t_zero;
+#endif
+ mask_nonzero_part = (((unsigned HOST_WIDE_INT) and_mask) >> t_zero);
+#if GCC_VERSION >= 3400
+ l_one = (width <= HOST_BITS_PER_INT
+ ? __builtin_popcount (mask_nonzero_part)
+ : (width <= HOST_BITS_PER_LONG
+ ? __builtin_popcountl (mask_nonzero_part)
+ : __builtin_popcountll (mask_nonzero_part)));
+#else
+ /* calculate the number of leading 1-bits.
+ we use _popcount above, because the second condition check
+ of "if" below will make sure there is no gap between
+ those 1-bits. */
+ l_one = sizeof (and_mask) * CHAR_BIT;
+ while ((and_mask >> (l_one - 1)) & 1)
+ --l_one;
+ l_one = sizeof (and_mask) * CHAR_BIT - l_one;
+#endif
+
+ if ((ashiftrt_imm + 1) == lshiftrt_imm
+ && (mask_nonzero_part
+ == ((HOST_WIDE_INT_C (1) << (ashiftrt_imm + 1)) - 1))
+ && lshiftrt_imm == l_one)
+ return simplify_gen_binary (ASHIFTRT, mode, XEXP (opleft, 0),
+ XEXP (opleft, 1));
+ }
+
tem = simplify_byte_swapping_operation (code, mode, op0, op1);
if (tem)
return tem;
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile { target aarch64*-*-* mips64*-*-* sparc64*-*-* } } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-O2 -fdump-rtl-combine" } */
+
+__int128_t
+load2 (int data)
+{
+ return (__int128_t) data << 50;
+}
+
+/* { dg-final { scan-rtl-dump-not "ior" "combine" } } */
+/* { dg-final { cleanup-rtl-dump "combine" } } */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile { target arm*-*-* mips*-*-* sparc*-*-* } } */
+/* { dg-options "-O2 -fdump-rtl-combine" } */
+
+long long
+load1 (int data)
+{
+ return (long long) data << 12;
+}
+
+/* { dg-final { scan-rtl-dump-not "ior" "combine" } } */
+/* { dg-final { cleanup-rtl-dump "combine" } } */
new file mode 100644
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -save-temps" } */
+
+extern void abort (void);
+
+#define GEN_TEST_CASE(x, y, z)\
+__uint128_t __attribute__ ((noinline))\
+ushift_##x##_##z (unsigned y data)\
+{\
+ return (__uint128_t) data << x;\
+}\
+__int128_t __attribute__ ((noinline)) \
+shift_##x##_##z (y data) \
+{\
+ return (__int128_t) data << x;\
+}
+
+GEN_TEST_CASE (53, int, i)
+GEN_TEST_CASE (3, long long, ll)
+GEN_TEST_CASE (13, long long, ll)
+GEN_TEST_CASE (53, long long, ll)
+
+int
+main (int argc, char **argv)
+{
+
+#define SHIFT_CHECK(x, y, z, p) \
+ if (ushift_##y##_##p (x)\
+ != ((__uint128_t) (unsigned z) x << y)) \
+ abort ();\
+ if (shift_##y##_##p (x)\
+ != ((__uint128_t) (signed z) x << y)) \
+ abort ();
+
+ SHIFT_CHECK (0x12345678, 53, int, i)
+ SHIFT_CHECK (0xcafecafe, 53, int, i)
+
+ SHIFT_CHECK (0x1234567890abcdefLL, 3, long long, ll)
+ SHIFT_CHECK (0x1234567890abcdefLL, 13, long long, ll)
+ SHIFT_CHECK (0x1234567890abcdefLL, 53, long long, ll)
+ SHIFT_CHECK (0xcafecafedeaddeadLL, 3, long long, ll)
+ SHIFT_CHECK (0xcafecafedeaddeadLL, 13, long long, ll)
+ SHIFT_CHECK (0xcafecafedeaddeadLL, 53, long long, ll)
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "asr" 4 } } */
+/* { dg-final { cleanup-saved-temps } } */
new file mode 100644
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -save-temps" } */
+
+extern void abort (void);
+
+#define GEN_TEST_CASE(x)\
+unsigned long long __attribute__ ((noinline))\
+ushift_ ## x (unsigned int data)\
+{\
+ return (unsigned long long) data << x;\
+}\
+long long __attribute__ ((noinline)) \
+shift_ ## x (int data) \
+{\
+ return (long long) data << x;\
+}
+
+GEN_TEST_CASE (3)
+GEN_TEST_CASE (23)
+GEN_TEST_CASE (30)
+int
+main (int argc, char **argv)
+{
+
+#define SHIFT_CHECK(x, y) \
+ if (ushift_ ## y (x)\
+ != ((unsigned long long) (unsigned) x << y)) \
+ abort (); \
+ if (shift_ ## y (x)\
+ != ((long long) (signed) x << y)) \
+ abort ();
+
+ SHIFT_CHECK (0x12345678, 3)
+ SHIFT_CHECK (0xcafecafe, 3)
+ SHIFT_CHECK (0x12345678, 23)
+ SHIFT_CHECK (0xcafecafe, 23)
+ SHIFT_CHECK (0x12345678, 30)
+ SHIFT_CHECK (0xcafecafe, 30)
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "asr" 3 } } */
+/* { dg-final { cleanup-saved-temps } } */