Jiong Wang <jiong.w...@arm.com> 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

Reply via email to