public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Sebor <msebor@gmail.com>
To: Jakub Jelinek <jakub@redhat.com>,
	Richard Biener <rguenther@suse.de>,
	Jonathan Wakely <jwakely@redhat.com>,
	Jason Merrill <jason@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] phiopt: Optimize (x <=> y) cmp z [PR94589]
Date: Wed, 5 May 2021 09:45:25 -0600	[thread overview]
Message-ID: <72f2b8a0-89aa-f3af-74b2-8358103e8b44@gmail.com> (raw)
In-Reply-To: <20210504074413.GI1179226@tucnak>

On 5/4/21 1:44 AM, Jakub Jelinek via Gcc-patches wrote:
> Hi!
> 
> genericize_spaceship genericizes i <=> j to approximately
> ({ int c; if (i == j) c = 0; else if (i < j) c = -1; else c = 1; c; })
> for strong ordering and
> ({ int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; c; })
> for partial ordering.
> The C++ standard supports then == or != comparisons of that against
> strong/partial ordering enums, or </<=/==/!=/>/>= comparisons of <=> result
> against literal 0.
> 
> In some cases we already optimize that but in many cases we keep performing
> all the 2 or 3 comparisons, compute the spaceship value and then compare
> that.
> 
> The following patch recognizes those patterns if the <=> operands are
> integral types or floating point (the latter only for -ffast-math) and
> optimizes it to the single comparison that is needed (plus adds debug stmts
> if needed for the spaceship result).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Just a few words on readabilty.

I didn't follow all the logic carefully but I found the code very
dense and hard to read, and a little too frugal with comments.
The new spaceship_replacement function is over 340 lines long!  It
could stand to be broken up into a few smaller logical pieces to
be easier to read and understand.  Commenting the pieces would
also help (a lot).  (It may seem crystal clear to you the way it
is but not all of us read code as it was prose.  It's good to
keep that in mind.)

Overall, long functions are easier to read if they make more liberal
use of vertical whitespace than when they look like one uninterrupted
stream of text.  I see that sometimes you separate chunks of code with
blank lines but other times you don't.  I'm not sure I see any pattern
to it but it would help to separate logical blocks with blank lines,
especially after return statements.  I marked up a few spots to give
you a general idea what I mean.

Martin

> 
> There are two things I'd like to address in a follow-up:
> 1) if (HONOR_NANS (TREE_TYPE (lhs1)) || HONOR_SIGNED_ZEROS (TREE_TYPE (lhs1)))
> is what I've copied from elsewhere in phiopt, but thinking about it,
> alll we care is probably only HONOR_NANS, the matched pattern starts with
> == or != comparison and branches to the PHI bb with -1/0/1/2 result if it is
> equal, which should be the case for signed zero differences.
> 2) the pr94589-2.C testcase should be matching just 12 times each, but runs
> into operator>=(strong_ordering, unspecified) being defined as
> (_M_value&1)==_M_value
> rather than _M_value>=0.  When not honoring NaNs, the 2 case should be
> unreachable and so (_M_value&1)==_M_value is then equivalent to _M_value>=0,
> but is not a single use but two uses.  I'll need to pattern match that case
> specially.
> 
> 2021-05-04  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/94589
> 	* tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Call
> 	spaceship_replacement.
> 	(cond_only_block_p, spaceship_replacement): New functions.
> 
> 	* gcc.dg/pr94589-1.c: New test.
> 	* gcc.dg/pr94589-2.c: New test.
> 	* gcc.dg/pr94589-3.c: New test.
> 	* gcc.dg/pr94589-4.c: New test.
> 	* g++.dg/opt/pr94589-1.C: New test.
> 	* g++.dg/opt/pr94589-2.C: New test.
> 	* g++.dg/opt/pr94589-3.C: New test.
> 	* g++.dg/opt/pr94589-4.C: New test.
> 
> --- gcc/tree-ssa-phiopt.c.jj	2021-05-02 10:17:49.095397758 +0200
> +++ gcc/tree-ssa-phiopt.c	2021-05-03 17:49:54.233300624 +0200
> @@ -64,6 +64,8 @@ static bool abs_replacement (basic_block
>   			     edge, edge, gimple *, tree, tree);
>   static bool xor_replacement (basic_block, basic_block,
>   			     edge, edge, gimple *, tree, tree);
> +static bool spaceship_replacement (basic_block, basic_block,
> +				   edge, edge, gimple *, tree, tree);
>   static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block,
>   						      edge, edge, gimple *,
>   						      tree, tree);
> @@ -357,6 +359,8 @@ tree_ssa_phiopt_worker (bool do_store_el
>   	    cfgchanged = true;
>   	  else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
>   	    cfgchanged = true;
> +	  else if (spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
> +	    cfgchanged = true;
>   	}
>       }
>   
> @@ -1806,6 +1810,420 @@ minmax_replacement (basic_block cond_bb,
>   
>     return true;
>   }
> +
> +/* Return true if the only executable statement in BB is a GIMPLE_COND.  */
> +
> +static bool
> +cond_only_block_p (basic_block bb)
> +{
> +  /* BB must have no executable statements.  */
> +  gimple_stmt_iterator gsi = gsi_after_labels (bb);
> +  if (phi_nodes (bb))
> +    return false;
> +  while (!gsi_end_p (gsi))
> +    {
> +      gimple *stmt = gsi_stmt (gsi);
> +      if (is_gimple_debug (stmt))
> +	;
> +      else if (gimple_code (stmt) == GIMPLE_NOP
> +	       || gimple_code (stmt) == GIMPLE_PREDICT
> +	       || gimple_code (stmt) == GIMPLE_COND)
> +	;
> +      else
> +	return false;
> +      gsi_next (&gsi);
> +    }
> +  return true;
> +}
> +
> +/* Attempt to optimize (x <=> y) cmp 0 and similar comparisons.
> +   For strong ordering <=> try to match something like:
> +    <bb 2> :
> +    if (x_4(D) != y_5(D))
> +      goto <bb 3>; [INV]
> +    else
> +      goto <bb 6>; [INV]
> +
> +    <bb 3> :
> +    if (x_4(D) < y_5(D))
> +      goto <bb 6>; [INV]
> +    else
> +      goto <bb 4>; [INV]
> +
> +    <bb 4> :
> +
> +    <bb 6> :
> +    # iftmp.0_2 = PHI <1(4), 0(2), -1(3)>
> +    _1 = iftmp.0_2 == 0;
> +
> +   and for partial ordering <=> something like:
> +
> +    <bb 2> :
> +    if (a_3(D) == b_5(D))
> +      goto <bb 6>; [50.00%]
> +    else
> +      goto <bb 3>; [50.00%]
> +
> +    <bb 3> [local count: 536870913]:
> +    if (a_3(D) < b_5(D))
> +      goto <bb 6>; [50.00%]
> +    else
> +      goto <bb 4>; [50.00%]
> +
> +    <bb 4> [local count: 268435456]:
> +    if (a_3(D) > b_5(D))
> +      goto <bb 6>; [50.00%]
> +    else
> +      goto <bb 5>; [50.00%]
> +
> +    <bb 5> [local count: 134217728]:
> +
> +    <bb 6> [local count: 1073741824]:
> +    # SR.27_4 = PHI <0(2), -1(3), 1(4), 2(5)>
> +    _2 = SR.27_4 > 0;  */

