On Wed, 20 Nov 2024, Jakub Jelinek wrote:

> Hi!
> 
> The following patch optimizes spaceship followed by comparisons of the
> spaceship value even for floating point spaceship when NaNs can appear.
> operator<=> for this emits roughly
> signed char c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 
> 1; else c = 2; 
> and I believe the
> /* The optimization may be unsafe due to NaNs.  */
> comment just isn't true.
> Sure, the i == j comparison doesn't raise exceptions on qNaNs, but if
> one of the operands is qNaN, then i == j is false and i < j or i > j
> is then executed and raises exceptions even on qNaNs.
> And we can safely optimize say
> c == -1 comparison after the above into i < j, that also raises
> exceptions like before and handles NaNs the same way as the original.
> The only unsafe transormation would be c == 0 or c != 0, turning it
> into i == j or i != j wouldn't raise exception, so I'm not doing that
> optimization (but other parts of the compiler optimize the i < j comparison
> away anyway).
> 
> Anyway, to match the HONOR_NANS case, we need to verify that the
> second comparison has true edge to the phi_bb (yielding there -1 or 1),
> it can't be the false edge because when NaNs are honored, the false
> edge is for both the case where the inverted comparison is true or when
> one of the operands is NaN.  Similarly we need to ensure that the two
> non-equality comparisons are the opposite, while for -ffast-math we can in
> some cases get one comparison x >= 5.0 and the other x > 5.0 and it is fine,
> because NaN is UB, when NaNs are honored, they must be different to leave
> the unordered case with 2 value as the last one remaining.
> The patch also punts if HONOR_NANS and the phi has just 3 arguments instead
> of 4.
> When NaNs are honored, we also in some cases need to perform some comparison
> and then invert its result (so that exceptions are properly thrown and we
> get the correct result).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Richard.

