> 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