The code below uses variable names like lhs1, rhs1, lhs2, and rhs2
that correspond to some of the operands above.  Annotating the code
above with the names of the variables would make the function easier
to understand.

> +
> +static bool
> +spaceship_replacement (basic_block cond_bb, basic_block middle_bb,
> +		       edge e0, edge e1, gimple *phi,
> +		       tree arg0, tree arg1)
> +{
> +  if (!INTEGRAL_TYPE_P (TREE_TYPE (PHI_RESULT (phi)))
> +      || TYPE_UNSIGNED (TREE_TYPE (PHI_RESULT (phi)))
> +      || !tree_fits_shwi_p (arg0)
> +      || !tree_fits_shwi_p (arg1)
> +      || !IN_RANGE (tree_to_shwi (arg0), -1, 2)
> +      || !IN_RANGE (tree_to_shwi (arg1), -1, 2))
> +    return false;
> +
> +  use_operand_p use_p;
> +  gimple *use_stmt;
> +  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)))
> +    return false;
> +  if (!single_imm_use (PHI_RESULT (phi), &use_p, &use_stmt))
> +    return false;

Add a blank line here and a comment below.

> +  enum tree_code cmp;
> +  tree lhs, rhs;
> +  if (gimple_code (use_stmt) == GIMPLE_COND)
> +    {
> +      cmp = gimple_cond_code (use_stmt);
> +      lhs = gimple_cond_lhs (use_stmt);
> +      rhs = gimple_cond_rhs (use_stmt);
> +    }
> +  else if (is_gimple_assign (use_stmt))
> +    {
> +      if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS)
> +	{
> +	  cmp = gimple_assign_rhs_code (use_stmt);
> +	  lhs = gimple_assign_rhs1 (use_stmt);
> +	  rhs = gimple_assign_rhs2 (use_stmt);
> +	}
> +      else if (gimple_assign_rhs_code (use_stmt) == COND_EXPR)
> +	{
> +	  tree cond = gimple_assign_rhs1 (use_stmt);
> +	  if (!COMPARISON_CLASS_P (cond))
> +	    return false;
> +	  cmp = TREE_CODE (cond);
> +	  lhs = TREE_OPERAND (cond, 0);
> +	  rhs = TREE_OPERAND (cond, 1);
> +	}
> +      else
> +	return false;
> +    }
> +  else
> +    return false;

Add a blank line here.

> +  switch (cmp)
> +    {
> +    case EQ_EXPR:
> +    case NE_EXPR:
> +    case LT_EXPR:
> +    case GT_EXPR:
> +    case LE_EXPR:
> +    case GE_EXPR:
> +      break;
> +    default:
> +      return false;
> +    }

Add a blank line here.

