This patch addresses issues Richi raised from V1. Specifically it relieves the callers from having to try op0 COND op1 and op1 COND' op0 separately and adds some additional comments about motivation. There may have been minor nits Richi pointed out, if so, they were addressed as well.
Bootstrapped and regression tested as part of the full patch series. OK for the trunk? Jeff
* tree-vrp.c (overflow_comparison_p_1): New function. (overflow_comparison_p): New function. diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index ad8173c..2c03a74 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -5186,6 +5186,118 @@ masked_increment (const wide_int &val_in, const wide_int &mask, return val ^ sgnbit; } +/* Helper for overflow_comparison_p + + OP0 CODE OP1 is a comparison. Examine the comparison and potentially + OP1's defining statement to see if it ultimately has the form + OP0 CODE (OP0 PLUS INTEGER_CST) + + If so, return TRUE indicating this is an overflow test and store into + *NEW_CST an updated constant that can be used in a narrowed range test. + + REVERSED indicates if the comparison was originally: + + OP1 CODE' OP0. + + This affects how we build the updated constant. */ + +static bool +overflow_comparison_p_1 (enum tree_code code, tree op0, tree op1, + bool follow_assert_exprs, bool reversed, tree *new_cst) +{ + /* See if this is a relational operation between two SSA_NAMES with + unsigned, overflow wrapping values. If so, check it more deeply. */ + if ((code == LT_EXPR || code == LE_EXPR + || code == GE_EXPR || code == GT_EXPR) + && TREE_CODE (op0) == SSA_NAME + && TREE_CODE (op1) == SSA_NAME + && INTEGRAL_TYPE_P (TREE_TYPE (op0)) + && TYPE_UNSIGNED (TREE_TYPE (op0)) + && TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0))) + { + gimple *op1_def = SSA_NAME_DEF_STMT (op1); + + /* If requested, follow any ASSERT_EXPRs backwards for OP1. */ + if (follow_assert_exprs) + { + while (gimple_assign_single_p (op1_def) + && TREE_CODE (gimple_assign_rhs1 (op1_def)) == ASSERT_EXPR) + { + op1 = TREE_OPERAND (gimple_assign_rhs1 (op1_def), 0); + if (TREE_CODE (op1) != SSA_NAME) + break; + op1_def = SSA_NAME_DEF_STMT (op1); + } + } + + /* Now look at the defining statement of OP1 to see if it adds + or subtracts a nonzero constant from another operand. */ + if (op1_def + && is_gimple_assign (op1_def) + && gimple_assign_rhs_code (op1_def) == PLUS_EXPR + && TREE_CODE (gimple_assign_rhs2 (op1_def)) == INTEGER_CST + && !integer_zerop (gimple_assign_rhs2 (op1_def))) + { + tree target = gimple_assign_rhs1 (op1_def); + + /* If requested, follow ASSERT_EXPRs backwards for op0 looking + for one where TARGET appears on the RHS. */ + if (follow_assert_exprs) + { + /* Now see if that "other operand" is op0, following the chain + of ASSERT_EXPRs if necessary. */ + gimple *op0_def = SSA_NAME_DEF_STMT (op0); + while (op0 != target + && gimple_assign_single_p (op0_def) + && TREE_CODE (gimple_assign_rhs1 (op0_def)) == ASSERT_EXPR) + { + op0 = TREE_OPERAND (gimple_assign_rhs1 (op0_def), 0); + if (TREE_CODE (op0) != SSA_NAME) + break; + op0_def = SSA_NAME_DEF_STMT (op0); + } + } + + /* If we did not find our target SSA_NAME, then this is not + an overflow test. */ + if (op0 != target) + return false; + + tree type = TREE_TYPE (op0); + wide_int max = wi::max_value (TYPE_PRECISION (type), UNSIGNED); + tree inc = gimple_assign_rhs2 (op1_def); + if (reversed) + *new_cst = wide_int_to_tree (type, max + inc); + else + *new_cst = wide_int_to_tree (type, max - inc); + return true; + } + } + return false; +} + +/* OP0 CODE OP1 is a comparison. Examine the comparison and potentially + OP1's defining statement to see if it ultimately has the form + OP0 CODE (OP0 PLUS INTEGER_CST) + + If so, return TRUE indicating this is an overflow test and store into + *NEW_CST an updated constant that can be used in a narrowed range test. + + These statements are left as-is in the IL to facilitate discovery of + {ADD,SUB}_OVERFLOW sequences later in the optimizer pipeline. But + the alternate range representation is often useful within VRP. */ + +static bool +overflow_comparison_p (tree_code code, tree name, tree val, + bool use_equiv_p, tree *new_cst) +{ + if (overflow_comparison_p_1 (code, name, val, use_equiv_p, false, new_cst)) + return true; + return overflow_comparison_p_1 (swap_tree_comparison (code), val, name, + use_equiv_p, true, new_cst); +} + + /* Try to register an edge assertion for SSA name NAME on edge E for the condition COND contributing to the conditional jump pointed to by BSI. Invert the condition COND if INVERT is true. */