Hi! As described in the PR, this is an attempt to avoid false positive -Warray-bounds warnings by adding some extra ASSERT_EXPRs in vrp, so that it can better optimize the code. For if (x >> cst1 == cst2) we can assert that (x - ((unsigned) cst2 << cst1) < (1U << cst1)) and e.g. for if (x >> cst1 >= cst2) we can assert that (x >= (cst2 << cst1)).
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2012-01-02 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/51721 * tree-vrp.c (register_edge_assert_for_2): If comparing lhs of right shift by constant with an integer constant, add ASSERT_EXPRs for the rhs1 of the right shift. * gcc.dg/tree-ssa/vrp63.c: New test. * gcc.dg/pr51721.c: New test. --- gcc/tree-vrp.c.jj 2011-12-02 01:52:27.000000000 +0100 +++ gcc/tree-vrp.c 2012-01-02 09:33:08.676635403 +0100 @@ -4464,6 +4464,93 @@ register_edge_assert_for_2 (tree name, e } } + /* Similarly add asserts for NAME == CST and NAME being defined as + NAME = NAME2 >> CST2. */ + if (TREE_CODE_CLASS (comp_code) == tcc_comparison + && TREE_CODE (val) == INTEGER_CST) + { + gimple def_stmt = SSA_NAME_DEF_STMT (name); + tree name2 = NULL_TREE, cst2 = NULL_TREE; + tree val2 = NULL_TREE; + unsigned HOST_WIDE_INT mask[2] = { 0, 0 }; + + /* Extract CST2 from the right shift. */ + if (is_gimple_assign (def_stmt) + && gimple_assign_rhs_code (def_stmt) == RSHIFT_EXPR) + { + name2 = gimple_assign_rhs1 (def_stmt); + cst2 = gimple_assign_rhs2 (def_stmt); + if (TREE_CODE (name2) == SSA_NAME + && host_integerp (cst2, 1) + && (unsigned HOST_WIDE_INT) tree_low_cst (cst2, 1) + < 2 * HOST_BITS_PER_WIDE_INT + && INTEGRAL_TYPE_P (TREE_TYPE (name2)) + && live_on_edge (e, name2) + && !has_single_use (name2)) + { + if ((unsigned HOST_WIDE_INT) tree_low_cst (cst2, 1) + < HOST_BITS_PER_WIDE_INT) + mask[0] = ((unsigned HOST_WIDE_INT) 1 + << tree_low_cst (cst2, 1)) - 1; + else + { + mask[1] = ((unsigned HOST_WIDE_INT) 1 + << (tree_low_cst (cst2, 1) + - HOST_BITS_PER_WIDE_INT)) - 1; + mask[0] = -1; + } + val2 = fold_binary (LSHIFT_EXPR, TREE_TYPE (val), val, cst2); + } + } + + if (val2 != NULL_TREE + && TREE_CODE (val2) == INTEGER_CST + && simple_cst_equal (fold_build2 (RSHIFT_EXPR, + TREE_TYPE (val), + val2, cst2), val)) + { + enum tree_code new_comp_code = comp_code; + tree tmp, new_val; + + tmp = name2; + if (comp_code == EQ_EXPR || comp_code == NE_EXPR) + { + if (!TYPE_UNSIGNED (TREE_TYPE (val))) + { + unsigned int prec = TYPE_PRECISION (TREE_TYPE (val)); + tree type = build_nonstandard_integer_type (prec, 1); + tmp = build1 (NOP_EXPR, type, name2); + val2 = fold_convert (type, val2); + } + tmp = fold_build2 (MINUS_EXPR, TREE_TYPE (tmp), tmp, val2); + new_val = build_int_cst_wide (TREE_TYPE (tmp), mask[0], mask[1]); + new_comp_code = comp_code == EQ_EXPR ? LE_EXPR : GT_EXPR; + } + else if (comp_code == LT_EXPR || comp_code == GE_EXPR) + new_val = val2; + else + { + new_val = build_int_cst_wide (TREE_TYPE (val2), + mask[0], mask[1]); + new_val = fold_binary (BIT_IOR_EXPR, TREE_TYPE (val2), + val2, new_val); + } + + if (dump_file) + { + fprintf (dump_file, "Adding assert for "); + print_generic_expr (dump_file, name2, 0); + fprintf (dump_file, " from "); + print_generic_expr (dump_file, tmp, 0); + fprintf (dump_file, "\n"); + } + + register_new_assert_for (name2, tmp, new_comp_code, new_val, + NULL, e, bsi); + retval = true; + } + } + return retval; } --- gcc/testsuite/gcc.dg/tree-ssa/vrp63.c.jj 2012-01-02 10:47:57.972533062 +0100 +++ gcc/testsuite/gcc.dg/tree-ssa/vrp63.c 2012-01-02 10:47:27.000000000 +0100 @@ -0,0 +1,345 @@ +/* PR tree-optimization/51721 */ +/* { dg-do link } */ +/* { dg-options "-O2" } */ + +extern void link_error (void); + +#define BITSM1 (sizeof (int) * __CHAR_BIT__ - 1) + +void +f1 (unsigned int s) +{ + if (s >> 1 == 0) + { + if (s == 2 || s == -1U) + link_error (); + } + else + { + if (s == 0 || s == 1) + link_error (); + } +} + +void +f2 (unsigned int s) +{ + if (s >> 4 != 3) + { + if (s == 48 || s == 57 || s == 63) + link_error (); + } + else + { + if (s == 47 || s == 64 || s == 0 || s == -1U) + link_error (); + } +} + +void +f3 (int s) +{ + if (s >> 3 == -2) + { + if (s == -17 || s == -8 || s == 0 + || s == -__INT_MAX__ - 1 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == -16 || s == -12 || s == -9) + link_error (); + } +} + +void +f4 (unsigned int s) +{ + if (s >> 2 < 4) + { + if (s == 16 || s == 20 || s == -1U) + link_error (); + } + else + { + if (s == 0 || s == 2 || s == 14 || s == 15) + link_error (); + } +} + +void +f5 (unsigned int s) +{ + if (s >> 3 <= 7) + { + if (s == 64 || s == 68 || s == -1U) + link_error (); + } + else + { + if (s == 0 || s == 1 || s == 62 || s == 63) + link_error (); + } +} + +void +f6 (unsigned int s) +{ + if (s >> 1 > 2) + { + if (s == 0 || s == 3 || s == 5) + link_error (); + } + else + { + if (s == 6 || s == 8 || s == -1U) + link_error (); + } +} + +void +f7 (unsigned int s) +{ + if (s >> 5 >= 7) + { + if (s == 0 || s == 2 || s == 221 || s == 223) + link_error (); + } + else + { + if (s == 224 || s == 256 || s == 258 || s == -1U) + link_error (); + } +} + +void +f8 (int s) +{ + if (s >> 2 < -3) + { + if (s == -12 || s == -10 || s == 0 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == -13 || s == -16 || s == -__INT_MAX__ - 1) + link_error (); + } +} + +void +f9 (int s) +{ + if (s >> 3 <= -2) + { + if (s == -8 || s == -6 || s == 0 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == -9 || s == -11 || s == -__INT_MAX__ - 1) + link_error (); + } +} + +void +f10 (int s) +{ + if (s >> 1 > -4) + { + if (s == -7 || s == -9 || s == -__INT_MAX__ - 1) + link_error (); + } + else + { + if (s == -6 || s == -4 || s == 0 || s == __INT_MAX__) + link_error (); + } +} + +void +f11 (int s) +{ + if (s >> 3 >= -6) + { + if (s == -49 || s == -51 || s == -__INT_MAX__ - 1) + link_error (); + } + else + { + if (s == -48 || s == -46 || s == 0 || s == __INT_MAX__) + link_error (); + } +} + +void +f12 (int s) +{ + if (s >> 2 < 4) + { + if (s == 16 || s == 20 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == 0 || s == 2 || s == 14 || s == 15 + || s == -2 || s == -__INT_MAX__ - 1) + link_error (); + } +} + +void +f13 (int s) +{ + if (s >> 3 <= 7) + { + if (s == 64 || s == 68 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == 0 || s == 1 || s == 62 || s == 63 + || s == -2 || s == -__INT_MAX__ - 1) + link_error (); + } +} + +void +f14 (int s) +{ + if (s >> 1 > 2) + { + if (s == 0 || s == 3 || s == 5 + || s == -2 || s == -__INT_MAX__ - 1) + link_error (); + } + else + { + if (s == 6 || s == 8 || s == __INT_MAX__) + link_error (); + } +} + +void +f15 (int s) +{ + if (s >> 5 >= 7) + { + if (s == 0 || s == 2 || s == 221 || s == 223 + || s == -2 || s == -__INT_MAX__ - 1) + link_error (); + } + else + { + if (s == 224 || s == 256 || s == 258 || s == __INT_MAX__) + link_error (); + } +} + +unsigned int +f16 (unsigned int s) +{ + unsigned int t = s >> BITSM1; + if (t != 0) + { + if (s == 0 || s == 5 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == 1U + __INT_MAX__ || s == 6U + __INT_MAX__ || s == -1U) + link_error (); + } + return t; +} + +int +f17 (int s) +{ + int t = s >> BITSM1; + if (t == 0) + { + if (s == -1 || s == -5 || s == -__INT_MAX__ - 1) + link_error (); + } + else + { + if (s == 0 || s == 5 || s == __INT_MAX__) + link_error (); + } + return t; +} + +unsigned int +f18 (unsigned int s) +{ + unsigned int t = s >> BITSM1; + if (t >= 1) + { + if (s == 0 || s == 5 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == 1U + __INT_MAX__ || s == 6U + __INT_MAX__ || s == -1U) + link_error (); + } + return t; +} + +int +f19 (int s) +{ + int t = s >> BITSM1; + if (t >= 0) + { + if (s == -1 || s == -5 || s == -__INT_MAX__ - 1) + link_error (); + } + else + { + if (s == 0 || s == 5 || s == __INT_MAX__) + link_error (); + } + return t; +} + +unsigned int +f20 (unsigned int s) +{ + unsigned int t = s >> BITSM1; + if (t < 1) + { + if (s == 1U + __INT_MAX__ || s == 6U + __INT_MAX__ || s == -1U) + link_error (); + } + else + { + if (s == 0 || s == 5 || s == __INT_MAX__) + link_error (); + } + return t; +} + +int +f21 (int s) +{ + int t = s >> BITSM1; + if (t < 0) + { + if (s == 0 || s == 5 || s == __INT_MAX__) + link_error (); + } + else + { + if (s == -1 || s == -5 || s == -__INT_MAX__ - 1) + link_error (); + } + return t; +} + +int +main () +{ + return 0; +} --- gcc/testsuite/gcc.dg/pr51721.c.jj 2012-01-02 09:35:51.621616998 +0100 +++ gcc/testsuite/gcc.dg/pr51721.c 2012-01-02 09:35:39.000000000 +0100 @@ -0,0 +1,31 @@ +/* PR tree-optimization/51721 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -Warray-bounds" } */ + +static int a[10], b[10], c[10], d[10]; + +unsigned int +f (unsigned int v) +{ + return v == 17 ? 11 : v; +} + +unsigned int +g (unsigned int v) +{ + return v == 17 ? 17 : v; +} + +void +t (unsigned int s) +{ + if (s >> 1 == 0) + { + a[f (s)] = 0; /* { dg-bogus "array subscript is above array bounds" } */ + a[f (s)] = 0; /* { dg-bogus "array subscript is above array bounds" } */ + b[f (s)] = 0; /* { dg-bogus "array subscript is above array bounds" } */ + c[g (s)] = 0; /* { dg-bogus "array subscript is above array bounds" } */ + c[g (s)] = 0; /* { dg-bogus "array subscript is above array bounds" } */ + d[f (s)] = 0; /* { dg-bogus "array subscript is above array bounds" } */ + } +} Jakub