From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-qk1-x72e.google.com (mail-qk1-x72e.google.com [IPv6:2607:f8b0:4864:20::72e]) by sourceware.org (Postfix) with ESMTPS id E411E3857410 for ; Wed, 5 May 2021 15:45:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E411E3857410 Received: by mail-qk1-x72e.google.com with SMTP id q127so1955384qkb.1 for ; Wed, 05 May 2021 08:45:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=+yK60JzMENF5r4VGPTIWJHZs5IY8/4XMeSknHVXmwfY=; b=Qmen98AOLeEjrd/sRW0yzZ8H6uV5mjJq3qnDWJE7NHWKIeRK5VOy8dUcwUtY+iZOpG 2mEA2TX/44E6ITHFuk91lU+VkwJ7fOIohGb0ARKEIlFdy8stqgF06/GIQ3kmyqBLvUmp xKNY+yIutVR1Frcdhmw1W+O8BbASzS4ENiuJYaCv74K+UJZIeWp70+CtmnW6+hqrxp2W zvJ7JEv/mk2kbJtvTMDyvh0PHFzWp8/2XrWrq8SI5Btuov2GNzIHd9jx5uxtiEcnnAUn G8GSJ/lk2vPGu7jcxz5iWKrglRUlJ9wIKEAEY9MhgSUBNDsDK0W+zacYmbfCNyOrO79o blbw== X-Gm-Message-State: AOAM53389XOBrxPfmf7oBA+sn1ecd/e3zGqyAzIulr0BT9t+iz4fd6qQ prT+IgGC+r3/hrx/rY6Fll7Q3utPcB8= X-Google-Smtp-Source: ABdhPJx9FyvZGRSgG8f1xQa8upICiEQgWP9yfZH5ZyQFEVvsmcb/6s7SmoeIgKxj4il0S6exCGeA5g== X-Received: by 2002:a37:a9d2:: with SMTP id s201mr25298524qke.417.1620229527762; Wed, 05 May 2021 08:45:27 -0700 (PDT) Received: from [192.168.0.41] (71-218-14-121.hlrn.qwest.net. [71.218.14.121]) by smtp.gmail.com with ESMTPSA id m22sm6064331qkk.65.2021.05.05.08.45.26 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 05 May 2021 08:45:27 -0700 (PDT) Subject: Re: [PATCH] phiopt: Optimize (x <=> y) cmp z [PR94589] To: Jakub Jelinek , Richard Biener , Jonathan Wakely , Jason Merrill Cc: gcc-patches@gcc.gnu.org References: <20210504074413.GI1179226@tucnak> From: Martin Sebor Message-ID: <72f2b8a0-89aa-f3af-74b2-8358103e8b44@gmail.com> Date: Wed, 5 May 2021 09:45:25 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.2 MIME-Version: 1.0 In-Reply-To: <20210504074413.GI1179226@tucnak> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-3.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SCC_10_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=no autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 May 2021 15:45:33 -0000 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 > > 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: > + : > + if (x_4(D) != y_5(D)) > + goto ; [INV] > + else > + goto ; [INV] > + > + : > + if (x_4(D) < y_5(D)) > + goto ; [INV] > + else > + goto ; [INV] > + > + : > + > + : > + # iftmp.0_2 = PHI <1(4), 0(2), -1(3)> > + _1 = iftmp.0_2 == 0; > + > + and for partial ordering <=> something like: > + > + : > + if (a_3(D) == b_5(D)) > + goto ; [50.00%] > + else > + goto ; [50.00%] > + > + [local count: 536870913]: > + if (a_3(D) < b_5(D)) > + goto ; [50.00%] > + else > + goto ; [50.00%] > + > + [local count: 268435456]: > + if (a_3(D) > b_5(D)) > + goto ; [50.00%] > + else > + goto ; [50.00%] > + > + [local count: 134217728]: > + > + [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 (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 (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 (cond3)); > + else > + gimple_cond_make_false (as_a (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 > + > +#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 > + > +#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 >