On Tue, Sep 29, 2026 at 7:45 PM Andrea Pinski
<[email protected]> wrote:
>
> Factoring out negative/bit_not when defined from a convert from
> a boolean should happen as it allows for more phiopt optimizations in
> many cases.  Also require the constant be 0/1 with - or ~ applied to it;
> that is for neg, -1 or 0 and for not, ~1 (-2) or ~0 (-1).  This restricts
> what is done to what most likely will reduce further.  We can tighten
> up the restriction further if needed but I think this is a reasonible
> heuristics and allows for what is needed to allow to fix the regression
> that would come from allowing -(convert)CMP in early phi-opt.
>
> This is alternative to 
> https://gcc.gnu.org/pipermail/gcc-patches/2026-July/724647.html  .
>
> Bootstrapped and tested on x86_64-linux-gnu.

I forgot I was going to add the testcases from that patch but got
distracted as I was doing family stuff.  Whoops sorry about that.


>
>         PR tree-optimization/127654
>
> gcc/ChangeLog:
>
>         * tree-ssa-phiopt.cc (factor_out_conditional_operation): Also
>         allow NEGATIVE_EXPR and BIT_NOT_EXPR with a constant in some
>         cases.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/tree-ssa/ssa-ifcombine-7a.c: New test.
>
> Signed-off-by: Andrea Pinski <[email protected]>
> ---
>  .../gcc.dg/tree-ssa/ssa-ifcombine-7a.c        | 27 +++++++
>  gcc/tree-ssa-phiopt.cc                        | 77 +++++++++++++++----
>  2 files changed, 90 insertions(+), 14 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-7a.c
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-7a.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-7a.c
> new file mode 100644
> index 00000000000..022d0f5c623
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-7a.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O -fdump-tree-phiopt1-details -fdump-tree-phiopt2" } */
> +/* This is a variant of ssa-ifcombine-7.c which tests phiopt rather than 
> ifcombine,
> +   dealing with -1 formation.  */
> +/* PR tree-optimization/127654 */
> +
> +int test1 (int i, int j)
> +{
> +  if (i >= j) {
> +    return -(i == j);
> +  }
> +  return -1;
> +}
> +int test2 (int i, int j)
> +{
> +  if (i >= j) {
> +    return ~(i == j);
> +  }
> +  return ~1;
> +}
> +
> +/* The above should be optimized to a i <= j test by ifcombine.  */
> +
> +/* { dg-final { scan-tree-dump-times " <= " 2 "phiopt2" } } */
> +/* { dg-final { scan-tree-dump-not " == " "phiopt2" } } */
> +/* Facting out the - and the cast out of test1 and test2 so 4 times.  */
> +/* { dg-final { scan-tree-dump-times "changed to factor operation out from 
> COND_EXPR" 4 "phiopt1" } } */
> diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
> index 7e13c8ff129..6f4eb8fe547 100644
> --- a/gcc/tree-ssa-phiopt.cc
> +++ b/gcc/tree-ssa-phiopt.cc
> @@ -460,21 +460,63 @@ factor_out_conditional_operation (edge e0, edge e1, 
> basic_block merge,
>        /* For constants only handle if the phi was the only one. */
>        if (single_non_singleton_phi_for_edges (phi_nodes (merge), e0, e1) == 
> NULL)
>         return false;
> -      /* TODO: handle more than just casts here. */
> -      if (!gimple_assign_cast_p (arg0_def_stmt))
> +      /* TODO: handle more than just casts and ~/- here. */
> +      if (!gimple_assign_cast_p (arg0_def_stmt)
> +         && arg0_op.code != NEGATE_EXPR
> +         && arg0_op.code != BIT_NOT_EXPR)
>         return false;
>        if (!is_factor_profitable (arg0_def_stmt, merge, arg0_op.ops, 
> arg0_op.num_ops))
>         return false;
>
> +      // Heuristics for ~/-, is about being able to being able to handle
> +      // `if (a) t = -1; else t = -(CMP);`
> +      // and the like.  - is usually used for a mask to emulate a
> +      // vector.
> +      if (arg0_op.code == NEGATE_EXPR
> +         || arg0_op.code == BIT_NOT_EXPR)
> +       {
> +         if (TREE_CODE (arg1) != INTEGER_CST
> +             || TREE_CODE (new_arg0) != SSA_NAME)
> +           return false;
> +
> +         // For neg, only allow -1, 0 as those
> +         //  the only ones which will reduce.
> +         if (arg0_op.code == NEGATE_EXPR
> +             && !integer_zerop (arg1)
> +             && !integer_minus_onep (arg1))
> +           return false;
> +         // For ~, only allow -2 (~1), -1 (~0) as those
> +         //  the only ones which will reduce.
> +         if (arg0_op.code == BIT_NOT_EXPR
> +             && !integer_minus_onep (arg1)
> +             && ~wi::to_wide (arg1) != 1)
> +           return false;
> +
> +         // Look to see if the -/~ comes from a cast from a boolean.
> +         gimple *arg0_def_def_stmt = SSA_NAME_DEF_STMT (new_arg0);
> +         if (gimple_bb (arg0_def_def_stmt) != gimple_bb (arg0_def_stmt))
> +           return false;
> +         if (!gimple_assign_cast_p (arg0_def_def_stmt))
> +           return false;
> +         tree_code ass_code = gimple_assign_rhs_code (arg0_def_def_stmt);
> +         if (!CONVERT_EXPR_CODE_P (ass_code))
> +           return false;
> +         tree rhs_type = TREE_TYPE (gimple_assign_rhs1 (arg0_def_def_stmt));
> +         if (!INTEGRAL_TYPE_P (rhs_type)
> +             || !TYPE_UNSIGNED (rhs_type)
> +             || TYPE_PRECISION (rhs_type) != 1)
> +           return false;
> +       }
> +
>        /* If arg1 is an INTEGER_CST, fold it to new type if it fits, or else
>          if the bits will not be modified during the conversion, except for
>          boolean types whose precision is not 1 (see int_fits_type_p).  */
> -      if (!INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
> -         || !(int_fits_type_p (arg1, TREE_TYPE (new_arg0))
> -              || (TYPE_PRECISION (TREE_TYPE (new_arg0))
> -                  == TYPE_PRECISION (TREE_TYPE (arg1))
> -                  && (TREE_CODE (TREE_TYPE (new_arg0)) != BOOLEAN_TYPE
> -                      || TYPE_PRECISION (TREE_TYPE (new_arg0)) == 1))))
> +      else if (!INTEGRAL_TYPE_P (TREE_TYPE (new_arg0))
> +              || !(int_fits_type_p (arg1, TREE_TYPE (new_arg0))
> +                   || (TYPE_PRECISION (TREE_TYPE (new_arg0))
> +                        == TYPE_PRECISION (TREE_TYPE (arg1))
> +                       && (TREE_CODE (TREE_TYPE (new_arg0)) != BOOLEAN_TYPE
> +                           || TYPE_PRECISION (TREE_TYPE (new_arg0)) == 1))))
>         return false;
>
>        /* For the INTEGER_CST case, we are just moving the
> @@ -488,11 +530,11 @@ factor_out_conditional_operation (edge e0, edge e1, 
> basic_block merge,
>          etc.).  See PR71016.
>          Note no-op conversions don't have this issue as
>          it will not generate any zero/sign extend in that case.  */
> -      if ((TYPE_PRECISION (TREE_TYPE (new_arg0))
> -          != TYPE_PRECISION (TREE_TYPE (arg1)))
> -         && new_arg0 != gimple_cond_lhs (cond_stmt)
> -         && new_arg0 != gimple_cond_rhs (cond_stmt)
> -         && gimple_bb (arg0_def_stmt) == e0->src)
> +      else if ((TYPE_PRECISION (TREE_TYPE (new_arg0))
> +               != TYPE_PRECISION (TREE_TYPE (arg1)))
> +              && new_arg0 != gimple_cond_lhs (cond_stmt)
> +              && new_arg0 != gimple_cond_rhs (cond_stmt)
> +              && gimple_bb (arg0_def_stmt) == e0->src)
>         {
>           gsi = gsi_for_stmt (arg0_def_stmt);
>           gsi_prev_nondebug (&gsi);
> @@ -531,7 +573,14 @@ factor_out_conditional_operation (edge e0, edge e1, 
> basic_block merge,
>                 return false;
>             }
>         }
> -      new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
> +
> +      // - is still the opposite of -, likewise for ~.
> +      if (arg0_op.code == NEGATE_EXPR
> +         || arg0_op.code == BIT_NOT_EXPR)
> +       new_arg1 = fold_build1 ((tree_code)arg0_op.code,
> +                               TREE_TYPE (new_arg0), arg1);
> +      else
> +       new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
>
>        /* Drop the overflow that fold_convert might add. */
>        if (TREE_OVERFLOW (new_arg1))
> --
> 2.43.0
>

Reply via email to