On Mon, Feb 23, 2026 at 10:53 AM Avinash Jayakar <[email protected]> wrote: > > Hi, > > Please find the patch proposed to handle some more cases for spaceship > optimization below. > > Bootstrapped and regtested on powerpc64le-linux-gnu without any regressions. > > Requesting review and suggestions on the test cases. > > I do have one test file with 24 tests but did not send it with this patch > since currently in test cases there is no way of checking if target supports > spaceship optab, would it be ok to add check_effective_target_spaceship in > target-supports.exp? Or is there a better way to add these test cases? > > Following is the list of 24 tests: > > Following 8 are recognized in current trunk. > a == b ? 0 : a > b ? 1 : -1 > a == b ? 0 : a < b ? -1 : 1 > a == b ? 0 : a >= b ? 1 : -1 > a == b ? 0 : a <= b ? -1 : 1 > a != b ? (a > b ? 1 : -1) : 0 > a != b ? (a < b ? -1 : 1) : 0 > a != b ? (a >= b ? 1 : -1) : 0 > a != b ? (a <= b ? -1 : 1) : 0 > > Below tests are recognized with the patch. > a < b ? -1 : a > b ? 1 : 0 > a < b ? -1 : a == b ? 0 : 1 > a < b ? -1 : a != b ? 1 : 0 > a < b ? -1 : a <= b ? 0 : 1 > a > b ? 1 : a == b ? 0 : -1 > a > b ? 1 : a < b ? -1 : 0 > a > b ? 1 : a != b ? -1 : 0 > a > b ? 1 : a >= b ? 0 : -1 > a <= b ? (a == b ? 0 : -1) : 1 > a <= b ? (a >= b ? 0 : -1) : 1 > a <= b ? (a != b ? -1 : 0) : 1 > a <= b ? (a < b ? -1 : 0) : 1 > a >= b ? (a == b ? 0 : 1) : -1 > a >= b ? (a != b ? 1 : 0) : -1 > a >= b ? (a <= b ? 0 : 1) : -1 > a >= b ? (a > b ? 1 : 0) : -1 > > Thanks and regards, > Avinash Jayakar
I wonder whether match.pd matches with (cond^ ...) similar to the saturating arithmetic patterns can be used to make the matchings more maintainable? > There are certain patterns that are not recognized by the method > optimize_spaceship. For example, > a == b ? 0 : (a > b) : 1 : -1; > is rightly recognized as spaceship operator. But writing it as > a <= b ? -(a < b) : 1 or > a >= b ? (a > b) : -1 > is not being currently recognized. > > This patch recognizes such patterns and chooses to emit the spaceship > optab if target supports it, which improves code-generation for such > targets. > > 2026-02-23 Avinash Jayakar <[email protected]> > > gcc/ChangeLog: > * tree-ssa-math-opts.cc (optimize_spaceship_for_ge_le): New > function. > (math_opts_dom_walker::after_dom_children): Use new fn, before > running optimize_spaceship. > --- > gcc/tree-ssa-math-opts.cc | 162 +++++++++++++++++++++++++++++++++++++- > 1 file changed, 161 insertions(+), 1 deletion(-) > > diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc > index bb67dca560b..a52118fafba 100644 > --- a/gcc/tree-ssa-math-opts.cc > +++ b/gcc/tree-ssa-math-opts.cc > @@ -6096,6 +6096,165 @@ convert_mult_to_highpart (gassign *stmt, > gimple_stmt_iterator *gsi) > return true; > } > > +static bool > +optimize_spaceship_for_ge_le (gcond *stmt) > +{ > + /* Check condition form: a >= b or a <= b */ > + enum tree_code code = gimple_cond_code (stmt); > + if (code != GE_EXPR && code != LE_EXPR) > + return false; > + > + tree arg1 = gimple_cond_lhs (stmt); > + tree arg2 = gimple_cond_rhs (stmt); > + > + if (!INTEGRAL_TYPE_P (TREE_TYPE (arg1)) > + || optab_handler (spaceship_optab, > + TYPE_MODE (TREE_TYPE (arg1))) == CODE_FOR_nothing > + || operand_equal_p (arg1, arg2, 0)) > + return false; > + > + basic_block bb0 = gimple_bb (stmt); > + > + /* Identify successors */ > + edge e_true = EDGE_SUCC (bb0, 0); > + edge e_false = EDGE_SUCC (bb0, 1); > + > + if (!(e_true->flags & EDGE_TRUE_VALUE)) > + std::swap (e_true, e_false); > + > + basic_block bb1 = e_true->dest; > + basic_block bb2 = e_false->dest; > + > + // bb1 must be single-pred, single-succ > + if (!single_pred_p (bb1) || !single_succ_p (bb1)) > + return false; > + > + if (single_succ (bb1) != bb2) > + return false; > + > + gimple_stmt_iterator gsi = gsi_start_bb (bb1); > + > + // if there is no stmt in bb1, no opt > + if (gsi_end_p (gsi)) > + return false; > + > + // first stmt in the bb must be a comparison > + // NE_EXPR works for both GE and LE > + // else if GE, then true block must have GT > + // if LE, then true block must have LT > + gassign *cmp = dyn_cast <gassign *> (gsi_stmt (gsi)); > + if (!cmp > + || (gimple_assign_rhs_code (cmp) != NE_EXPR > + && ((code == GE_EXPR && gimple_assign_rhs_code (cmp) != GT_EXPR) > + || (code == LE_EXPR && gimple_assign_rhs_code (cmp) != > LT_EXPR)))) > + return false; > + > + // arguments participating in comparison must be same in original compare > + if (!operand_equal_p (gimple_assign_rhs1 (cmp), arg1, 0) > + || !operand_equal_p (gimple_assign_rhs2 (cmp), arg2, 0)) > + return false; > + > + // grab the value of comparison is a ssa value > + tree booltmp = gimple_assign_lhs (cmp); > + > + // now goto next stmt to check if > + gsi_next (&gsi); > + if (gsi_end_p (gsi)) > + return false; > + > + // to check if it is a simple assignment with nothing happening in rhs. > + gassign *cast = dyn_cast <gassign *> (gsi_stmt (gsi)); > + if (!cast || gimple_assign_rhs_code (cast) != NOP_EXPR) > + return false; > + > + if (gimple_assign_rhs1 (cast) != booltmp) > + return false; > + > + // The true block in case of LE, contains NEGATE_EXPR > + // i.e., -(a < b) or -(a != b) > + if (code == LE_EXPR) > + { > + booltmp = gimple_assign_lhs (cast); > + gsi_next (&gsi); > + if (gsi_end_p (gsi)) > + return false; > + cast = dyn_cast <gassign *> (gsi_stmt (gsi)); > + if (!cast || gimple_assign_rhs_code (cast) != NEGATE_EXPR) > + return false; > + > + if (gimple_assign_rhs1 (cast) != booltmp) > + return false; > + } > + > + tree casttmp = gimple_assign_lhs (cast); > + > + // Target bb must have single phi > + if (!gimple_seq_empty_p (bb2->il.gimple.phi_nodes)) > + { > + gphi *phi = NULL; > + gphi_iterator saved_psi; > + // Let this bb have only one phi for now > + for (gphi_iterator psi = gsi_start_phis (bb2); > + !gsi_end_p (psi); gsi_next (&psi)) > + { > + if (phi) > + return false; > + phi = psi.phi (); > + saved_psi = psi; > + } > + > + if (!phi) > + return false; > + > + tree arg_from_bb0 = > + gimple_phi_arg_def_from_edge (phi, e_false); > + > + tree arg_from_bb1 = > + gimple_phi_arg_def_from_edge (phi, > + single_succ_edge (bb1)); > + > + // For GE, the false path is -1, while for LE it is +1 > + if ((code == GE_EXPR && !integer_minus_onep (arg_from_bb0)) > + || (code == LE_EXPR && !integer_onep (arg_from_bb0))) > + return false; > + > + if (arg_from_bb1 != casttmp) > + return false; > + > + /* Build IFN_SPACESHIP (a, b, 1) */ > + tree arg3 = build_int_cst (integer_type_node, 1); > + > + gcall *gc = > + gimple_build_call_internal (IFN_SPACESHIP, 3, > + arg1, arg2, arg3); > + > + tree lhs = make_ssa_name (integer_type_node); > + gimple_call_set_lhs (gc, lhs); > + > + gimple_stmt_iterator gsi0 = gsi_for_stmt (stmt); > + gsi_insert_before (&gsi0, gc, GSI_SAME_STMT); > + > + /* Replace PHI */ > + tree phi_res = gimple_phi_result (phi); > + > + if (!useless_type_conversion_p (TREE_TYPE (phi_res), > + integer_type_node)) > + { > + tree tmp = make_ssa_name (TREE_TYPE (phi_res)); > + gassign *conv = > + gimple_build_assign (tmp, NOP_EXPR, lhs); > + gsi_insert_before (&gsi0, conv, GSI_SAME_STMT); > + lhs = tmp; > + } > + > + replace_uses_by (phi_res, lhs); > + > + return true; > + } > + > + return false; > +} > + > /* If target has spaceship<MODE>3 expander, pattern recognize > <bb 2> [local count: 1073741824]: > if (a_2(D) == b_3(D)) > @@ -6643,7 +6802,8 @@ math_opts_dom_walker::after_dom_children (basic_block > bb) > else if (gimple_code (stmt) == GIMPLE_COND) > { > match_single_bit_test (&gsi, stmt); > - optimize_spaceship (as_a <gcond *> (stmt)); > + if (!optimize_spaceship_for_ge_le (as_a <gcond *> (stmt))) > + optimize_spaceship (as_a <gcond *> (stmt)); > } > gsi_next (&gsi); > } > -- > 2.51.0 >