> +  if (lhs != PHI_RESULT (phi)
> +      || !tree_fits_shwi_p (rhs)
> +      || !IN_RANGE (tree_to_shwi (rhs), -1, 1))
> +    return false;
> +
> +  if (!empty_block_p (middle_bb))
> +    return false;
> +
> +  basic_block phi_bb = gimple_bb (phi);
> +  gcc_assert (phi_bb == e0->dest && phi_bb == e1->dest);
> +  if (!IN_RANGE (EDGE_COUNT (phi_bb->preds), 3, 4))
> +    return false;

Helpful blank lines above.

> +
> +  gcond *cond1 = as_a <gcond *> (last_stmt (cond_bb));
> +  enum tree_code cmp1 = gimple_cond_code (cond1);
> +  if (cmp1 != LT_EXPR && cmp1 != GT_EXPR)
> +    return false;

Add a blank line here.

We define lhs and rhs above and lhs1 and rhs1 below.  A comment
explaining what the variables correspond to would help (as might
choosing better names).

> +  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)) || HONOR_SIGNED_ZEROS (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))
> +    return false;
> +
> +  if (!single_pred_p (cond_bb) || !cond_only_block_p (cond_bb))
> +    return false;
> +

Helpful blank lines above.

The code below could use a comment.

> +  basic_block cond2_bb = single_pred (cond_bb);
> +  if (EDGE_COUNT (cond2_bb->succs) != 2)
> +    return false;
> +  edge cond2_phi_edge;
> +  if (EDGE_SUCC (cond2_bb, 0)->dest == cond_bb)
> +    {
> +      if (EDGE_SUCC (cond2_bb, 1)->dest != phi_bb)
> +	return false;
> +      cond2_phi_edge = EDGE_SUCC (cond2_bb, 1);
> +    }
> +  else if (EDGE_SUCC (cond2_bb, 0)->dest != phi_bb)
> +    return false;
> +  else
> +    cond2_phi_edge = EDGE_SUCC (cond2_bb, 0);

Add blank line here.

The code below could use a comment.  Same for lhs2 and rhs2 (picking
better names might also help).

> +  tree arg2 = gimple_phi_arg_def (phi, cond2_phi_edge->dest_idx);
> +  if (!tree_fits_shwi_p (arg2))
> +    return false;
> +  gimple *cond2 = last_stmt (cond2_bb);
> +  if (cond2 == NULL || gimple_code (cond2) != GIMPLE_COND)
> +    return false;
> +  enum tree_code cmp2 = gimple_cond_code (cond2);
> +  tree lhs2 = gimple_cond_lhs (cond2);
> +  tree rhs2 = gimple_cond_rhs (cond2);
> +  if (lhs2 == lhs1)
> +    {
> +      if (!operand_equal_p (rhs2, rhs1, 0))
> +	return false;
> +    }
> +  else if (lhs2 == rhs1)
> +    {
> +      if (rhs2 != lhs1)
> +	return false;
> +    }
> +  else
> +    return false;

Add a blank line here.

The big if statement below could use a comment.

