This improves VRP so that two of the three (the remaining one invalid IMHO) spurious array-bound warnings in PR55079 no longer appear. With the patch we now properly handle
MIN_EXPR <[1, 6], VARYING> and register asserts for i_2 in i_2 = i_1 + 1; if (i_1 != 0) which is a common pattern from tests of post-modify expressions. For gcc.dg/tree-ssa/ssa-pre-1.c this is too fancy and thus I needed to adjust the testcase to avoid VRP being too clever. Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2012-12-10 Richard Biener <rguent...@suse.de> PR tree-optimization/55079 * tree-vrp.c (extract_range_from_binary_expr_1): Handle MAX/MIN_EXPR for more cases. (register_edge_assert_for_2): Register asserts for post-in/decrement tests. (check_array_ref): Dump what expression we emit array bound warnings for. (search_for_addr_array): Likewise. * gcc.dg/Warray-bounds-9.c: New testcase. * gcc.dg/Warray-bounds-10.c: Likewise. * gcc.dg/tree-ssa/ssa-pre-1.c: Adjust. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c (revision 194358) --- gcc/tree-vrp.c (working copy) *************** extract_range_from_binary_expr_1 (value_ *** 2349,2354 **** --- 2349,2356 ---- && code != EXACT_DIV_EXPR && code != ROUND_DIV_EXPR && code != TRUNC_MOD_EXPR + && code != MIN_EXPR + && code != MAX_EXPR && (vr0.type == VR_VARYING || vr1.type == VR_VARYING || vr0.type != vr1.type *************** extract_range_from_binary_expr_1 (value_ *** 2602,2622 **** else if (code == MIN_EXPR || code == MAX_EXPR) { ! if (vr0.type == VR_ANTI_RANGE) { ! /* For MIN_EXPR and MAX_EXPR with two VR_ANTI_RANGEs, ! the resulting VR_ANTI_RANGE is the same - intersection ! of the two ranges. */ ! min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min); ! max = vrp_int_const_binop (MIN_EXPR, vr0.max, vr1.max); } else { ! /* For operations that make the resulting range directly ! proportional to the original ranges, apply the operation to ! the same end of each range. */ ! min = vrp_int_const_binop (code, vr0.min, vr1.min); ! max = vrp_int_const_binop (code, vr0.max, vr1.max); } } else if (code == MULT_EXPR) --- 2604,2652 ---- else if (code == MIN_EXPR || code == MAX_EXPR) { ! if (vr0.type == VR_RANGE ! && !symbolic_range_p (&vr0)) { ! type = VR_RANGE; ! if (vr1.type == VR_RANGE ! && !symbolic_range_p (&vr1)) ! { ! /* For operations that make the resulting range directly ! proportional to the original ranges, apply the operation to ! the same end of each range. */ ! min = vrp_int_const_binop (code, vr0.min, vr1.min); ! max = vrp_int_const_binop (code, vr0.max, vr1.max); ! } ! else if (code == MIN_EXPR) ! { ! min = vrp_val_min (expr_type); ! max = vr0.max; ! } ! else if (code == MAX_EXPR) ! { ! min = vr0.min; ! max = vrp_val_max (expr_type); ! } ! } ! else if (vr1.type == VR_RANGE ! && !symbolic_range_p (&vr1)) ! { ! type = VR_RANGE; ! if (code == MIN_EXPR) ! { ! min = vrp_val_min (expr_type); ! max = vr1.max; ! } ! else if (code == MAX_EXPR) ! { ! min = vr1.min; ! max = vrp_val_max (expr_type); ! } } else { ! set_value_range_to_varying (vr); ! return; } } else if (code == MULT_EXPR) *************** register_edge_assert_for_2 (tree name, e *** 4707,4712 **** --- 4737,4781 ---- } } + /* In the case of post-in/decrement tests like if (i++) ... and uses + of the in/decremented value on the edge the extra name we want to + assert for is not on the def chain of the name compared. Instead + it is in the set of use stmts. */ + if ((comp_code == NE_EXPR + || comp_code == EQ_EXPR) + && TREE_CODE (val) == INTEGER_CST) + { + imm_use_iterator ui; + gimple use_stmt; + FOR_EACH_IMM_USE_STMT (use_stmt, ui, name) + { + /* Cut off to use-stmts that are in the predecessor. */ + if (gimple_bb (use_stmt) != e->src) + continue; + + if (!is_gimple_assign (use_stmt)) + continue; + + enum tree_code code = gimple_assign_rhs_code (use_stmt); + if (code != PLUS_EXPR + && code != MINUS_EXPR) + continue; + + tree cst = gimple_assign_rhs2 (use_stmt); + if (TREE_CODE (cst) != INTEGER_CST) + continue; + + tree name2 = gimple_assign_lhs (use_stmt); + if (live_on_edge (e, name2)) + { + cst = int_const_binop (code, val, cst); + register_new_assert_for (name2, name2, comp_code, cst, + NULL, e, bsi); + retval = true; + } + } + } + if (TREE_CODE_CLASS (comp_code) == tcc_comparison && TREE_CODE (val) == INTEGER_CST) { *************** check_array_ref (location_t location, tr *** 5943,5948 **** --- 6012,6022 ---- : (tree_int_cst_lt (up_bound, up_sub) || tree_int_cst_equal (up_bound_p1, up_sub)))) { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Array bound warning for "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, ref); + } warning_at (location, OPT_Warray_bounds, "array subscript is above array bounds"); TREE_NO_WARNING (ref) = 1; *************** check_array_ref (location_t location, tr *** 5950,5955 **** --- 6024,6034 ---- else if (TREE_CODE (low_sub) == INTEGER_CST && tree_int_cst_lt (low_sub, low_bound)) { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Array bound warning for "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, ref); + } warning_at (location, OPT_Warray_bounds, "array subscript is below array bounds"); TREE_NO_WARNING (ref) = 1; *************** search_for_addr_array (tree t, location_ *** 6018,6023 **** --- 6097,6107 ---- idx = idx.sdiv (tree_to_double_int (el_sz), TRUNC_DIV_EXPR); if (idx.slt (double_int_zero)) { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Array bound warning for "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, t); + } warning_at (location, OPT_Warray_bounds, "array subscript is below array bounds"); TREE_NO_WARNING (t) = 1; *************** search_for_addr_array (tree t, location_ *** 6026,6031 **** --- 6110,6120 ---- - tree_to_double_int (low_bound) + double_int_one)) { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Array bound warning for "); + dump_generic_expr (MSG_NOTE, TDF_SLIM, t); + } warning_at (location, OPT_Warray_bounds, "array subscript is above array bounds"); TREE_NO_WARNING (t) = 1; Index: gcc/testsuite/gcc.dg/Warray-bounds-9.c =================================================================== *** gcc/testsuite/gcc.dg/Warray-bounds-9.c (revision 0) --- gcc/testsuite/gcc.dg/Warray-bounds-9.c (working copy) *************** *** 0 **** --- 1,19 ---- + /* { dg-do compile } */ + /* { dg-options "-O3 -Warray-bounds" } */ + + int a[8]; + + void + test(unsigned int n) + { + unsigned int i; + unsigned int j; + if (n<8) + for (j=0;j<n;j++) + { + i = j; + do + a[i+1]=a[i]; + while (i--); + } + } Index: gcc/testsuite/gcc.dg/Warray-bounds-10.c =================================================================== *** gcc/testsuite/gcc.dg/Warray-bounds-10.c (revision 0) --- gcc/testsuite/gcc.dg/Warray-bounds-10.c (working copy) *************** *** 0 **** --- 1,25 ---- + /* { dg-do compile } */ + /* { dg-options "-O3 -Warray-bounds" } */ + + int f(unsigned len, int buflen) + { + unsigned taillen; + unsigned slen; + unsigned i; + int b[17]; /* needed <= 17 to trigger Warning */ + int j = 0; /* needed to trigger Warning */ + + b[0] = 0; + taillen= buflen & 7; /* taillen [0..7] */ + + if(taillen) { /* taillen [1..7] */ + slen= 8 - taillen; /* slen [7..1] */ + if (len<slen) /* needed to trigger Warning */ + slen=len; /* slen' < slen */ + for(i=0; i<slen; i++) { + j = b[taillen]; /* taillen + slen = [1..7] + [7..1] = 8 */ + taillen++; + } + } + return j; + } Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c (revision 194358) --- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c (working copy) *************** int foo(int argc, char **argv) *** 9,15 **** b = argc + 1; c = argc + 2; a = b + c; ! if (argc * 2) { c = argc + 3; } --- 9,15 ---- b = argc + 1; c = argc + 2; a = b + c; ! if (argc > 2) { c = argc + 3; }