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)