> +  tree arg3 = arg2;
> +  basic_block cond3_bb = cond2_bb;
> +  edge cond3_phi_edge = cond2_phi_edge;
> +  gimple *cond3 = cond2;
> +  enum tree_code cmp3 = cmp2;
> +  tree lhs3 = lhs2;
> +  tree rhs3 = rhs2;
> +  if (EDGE_COUNT (phi_bb->preds) == 4)
> +    {
> +      if (absu_hwi (tree_to_shwi (arg2)) != 1)
> +	return false;

Add a blank line here.

> +      if (e1->flags & EDGE_TRUE_VALUE)
> +	{
> +	  if (tree_to_shwi (arg0) != 2
> +	      || absu_hwi (tree_to_shwi (arg1)) != 1
> +	      || wi::to_widest (arg1) == wi::to_widest (arg2))
> +	    return false;
> +	}
> +      else if (tree_to_shwi (arg1) != 2
> +	       || absu_hwi (tree_to_shwi (arg0)) != 1
> +	       || wi::to_widest (arg0) == wi::to_widest (arg1))
> +	return false;

Add a blank line here.

> +      if (cmp2 != LT_EXPR && cmp2 != GT_EXPR)
> +	return false;

Add a blank line here.

> +      /* if (x < y) goto phi_bb; else fallthru;
> +	 if (x > y) goto phi_bb; else fallthru;
> +	 bbx:;
> +	 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 second goto phi_bb is not the true edge, it is not.  */
> +      if ((lhs2 == lhs1)
> +	  ^ (cmp2 == cmp1)
> +	  ^ ((e1->flags & EDGE_TRUE_VALUE) != 0))
> +	return false;

Add a blank line here and a comment for code below?

> +      if ((cond2_phi_edge->flags & EDGE_TRUE_VALUE) == 0)
> +	return false;
> +      if (!single_pred_p (cond2_bb) || !cond_only_block_p (cond2_bb))
> +	return false;
> +      cond3_bb = single_pred (cond2_bb);
> +      if (EDGE_COUNT (cond2_bb->succs) != 2)
> +	return false;
> +      if (EDGE_SUCC (cond3_bb, 0)->dest == cond2_bb)
> +	{
> +	  if (EDGE_SUCC (cond3_bb, 1)->dest != phi_bb)
> +	    return false;
> +	  cond3_phi_edge = EDGE_SUCC (cond3_bb, 1);
> +	}
> +      else if (EDGE_SUCC (cond3_bb, 0)->dest != phi_bb)
> +	return false;
> +      else
> +	cond3_phi_edge = EDGE_SUCC (cond3_bb, 0);

Add a blank line here and comment for code below.

> +      arg3 = gimple_phi_arg_def (phi, cond3_phi_edge->dest_idx);
> +      cond3 = last_stmt (cond3_bb);
> +      if (cond3 == NULL || gimple_code (cond3) != GIMPLE_COND)
> +	return false;
> +      cmp3 = gimple_cond_code (cond3);
> +      lhs3 = gimple_cond_lhs (cond3);
> +      rhs3 = gimple_cond_rhs (cond3);
> +      if (lhs3 == lhs1)
> +	{
> +	  if (!operand_equal_p (rhs3, rhs1, 0))
> +	    return false;
> +	}
> +      else if (lhs3 == rhs1)
> +	{
> +	  if (rhs3 != lhs1)
> +	    return false;
> +	}
> +      else
> +	return false;
> +    }
> +  else if (absu_hwi (tree_to_shwi (arg0)) != 1
> +	   || absu_hwi (tree_to_shwi (arg1)) != 1
> +	   || wi::to_widest (arg0) == wi::to_widest (arg1))
> +    return false;
> +
> +  if (!integer_zerop (arg3) || (cmp3 != EQ_EXPR && cmp3 != NE_EXPR))
> +    return false;
> +  if ((cond3_phi_edge->flags & (cmp3 == EQ_EXPR
> +				? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) == 0)
> +    return false;
> +

Helpful blank lines above.

> +  /* lhs1 one_cmp rhs1 results in PHI_RESULT (phi) of 1.  */
> +  enum tree_code one_cmp;
> +  if ((cmp1 == LT_EXPR)
> +      ^ (!integer_onep ((e1->flags & EDGE_TRUE_VALUE) ? arg1 : arg0)))
> +    one_cmp = LT_EXPR;
> +  else
> +    one_cmp = GT_EXPR;
> +

The switch statement below could use a comment explaining what it
does.  Better yet, move it to its own function with such a comment.

> +  enum tree_code res_cmp;
> +  switch (cmp)
> +    {
> +    case EQ_EXPR:
> +      if (integer_zerop (rhs))
> +	res_cmp = EQ_EXPR;
> +      else if (integer_minus_onep (rhs))
> +	res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
> +      else if (integer_onep (rhs))
> +	res_cmp = one_cmp;
> +      else
> +	return false;
> +      break;
> +    case NE_EXPR:
> +      if (integer_zerop (rhs))
> +	res_cmp = NE_EXPR;
> +      else if (integer_minus_onep (rhs))
> +	res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
> +      else if (integer_onep (rhs))
> +	res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR;
> +      else
> +	return false;
> +      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;
> +      else
> +	return false;
> +      break;
> +    case LE_EXPR:
> +      if (integer_zerop (rhs))
> +	res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR;
> +      else if (integer_minus_onep (rhs))
> +	res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR;
> +      else
> +	return false;
> +      break;
> +    case GT_EXPR:
> +      if (integer_minus_onep (rhs))
> +	res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
> +      else if (integer_zerop (rhs))
> +	res_cmp = one_cmp;
> +      else
> +	return false;
> +      break;
> +    case GE_EXPR:
> +      if (integer_zerop (rhs))
> +	res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR;
> +      else if (integer_onep (rhs))
> +	res_cmp = one_cmp;
> +      else
> +	return false;
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +

Add a comment for code below.

> +  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);
> +    }
> +  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);
> +    }
> +  else
> +    {
> +      tree cond = build2 (res_cmp, TREE_TYPE (gimple_assign_rhs1 (use_stmt)),
> +			  lhs1, rhs1);
> +      gimple_assign_set_rhs1 (use_stmt, cond);
> +    }
> +  update_stmt (use_stmt);
> +  if (cmp3 == EQ_EXPR)
> +    gimple_cond_make_true (as_a <gcond *> (cond3));
> +  else
> +    gimple_cond_make_false (as_a <gcond *> (cond3));
> +  update_stmt (cond3);
> +

Add a comment.

