This refactors register_edge_assert_for_* so that EVRP can use the "advanced" extraction of ranges from conditions. It is a re-send of one part of a series from last December, third part first (and thus slightly different).
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2016-12-02 Richard Biener <rguent...@suse.de> * tree-vrp.c (assert_info): New struct. (add_assert_info): New helper. (register_edge_assert_for_2): Refactor to add asserts to a vector of assert_info. (register_edge_assert_for_1): Likewise. (register_edge_assert_for): Likewise. (finish_register_edge_assert_for): New helper actually registering asserts where live on edge. (find_conditional_asserts): Adjust. (find_switch_asserts): Likewise. (evrp_dom_walker::try_find_new_range): Generalize. (evrp_dom_walker::before_dom_children): Use register_edge_assert_for. * gcc.dg/tree-ssa/evrp7.c: New testcase. * gcc.dg/tree-ssa/evrp8.c: Likewise. * gcc.dg/tree-ssa/evrp9.c: Likewise. * gcc.dg/tree-ssa/vrp35.c: Disable EVRP. * gcc.dg/tree-ssa/vrp36.c: Likewise. * gcc.dg/tree-ssa/pr49039.c: Likewise. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c (revision 247293) --- gcc/tree-vrp.c (working copy) *************** static tree vrp_evaluate_conditional_war *** 89,94 **** --- 89,109 ---- tree, tree, bool, bool *, bool *); + struct assert_info + { + /* Predicate code for the ASSERT_EXPR. Must be COMPARISON_CLASS_P. */ + enum tree_code comp_code; + + /* Name to register the assert for. */ + tree name; + + /* Value being compared against. */ + tree val; + + /* Expression to compare. */ + tree expr; + }; + /* Location information for ASSERT_EXPRs. Each instance of this structure describes an ASSERT_EXPR for an SSA name. Since a single SSA name may have more than one assertion associated with it, these *************** debug_all_asserts (void) *** 5029,5034 **** --- 5044,5062 ---- dump_all_asserts (stderr); } + /* Push the assert info for NAME, EXPR, COMP_CODE and VAL to ASSERTS. */ + + static void + add_assert_info (vec<assert_info> &asserts, + tree name, tree expr, enum tree_code comp_code, tree val) + { + assert_info info; + info.comp_code = comp_code; + info.name = name; + info.val = val; + info.expr = expr; + asserts.safe_push (info); + } /* If NAME doesn't have an ASSERT_EXPR registered for asserting 'EXPR COMP_CODE VAL' at a location that dominates block BB or *************** overflow_comparison_p (tree_code code, t *** 5357,5365 **** Invert the condition COND if INVERT is true. */ static void ! register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi, enum tree_code cond_code, ! tree cond_op0, tree cond_op1, bool invert) { tree val; enum tree_code comp_code; --- 5385,5394 ---- Invert the condition COND if INVERT is true. */ static void ! register_edge_assert_for_2 (tree name, edge e, enum tree_code cond_code, ! tree cond_op0, tree cond_op1, bool invert, ! vec<assert_info> &asserts) { tree val; enum tree_code comp_code; *************** register_edge_assert_for_2 (tree name, e *** 5370,5389 **** invert, &comp_code, &val)) return; ! /* Only register an ASSERT_EXPR if NAME was found in the sub-graph ! reachable from E. */ ! if (live_on_edge (e, name)) ! { ! tree x; ! if (overflow_comparison_p (comp_code, name, val, false, &x)) ! { ! enum tree_code new_code ! = ((comp_code == GT_EXPR || comp_code == GE_EXPR) ! ? GT_EXPR : LE_EXPR); ! register_new_assert_for (name, name, new_code, x, NULL, e, bsi); ! } ! register_new_assert_for (name, name, comp_code, val, NULL, e, bsi); } /* In the case of NAME <= CST and NAME being defined as NAME = (unsigned) NAME2 + CST2 we can assert NAME2 >= -CST2 --- 5399,5413 ---- invert, &comp_code, &val)) return; ! /* Queue the assert. */ ! tree x; ! if (overflow_comparison_p (comp_code, name, val, false, &x)) ! { ! enum tree_code new_code = ((comp_code == GT_EXPR || comp_code == GE_EXPR) ! ? GT_EXPR : LE_EXPR); ! add_assert_info (asserts, name, name, new_code, x); } + add_assert_info (asserts, name, name, comp_code, val); /* In the case of NAME <= CST and NAME being defined as NAME = (unsigned) NAME2 + CST2 we can assert NAME2 >= -CST2 *************** register_edge_assert_for_2 (tree name, e *** 5423,5430 **** && TREE_CODE (name3) == SSA_NAME && (cst2 == NULL_TREE || TREE_CODE (cst2) == INTEGER_CST) ! && INTEGRAL_TYPE_P (TREE_TYPE (name3)) ! && live_on_edge (e, name3)) { tree tmp; --- 5447,5453 ---- && TREE_CODE (name3) == SSA_NAME && (cst2 == NULL_TREE || TREE_CODE (cst2) == INTEGER_CST) ! && INTEGRAL_TYPE_P (TREE_TYPE (name3))) { tree tmp; *************** register_edge_assert_for_2 (tree name, e *** 5442,5456 **** fprintf (dump_file, "\n"); } ! register_new_assert_for (name3, tmp, comp_code, val, NULL, e, bsi); } /* If name2 is used later, create an ASSERT_EXPR for it. */ if (name2 != NULL_TREE && TREE_CODE (name2) == SSA_NAME && TREE_CODE (cst2) == INTEGER_CST ! && INTEGRAL_TYPE_P (TREE_TYPE (name2)) ! && live_on_edge (e, name2)) { tree tmp; --- 5465,5478 ---- fprintf (dump_file, "\n"); } ! add_assert_info (asserts, name3, tmp, comp_code, val); } /* If name2 is used later, create an ASSERT_EXPR for it. */ if (name2 != NULL_TREE && TREE_CODE (name2) == SSA_NAME && TREE_CODE (cst2) == INTEGER_CST ! && INTEGRAL_TYPE_P (TREE_TYPE (name2))) { tree tmp; *************** register_edge_assert_for_2 (tree name, e *** 5470,5476 **** fprintf (dump_file, "\n"); } ! register_new_assert_for (name2, tmp, comp_code, val, NULL, e, bsi); } } --- 5492,5498 ---- fprintf (dump_file, "\n"); } ! add_assert_info (asserts, name2, tmp, comp_code, val); } } *************** register_edge_assert_for_2 (tree name, e *** 5496,5503 **** continue; tree name2 = gimple_assign_lhs (use_stmt); ! if (TREE_CODE (name2) != SSA_NAME ! || !live_on_edge (e, name2)) continue; enum tree_code code = gimple_assign_rhs_code (use_stmt); --- 5518,5524 ---- continue; tree name2 = gimple_assign_lhs (use_stmt); ! if (TREE_CODE (name2) != SSA_NAME) continue; enum tree_code code = gimple_assign_rhs_code (use_stmt); *************** register_edge_assert_for_2 (tree name, e *** 5525,5532 **** if (TREE_OVERFLOW_P (cst)) cst = drop_tree_overflow (cst); ! register_new_assert_for (name2, name2, comp_code, cst, ! NULL, e, bsi); } } --- 5546,5552 ---- if (TREE_OVERFLOW_P (cst)) cst = drop_tree_overflow (cst); ! add_assert_info (asserts, name2, name2, comp_code, cst); } } *************** register_edge_assert_for_2 (tree name, e *** 5552,5566 **** tree op0 = gimple_assign_rhs1 (def_stmt); tree op1 = gimple_assign_rhs2 (def_stmt); if (TREE_CODE (op0) == SSA_NAME ! && TREE_CODE (op1) == INTEGER_CST ! && live_on_edge (e, op0)) { enum tree_code reverse_op = (rhs_code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); op1 = int_const_binop (reverse_op, val, op1); if (TREE_OVERFLOW (op1)) op1 = drop_tree_overflow (op1); ! register_new_assert_for (op0, op0, comp_code, op1, NULL, e, bsi); } } --- 5572,5585 ---- tree op0 = gimple_assign_rhs1 (def_stmt); tree op1 = gimple_assign_rhs2 (def_stmt); if (TREE_CODE (op0) == SSA_NAME ! && TREE_CODE (op1) == INTEGER_CST) { enum tree_code reverse_op = (rhs_code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); op1 = int_const_binop (reverse_op, val, op1); if (TREE_OVERFLOW (op1)) op1 = drop_tree_overflow (op1); ! add_assert_info (asserts, op0, op0, comp_code, op1); } } *************** register_edge_assert_for_2 (tree name, e *** 5578,5585 **** && prec == TYPE_PRECISION (TREE_TYPE (name2)) && (comp_code == LE_EXPR || comp_code == GT_EXPR || !tree_int_cst_equal (val, ! TYPE_MIN_VALUE (TREE_TYPE (val)))) ! && live_on_edge (e, name2)) { tree tmp, cst; enum tree_code new_comp_code = comp_code; --- 5597,5603 ---- && prec == TYPE_PRECISION (TREE_TYPE (name2)) && (comp_code == LE_EXPR || comp_code == GT_EXPR || !tree_int_cst_equal (val, ! TYPE_MIN_VALUE (TREE_TYPE (val))))) { tree tmp, cst; enum tree_code new_comp_code = comp_code; *************** register_edge_assert_for_2 (tree name, e *** 5606,5613 **** fprintf (dump_file, "\n"); } ! register_new_assert_for (name2, tmp, new_comp_code, cst, NULL, ! e, bsi); } } --- 5624,5630 ---- fprintf (dump_file, "\n"); } ! add_assert_info (asserts, name2, tmp, new_comp_code, cst); } } *************** register_edge_assert_for_2 (tree name, e *** 5623,5630 **** && tree_fits_uhwi_p (cst2) && INTEGRAL_TYPE_P (TREE_TYPE (name2)) && IN_RANGE (tree_to_uhwi (cst2), 1, prec - 1) ! && prec == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (val))) ! && live_on_edge (e, name2)) { mask = wi::mask (tree_to_uhwi (cst2), false, prec); val2 = fold_binary (LSHIFT_EXPR, TREE_TYPE (val), val, cst2); --- 5640,5646 ---- && tree_fits_uhwi_p (cst2) && INTEGRAL_TYPE_P (TREE_TYPE (name2)) && IN_RANGE (tree_to_uhwi (cst2), 1, prec - 1) ! && prec == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (val)))) { mask = wi::mask (tree_to_uhwi (cst2), false, prec); val2 = fold_binary (LSHIFT_EXPR, TREE_TYPE (val), val, cst2); *************** register_edge_assert_for_2 (tree name, e *** 5682,5689 **** fprintf (dump_file, "\n"); } ! register_new_assert_for (name2, tmp, new_comp_code, new_val, ! NULL, e, bsi); } } --- 5698,5704 ---- fprintf (dump_file, "\n"); } ! add_assert_info (asserts, name2, tmp, new_comp_code, new_val); } } *************** register_edge_assert_for_2 (tree name, e *** 5728,5739 **** if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2)) || !INTEGRAL_TYPE_P (TREE_TYPE (names[1])) || (TYPE_PRECISION (TREE_TYPE (name2)) ! != TYPE_PRECISION (TREE_TYPE (names[1]))) ! || !live_on_edge (e, names[1])) names[1] = NULL_TREE; } ! if (live_on_edge (e, name2)) ! names[0] = name2; } } if (names[0] || names[1]) --- 5743,5752 ---- if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2)) || !INTEGRAL_TYPE_P (TREE_TYPE (names[1])) || (TYPE_PRECISION (TREE_TYPE (name2)) ! != TYPE_PRECISION (TREE_TYPE (names[1])))) names[1] = NULL_TREE; } ! names[0] = name2; } } if (names[0] || names[1]) *************** register_edge_assert_for_2 (tree name, e *** 5924,5931 **** fprintf (dump_file, "\n"); } ! register_new_assert_for (names[i], tmp, LE_EXPR, ! new_val, NULL, e, bsi); } } } --- 5937,5943 ---- fprintf (dump_file, "\n"); } ! add_assert_info (asserts, names[i], tmp, LE_EXPR, new_val); } } } *************** register_edge_assert_for_2 (tree name, e *** 5941,5947 **** static void register_edge_assert_for_1 (tree op, enum tree_code code, ! edge e, gimple_stmt_iterator bsi) { gimple *op_def; tree val; --- 5953,5959 ---- static void register_edge_assert_for_1 (tree op, enum tree_code code, ! edge e, vec<assert_info> &asserts) { gimple *op_def; tree val; *************** register_edge_assert_for_1 (tree op, enu *** 5951,5963 **** if (TREE_CODE (op) != SSA_NAME) return; ! /* We know that OP will have a zero or nonzero value. If OP is used ! more than once go ahead and register an assert for OP. */ ! if (live_on_edge (e, op)) ! { ! val = build_int_cst (TREE_TYPE (op), 0); ! register_new_assert_for (op, op, code, val, NULL, e, bsi); ! } /* Now look at how OP is set. If it's set from a comparison, a truth operation or some bit operations, then we may be able --- 5963,5971 ---- if (TREE_CODE (op) != SSA_NAME) return; ! /* We know that OP will have a zero or nonzero value. */ ! val = build_int_cst (TREE_TYPE (op), 0); ! add_assert_info (asserts, op, op, code, val); /* Now look at how OP is set. If it's set from a comparison, a truth operation or some bit operations, then we may be able *************** register_edge_assert_for_1 (tree op, enu *** 5975,5983 **** tree op1 = gimple_assign_rhs2 (op_def); if (TREE_CODE (op0) == SSA_NAME) ! register_edge_assert_for_2 (op0, e, bsi, rhs_code, op0, op1, invert); if (TREE_CODE (op1) == SSA_NAME) ! register_edge_assert_for_2 (op1, e, bsi, rhs_code, op0, op1, invert); } else if ((code == NE_EXPR && gimple_assign_rhs_code (op_def) == BIT_AND_EXPR) --- 5983,5991 ---- tree op1 = gimple_assign_rhs2 (op_def); if (TREE_CODE (op0) == SSA_NAME) ! register_edge_assert_for_2 (op0, e, rhs_code, op0, op1, invert, asserts); if (TREE_CODE (op1) == SSA_NAME) ! register_edge_assert_for_2 (op1, e, rhs_code, op0, op1, invert, asserts); } else if ((code == NE_EXPR && gimple_assign_rhs_code (op_def) == BIT_AND_EXPR) *************** register_edge_assert_for_1 (tree op, enu *** 5989,6010 **** tree op1 = gimple_assign_rhs2 (op_def); if (TREE_CODE (op0) == SSA_NAME && has_single_use (op0)) ! register_edge_assert_for_1 (op0, code, e, bsi); if (TREE_CODE (op1) == SSA_NAME && has_single_use (op1)) ! register_edge_assert_for_1 (op1, code, e, bsi); } else if (gimple_assign_rhs_code (op_def) == BIT_NOT_EXPR && TYPE_PRECISION (TREE_TYPE (gimple_assign_lhs (op_def))) == 1) { /* Recurse, flipping CODE. */ code = invert_tree_comparison (code, false); ! register_edge_assert_for_1 (gimple_assign_rhs1 (op_def), code, e, bsi); } else if (gimple_assign_rhs_code (op_def) == SSA_NAME) { /* Recurse through the copy. */ ! register_edge_assert_for_1 (gimple_assign_rhs1 (op_def), code, e, bsi); } else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (op_def))) { --- 5997,6018 ---- tree op1 = gimple_assign_rhs2 (op_def); if (TREE_CODE (op0) == SSA_NAME && has_single_use (op0)) ! register_edge_assert_for_1 (op0, code, e, asserts); if (TREE_CODE (op1) == SSA_NAME && has_single_use (op1)) ! register_edge_assert_for_1 (op1, code, e, asserts); } else if (gimple_assign_rhs_code (op_def) == BIT_NOT_EXPR && TYPE_PRECISION (TREE_TYPE (gimple_assign_lhs (op_def))) == 1) { /* Recurse, flipping CODE. */ code = invert_tree_comparison (code, false); ! register_edge_assert_for_1 (gimple_assign_rhs1 (op_def), code, e, asserts); } else if (gimple_assign_rhs_code (op_def) == SSA_NAME) { /* Recurse through the copy. */ ! register_edge_assert_for_1 (gimple_assign_rhs1 (op_def), code, e, asserts); } else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (op_def))) { *************** register_edge_assert_for_1 (tree op, enu *** 6014,6020 **** if (INTEGRAL_TYPE_P (TREE_TYPE (rhs)) && (TYPE_PRECISION (TREE_TYPE (rhs)) <= TYPE_PRECISION (TREE_TYPE (op)))) ! register_edge_assert_for_1 (rhs, code, e, bsi); } } --- 6022,6028 ---- if (INTEGRAL_TYPE_P (TREE_TYPE (rhs)) && (TYPE_PRECISION (TREE_TYPE (rhs)) <= TYPE_PRECISION (TREE_TYPE (op)))) ! register_edge_assert_for_1 (rhs, code, e, asserts); } } *************** register_edge_assert_for_1 (tree op, enu *** 6023,6031 **** SI. */ static void ! register_edge_assert_for (tree name, edge e, gimple_stmt_iterator si, enum tree_code cond_code, tree cond_op0, ! tree cond_op1) { tree val; enum tree_code comp_code; --- 6031,6039 ---- SI. */ static void ! register_edge_assert_for (tree name, edge e, enum tree_code cond_code, tree cond_op0, ! tree cond_op1, vec<assert_info> &asserts) { tree val; enum tree_code comp_code; *************** register_edge_assert_for (tree name, edg *** 6043,6050 **** return; /* Register ASSERT_EXPRs for name. */ ! register_edge_assert_for_2 (name, e, si, cond_code, cond_op0, ! cond_op1, is_else_edge); /* If COND is effectively an equality test of an SSA_NAME against --- 6051,6058 ---- return; /* Register ASSERT_EXPRs for name. */ ! register_edge_assert_for_2 (name, e, cond_code, cond_op0, ! cond_op1, is_else_edge, asserts); /* If COND is effectively an equality test of an SSA_NAME against *************** register_edge_assert_for (tree name, edg *** 6064,6071 **** { tree op0 = gimple_assign_rhs1 (def_stmt); tree op1 = gimple_assign_rhs2 (def_stmt); ! register_edge_assert_for_1 (op0, NE_EXPR, e, si); ! register_edge_assert_for_1 (op1, NE_EXPR, e, si); } } --- 6072,6079 ---- { tree op0 = gimple_assign_rhs1 (def_stmt); tree op1 = gimple_assign_rhs2 (def_stmt); ! register_edge_assert_for_1 (op0, NE_EXPR, e, asserts); ! register_edge_assert_for_1 (op1, NE_EXPR, e, asserts); } } *************** register_edge_assert_for (tree name, edg *** 6086,6097 **** { tree op0 = gimple_assign_rhs1 (def_stmt); tree op1 = gimple_assign_rhs2 (def_stmt); ! register_edge_assert_for_1 (op0, EQ_EXPR, e, si); ! register_edge_assert_for_1 (op1, EQ_EXPR, e, si); } } } /* Determine whether the outgoing edges of BB should receive an ASSERT_EXPR for each of the operands of BB's LAST statement. --- 6094,6121 ---- { tree op0 = gimple_assign_rhs1 (def_stmt); tree op1 = gimple_assign_rhs2 (def_stmt); ! register_edge_assert_for_1 (op0, EQ_EXPR, e, asserts); ! register_edge_assert_for_1 (op1, EQ_EXPR, e, asserts); } } } + /* Finish found ASSERTS for E and register them at GSI. */ + + static void + finish_register_edge_assert_for (edge e, gimple_stmt_iterator gsi, + vec<assert_info> &asserts) + { + for (unsigned i = 0; i < asserts.length (); ++i) + /* Only register an ASSERT_EXPR if NAME was found in the sub-graph + reachable from E. */ + if (live_on_edge (e, asserts[i].name)) + register_new_assert_for (asserts[i].name, asserts[i].expr, + asserts[i].comp_code, asserts[i].val, + NULL, e, gsi); + } + + /* Determine whether the outgoing edges of BB should receive an ASSERT_EXPR for each of the operands of BB's LAST statement. *************** find_conditional_asserts (basic_block bb *** 6123,6133 **** /* Register the necessary assertions for each operand in the conditional predicate. */ FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE) ! register_edge_assert_for (op, e, bsi, gimple_cond_code (last), gimple_cond_lhs (last), ! gimple_cond_rhs (last)); } } --- 6147,6159 ---- /* Register the necessary assertions for each operand in the conditional predicate. */ + auto_vec<assert_info, 8> asserts; FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE) ! register_edge_assert_for (op, e, gimple_cond_code (last), gimple_cond_lhs (last), ! gimple_cond_rhs (last), asserts); ! finish_register_edge_assert_for (e, bsi, asserts); } } *************** find_switch_asserts (basic_block bb, gsw *** 6239,6250 **** /* Register the necessary assertions for the operand in the SWITCH_EXPR. */ ! register_edge_assert_for (op, e, bsi, max ? GE_EXPR : EQ_EXPR, ! op, fold_convert (TREE_TYPE (op), min)); if (max) ! register_edge_assert_for (op, e, bsi, LE_EXPR, op, ! fold_convert (TREE_TYPE (op), max)); } XDELETEVEC (ci); --- 6265,6280 ---- /* Register the necessary assertions for the operand in the SWITCH_EXPR. */ ! auto_vec<assert_info, 8> asserts; ! register_edge_assert_for (op, e, max ? GE_EXPR : EQ_EXPR, ! op, fold_convert (TREE_TYPE (op), min), ! asserts); if (max) ! register_edge_assert_for (op, e, LE_EXPR, op, ! fold_convert (TREE_TYPE (op), max), ! asserts); ! finish_register_edge_assert_for (e, bsi, asserts); } XDELETEVEC (ci); *************** find_switch_asserts (basic_block bb, gsw *** 6293,6300 **** if (max == NULL_TREE) { /* Register the assertion OP != MIN. */ min = fold_convert (TREE_TYPE (op), min); ! register_edge_assert_for (op, default_edge, bsi, NE_EXPR, op, min); } else { --- 6323,6333 ---- if (max == NULL_TREE) { /* Register the assertion OP != MIN. */ + auto_vec<assert_info, 8> asserts; min = fold_convert (TREE_TYPE (op), min); ! register_edge_assert_for (op, default_edge, NE_EXPR, op, min, ! asserts); ! finish_register_edge_assert_for (default_edge, bsi, asserts); } else { *************** public: *** 11160,11166 **** virtual void after_dom_children (basic_block); void push_value_range (tree var, value_range *vr); value_range *pop_value_range (tree var); ! value_range *try_find_new_range (tree op, tree_code code, tree limit); /* Cond_stack holds the old VR. */ auto_vec<std::pair <tree, value_range*> > stack; --- 11203,11209 ---- virtual void after_dom_children (basic_block); void push_value_range (tree var, value_range *vr); value_range *pop_value_range (tree var); ! value_range *try_find_new_range (tree, tree op, tree_code code, tree limit); /* Cond_stack holds the old VR. */ auto_vec<std::pair <tree, value_range*> > stack; *************** public: *** 11169,11187 **** auto_vec<gimple *> stmts_to_remove; }; ! /* Find new range for OP such that (OP CODE LIMIT) is true. */ value_range * ! evrp_dom_walker::try_find_new_range (tree op, tree_code code, tree limit) { value_range vr = VR_INITIALIZER; ! value_range *old_vr = get_value_range (op); /* Discover VR when condition is true. */ ! extract_range_for_var_from_comparison_expr (op, code, op, limit, &vr); - if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE) - vrp_intersect_ranges (&vr, old_vr); /* If we found any usable VR, set the VR to ssa_name and create a PUSH old value in the stack with the old VR. */ if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE) --- 11212,11229 ---- auto_vec<gimple *> stmts_to_remove; }; ! /* Find new range for NAME such that (OP CODE LIMIT) is true. */ value_range * ! evrp_dom_walker::try_find_new_range (tree name, ! tree op, tree_code code, tree limit) { value_range vr = VR_INITIALIZER; ! value_range *old_vr = get_value_range (name); /* Discover VR when condition is true. */ ! extract_range_for_var_from_comparison_expr (name, code, op, limit, &vr); /* If we found any usable VR, set the VR to ssa_name and create a PUSH old value in the stack with the old VR. */ if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE) *************** evrp_dom_walker::before_dom_children (ba *** 11245,11280 **** /* Entering a new scope. Try to see if we can find a VR here. */ tree op1 = gimple_cond_rhs (stmt); - tree_code code = gimple_cond_code (stmt); - if (TREE_OVERFLOW_P (op1)) op1 = drop_tree_overflow (op1); ! /* If condition is false, invert the cond. */ ! if (pred_e->flags & EDGE_FALSE_VALUE) ! code = invert_tree_comparison (gimple_cond_code (stmt), ! HONOR_NANS (op0)); ! /* Add VR when (OP0 CODE OP1) condition is true. */ ! value_range *op0_range = try_find_new_range (op0, code, op1); ! ! /* Register ranges for y in x < y where ! y might have ranges that are useful. */ ! tree limit; ! tree_code new_code; ! if (TREE_CODE (op1) == SSA_NAME ! && extract_code_and_val_from_cond_with_ops (op1, code, ! op0, op1, ! false, ! &new_code, &limit)) ! { ! /* Add VR when (OP1 NEW_CODE LIMIT) condition is true. */ ! value_range *op1_range = try_find_new_range (op1, new_code, limit); ! if (op1_range) ! push_value_range (op1, op1_range); ! } ! ! if (op0_range) ! push_value_range (op0, op0_range); } } --- 11287,11315 ---- /* Entering a new scope. Try to see if we can find a VR here. */ tree op1 = gimple_cond_rhs (stmt); if (TREE_OVERFLOW_P (op1)) op1 = drop_tree_overflow (op1); + tree_code code = gimple_cond_code (stmt); ! auto_vec<assert_info, 8> asserts; ! register_edge_assert_for (op0, pred_e, code, op0, op1, asserts); ! if (TREE_CODE (op1) == SSA_NAME) ! register_edge_assert_for (op1, pred_e, code, op0, op1, asserts); ! ! auto_vec<std::pair<tree, value_range *>, 8> vrs; ! for (unsigned i = 0; i < asserts.length (); ++i) ! { ! value_range *vr = try_find_new_range (asserts[i].name, ! asserts[i].expr, ! asserts[i].comp_code, ! asserts[i].val); ! if (vr) ! vrs.safe_push (std::make_pair (asserts[i].name, vr)); ! } ! /* Push updated ranges only after finding all of them to avoid ! ordering issues that can lead to worse ranges. */ ! for (unsigned i = 0; i < vrs.length (); ++i) ! push_value_range (vrs[i].first, vrs[i].second); } } *************** evrp_dom_walker::before_dom_children (ba *** 11462,11474 **** /* Add VR when (T COMP_CODE value) condition is true. */ value_range *op_range ! = try_find_new_range (t, comp_code, value); if (op_range) push_value_range (t, op_range); } } /* Add VR when (OP COMP_CODE value) condition is true. */ ! value_range *op_range = try_find_new_range (op, comp_code, value); if (op_range) push_value_range (op, op_range); --- 11497,11509 ---- /* Add VR when (T COMP_CODE value) condition is true. */ value_range *op_range ! = try_find_new_range (t, t, comp_code, value); if (op_range) push_value_range (t, op_range); } } /* Add VR when (OP COMP_CODE value) condition is true. */ ! value_range *op_range = try_find_new_range (op, op, comp_code, value); if (op_range) push_value_range (op, op_range); Index: gcc/testsuite/gcc.dg/tree-ssa/evrp7.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/evrp7.c (nonexistent) --- gcc/testsuite/gcc.dg/tree-ssa/evrp7.c (working copy) *************** *** 0 **** --- 1,14 ---- + /* { dg-do compile } */ + /* { dg-options "-O2 -fdump-tree-evrp-details" } */ + + int test1(int i, int k) + { + if (i > 0 && i <= 5 && k >= 10 && k < 42) + { + int j = i + 1 + k; + return j == 10; + } + return 1; + } + + /* { dg-final { scan-tree-dump "Removing dead stmt \[^\r\n\]* = j_.* == 10" "evrp" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/evrp8.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/evrp8.c (nonexistent) --- gcc/testsuite/gcc.dg/tree-ssa/evrp8.c (working copy) *************** *** 0 **** --- 1,11 ---- + /* { dg-do compile } */ + /* { dg-options "-O2 -fdump-tree-evrp-details" } */ + + int foo(int i) + { + if (i < 0 || i >= 5) + return i == 1; + return 1; + } + + /* { dg-final { scan-tree-dump "Removing dead stmt \[^\r\n\]* = i_.* == 1" "evrp" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/evrp9.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/evrp9.c (nonexistent) --- gcc/testsuite/gcc.dg/tree-ssa/evrp9.c (working copy) *************** *** 0 **** --- 1,28 ---- + /* PR tree-optimization/49039 */ + /* { dg-do compile } */ + /* { dg-options "-O2 -fdump-tree-evrp" } */ + + extern void bar (void); + + void + foo (unsigned int x, unsigned int y) + { + unsigned int minv, maxv; + if (x >= 3 && x <= 6) + return; + if (y >= 5 && y <= 8) + return; + minv = x < y ? x : y; + maxv = x > y ? x : y; + if (minv == 5) + bar (); + if (minv == 6) + bar (); + if (maxv == 5) + bar (); + if (maxv == 6) + bar (); + } + + /* { dg-final { scan-tree-dump-not "== 5" "evrp" } } */ + /* { dg-final { scan-tree-dump-not "== 6" "evrp" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/vrp35.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/vrp35.c (revision 247293) --- gcc/testsuite/gcc.dg/tree-ssa/vrp35.c (working copy) *************** *** 1,5 **** /* { dg-do compile } */ ! /* { dg-options "-O2 -fdump-tree-vrp1-details" } */ int test1(int i, int k) { --- 1,5 ---- /* { dg-do compile } */ ! /* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details" } */ int test1(int i, int k) { Index: gcc/testsuite/gcc.dg/tree-ssa/vrp36.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/vrp36.c (revision 247293) --- gcc/testsuite/gcc.dg/tree-ssa/vrp36.c (working copy) *************** *** 1,5 **** /* { dg-do compile } */ ! /* { dg-options "-O2 -fdump-tree-vrp1-details" } */ int foo(int i) { --- 1,5 ---- /* { dg-do compile } */ ! /* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1-details" } */ int foo(int i) { Index: gcc/testsuite/gcc.dg/tree-ssa/pr49039.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/pr49039.c (revision 247293) --- gcc/testsuite/gcc.dg/tree-ssa/pr49039.c (working copy) *************** *** 1,6 **** /* PR tree-optimization/49039 */ /* { dg-do compile } */ ! /* { dg-options "-O2 -fdump-tree-vrp1" } */ extern void bar (void); --- 1,6 ---- /* PR tree-optimization/49039 */ /* { dg-do compile } */ ! /* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1" } */ extern void bar (void);