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
>

Reply via email to