> +  if (MAY_HAVE_DEBUG_BIND_STMTS)
> +    {
> +      use_operand_p use_p;
> +      imm_use_iterator iter;
> +      bool has_debug_uses = false;
> +      FOR_EACH_IMM_USE_FAST (use_p, iter, PHI_RESULT (phi))
> +	{
> +	  gimple *use_stmt = USE_STMT (use_p);
> +	  gcc_assert (is_gimple_debug (use_stmt));
> +	  has_debug_uses = true;
> +	  break;
> +	}
> +

Add a comment.

> +      if (has_debug_uses)
> +	{
> +	  gimple_stmt_iterator gsi = gsi_after_labels (gimple_bb (phi));
> +	  tree type = TREE_TYPE (PHI_RESULT (phi));
> +	  tree temp1 = make_node (DEBUG_EXPR_DECL);
> +	  DECL_ARTIFICIAL (temp1) = 1;
> +	  TREE_TYPE (temp1) = type;
> +	  SET_DECL_MODE (temp1, TYPE_MODE (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));
> +	  gimple *g = gimple_build_debug_bind (temp1, t, phi);
> +	  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> +	  tree temp2 = make_node (DEBUG_EXPR_DECL);
> +	  DECL_ARTIFICIAL (temp2) = 1;
> +	  TREE_TYPE (temp2) = type;
> +	  SET_DECL_MODE (temp2, TYPE_MODE (type));
> +	  t = build2 (EQ_EXPR, boolean_type_node, lhs1, rhs2);
> +	  t = build3 (COND_EXPR, type, t, build_zero_cst (type), temp1);
> +	  g = gimple_build_debug_bind (temp2, t, phi);
> +	  gsi_insert_before (&gsi, g, GSI_SAME_STMT);
> +	  replace_uses_by (PHI_RESULT (phi), temp2);
> +	}
> +    }
> +
> +  return true;
> +}
>   
>   /* Convert
>   
> --- gcc/testsuite/gcc.dg/pr94589-1.c.jj	2021-05-03 17:32:14.940203230 +0200
> +++ gcc/testsuite/gcc.dg/pr94589-1.c	2021-05-03 17:54:33.081167518 +0200
> @@ -0,0 +1,35 @@
> +/* PR tree-optimization/94589 */
> +/* { dg-do compile } */
> +/* { 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\\) (?:<|<=|==|!=|>|>=) \[45]" 14 "optimized" } } */
> +
> +#define A __attribute__((noipa))
> +A int f1 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == 0; }
> +A int f2 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != 0; }
> +A int f3 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c > 0; }
> +A int f4 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c < 0; }
> +A int f5 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c >= 0; }
> +A int f6 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c <= 0; }
> +A int f7 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == -1; }
> +A int f8 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != -1; }
> +A int f9 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c > -1; }
> +A int f10 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c <= -1; }
> +A int f11 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == 1; }
> +A int f12 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != 1; }
> +A int f13 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c < 1; }
> +A int f14 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c >= 1; }
> +A int f15 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == 0; }
> +A int f16 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != 0; }
> +A int f17 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c > 0; }
> +A int f18 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c < 0; }
> +A int f19 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c >= 0; }
> +A int f20 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c <= 0; }
> +A int f21 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == -1; }
> +A int f22 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != -1; }
> +A int f23 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c > -1; }
> +A int f24 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c <= -1; }
> +A int f25 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == 1; }
> +A int f26 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != 1; }
> +A int f27 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c < 1; }
> +A int f28 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c >= 1; }
> --- gcc/testsuite/gcc.dg/pr94589-2.c.jj	2021-05-03 17:32:17.950169407 +0200
> +++ gcc/testsuite/gcc.dg/pr94589-2.c	2021-05-03 17:56:12.577049606 +0200
> @@ -0,0 +1,35 @@
> +/* PR tree-optimization/94589 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -g0 -ffast-math -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 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 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 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; }
> +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; }
> --- gcc/testsuite/gcc.dg/pr94589-3.c.jj	2021-05-03 17:32:19.998146397 +0200
> +++ gcc/testsuite/gcc.dg/pr94589-3.c	2021-05-03 18:02:41.628678802 +0200
> @@ -0,0 +1,97 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -g" } */
> +
> +#include "pr94589-1.c"
> +
> +#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, 8, 0);
> +  C (f1, 8, 8, 1);
> +  C (f1, 9, 8, 0);
> +  C (f2, 7, 8, 1);
> +  C (f2, 8, 8, 0);
> +  C (f2, 9, 8, 1);
> +  C (f3, 7, 8, 0);
> +  C (f3, 8, 8, 0);
> +  C (f3, 9, 8, 1);
> +  C (f4, 7, 8, 1);
> +  C (f4, 8, 8, 0);
> +  C (f4, 9, 8, 0);
> +  C (f5, 7, 8, 0);
> +  C (f5, 8, 8, 1);
> +  C (f5, 9, 8, 1);
> +  C (f6, 7, 8, 1);
> +  C (f6, 8, 8, 1);
> +  C (f6, 9, 8, 0);
> +  C (f7, 7, 8, 1);
> +  C (f7, 8, 8, 0);
> +  C (f7, 9, 8, 0);
> +  C (f8, 7, 8, 0);
> +  C (f8, 8, 8, 1);
> +  C (f8, 9, 8, 1);
> +  C (f9, 7, 8, 0);
> +  C (f9, 8, 8, 1);
> +  C (f9, 9, 8, 1);
> +  C (f10, 7, 8, 1);
> +  C (f10, 8, 8, 0);
> +  C (f10, 9, 8, 0);
> +  C (f11, 7, 8, 0);
> +  C (f11, 8, 8, 0);
> +  C (f11, 9, 8, 1);
> +  C (f12, 7, 8, 1);
> +  C (f12, 8, 8, 1);
> +  C (f12, 9, 8, 0);
> +  C (f13, 7, 8, 1);
> +  C (f13, 8, 8, 1);
> +  C (f13, 9, 8, 0);
> +  C (f14, 7, 8, 0);
> +  C (f14, 8, 8, 0);
> +  C (f14, 9, 8, 1);
> +  D (f15, 4, 0);
> +  D (f15, 5, 1);
> +  D (f15, 6, 0);
> +  D (f16, 4, 1);
> +  D (f16, 5, 0);
> +  D (f16, 6, 1);
> +  D (f17, 4, 0);
> +  D (f17, 5, 0);
> +  D (f17, 6, 1);
> +  D (f18, 4, 1);
> +  D (f18, 5, 0);
> +  D (f18, 6, 0);
> +  D (f19, 4, 0);
> +  D (f19, 5, 1);
> +  D (f19, 6, 1);
> +  D (f20, 4, 1);
> +  D (f20, 5, 1);
> +  D (f20, 6, 0);
> +  D (f21, 4, 1);
> +  D (f21, 5, 0);
> +  D (f21, 6, 0);
> +  D (f22, 4, 0);
> +  D (f22, 5, 1);
> +  D (f22, 6, 1);
> +  D (f23, 4, 0);
> +  D (f23, 5, 1);
> +  D (f23, 6, 1);
> +  D (f24, 4, 1);
> +  D (f24, 5, 0);
> +  D (f24, 6, 0);
> +  D (f25, 4, 0);
> +  D (f25, 5, 0);
> +  D (f25, 6, 1);
> +  D (f26, 4, 1);
> +  D (f26, 5, 1);
> +  D (f26, 6, 0);
> +  D (f27, 4, 1);
> +  D (f27, 5, 1);
> +  D (f27, 6, 0);
> +  D (f28, 4, 0);
> +  D (f28, 5, 0);
> +  D (f28, 6, 1);
> +  return 0;
> +}
> --- gcc/testsuite/gcc.dg/pr94589-4.c.jj	2021-05-03 17:32:21.915124851 +0200
> +++ gcc/testsuite/gcc.dg/pr94589-4.c	2021-05-03 18:12:50.748835798 +0200
> @@ -0,0 +1,97 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -g -ffast-math" } */
> +
> +#include "pr94589-2.c"
> +
> +#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 (f2, 7.0, 8.0, 1);
> +  C (f2, 8.0, 8.0, 0);
> +  C (f2, 9.0, 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 (f4, 7.0, 8.0, 1);
> +  C (f4, 8.0, 8.0, 0);
> +  C (f4, 9.0, 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 (f6, 7.0, 8.0, 1);
> +  C (f6, 8.0, 8.0, 1);
> +  C (f6, 9.0, 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 (f8, 7.0, 8.0, 0);
> +  C (f8, 8.0, 8.0, 1);
> +  C (f8, 9.0, 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 (f10, 7.0, 8.0, 1);
> +  C (f10, 8.0, 8.0, 0);
> +  C (f10, 9.0, 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 (f12, 7.0, 8.0, 1);
> +  C (f12, 8.0, 8.0, 1);
> +  C (f12, 9.0, 8.0, 0);
> +  C (f13, 7.0, 8.0, 1);
> +  C (f13, 8.0, 8.0, 1);
> +  C (f13, 9.0, 8.0, 0);
> +  C (f14, 7.0, 8.0, 0);
> +  C (f14, 8.0, 8.0, 0);
> +  C (f14, 9.0, 8.0, 1);
> +  D (f15, 4.0, 0);
> +  D (f15, 5.0, 1);
> +  D (f15, 6.0, 0);
> +  D (f16, 4.0, 1);
> +  D (f16, 5.0, 0);
> +  D (f16, 6.0, 1);
> +  D (f17, 4.0, 0);
> +  D (f17, 5.0, 0);
> +  D (f17, 6.0, 1);
> +  D (f18, 4.0, 1);
> +  D (f18, 5.0, 0);
> +  D (f18, 6.0, 0);
> +  D (f19, 4.0, 0);
> +  D (f19, 5.0, 1);
> +  D (f19, 6.0, 1);
> +  D (f20, 4.0, 1);
> +  D (f20, 5.0, 1);
> +  D (f20, 6.0, 0);
> +  D (f21, 4.0, 1);
> +  D (f21, 5.0, 0);
> +  D (f21, 6.0, 0);
> +  D (f22, 4.0, 0);
> +  D (f22, 5.0, 1);
> +  D (f22, 6.0, 1);
> +  D (f23, 4.0, 0);
> +  D (f23, 5.0, 1);
> +  D (f23, 6.0, 1);
> +  D (f24, 4.0, 1);
> +  D (f24, 5.0, 0);
> +  D (f24, 6.0, 0);
> +  D (f25, 4.0, 0);
> +  D (f25, 5.0, 0);
> +  D (f25, 6.0, 1);
> +  D (f26, 4.0, 1);
> +  D (f26, 5.0, 1);
> +  D (f26, 6.0, 0);
> +  D (f27, 4.0, 1);
> +  D (f27, 5.0, 1);
> +  D (f27, 6.0, 0);
> +  D (f28, 4.0, 0);
> +  D (f28, 5.0, 0);
> +  D (f28, 6.0, 1);
> +  return 0;
> +}
> --- gcc/testsuite/g++.dg/opt/pr94589-1.C.jj	2021-05-03 15:24:02.002046458 +0200
> +++ gcc/testsuite/g++.dg/opt/pr94589-1.C	2021-05-03 15:23:47.445210269 +0200
> @@ -0,0 +1,33 @@
> +// PR tree-optimization/94589
> +// { dg-do compile { target c++20 } }
> +// { dg-options "-O2 -g0 -fdump-tree-optimized" }
> +// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 12 "optimized" } }
> +// { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[45]" 12 "optimized" } }
> +
> +#include <compare>
> +
> +#define A __attribute__((noipa))
> +A bool f1 (int i, int j) { auto c = i <=> j; return c == 0; }
> +A bool f2 (int i, int j) { auto c = i <=> j; return c != 0; }
> +A bool f3 (int i, int j) { auto c = i <=> j; return c > 0; }
> +A bool f4 (int i, int j) { auto c = i <=> j; return c < 0; }
> +A bool f5 (int i, int j) { auto c = i <=> j; return c >= 0; }
> +A bool f6 (int i, int j) { auto c = i <=> j; return c <= 0; }
> +A bool f7 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::less; }
> +A bool f8 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::less; }
> +A bool f9 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::equal; }
> +A bool f10 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::equal; }
> +A bool f11 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::greater; }
> +A bool f12 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::greater; }
> +A bool f13 (int i) { auto c = i <=> 5; return c == 0; }
> +A bool f14 (int i) { auto c = i <=> 5; return c != 0; }
> +A bool f15 (int i) { auto c = i <=> 5; return c > 0; }
> +A bool f16 (int i) { auto c = i <=> 5; return c < 0; }
> +A bool f17 (int i) { auto c = i <=> 5; return c >= 0; }
> +A bool f18 (int i) { auto c = i <=> 5; return c <= 0; }
> +A bool f19 (int i) { auto c = i <=> 5; return c == std::strong_ordering::less; }
> +A bool f20 (int i) { auto c = i <=> 5; return c != std::strong_ordering::less; }
> +A bool f21 (int i) { auto c = i <=> 5; return c == std::strong_ordering::equal; }
> +A bool f22 (int i) { auto c = i <=> 5; return c != std::strong_ordering::equal; }
> +A bool f23 (int i) { auto c = i <=> 5; return c == std::strong_ordering::greater; }
> +A bool f24 (int i) { auto c = i <=> 5; return c != std::strong_ordering::greater; }
> --- gcc/testsuite/g++.dg/opt/pr94589-2.C.jj	2021-05-03 16:12:12.002540809 +0200
> +++ gcc/testsuite/g++.dg/opt/pr94589-2.C	2021-05-03 16:16:53.194380966 +0200
> @@ -0,0 +1,33 @@
> +// PR tree-optimization/94589
> +// { dg-do compile { target c++20 } }
> +// { dg-options "-O2 -g0 -ffast-math -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" } }
> +
> +#include <compare>
> +
> +#define A __attribute__((noipa))
> +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 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 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 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 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 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 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 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-3.C.jj	2021-05-03 16:22:29.898597327 +0200
> +++ gcc/testsuite/g++.dg/opt/pr94589-3.C	2021-05-03 17:21:23.290556509 +0200
> @@ -0,0 +1,84 @@
> +// { dg-do run { target c++20 } }
> +// { dg-options "-O2 -g" }
> +
> +#include "pr94589-1.C"
> +
> +#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, 8, false);
> +  C (f1, 8, 8, true);
> +  C (f1, 9, 8, false);
> +  C (f2, 7, 8, true);
> +  C (f2, 8, 8, false);
> +  C (f2, 9, 8, true);
> +  C (f3, 7, 8, false);
> +  C (f3, 8, 8, false);
> +  C (f3, 9, 8, true);
> +  C (f4, 7, 8, true);
> +  C (f4, 8, 8, false);
> +  C (f4, 9, 8, false);
> +  C (f5, 7, 8, false);
> +  C (f5, 8, 8, true);
> +  C (f5, 9, 8, true);
> +  C (f6, 7, 8, true);
> +  C (f6, 8, 8, true);
> +  C (f6, 9, 8, false);
> +  C (f7, 7, 8, true);
> +  C (f7, 8, 8, false);
> +  C (f7, 9, 8, false);
> +  C (f8, 7, 8, false);
> +  C (f8, 8, 8, true);
> +  C (f8, 9, 8, true);
> +  C (f9, 7, 8, false);
> +  C (f9, 8, 8, true);
> +  C (f9, 9, 8, false);
> +  C (f10, 7, 8, true);
> +  C (f10, 8, 8, false);
> +  C (f10, 9, 8, true);
> +  C (f11, 7, 8, false);
> +  C (f11, 8, 8, false);
> +  C (f11, 9, 8, true);
> +  C (f12, 7, 8, true);
> +  C (f12, 8, 8, true);
> +  C (f12, 9, 8, false);
> +  D (f13, 4, false);
> +  D (f13, 5, true);
> +  D (f13, 6, false);
> +  D (f14, 4, true);
> +  D (f14, 5, false);
> +  D (f14, 6, true);
> +  D (f15, 4, false);
> +  D (f15, 5, false);
> +  D (f15, 6, true);
> +  D (f16, 4, true);
> +  D (f16, 5, false);
> +  D (f16, 6, false);
> +  D (f17, 4, false);
> +  D (f17, 5, true);
> +  D (f17, 6, true);
> +  D (f18, 4, true);
> +  D (f18, 5, true);
> +  D (f18, 6, false);
> +  D (f19, 4, true);
> +  D (f19, 5, false);
> +  D (f19, 6, false);
> +  D (f20, 4, false);
> +  D (f20, 5, true);
> +  D (f20, 6, true);
> +  D (f21, 4, false);
> +  D (f21, 5, true);
> +  D (f21, 6, false);
> +  D (f22, 4, true);
> +  D (f22, 5, false);
> +  D (f22, 6, true);
> +  D (f23, 4, false);
> +  D (f23, 5, false);
> +  D (f23, 6, true);
> +  D (f24, 4, true);
> +  D (f24, 5, true);
> +  D (f24, 6, false);
> +}
> --- gcc/testsuite/g++.dg/opt/pr94589-4.C.jj	2021-05-03 17:21:40.968351902 +0200
> +++ gcc/testsuite/g++.dg/opt/pr94589-4.C	2021-05-03 17:23:13.313289481 +0200
> @@ -0,0 +1,84 @@
> +// { dg-do run { target c++20 } }
> +// { dg-options "-O2 -g -ffast-math" }
> +
> +#include "pr94589-2.C"
> +
> +#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 (f2, 7.0, 8.0, true);
> +  C (f2, 8.0, 8.0, false);
> +  C (f2, 9.0, 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 (f4, 7.0, 8.0, true);
> +  C (f4, 8.0, 8.0, false);
> +  C (f4, 9.0, 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 (f6, 7.0, 8.0, true);
> +  C (f6, 8.0, 8.0, true);
> +  C (f6, 9.0, 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 (f8, 7.0, 8.0, false);
> +  C (f8, 8.0, 8.0, true);
> +  C (f8, 9.0, 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 (f10, 7.0, 8.0, true);
> +  C (f10, 8.0, 8.0, false);
> +  C (f10, 9.0, 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 (f12, 7.0, 8.0, true);
> +  C (f12, 8.0, 8.0, true);
> +  C (f12, 9.0, 8.0, false);
> +  D (f13, 4.0, false);
> +  D (f13, 5.0, true);
> +  D (f13, 6.0, false);
> +  D (f14, 4.0, true);
> +  D (f14, 5.0, false);
> +  D (f14, 6.0, true);
> +  D (f15, 4.0, false);
> +  D (f15, 5.0, false);
> +  D (f15, 6.0, true);
> +  D (f16, 4.0, true);
> +  D (f16, 5.0, false);
> +  D (f16, 6.0, false);
> +  D (f17, 4.0, false);
> +  D (f17, 5.0, true);
> +  D (f17, 6.0, true);
> +  D (f18, 4.0, true);
> +  D (f18, 5.0, true);
> +  D (f18, 6.0, false);
> +  D (f19, 4.0, true);
> +  D (f19, 5.0, false);
> +  D (f19, 6.0, false);
> +  D (f20, 4.0, false);
> +  D (f20, 5.0, true);
> +  D (f20, 6.0, true);
> +  D (f21, 4.0, false);
> +  D (f21, 5.0, true);
> +  D (f21, 6.0, false);
> +  D (f22, 4.0, true);
> +  D (f22, 5.0, false);
> +  D (f22, 6.0, true);
> +  D (f23, 4.0, false);
> +  D (f23, 5.0, false);
> +  D (f23, 6.0, true);
> +  D (f24, 4.0, true);
> +  D (f24, 5.0, true);
> +  D (f24, 6.0, false);
> +}
> 
> 	Jakub
> 


      parent reply	other threads:[~2021-05-05 15:45 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-04  7:44 Jakub Jelinek
2021-05-04  9:42 ` Jonathan Wakely
2021-05-04  9:56   ` Jakub Jelinek
2021-05-05 11:39 ` Richard Biener
2021-05-05 13:18   ` [PATCH] phiopt, v2: " Jakub Jelinek
2021-05-05 14:17     ` Richard Biener
2021-05-05 11:45 ` [PATCH] phiopt: " Marc Glisse
2021-05-05 16:52   ` Jakub Jelinek
2021-05-06 10:22     ` Jakub Jelinek
2021-05-06 19:42       ` Marc Glisse
2021-05-11  7:34         ` [PATCH] match.pd: Optimize (x & y) == x into (x & ~y) == 0 [PR94589] Jakub Jelinek
2021-05-11  8:11           ` Marc Glisse
2021-05-11  8:20           ` Richard Biener
2021-05-14 17:26         ` [PATCH] phiopt: Optimize (x <=> y) cmp z [PR94589] Jakub Jelinek
2021-05-15 10:09           ` Marc Glisse
2021-05-05 15:45 ` Martin Sebor [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=72f2b8a0-89aa-f3af-74b2-8358103e8b44@gmail.com \
    --to=msebor@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=jason@redhat.com \
    --cc=jwakely@redhat.com \
    --cc=rguenther@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).