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 >
