> Am 18.12.2024 um 03:19 schrieb Alexandre Oliva <ol...@adacore.com>:
> 
> 
> Some bitfield compares with zero are optimized to range tests, so
> instead of X & ~(Bit - 1) != 0 what reaches ifcombine is X > (Bit - 1),
> where Bit is a power of two and X is unsigned.
> 
> This patch recognizes this optimized form of masked compares, and
> attempts to merge them like masked compares, which enables some more
> field merging that a folder version of fold_truth_andor used to handle
> without additional effort.
> 
> I haven't seen X & ~(Bit - 1) == 0 become X <= (Bit - 1), or X < Bit
> for that matter, but it was easy enough to handle the former
> symmetrically to the above.
> 
> The latter was also easy enough, and so was its symmetric, X >= Bit,
> that is handled like X & ~(Bit - 1) != 0.
> 
> Regstrapped on x86_64-linux-gnu and ppc64-linux-gnu, along with 4 other
> ifcombine patches.  Ok to install?

Ok

Richard 

> 
> for  gcc/ChangeLog
> 
>    * gimple-fold.cc (decode_field_reference): Accept incoming
>    mask.
>    (fold_truth_andor_for_ifcombine): Handle some compares with
>    powers of two, minus 1 or 0, like masked compares with zero.
> 
> for  gcc/testsuite/ChangeLog
> 
>    * gcc.dg/field-merge-15.c: New.
> ---
> gcc/gimple-fold.cc                    |   71 ++++++++++++++++++++++++++++++++-
> gcc/testsuite/gcc.dg/field-merge-15.c |   36 +++++++++++++++++
> 2 files changed, 104 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/field-merge-15.c
> 
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index 06913d57f8aec..856ee5369a8c9 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -7509,8 +7509,10 @@ gimple_binop_def_p (enum tree_code code, tree t, tree 
> op[2])
> 
>    *PREVERSEP is set to the storage order of the field.
> 
> -   *PAND_MASK is set to the mask found in a BIT_AND_EXPR, if any.
> -   If PAND_MASK *is NULL, BIT_AND_EXPR is not recognized.
> +   *PAND_MASK is set to the mask found in a BIT_AND_EXPR, if any.  If
> +   PAND_MASK *is NULL, BIT_AND_EXPR is not recognized.  If *PAND_MASK
> +   is initially set to a mask with nonzero precision, that mask is
> +   combined with the found mask, or adjusted in precision to match.
> 
>    *XOR_P is to be FALSE if EXP might be a XOR used in a compare, in which
>    case, if XOR_CMP_OP is a zero constant, it will be overridden with *PEXP,
> @@ -7561,14 +7563,30 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT 
> *pbitsize,
>       exp = res_ops[0];
>     }
> 
> -  /* Recognize and save a masking operation.  */
> +  /* Recognize and save a masking operation.  Combine it with an
> +     incoming mask.  */
>   if (pand_mask && gimple_binop_def_p (BIT_AND_EXPR, exp, res_ops)
>       && uniform_integer_cst_p (res_ops[1]))
>     {
>       loc[1] = gimple_location (SSA_NAME_DEF_STMT (exp));
>       exp = res_ops[0];
>       and_mask = wi::to_wide (res_ops[1]);
> +      unsigned prec_in = pand_mask->get_precision ();
> +      if (prec_in)
> +    {
> +      unsigned prec_op = and_mask.get_precision ();
> +      if (prec_in >= prec_op)
> +        {
> +          if (prec_in > prec_op)
> +        and_mask = wide_int::from (and_mask, prec_in, UNSIGNED);
> +          and_mask &= *pand_mask;
> +        }
> +      else
> +        and_mask &= wide_int::from (*pand_mask, prec_op, UNSIGNED);
> +    }
>     }
> +  else if (pand_mask)
> +    and_mask = *pand_mask;
> 
>   /* Turn (a ^ b) [!]= 0 into a [!]= b.  */
>   if (xor_p && gimple_binop_def_p (BIT_XOR_EXPR, exp, res_ops)
> @@ -8019,6 +8037,8 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
> tree truth_type,
>       return 0;
>     }
> 
> +  /* Prepare to turn compares of signed quantities with zero into
> +     sign-bit tests.  */
>   bool lsignbit = false, rsignbit = false;
>   if ((lcode == LT_EXPR || lcode == GE_EXPR)
>       && integer_zerop (lr_arg)
> @@ -8028,6 +8048,31 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
> tree truth_type,
>       lsignbit = true;
>       lcode = (lcode == LT_EXPR ? NE_EXPR : EQ_EXPR);
>     }
> +  /* Turn compares of unsigned quantities with powers of two into
> +     equality tests of masks.  */
> +  else if ((lcode == LT_EXPR || lcode == GE_EXPR)
> +       && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg))
> +       && TYPE_UNSIGNED (TREE_TYPE (ll_arg))
> +       && uniform_integer_cst_p (lr_arg)
> +       && wi::popcount (wi::to_wide (lr_arg)) == 1)
> +    {
> +      ll_and_mask = ~(wi::to_wide (lr_arg) - 1);
> +      lcode = (lcode == GE_EXPR ? NE_EXPR : EQ_EXPR);
> +      lr_arg = wide_int_to_tree (TREE_TYPE (ll_arg), ll_and_mask * 0);
> +    }
> +  /* Turn compares of unsigned quantities with powers of two minus one
> +     into equality tests of masks.  */
> +  else if ((lcode == LE_EXPR || lcode == GT_EXPR)
> +       && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg))
> +       && TYPE_UNSIGNED (TREE_TYPE (ll_arg))
> +       && uniform_integer_cst_p (lr_arg)
> +       && wi::popcount (wi::to_wide (lr_arg) + 1) == 1)
> +    {
> +      ll_and_mask = ~wi::to_wide (lr_arg);
> +      lcode = (lcode == GT_EXPR ? NE_EXPR : EQ_EXPR);
> +      lr_arg = wide_int_to_tree (TREE_TYPE (ll_arg), ll_and_mask * 0);
> +    }
> +  /* Likewise for the second compare.  */
>   if ((rcode == LT_EXPR || rcode == GE_EXPR)
>       && integer_zerop (rr_arg)
>       && INTEGRAL_TYPE_P (TREE_TYPE (rl_arg))
> @@ -8036,6 +8081,26 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
> tree truth_type,
>       rsignbit = true;
>       rcode = (rcode == LT_EXPR ? NE_EXPR : EQ_EXPR);
>     }
> +  else if ((rcode == LT_EXPR || rcode == GE_EXPR)
> +       && INTEGRAL_TYPE_P (TREE_TYPE (rl_arg))
> +       && TYPE_UNSIGNED (TREE_TYPE (rl_arg))
> +       && uniform_integer_cst_p (rr_arg)
> +       && wi::popcount (wi::to_wide (rr_arg)) == 1)
> +    {
> +      rl_and_mask = ~(wi::to_wide (rr_arg) - 1);
> +      rcode = (rcode == GE_EXPR ? NE_EXPR : EQ_EXPR);
> +      rr_arg = wide_int_to_tree (TREE_TYPE (rl_arg), rl_and_mask * 0);
> +    }
> +  else if ((rcode == LE_EXPR || rcode == GT_EXPR)
> +       && INTEGRAL_TYPE_P (TREE_TYPE (rl_arg))
> +       && TYPE_UNSIGNED (TREE_TYPE (rl_arg))
> +       && uniform_integer_cst_p (rr_arg)
> +       && wi::popcount (wi::to_wide (rr_arg) + 1) == 1)
> +    {
> +      rl_and_mask = ~wi::to_wide (rr_arg);
> +      rcode = (rcode == GT_EXPR ? NE_EXPR : EQ_EXPR);
> +      rr_arg = wide_int_to_tree (TREE_TYPE (rl_arg), rl_and_mask * 0);
> +    }
> 
>   /* See if the comparisons can be merged.  Then get all the parameters for
>      each side.  */
> diff --git a/gcc/testsuite/gcc.dg/field-merge-15.c 
> b/gcc/testsuite/gcc.dg/field-merge-15.c
> new file mode 100644
> index 0000000000000..34641e893c92f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/field-merge-15.c
> @@ -0,0 +1,36 @@
> +/* { dg-do run } */
> +/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +
> +/* Check that bitfield compares-with-zero turned into GT and LE compares with
> +   powers-of-two minus 1 are optimized.  */
> +
> +struct s {
> +  short a : sizeof (short) * __CHAR_BIT__ - 3;
> +  short b : 3;
> +  short c : 3;
> +  short d : sizeof (short) * __CHAR_BIT__ - 3;
> +} __attribute__ ((aligned (4)));
> +
> +struct s p = { 15, 7, 3, 1 };
> +struct s q = { 0, 0, 0, 0 };
> +
> +void f ()
> +{
> +  if (p.a || p.b || p.c || p.d)
> +    return;
> +  __builtin_abort ();
> +}
> +
> +void g ()
> +{
> +  if (q.a || q.b || q.c || q.d)
> +    __builtin_abort ();
> +}
> +
> +int main () {
> +  f ();
> +  g ();
> +  return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "optimizing" 6 "ifcombine" } } */
> 
> --
> Alexandre Oliva, happy hacker            https://FSFLA.org/blogs/lxo/
>   Free Software Activist                   GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive

Reply via email to