From patchwork Sun Jun 10 14:16:24 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 164001 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 3352AB6FD7 for ; Mon, 11 Jun 2012 00:17:41 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1339942662; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Date: From:To:Subject:Message-ID:User-Agent:MIME-Version:Content-Type: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=ednaPkK7H93jHTDHkgWz ZhrYdwE=; b=JaDAQP1QIo9xDbWcF7QB2l/1ny3eUbX3Jk/04nbesLiDQn1PUksB 5OTBKmOdZIV7ZLFTJGlPpYtfTTgcAYIViNe1W5sCU0PTD6pQdnYsz5GVZnpEAQxI ypCQguq0XeW58eEaNoM2cxwagtKKGPIeSeM1lklw3md9whctt5NAPU4= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Date:From:To:Subject:Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=TW9zANCrXpn2dLT72XxnOMklZGGubtiVZDEdIsYxj9f/avJPqd9a3ZABb23oop hbt9UH6c9iVvKYdRMgm8C5Wd02tVeNR1/GYmHgTx0Y+keBeVWKYmmRlPLSGtDbmp Vg/gashBAFuklHA1NTTDuEEGC8vHz7nS5P2rza94KrNEY=; Received: (qmail 31338 invoked by alias); 10 Jun 2012 14:17:36 -0000 Received: (qmail 31321 invoked by uid 22791); 10 Jun 2012 14:17:32 -0000 X-SWARE-Spam-Status: No, hits=-5.8 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, SARE_OBFU_ALL, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail1-relais-roc.national.inria.fr (HELO mail1-relais-roc.national.inria.fr) (192.134.164.82) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 10 Jun 2012 14:17:15 +0000 Received: from afontenayssb-151-1-52-143.w82-121.abo.wanadoo.fr (HELO laptop-mg.local) ([82.121.89.143]) by mail1-relais-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 10 Jun 2012 16:17:00 +0200 Date: Sun, 10 Jun 2012 16:16:24 +0200 (CEST) From: Marc Glisse To: gcc-patches@gcc.gnu.org Subject: [Patch] PR 51938: extend ifcombine Message-ID: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hello, currently, tree-ssa-ifcombine handles pairs of imbricated "if"s that share the same then branch, or the same else branch. There is no particular reason why it couldn't also handle the case where the then branch of one is the else branch of the other, which is what I do here. Any comments? 2012-06-10 Marc Glisse gcc/ PR tree-optimization/51938 * fold-const.c (combine_comparisons): Extra argument. Handle inverted conditions. (fold_truth_andor_1): Update call to combine_comparisons. * gimple-fold.c (swap12): New function. (and_comparisons_1): Extra argument. Handle inverted conditions. (and_var_with_comparison_1): Update call to and_comparisons_1. (maybe_fold_and_comparisons): Extra argument. Update call to and_comparisons_1. (or_comparisons_1): Extra argument. Handle inverted conditions. (or_var_with_comparison_1): Update call to or_comparisons_1. (maybe_fold_or_comparisons): Extra argument. Update call to or_comparisons_1. * tree-ssa-ifcombine.c (ifcombine_ifnotandif): New function. (ifcombine_ifnotorif): New function. (tree_ssa_ifcombine_bb): Call them. (ifcombine_iforif): Update call to maybe_fold_or_comparisons. (ifcombine_ifandif): Update call to maybe_fold_and_comparisons. * tree-ssa-reassoc.c (eliminate_redundant_comparison): Update calls to maybe_fold_or_comparisons and maybe_fold_and_comparisons. * tree-if-conv.c (fold_or_predicates): Update call to maybe_fold_or_comparisons. * gimple.h (maybe_fold_and_comparisons): Match gimple-fold.c prototype. (maybe_fold_or_comparisons): Likewise. * tree.h (combine_comparisons): Match fold-const.c prototype. gcc/testsuite/ PR tree-optimization/51938 * gcc.dg/tree-ssa/ssa-ifcombine-8.c: New testcase. * gcc.dg/tree-ssa/ssa-ifcombine-9.c: New testcase. Index: fold-const.c =================================================================== --- fold-const.c (revision 188331) +++ fold-const.c (working copy) @@ -2247,35 +2247,46 @@ compcode_to_comparison (enum comparison_ gcc_unreachable (); } } /* Return a tree for the comparison which is the combination of doing the AND or OR (depending on CODE) of the two operations LCODE - and RCODE on the identical operands LL_ARG and LR_ARG. Take into account - the possibility of trapping if the mode has NaNs, and return NULL_TREE + and RCODE on the identical operands LL_ARG and LR_ARG. The bit 0 + (resp. 1) of inv indicates, when set, that the result of the + operation LCODE needs to be inverted. Take into account the + possibility of trapping if the mode has NaNs, and return NULL_TREE if this makes the transformation invalid. */ tree combine_comparisons (location_t loc, enum tree_code code, enum tree_code lcode, enum tree_code rcode, tree truth_type, - tree ll_arg, tree lr_arg) + tree ll_arg, tree lr_arg, int inv) { bool honor_nans = HONOR_NANS (TYPE_MODE (TREE_TYPE (ll_arg))); enum comparison_code lcompcode = comparison_to_compcode (lcode); enum comparison_code rcompcode = comparison_to_compcode (rcode); + int lcompcode2 = lcompcode; + int rcompcode2 = rcompcode; int compcode; + bool exchg = false; + tree ret; + + if (inv & 1) + lcompcode2 = COMPCODE_TRUE - lcompcode2; + if (inv & 2) + rcompcode2 = COMPCODE_TRUE - rcompcode2; switch (code) { case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: - compcode = lcompcode & rcompcode; + compcode = lcompcode2 & rcompcode2; break; case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: - compcode = lcompcode | rcompcode; + compcode = lcompcode2 | rcompcode2; break; default: return NULL_TREE; } @@ -2318,25 +2329,38 @@ combine_comparisons (location_t loc, if (rtrap && !ltrap && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) return NULL_TREE; /* If we changed the conditions that cause a trap, we lose. */ if ((ltrap || rtrap) != trap) + { + /* Try the inverse condition. */ + compcode = COMPCODE_TRUE - compcode; + exchg = true; + trap = (compcode & COMPCODE_UNORD) == 0 + && (compcode != COMPCODE_EQ) + && (compcode != COMPCODE_ORD); + } + if ((ltrap || rtrap) != trap) return NULL_TREE; } + /* The inversion can't lead to a constant. */ if (compcode == COMPCODE_TRUE) return constant_boolean_node (true, truth_type); else if (compcode == COMPCODE_FALSE) return constant_boolean_node (false, truth_type); else { enum tree_code tcode; tcode = compcode_to_comparison ((enum comparison_code) compcode); - return fold_build2_loc (loc, tcode, truth_type, ll_arg, lr_arg); + ret = fold_build2_loc (loc, tcode, truth_type, ll_arg, lr_arg); + if (exchg) + ret = fold_build1_loc (loc, TRUTH_NOT_EXPR, truth_type, ret); + return ret; } } /* Return nonzero if two operands (typically of the same tree node) are necessarily equal. If either argument has side-effects this function returns zero. FLAGS modifies behavior as follows: @@ -5115,22 +5139,22 @@ fold_truth_andor_1 (location_t loc, enum && simple_operand_p (lr_arg)) { if (operand_equal_p (ll_arg, rl_arg, 0) && operand_equal_p (lr_arg, rr_arg, 0)) { result = combine_comparisons (loc, code, lcode, rcode, - truth_type, ll_arg, lr_arg); + truth_type, ll_arg, lr_arg, 0); if (result) return result; } else if (operand_equal_p (ll_arg, rr_arg, 0) && operand_equal_p (lr_arg, rl_arg, 0)) { result = combine_comparisons (loc, code, lcode, swap_tree_comparison (rcode), - truth_type, ll_arg, lr_arg); + truth_type, ll_arg, lr_arg, 0); if (result) return result; } } code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR) Index: gimple.h =================================================================== --- gimple.h (revision 188331) +++ gimple.h (working copy) @@ -5309,12 +5309,12 @@ void gimplify_and_update_call_from_tree tree gimple_fold_builtin (gimple); bool fold_stmt (gimple_stmt_iterator *); bool fold_stmt_inplace (gimple_stmt_iterator *); tree get_symbol_constant_value (tree); tree canonicalize_constructor_val (tree, tree); extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, - enum tree_code, tree, tree); + enum tree_code, tree, tree, int); extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree, - enum tree_code, tree, tree); + enum tree_code, tree, tree, int); bool gimple_val_nonnegative_real_p (tree); #endif /* GCC_GIMPLE_H */ Index: tree.h =================================================================== --- tree.h (revision 188331) +++ tree.h (working copy) @@ -5366,13 +5366,13 @@ extern bool tree_invalid_nonnegative_war extern bool tree_call_nonnegative_warnv_p (tree, tree, tree, tree, bool *); extern bool tree_expr_nonzero_warnv_p (tree, bool *); extern bool fold_real_zero_addition_p (const_tree, const_tree, int); extern tree combine_comparisons (location_t, enum tree_code, enum tree_code, - enum tree_code, tree, tree, tree); + enum tree_code, tree, tree, tree, int); extern void debug_fold_checksum (const_tree); /* Return nonzero if CODE is a tree code that represents a truth value. */ static inline bool truth_value_p (enum tree_code code) { Index: tree-ssa-ifcombine.c =================================================================== --- tree-ssa-ifcombine.c (revision 188331) +++ tree-ssa-ifcombine.c (working copy) @@ -372,13 +372,13 @@ ifcombine_ifandif (basic_block inner_con if (!(t = maybe_fold_and_comparisons (gimple_cond_code (inner_cond), gimple_cond_lhs (inner_cond), gimple_cond_rhs (inner_cond), gimple_cond_code (outer_cond), gimple_cond_lhs (outer_cond), - gimple_cond_rhs (outer_cond)))) + gimple_cond_rhs (outer_cond), 0))) return false; t = canonicalize_cond_expr_cond (t); if (!t) return false; gimple_cond_set_condition_from_tree (inner_cond, t); update_stmt (inner_cond); @@ -520,13 +520,13 @@ ifcombine_iforif (basic_block inner_cond if (!(t = maybe_fold_or_comparisons (gimple_cond_code (inner_cond), gimple_cond_lhs (inner_cond), gimple_cond_rhs (inner_cond), gimple_cond_code (outer_cond), gimple_cond_lhs (outer_cond), - gimple_cond_rhs (outer_cond)))) + gimple_cond_rhs (outer_cond), 0))) return false; t = canonicalize_cond_expr_cond (t); if (!t) return false; gimple_cond_set_condition_from_tree (inner_cond, t); update_stmt (inner_cond); @@ -545,12 +545,156 @@ ifcombine_iforif (basic_block inner_cond return true; } return false; } +/* If-convert on a !a||b pattern. The inner if is specified by its + INNER_COND_BB, the outer by OUTER_COND_BB. Returns true if the + edges to the common outer else basic-block / inner then basic-block + were merged. */ + +static bool +ifcombine_ifnotorif (basic_block inner_cond_bb, basic_block outer_cond_bb) +{ + gimple inner_cond, outer_cond; + + inner_cond = last_stmt (inner_cond_bb); + if (!inner_cond + || gimple_code (inner_cond) != GIMPLE_COND) + return false; + + outer_cond = last_stmt (outer_cond_bb); + if (!outer_cond + || gimple_code (outer_cond) != GIMPLE_COND) + return false; + + /* See if we have two comparisons that we can merge into one. */ + if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison + && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison) + { + tree t; + bool inv = false; + + if (!(t = maybe_fold_or_comparisons (gimple_cond_code (inner_cond), + gimple_cond_lhs (inner_cond), + gimple_cond_rhs (inner_cond), + gimple_cond_code (outer_cond), + gimple_cond_lhs (outer_cond), + gimple_cond_rhs (outer_cond), 2))) + return false; + + if (TREE_CODE (t) == TRUTH_NOT_EXPR) + { + inv = true; + t = TREE_OPERAND (t, 0); + } + + t = canonicalize_cond_expr_cond (t); + if (!t) + return false; + + if (inv) + { + edge t = EDGE_SUCC (inner_cond_bb, 0); + edge e = EDGE_SUCC (inner_cond_bb, 1); + t->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); + e->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); + } + gimple_cond_set_condition_from_tree (inner_cond, t); + update_stmt (inner_cond); + + /* Leave CFG optimization to cfg_cleanup. */ + gimple_cond_set_condition_from_tree (outer_cond, boolean_true_node); + update_stmt (outer_cond); + + if (dump_file) + { + fprintf (dump_file, "optimizing two comparisons to "); + print_generic_expr (dump_file, t, 0); + fprintf (dump_file, "\n"); + } + + return true; + } + + return false; +} + +/* If-convert on a !a&&b pattern. The inner if is specified by its + INNER_COND_BB, the outer by OUTER_COND_BB. Returns true if the + edges to the common outer then basic-block / inner else basic-block + were merged. */ + +static bool +ifcombine_ifnotandif (basic_block inner_cond_bb, basic_block outer_cond_bb) +{ + gimple inner_cond, outer_cond; + + inner_cond = last_stmt (inner_cond_bb); + if (!inner_cond + || gimple_code (inner_cond) != GIMPLE_COND) + return false; + + outer_cond = last_stmt (outer_cond_bb); + if (!outer_cond + || gimple_code (outer_cond) != GIMPLE_COND) + return false; + + /* See if we have two comparisons that we can merge into one. */ + if (TREE_CODE_CLASS (gimple_cond_code (inner_cond)) == tcc_comparison + && TREE_CODE_CLASS (gimple_cond_code (outer_cond)) == tcc_comparison) + { + tree t; + bool inv = false; + + if (!(t = maybe_fold_and_comparisons (gimple_cond_code (inner_cond), + gimple_cond_lhs (inner_cond), + gimple_cond_rhs (inner_cond), + gimple_cond_code (outer_cond), + gimple_cond_lhs (outer_cond), + gimple_cond_rhs (outer_cond), 2))) + return false; + + if (TREE_CODE (t) == TRUTH_NOT_EXPR) + { + inv = true; + t = TREE_OPERAND (t, 0); + } + + t = canonicalize_cond_expr_cond (t); + if (!t) + return false; + + if (inv) + { + edge t = EDGE_SUCC (inner_cond_bb, 0); + edge e = EDGE_SUCC (inner_cond_bb, 1); + t->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); + e->flags ^= (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); + } + gimple_cond_set_condition_from_tree (inner_cond, t); + update_stmt (inner_cond); + + /* Leave CFG optimization to cfg_cleanup. */ + gimple_cond_set_condition_from_tree (outer_cond, boolean_false_node); + update_stmt (outer_cond); + + if (dump_file) + { + fprintf (dump_file, "optimizing two comparisons to "); + print_generic_expr (dump_file, t, 0); + fprintf (dump_file, "\n"); + } + + return true; + } + + return false; +} + /* Recognize a CFG pattern and dispatch to the appropriate if-conversion helper. We start with BB as the innermost worker basic-block. Returns true if a transformation was done. */ static bool tree_ssa_ifcombine_bb (basic_block inner_cond_bb) @@ -607,12 +751,52 @@ tree_ssa_ifcombine_bb (basic_block inner if (q) goto then_bb; else goto ...; ... */ return ifcombine_iforif (inner_cond_bb, outer_cond_bb); } + + /* The !|| form is characterized by an outer else_bb that + matches the inner else_bb, with the two edges leading to it + mergable. The latter is guaranteed by matching PHI arguments + in the else_bb and the inner cond_bb having no side-effects. */ + if (recognize_if_then_else (outer_cond_bb, &inner_cond_bb, &then_bb) + && same_phi_args_p (outer_cond_bb, inner_cond_bb, then_bb) + && bb_no_side_effects_p (inner_cond_bb)) + { + /* We have + + if (q) goto inner_cond_bb; else goto then_bb; + + if (p) goto then_bb; else goto ...; + ... + + ... + */ + return ifcombine_ifnotorif (inner_cond_bb, outer_cond_bb); + } + + /* The !&& form is characterized by an outer then_bb that + matches the inner else_bb, with the two edges leading to it + mergable. The latter is guaranteed by matching PHI arguments + in the else_bb and the inner cond_bb having no side-effects. */ + if (recognize_if_then_else (outer_cond_bb, &else_bb, &inner_cond_bb) + && same_phi_args_p (outer_cond_bb, inner_cond_bb, else_bb) + && bb_no_side_effects_p (inner_cond_bb)) + { + /* We have + + if (q) goto else_bb; else goto inner_cond_bb; + + if (p) goto ...; else goto else_bb; + ... + + ... + */ + return ifcombine_ifnotandif (inner_cond_bb, outer_cond_bb); + } } return false; } /* Main entry for the tree if-conversion pass. */ Index: tree-ssa-reassoc.c =================================================================== --- tree-ssa-reassoc.c (revision 188331) +++ tree-ssa-reassoc.c (working copy) @@ -1539,17 +1539,17 @@ eliminate_redundant_comparison (enum tre /* If we got here, we have a match. See if we can combine the two comparisons. */ if (opcode == BIT_IOR_EXPR) t = maybe_fold_or_comparisons (lcode, op1, op2, rcode, gimple_assign_rhs1 (def2), - gimple_assign_rhs2 (def2)); + gimple_assign_rhs2 (def2), 0); else t = maybe_fold_and_comparisons (lcode, op1, op2, rcode, gimple_assign_rhs1 (def2), - gimple_assign_rhs2 (def2)); + gimple_assign_rhs2 (def2), 0); if (!t) continue; /* maybe_fold_and_comparisons and maybe_fold_or_comparisons always give us a boolean_type_node value back. If the original BIT_AND_EXPR or BIT_IOR_EXPR was of a wider integer type, Index: gimple-fold.c =================================================================== --- gimple-fold.c (revision 188331) +++ gimple-fold.c (working copy) @@ -1470,29 +1470,34 @@ same_bool_result_p (const_tree op1, cons } /* Forward declarations for some mutually recursive functions. */ static tree and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, - enum tree_code code2, tree op2a, tree op2b); + enum tree_code code2, tree op2a, tree op2b, int inv); static tree and_var_with_comparison (tree var, bool invert, enum tree_code code2, tree op2a, tree op2b); static tree and_var_with_comparison_1 (gimple stmt, enum tree_code code2, tree op2a, tree op2b); static tree or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, - enum tree_code code2, tree op2a, tree op2b); + enum tree_code code2, tree op2a, tree op2b, int inv); static tree or_var_with_comparison (tree var, bool invert, enum tree_code code2, tree op2a, tree op2b); static tree or_var_with_comparison_1 (gimple stmt, enum tree_code code2, tree op2a, tree op2b); +static int swap12 (int flags) +{ + return ((flags & 1) << 1) | (flags >> 1); +} + /* Helper function for and_comparisons_1: try to simplify the AND of the ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B). If INVERT is true, invert the value of the VAR before doing the AND. Return NULL_EXPR if we can't simplify this to a single expression. */ static tree @@ -1556,13 +1561,14 @@ and_var_with_comparison_1 (gimple stmt, { tree t = and_comparisons_1 (innercode, gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt), code2, op2a, - op2b); + op2b, + 0); if (t) return t; } /* If the definition is an AND or OR expression, we may be able to simplify by reassociating. */ @@ -1601,13 +1607,13 @@ and_var_with_comparison_1 (gimple stmt, if (TREE_CODE (inner1) == SSA_NAME && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1)) && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s), gimple_assign_rhs1 (s), gimple_assign_rhs2 (s), - code2, op2a, op2b))) + code2, op2a, op2b, 0))) { /* Handle the AND case, where we are reassociating: (inner1 AND inner2) AND (op2a code2 op2b) => (t AND inner2) If the partial result t is a constant, we win. Otherwise continue on to try reassociating with the other inner test. */ @@ -1633,13 +1639,13 @@ and_var_with_comparison_1 (gimple stmt, if (TREE_CODE (inner2) == SSA_NAME && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2)) && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s), gimple_assign_rhs1 (s), gimple_assign_rhs2 (s), - code2, op2a, op2b))) + code2, op2a, op2b, 0))) { /* Handle the AND case, where we are reassociating: (inner1 AND inner2) AND (op2a code2 op2b) => (inner1 AND t) */ if (is_and) { @@ -1683,43 +1689,50 @@ and_var_with_comparison_1 (gimple stmt, /* Try to simplify the AND of two comparisons defined by (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively. If this can be done without constructing an intermediate value, return the resulting tree; otherwise NULL_TREE is returned. This function is deliberately asymmetric as it recurses on SSA_DEFs - in the first comparison but not the second. */ + in the first comparison but not the second. + If inv & 1, the first test is actually !(OP1A CODE1 OP1B). + If inv & 2, the second test is actually !(OP2A CODE2 OP2B). */ static tree and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, - enum tree_code code2, tree op2a, tree op2b) + enum tree_code code2, tree op2a, tree op2b, int inv) { /* First check for ((x CODE1 y) AND (x CODE2 y)). */ if (operand_equal_p (op1a, op2a, 0) && operand_equal_p (op1b, op2b, 0)) { /* Result will be either NULL_TREE, or a combined comparison. */ tree t = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ANDIF_EXPR, code1, code2, - boolean_type_node, op1a, op1b); + boolean_type_node, op1a, op1b, inv); if (t) return t; } /* Likewise the swapped case of the above. */ if (operand_equal_p (op1a, op2b, 0) && operand_equal_p (op1b, op2a, 0)) { /* Result will be either NULL_TREE, or a combined comparison. */ tree t = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ANDIF_EXPR, code1, swap_tree_comparison (code2), - boolean_type_node, op1a, op1b); + boolean_type_node, op1a, op1b, inv); if (t) return t; } + if (inv & 1) code1 = invert_tree_comparison (code1, + HONOR_NANS (TYPE_MODE (TREE_TYPE (op1a)))); + if (inv & 2) code2 = invert_tree_comparison (code2, + HONOR_NANS (TYPE_MODE (TREE_TYPE (op2a)))); + /* If both comparisons are of the same value against constants, we might be able to merge them. */ if (operand_equal_p (op1a, op2a, 0) && TREE_CODE (op1b) == INTEGER_CST && TREE_CODE (op2b) == INTEGER_CST) { @@ -1935,23 +1948,26 @@ and_comparisons_1 (enum tree_code code1, /* Try to simplify the AND of two comparisons, specified by (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively. If this can be simplified to a single expression (without requiring introducing more SSA variables to hold intermediate values), return the resulting tree. Otherwise return NULL_TREE. - If the result expression is non-null, it has boolean type. */ + If the result expression is non-null, it has boolean type. + If inv & 1, the first test is actually !(OP1A CODE1 OP1B). + If inv & 2, the second test is actually !(OP2A CODE2 OP2B). */ tree maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b, - enum tree_code code2, tree op2a, tree op2b) + enum tree_code code2, tree op2a, tree op2b, int inv) { - tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b); + tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b, inv); if (t) return t; else - return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b); + return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b, + swap12 (inv)); } /* Helper function for or_comparisons_1: try to simplify the OR of the ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B). If INVERT is true, invert the value of VAR before doing the OR. Return NULL_EXPR if we can't simplify this to a single expression. */ @@ -2017,13 +2033,14 @@ or_var_with_comparison_1 (gimple stmt, { tree t = or_comparisons_1 (innercode, gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt), code2, op2a, - op2b); + op2b, + 0); if (t) return t; } /* If the definition is an AND or OR expression, we may be able to simplify by reassociating. */ @@ -2062,13 +2079,13 @@ or_var_with_comparison_1 (gimple stmt, if (TREE_CODE (inner1) == SSA_NAME && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1)) && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s), gimple_assign_rhs1 (s), gimple_assign_rhs2 (s), - code2, op2a, op2b))) + code2, op2a, op2b, 0))) { /* Handle the OR case, where we are reassociating: (inner1 OR inner2) OR (op2a code2 op2b) => (t OR inner2) If the partial result t is a constant, we win. Otherwise continue on to try reassociating with the other inner test. */ @@ -2094,13 +2111,13 @@ or_var_with_comparison_1 (gimple stmt, if (TREE_CODE (inner2) == SSA_NAME && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2)) && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s), gimple_assign_rhs1 (s), gimple_assign_rhs2 (s), - code2, op2a, op2b))) + code2, op2a, op2b, 0))) { /* Handle the OR case, where we are reassociating: (inner1 OR inner2) OR (op2a code2 op2b) => (inner1 OR t) => (t OR partial) */ if (is_or) @@ -2145,43 +2162,50 @@ or_var_with_comparison_1 (gimple stmt, /* Try to simplify the OR of two comparisons defined by (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively. If this can be done without constructing an intermediate value, return the resulting tree; otherwise NULL_TREE is returned. This function is deliberately asymmetric as it recurses on SSA_DEFs - in the first comparison but not the second. */ + in the first comparison but not the second. + If inv & 1, the first test is actually !(OP1A CODE1 OP1B). + If inv & 2, the second test is actually !(OP2A CODE2 OP2B). */ static tree or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b, - enum tree_code code2, tree op2a, tree op2b) + enum tree_code code2, tree op2a, tree op2b, int inv) { /* First check for ((x CODE1 y) OR (x CODE2 y)). */ if (operand_equal_p (op1a, op2a, 0) && operand_equal_p (op1b, op2b, 0)) { /* Result will be either NULL_TREE, or a combined comparison. */ tree t = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ORIF_EXPR, code1, code2, - boolean_type_node, op1a, op1b); + boolean_type_node, op1a, op1b, inv); if (t) return t; } /* Likewise the swapped case of the above. */ if (operand_equal_p (op1a, op2b, 0) && operand_equal_p (op1b, op2a, 0)) { /* Result will be either NULL_TREE, or a combined comparison. */ tree t = combine_comparisons (UNKNOWN_LOCATION, TRUTH_ORIF_EXPR, code1, swap_tree_comparison (code2), - boolean_type_node, op1a, op1b); + boolean_type_node, op1a, op1b, inv); if (t) return t; } + if (inv & 1) code1 = invert_tree_comparison (code1, + HONOR_NANS (TYPE_MODE (TREE_TYPE (op1a)))); + if (inv & 2) code2 = invert_tree_comparison (code2, + HONOR_NANS (TYPE_MODE (TREE_TYPE (op2a)))); + /* If both comparisons are of the same value against constants, we might be able to merge them. */ if (operand_equal_p (op1a, op2a, 0) && TREE_CODE (op1b) == INTEGER_CST && TREE_CODE (op2b) == INTEGER_CST) { @@ -2397,23 +2421,26 @@ or_comparisons_1 (enum tree_code code1, /* Try to simplify the OR of two comparisons, specified by (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively. If this can be simplified to a single expression (without requiring introducing more SSA variables to hold intermediate values), return the resulting tree. Otherwise return NULL_TREE. - If the result expression is non-null, it has boolean type. */ + If the result expression is non-null, it has boolean type. + If inv & 1, the first test is actually !(OP1A CODE1 OP1B). + If inv & 2, the second test is actually !(OP2A CODE2 OP2B). */ tree maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b, - enum tree_code code2, tree op2a, tree op2b) + enum tree_code code2, tree op2a, tree op2b, int inv) { - tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b); + tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b, inv); if (t) return t; else - return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b); + return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b, + swap12 (inv)); } /* Fold STMT to a constant using VALUEIZE to valueize SSA names. Either NULL_TREE, a simplified but non-constant or a constant Index: tree-if-conv.c =================================================================== --- tree-if-conv.c (revision 188331) +++ tree-if-conv.c (working copy) @@ -315,13 +315,13 @@ fold_or_predicates (location_t loc, tree enum tree_code code1 = parse_predicate (c1, &op1a, &op1b); enum tree_code code2 = parse_predicate (c2, &op2a, &op2b); if (code1 != ERROR_MARK && code2 != ERROR_MARK) { tree t = maybe_fold_or_comparisons (code1, op1a, op1b, - code2, op2a, op2b); + code2, op2a, op2b, 0); if (t) return t; } return fold_build2_loc (loc, TRUTH_OR_EXPR, boolean_type_node, c1, c2); } Index: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c =================================================================== --- testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c (revision 0) +++ testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c (revision 0) @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O -ftrapping-math -fdump-tree-ifcombine" } */ + +double test1 (double i, double j) +{ + if (i >= j) + if (i <= j) + goto plif; + else + goto plouf; + else + goto plif; + +plif: + return 0; +plouf: + return -1; +} + +/* The above should be optimized to a i > j test by ifcombine, + which also switches plif and plouf. */ + +/* { dg-final { scan-tree-dump " > " "ifcombine" } } */ +/* { dg-final { cleanup-tree-dump "ifcombine" } } */ Property changes on: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-8.c ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision URL Added: svn:eol-style + native Index: testsuite/gcc.dg/tree-ssa/ssa-ifcombine-9.c =================================================================== --- testsuite/gcc.dg/tree-ssa/ssa-ifcombine-9.c (revision 0) +++ testsuite/gcc.dg/tree-ssa/ssa-ifcombine-9.c (revision 0) @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ifcombine" } */ + +void f (); +enum Sign { NEG=-1, ZERO, POS }; + +static inline enum Sign sign (double x) +{ + if (x > 0) return POS; + if (x < 0) return NEG; + return ZERO; +} +void g (double x) +{ + if (sign (x) == NEG) f(); +} + +/* The above should be optimized to x < 0 by ifcombine. */ + +/* { dg-final { scan-tree-dump "optimizing.* < " "ifcombine" } } */ +/* { dg-final { cleanup-tree-dump "ifcombine" } } */