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. 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