> 2024-11-20  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR tree-optimization/94589
>       PR tree-optimization/117612
>       * tree-ssa-phiopt.cc (spaceship_replacement): Handle
>       HONOR_NANS (TREE_TYPE (lhs1)) case when possible.
> 
>       * gcc.dg/pr94589-5.c: New test.
>       * gcc.dg/pr94589-6.c: New test.
>       * g++.dg/opt/pr94589-5.C: New test.
>       * g++.dg/opt/pr94589-6.C: New test.
> 
> --- gcc/tree-ssa-phiopt.cc.jj 2024-11-20 13:19:03.065777085 +0100
> +++ gcc/tree-ssa-phiopt.cc    2024-11-20 13:22:52.294582678 +0100
> @@ -2588,9 +2588,6 @@ spaceship_replacement (basic_block cond_
>      }
>    tree lhs1 = gimple_cond_lhs (cond1);
>    tree rhs1 = gimple_cond_rhs (cond1);
> -  /* The optimization may be unsafe due to NaNs.  */
> -  if (HONOR_NANS (TREE_TYPE (lhs1)))
> -    return false;
>    if (TREE_CODE (lhs1) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs1))
>      return false;
>    if (TREE_CODE (rhs1) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1))
> @@ -2681,6 +2678,9 @@ spaceship_replacement (basic_block cond_
>      {
>        if (absu_hwi (tree_to_shwi (arg2)) != 1)
>       return false;
> +      if ((cond2_phi_edge->flags & EDGE_FALSE_VALUE)
> +       && HONOR_NANS (TREE_TYPE (lhs1)))
> +     return false;
>        if (e1->flags & EDGE_TRUE_VALUE)
>       {
>         if (tree_to_shwi (arg0) != 2
> @@ -2708,14 +2708,20 @@ spaceship_replacement (basic_block cond_
>        phi_bb:;
>        is ok, but if x and y are swapped in one of the comparisons,
>        or the comparisons are the same and operands not swapped,
> -      or the true and false edges are swapped, it is not.  */
> +      or the true and false edges are swapped, it is not.
> +      For HONOR_NANS, the edge flags are irrelevant and the comparisons
> +      must be different for non-swapped operands and same for swapped
> +      operands.  */
>        if ((lhs2 == lhs1)
> -       ^ (((cond2_phi_edge->flags
> -            & ((cmp2 == LT_EXPR || cmp2 == LE_EXPR)
> -               ? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0)
> -          != ((e1->flags
> -               & ((cmp1 == LT_EXPR || cmp1 == LE_EXPR)
> -                  ? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0)))
> +       ^ (HONOR_NANS (TREE_TYPE (lhs1))
> +          ? ((cmp2 == LT_EXPR || cmp2 == LE_EXPR)
> +             != (cmp1 == LT_EXPR || cmp1 == LE_EXPR))
> +          : (((cond2_phi_edge->flags
> +               & ((cmp2 == LT_EXPR || cmp2 == LE_EXPR)
> +                  ? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0)
> +             != ((e1->flags
> +                  & ((cmp1 == LT_EXPR || cmp1 == LE_EXPR)
> +                      ? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) != 0))))
>       return false;
>        if (!single_pred_p (cond2_bb) || !cond_only_block_p (cond2_bb))
>       return false;
> @@ -2754,7 +2760,8 @@ spaceship_replacement (basic_block cond_
>      }
>    else if (absu_hwi (tree_to_shwi (arg0)) != 1
>          || absu_hwi (tree_to_shwi (arg1)) != 1
> -        || wi::to_widest (arg0) == wi::to_widest (arg1))
> +        || wi::to_widest (arg0) == wi::to_widest (arg1)
> +        || HONOR_NANS (TREE_TYPE (lhs1)))
>      return false;
>  
>    if (!integer_zerop (arg3) || (cmp3 != EQ_EXPR && cmp3 != NE_EXPR))
> @@ -2772,10 +2779,11 @@ spaceship_replacement (basic_block cond_
>      one_cmp = GT_EXPR;
>  
>    enum tree_code res_cmp;
> +  bool negate_p = false;
>    switch (cmp)
>      {
>      case EQ_EXPR:
> -      if (integer_zerop (rhs))
> +      if (integer_zerop (rhs) && !HONOR_NANS (TREE_TYPE (lhs1)))
>       res_cmp = EQ_EXPR;
>        else if (integer_minus_onep (rhs))
>       res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
> @@ -2785,7 +2793,7 @@ spaceship_replacement (basic_block cond_
>       return false;
>        break;
>      case NE_EXPR:
> -      if (integer_zerop (rhs))
> +      if (integer_zerop (rhs) && !HONOR_NANS (TREE_TYPE (lhs1)))
>       res_cmp = NE_EXPR;
>        else if (integer_minus_onep (rhs))
>       res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
> @@ -2793,12 +2801,18 @@ spaceship_replacement (basic_block cond_
>       res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR;
>        else
>       return false;
> +      if (HONOR_NANS (TREE_TYPE (lhs1)))
> +     negate_p = true;
>        break;
>      case LT_EXPR:
>        if (integer_onep (rhs))
>       res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR;
>        else if (integer_zerop (rhs))
> -     res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
> +     {
> +       if (HONOR_NANS (TREE_TYPE (lhs1)) && orig_use_lhs)
> +         negate_p = true;
> +       res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
> +     }
>        else
>       return false;
>        break;
> @@ -2817,12 +2831,22 @@ spaceship_replacement (basic_block cond_
>       res_cmp = one_cmp;
>        else
>       return false;
> +      if (HONOR_NANS (TREE_TYPE (lhs1)))
> +     negate_p = true;
>        break;
>      case GE_EXPR:
>        if (integer_zerop (rhs))
> -     res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
> +     {
> +       if (HONOR_NANS (TREE_TYPE (lhs1)) && !orig_use_lhs)
> +         negate_p = true;
> +       res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
> +     }
>        else if (integer_onep (rhs))
> -     res_cmp = one_cmp;
> +     {
> +       if (HONOR_NANS (TREE_TYPE (lhs1)))
> +         negate_p = true;
> +       res_cmp = one_cmp;
> +     }
>        else
>       return false;
>        break;
> @@ -2830,23 +2854,37 @@ spaceship_replacement (basic_block cond_
>        gcc_unreachable ();
>      }
>  
> +  tree clhs1 = lhs1, crhs1 = rhs1;
> +  if (negate_p)
> +    {
> +      if (cfun->can_throw_non_call_exceptions)
> +     return false;
> +      res_cmp = invert_tree_comparison (res_cmp, false);
> +      clhs1 = make_ssa_name (boolean_type_node);
> +      gimple *g = gimple_build_assign (clhs1, res_cmp, lhs1, rhs1);
> +      gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
> +      gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> +      crhs1 = boolean_false_node;
> +      res_cmp = EQ_EXPR;
> +    }  
> +
>    if (gimple_code (use_stmt) == GIMPLE_COND)
>      {
>        gcond *use_cond = as_a <gcond *> (use_stmt);
>        gimple_cond_set_code (use_cond, res_cmp);
> -      gimple_cond_set_lhs (use_cond, lhs1);
> -      gimple_cond_set_rhs (use_cond, rhs1);
> +      gimple_cond_set_lhs (use_cond, clhs1);
> +      gimple_cond_set_rhs (use_cond, crhs1);
>      }
>    else if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS)
>      {
>        gimple_assign_set_rhs_code (use_stmt, res_cmp);
> -      gimple_assign_set_rhs1 (use_stmt, lhs1);
> -      gimple_assign_set_rhs2 (use_stmt, rhs1);
> +      gimple_assign_set_rhs1 (use_stmt, clhs1);
> +      gimple_assign_set_rhs2 (use_stmt, crhs1);
>      }
>    else
>      {
>        tree cond = build2 (res_cmp, TREE_TYPE (gimple_assign_rhs1 (use_stmt)),
> -                       lhs1, rhs1);
> +                       clhs1, crhs1);
>        gimple_assign_set_rhs1 (use_stmt, cond);
>      }
>    update_stmt (use_stmt);
> @@ -2890,14 +2928,31 @@ spaceship_replacement (basic_block cond_
>            # DEBUG D#2 => i_2(D) == j_3(D) ? 0 : D#1
>            where > stands for the comparison that yielded 1
>            and replace debug uses of phi result with that D#2.
> -          Ignore the value of 2, because if NaNs aren't expected,
> -          all floating point numbers should be comparable.  */
> +          Ignore the value of 2 if !HONOR_NANS, because if NaNs
> +          aren't expected, all floating point numbers should be
> +          comparable.  If HONOR_NANS, emit something like:
> +          # DEBUG D#1 => i_2(D) < j_3(D) ? -1 : 2
> +          # DEBUG D#2 => i_2(D) > j_3(D) ? 1 : D#1
> +          # DEBUG D#3 => i_2(D) == j_3(D) ? 0 : D#2
> +          instead.  */
>         gimple_stmt_iterator gsi = gsi_after_labels (gimple_bb (phi));
>         tree type = TREE_TYPE (phires);
> +       tree minus_one = build_int_cst (type, -1);
> +       if (HONOR_NANS (TREE_TYPE (lhs1)))
> +         {
> +           tree temp3 = build_debug_expr_decl (type);
> +           tree t = build2 (one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR,
> +                            boolean_type_node, lhs1, rhs2);
> +           t = build3 (COND_EXPR, type, t, minus_one,
> +                       build_int_cst (type, 2));
> +           gimple *g = gimple_build_debug_bind (temp3, t, phi);
> +           gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> +           minus_one = temp3;
> +         }
>         tree temp1 = build_debug_expr_decl (type);
>         tree t = build2 (one_cmp, boolean_type_node, lhs1, rhs2);
>         t = build3 (COND_EXPR, type, t, build_one_cst (type),
> -                   build_int_cst (type, -1));
> +                   minus_one);
>         gimple *g = gimple_build_debug_bind (temp1, t, phi);
>         gsi_insert_before (&gsi, g, GSI_SAME_STMT);
>         tree temp2 = build_debug_expr_decl (type);
> @@ -2908,13 +2963,19 @@ spaceship_replacement (basic_block cond_
>         replace_uses_by (phires, temp2);
>         if (orig_use_lhs)
>           {
> -           if (has_cast_debug_uses)
> +           if (has_cast_debug_uses
> +               || (HONOR_NANS (TREE_TYPE (lhs1)) && !is_cast))
>               {
>                 tree temp3 = make_node (DEBUG_EXPR_DECL);
>                 DECL_ARTIFICIAL (temp3) = 1;
>                 TREE_TYPE (temp3) = TREE_TYPE (orig_use_lhs);
>                 SET_DECL_MODE (temp3, TYPE_MODE (type));
> -               t = fold_convert (TREE_TYPE (temp3), temp2);
> +               if (has_cast_debug_uses)
> +                 t = fold_convert (TREE_TYPE (temp3), temp2);
> +               else
> +                 t = build2 (BIT_AND_EXPR, TREE_TYPE (temp3),
> +                             temp2, build_int_cst (TREE_TYPE (temp3),
> +                                                   ~1));
>                 g = gimple_build_debug_bind (temp3, t, phi);
>                 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
>                 replace_uses_by (orig_use_lhs, temp3);
> --- gcc/testsuite/gcc.dg/pr94589-5.c.jj       2024-11-20 13:42:08.569464679 
> +0100
> +++ gcc/testsuite/gcc.dg/pr94589-5.c  2024-11-20 14:06:58.188702990 +0100
> @@ -0,0 +1,35 @@
> +/* PR tree-optimization/94589 */
> +/* { dg-do compile { target inf } } */
> +/* { dg-options "-O2 -g0 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|>|>=) 
> \[ij]_\[0-9]+\\(D\\)" 14 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|>|>=) 5\\.0" 
> 14 "optimized" } } */
> +
> +#define A __attribute__((noipa))
> +A int f3 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c > 0; }
> +A int f4 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c < 0; }
> +A int f5 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c >= 0; }
> +A int f6 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c <= 0; }
> +A int f7 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c == -1; }
> +A int f8 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c != -1; }
> +A int f9 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c > -1; }
> +A int f10 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c <= -1; }
> +A int f11 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c == 1; }
> +A int f12 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c != 1; }
> +A int f13 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c < 1; }
> +A int f14 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c >= 1; }
> +A int f17 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c > 0; }
> +A int f18 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c < 0; }
> +A int f19 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c >= 0; }
> +A int f20 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c <= 0; }
> +A int f21 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c == -1; }
> +A int f22 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c != -1; }
> +A int f23 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c > -1; }
> +A int f24 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c <= -1; }
> +A int f25 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c == 1; }
> +A int f26 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c != 1; }
> +A int f27 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c < 1; }
> +A int f28 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c >= 1; }
> +A int f29 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return (c & ~1) == 0; }
> +A int f30 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return (c & ~1) != 0; }
> +A int f31 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return (c & ~1) == 0; }
> +A int f32 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return (c & ~1) != 0; }
> --- gcc/testsuite/gcc.dg/pr94589-6.c.jj       2024-11-20 13:42:12.217413816 
> +0100
> +++ gcc/testsuite/gcc.dg/pr94589-6.c  2024-11-20 13:55:52.353980959 +0100
> @@ -0,0 +1,146 @@
> +/* { dg-do run { target inf } } */
> +/* { dg-options "-O2 -g" } */
> +
> +#include "pr94589-5.c"
> +
> +A int f1 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c == 0; }
> +A int f2 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c 
> = -1; else if (i > j) c = 1; else c = 2; return c != 0; }
> +A int f15 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c == 0; }
> +A int f16 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; 
> else if (i > 5.0) c = 1; else c = 2; return c != 0; }
> +
> +#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort ()
> +#define D(fn, i, r) if (fn (i) != r) __builtin_abort ()
> +
> +int
> +main ()
> +{
> +  C (f1, 7.0, 8.0, 0);
> +  C (f1, 8.0, 8.0, 1);
> +  C (f1, 9.0, 8.0, 0);
> +  C (f1, __builtin_nan (""), 8.0, 0);
> +  C (f2, 7.0, 8.0, 1);
> +  C (f2, 8.0, 8.0, 0);
> +  C (f2, 9.0, 8.0, 1);
> +  C (f2, __builtin_nan (""), 8.0, 1);
> +  C (f3, 7.0, 8.0, 0);
> +  C (f3, 8.0, 8.0, 0);
> +  C (f3, 9.0, 8.0, 1);
> +  C (f3, __builtin_nan (""), 8.0, 1);
> +  C (f4, 7.0, 8.0, 1);
> +  C (f4, 8.0, 8.0, 0);
> +  C (f4, 9.0, 8.0, 0);
> +  C (f4, __builtin_nan (""), 8.0, 0);
> +  C (f5, 7.0, 8.0, 0);
> +  C (f5, 8.0, 8.0, 1);
> +  C (f5, 9.0, 8.0, 1);
> +  C (f5, __builtin_nan (""), 8.0, 1);
> +  C (f6, 7.0, 8.0, 1);
> +  C (f6, 8.0, 8.0, 1);
> +  C (f6, 9.0, 8.0, 0);
> +  C (f6, __builtin_nan (""), 8.0, 0);
> +  C (f7, 7.0, 8.0, 1);
> +  C (f7, 8.0, 8.0, 0);
> +  C (f7, 9.0, 8.0, 0);
> +  C (f7, __builtin_nan (""), 8.0, 0);
> +  C (f8, 7.0, 8.0, 0);
> +  C (f8, 8.0, 8.0, 1);
> +  C (f8, 9.0, 8.0, 1);
> +  C (f8, __builtin_nan (""), 8.0, 1);
> +  C (f9, 7.0, 8.0, 0);
> +  C (f9, 8.0, 8.0, 1);
> +  C (f9, 9.0, 8.0, 1);
> +  C (f9, __builtin_nan (""), 8.0, 1);
> +  C (f10, 7.0, 8.0, 1);
> +  C (f10, 8.0, 8.0, 0);
> +  C (f10, 9.0, 8.0, 0);
> +  C (f10, __builtin_nan (""), 8.0, 0);
> +  C (f11, 7.0, 8.0, 0);
> +  C (f11, 8.0, 8.0, 0);
> +  C (f11, 9.0, 8.0, 1);
> +  C (f11, __builtin_nan (""), 8.0, 0);
> +  C (f12, 7.0, 8.0, 1);
> +  C (f12, 8.0, 8.0, 1);
> +  C (f12, 9.0, 8.0, 0);
> +  C (f12, __builtin_nan (""), 8.0, 1);
> +  C (f13, 7.0, 8.0, 1);
> +  C (f13, 8.0, 8.0, 1);
> +  C (f13, 9.0, 8.0, 0);
> +  C (f13, __builtin_nan (""), 8.0, 0);
> +  C (f14, 7.0, 8.0, 0);
> +  C (f14, 8.0, 8.0, 0);
> +  C (f14, 9.0, 8.0, 1);
> +  C (f14, __builtin_nan (""), 8.0, 1);
> +  D (f15, 4.0, 0);
> +  D (f15, 5.0, 1);
> +  D (f15, 6.0, 0);
> +  D (f15, __builtin_nan (""), 0);
> +  D (f16, 4.0, 1);
> +  D (f16, 5.0, 0);
> +  D (f16, 6.0, 1);
> +  D (f16, __builtin_nan (""), 1);
> +  D (f17, 4.0, 0);
> +  D (f17, 5.0, 0);
> +  D (f17, 6.0, 1);
> +  D (f17, __builtin_nan (""), 1);
> +  D (f18, 4.0, 1);
> +  D (f18, 5.0, 0);
> +  D (f18, 6.0, 0);
> +  D (f18, __builtin_nan (""), 0);
> +  D (f19, 4.0, 0);
> +  D (f19, 5.0, 1);
> +  D (f19, 6.0, 1);
> +  D (f19, __builtin_nan (""), 1);
> +  D (f20, 4.0, 1);
> +  D (f20, 5.0, 1);
> +  D (f20, 6.0, 0);
> +  D (f20, __builtin_nan (""), 0);
> +  D (f21, 4.0, 1);
> +  D (f21, 5.0, 0);
> +  D (f21, 6.0, 0);
> +  D (f21, __builtin_nan (""), 0);
> +  D (f22, 4.0, 0);
> +  D (f22, 5.0, 1);
> +  D (f22, 6.0, 1);
> +  D (f22, __builtin_nan (""), 1);
> +  D (f23, 4.0, 0);
> +  D (f23, 5.0, 1);
> +  D (f23, 6.0, 1);
> +  D (f23, __builtin_nan (""), 1);
> +  D (f24, 4.0, 1);
> +  D (f24, 5.0, 0);
> +  D (f24, 6.0, 0);
> +  D (f24, __builtin_nan (""), 0);
> +  D (f25, 4.0, 0);
> +  D (f25, 5.0, 0);
> +  D (f25, 6.0, 1);
> +  D (f25, __builtin_nan (""), 0);
> +  D (f26, 4.0, 1);
> +  D (f26, 5.0, 1);
> +  D (f26, 6.0, 0);
> +  D (f26, __builtin_nan (""), 1);
> +  D (f27, 4.0, 1);
> +  D (f27, 5.0, 1);
> +  D (f27, 6.0, 0);
> +  D (f27, __builtin_nan (""), 0);
> +  D (f28, 4.0, 0);
> +  D (f28, 5.0, 0);
> +  D (f28, 6.0, 1);
> +  D (f28, __builtin_nan (""), 1);
> +  C (f29, 7.0, 8.0, 0);
> +  C (f29, 8.0, 8.0, 1);
> +  C (f29, 9.0, 8.0, 1);
> +  C (f29, __builtin_nan (""), 8.0, 0);
> +  C (f30, 7.0, 8.0, 1);
> +  C (f30, 8.0, 8.0, 0);
> +  C (f30, 9.0, 8.0, 0);
> +  C (f30, __builtin_nan (""), 8.0, 1);
> +  D (f31, 4.0, 0);
> +  D (f31, 5.0, 1);
> +  D (f31, 6.0, 1);
> +  D (f31, __builtin_nan (""), 0);
> +  D (f32, 4.0, 1);
> +  D (f32, 5.0, 0);
> +  D (f32, 6.0, 0);
> +  D (f32, __builtin_nan (""), 1);
> +  return 0;
> +}
> --- gcc/testsuite/g++.dg/opt/pr94589-5.C.jj   2024-11-20 14:02:35.368365220 
> +0100
> +++ gcc/testsuite/g++.dg/opt/pr94589-5.C      2024-11-20 14:10:56.684375891 
> +0100
> @@ -0,0 +1,26 @@
> +// PR tree-optimization/94589
> +// { dg-do compile { target c++20 } }
> +// { dg-require-effective-target inf }
> +// { dg-options "-O2 -g0 -fdump-tree-optimized" }
> +// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|>|>=) 
> \[ij]_\[0-9]+\\(D\\)" 8 "optimized" } }
> +// { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|>|>=) 5\\.0" 
> 8 "optimized" } }
> +
> +#include <compare>
> +
> +#define A __attribute__((noipa))
> +A bool f3 (double i, double j) { auto c = i <=> j; return c > 0; }
> +A bool f4 (double i, double j) { auto c = i <=> j; return c < 0; }
> +A bool f5 (double i, double j) { auto c = i <=> j; return c >= 0; }
> +A bool f6 (double i, double j) { auto c = i <=> j; return c <= 0; }
> +A bool f7 (double i, double j) { auto c = i <=> j; return c == 
> std::partial_ordering::less; }
> +A bool f8 (double i, double j) { auto c = i <=> j; return c != 
> std::partial_ordering::less; }
> +A bool f11 (double i, double j) { auto c = i <=> j; return c == 
> std::partial_ordering::greater; }
> +A bool f12 (double i, double j) { auto c = i <=> j; return c != 
> std::partial_ordering::greater; }
> +A bool f15 (double i) { auto c = i <=> 5.0; return c > 0; }
> +A bool f16 (double i) { auto c = i <=> 5.0; return c < 0; }
> +A bool f17 (double i) { auto c = i <=> 5.0; return c >= 0; }
> +A bool f18 (double i) { auto c = i <=> 5.0; return c <= 0; }
> +A bool f19 (double i) { auto c = i <=> 5.0; return c == 
> std::partial_ordering::less; }
> +A bool f20 (double i) { auto c = i <=> 5.0; return c != 
> std::partial_ordering::less; }
> +A bool f23 (double i) { auto c = i <=> 5.0; return c == 
> std::partial_ordering::greater; }
> +A bool f24 (double i) { auto c = i <=> 5.0; return c != 
> std::partial_ordering::greater; }
> --- gcc/testsuite/g++.dg/opt/pr94589-6.C.jj   2024-11-20 14:03:26.737649428 
> +0100
> +++ gcc/testsuite/g++.dg/opt/pr94589-6.C      2024-11-20 14:19:36.720119946 
> +0100
> @@ -0,0 +1,138 @@
> +// { dg-do run { target c++20 } }
> +// { dg-require-effective-target inf }
> +// { dg-options "-O2 -g" }
> +
> +#include "pr94589-5.C"
> +
> +A bool f1 (double i, double j) { auto c = i <=> j; return c == 0; }
> +A bool f2 (double i, double j) { auto c = i <=> j; return c != 0; }
> +A bool f9 (double i, double j) { auto c = i <=> j; return c == 
> std::partial_ordering::equivalent; }
> +A bool f10 (double i, double j) { auto c = i <=> j; return c != 
> std::partial_ordering::equivalent; }
> +A bool f13 (double i) { auto c = i <=> 5.0; return c == 0; }
> +A bool f14 (double i) { auto c = i <=> 5.0; return c != 0; }
> +A bool f21 (double i) { auto c = i <=> 5.0; return c == 
> std::partial_ordering::equivalent; }
> +A bool f22 (double i) { auto c = i <=> 5.0; return c != 
> std::partial_ordering::equivalent; }
> +A bool f25 (double i, double j) { auto c = i <=> j; return c == 
> std::partial_ordering::unordered; }
> +A bool f26 (double i, double j) { auto c = i <=> j; return c != 
> std::partial_ordering::unordered; }
> +A bool f27 (double i) { auto c = i <=> 5.0; return c == 
> std::partial_ordering::unordered; }
> +A bool f28 (double i) { auto c = i <=> 5.0; return c != 
> std::partial_ordering::unordered; }
> +
> +#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort ()
> +#define D(fn, i, r) if (fn (i) != r) __builtin_abort ()
> +
> +int
> +main ()
> +{
> +  C (f1, 7.0, 8.0, false);
> +  C (f1, 8.0, 8.0, true);
> +  C (f1, 9.0, 8.0, false);
> +  C (f1, __builtin_nan (""), 8.0, false);
> +  C (f2, 7.0, 8.0, true);
> +  C (f2, 8.0, 8.0, false);
> +  C (f2, 9.0, 8.0, true);
> +  C (f2, __builtin_nan (""), 8.0, true);
> +  C (f3, 7.0, 8.0, false);
> +  C (f3, 8.0, 8.0, false);
> +  C (f3, 9.0, 8.0, true);
> +  C (f3, __builtin_nan (""), 8.0, false);
> +  C (f4, 7.0, 8.0, true);
> +  C (f4, 8.0, 8.0, false);
> +  C (f4, 9.0, 8.0, false);
> +  C (f4, __builtin_nan (""), 8.0, false);
> +  C (f5, 7.0, 8.0, false);
> +  C (f5, 8.0, 8.0, true);
> +  C (f5, 9.0, 8.0, true);
> +  C (f5, __builtin_nan (""), 8.0, false);
> +  C (f6, 7.0, 8.0, true);
> +  C (f6, 8.0, 8.0, true);
> +  C (f6, 9.0, 8.0, false);
> +  C (f6, __builtin_nan (""), 8.0, false);
> +  C (f7, 7.0, 8.0, true);
> +  C (f7, 8.0, 8.0, false);
> +  C (f7, 9.0, 8.0, false);
> +  C (f7, __builtin_nan (""), 8.0, false);
> +  C (f8, 7.0, 8.0, false);
> +  C (f8, 8.0, 8.0, true);
> +  C (f8, 9.0, 8.0, true);
> +  C (f8, __builtin_nan (""), 8.0, true);
> +  C (f9, 7.0, 8.0, false);
> +  C (f9, 8.0, 8.0, true);
> +  C (f9, 9.0, 8.0, false);
> +  C (f9, __builtin_nan (""), 8.0, false);
> +  C (f10, 7.0, 8.0, true);
> +  C (f10, 8.0, 8.0, false);
> +  C (f10, 9.0, 8.0, true);
> +  C (f10, __builtin_nan (""), 8.0, true);
> +  C (f11, 7.0, 8.0, false);
> +  C (f11, 8.0, 8.0, false);
> +  C (f11, 9.0, 8.0, true);
> +  C (f11, __builtin_nan (""), 8.0, false);
> +  C (f12, 7.0, 8.0, true);
> +  C (f12, 8.0, 8.0, true);
> +  C (f12, 9.0, 8.0, false);
> +  C (f12, __builtin_nan (""), 8.0, true);
> +  D (f13, 4.0, false);
> +  D (f13, 5.0, true);
> +  D (f13, 6.0, false);
> +  D (f13, __builtin_nan (""), false);
> +  D (f14, 4.0, true);
> +  D (f14, 5.0, false);
> +  D (f14, 6.0, true);
> +  D (f14, __builtin_nan (""), true);
> +  D (f15, 4.0, false);
> +  D (f15, 5.0, false);
> +  D (f15, 6.0, true);
> +  D (f15, __builtin_nan (""), false);
> +  D (f16, 4.0, true);
> +  D (f16, 5.0, false);
> +  D (f16, 6.0, false);
> +  D (f16, __builtin_nan (""), false);
> +  D (f17, 4.0, false);
> +  D (f17, 5.0, true);
> +  D (f17, 6.0, true);
> +  D (f17, __builtin_nan (""), false);
> +  D (f18, 4.0, true);
> +  D (f18, 5.0, true);
> +  D (f18, 6.0, false);
> +  D (f18, __builtin_nan (""), false);
> +  D (f19, 4.0, true);
> +  D (f19, 5.0, false);
> +  D (f19, 6.0, false);
> +  D (f19, __builtin_nan (""), false);
> +  D (f20, 4.0, false);
> +  D (f20, 5.0, true);
> +  D (f20, 6.0, true);
> +  D (f20, __builtin_nan (""), true);
> +  D (f21, 4.0, false);
> +  D (f21, 5.0, true);
> +  D (f21, 6.0, false);
> +  D (f21, __builtin_nan (""), false);
> +  D (f22, 4.0, true);
> +  D (f22, 5.0, false);
> +  D (f22, 6.0, true);
> +  D (f22, __builtin_nan (""), true);
> +  D (f23, 4.0, false);
> +  D (f23, 5.0, false);
> +  D (f23, 6.0, true);
> +  D (f23, __builtin_nan (""), false);
> +  D (f24, 4.0, true);
> +  D (f24, 5.0, true);
> +  D (f24, 6.0, false);
> +  D (f24, __builtin_nan (""), true);
> +  C (f25, 7.0, 8.0, false);
> +  C (f25, 8.0, 8.0, false);
> +  C (f25, 9.0, 8.0, false);
> +  C (f25, __builtin_nan (""), 8.0, true);
> +  C (f26, 7.0, 8.0, true);
> +  C (f26, 8.0, 8.0, true);
> +  C (f26, 9.0, 8.0, true);
> +  C (f26, __builtin_nan (""), 8.0, false);
> +  D (f27, 4.0, false);
> +  D (f27, 5.0, false);
> +  D (f27, 6.0, false);
> +  D (f27, __builtin_nan (""), true);
> +  D (f28, 4.0, true);
> +  D (f28, 5.0, true);
> +  D (f28, 6.0, true);
> +  D (f28, __builtin_nan (""), false);
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to