Jiong Wang <[email protected]> writes:
> + /* 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;
Please do this using wi:: instead, which in particular should make
the popcount stuff easier. E.g. the first large "if" would probably be:
if (GET_CODE (opleft) == LSHIFTRT
&& GET_CODE (opright) == ASHIFT
--> && CONST_SCALAR_INT_P (XEXP (opleft, 1))
--> && CONST_SCALAR_INT_P (XEXP (opright, 1))
--> && (wi::add (XEXP (opleft, 1), 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));
The HOST_WIDE_INTs in the second big "if" would then be wide_ints.
Thanks,
Richard