Richard, this patch fixes PR53986.
The patch calculates the range of an LSHIFT_EXPR in case both operands are constants ranges, and the operation is guaranteed not to overflow. F.i., it evaluates [1, 2] << [1, 8] to [2, 512]. Bootstrapped and reg-tested (ada inclusive) on x86_64. Ok for trunk? Thanks, - Tom 2012-08-25 Tom de Vries <t...@codesourcery.com> PR tree-optimization/53986 * tree-vrp.c (extract_range_from_multiplicative_op_1): Allow LSHIFT_EXPR. (extract_range_from_binary_expr_1): Handle LSHIFT with constant range as shift amount. * gcc.dg/tree-ssa/vrp80.c: New test. * gcc.dg/tree-ssa/vrp80-2.c: Same.
Index: gcc/tree-vrp.c =================================================================== --- gcc/tree-vrp.c (revision 190553) +++ gcc/tree-vrp.c (working copy) @@ -2068,7 +2068,8 @@ extract_range_from_multiplicative_op_1 ( || code == CEIL_DIV_EXPR || code == EXACT_DIV_EXPR || code == ROUND_DIV_EXPR - || code == RSHIFT_EXPR); + || code == RSHIFT_EXPR + || code == LSHIFT_EXPR); gcc_assert ((vr0->type == VR_RANGE || (code == MULT_EXPR && vr0->type == VR_ANTI_RANGE)) && vr0->type == vr1->type); @@ -2767,6 +2768,27 @@ extract_range_from_binary_expr_1 (value_ flag_wrapv = saved_flag_wrapv; return; } + else if (code == LSHIFT_EXPR + && range_int_cst_p (&vr0)) + { + int overflow_pos = TYPE_PRECISION (expr_type); + int bound_shift; + double_int bound; + + if (!TYPE_UNSIGNED (expr_type)) + overflow_pos -= 1; + + bound_shift = overflow_pos - TREE_INT_CST_LOW (vr1.max); + bound = double_int_one.llshift (bound_shift, + TYPE_PRECISION (expr_type)); + if (tree_to_double_int (vr0.max).ult (bound)) + { + /* In the absense of overflow, (a << b) is equivalent + to (a * 2^b). */ + extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1); + return; + } + } } set_value_range_to_varying (vr); return; Index: gcc/testsuite/gcc.dg/tree-ssa/vrp80.c =================================================================== --- /dev/null (new file) +++ gcc/testsuite/gcc.dg/tree-ssa/vrp80.c (revision 0) @@ -0,0 +1,33 @@ +/* { dg-do link } */ +/* { dg-options "-O2 -fno-tree-switch-conversion" } */ + +extern void link_error (void); + +/* Test <<. */ + +void +f3 (int s, int b) +{ + if (s >> 3 == -2) + /* s in range [-16, -9]. */ + { + s += 17; + /* s in range [1, 8]. */ + b = (b & 1) + 1; + /* b in range [1, 2]. */ + b = b << s; + /* b in range [bmin << smin, bmax << smax], + == [1 << 1, 2 << 8] + == [2, 512]. */ + if (b == 1 || b == 513) + link_error (); + } +} + +int +main () +{ + return 0; +} + + Index: gcc/testsuite/gcc.dg/tree-ssa/vrp80-2.c =================================================================== --- /dev/null (new file) +++ gcc/testsuite/gcc.dg/tree-ssa/vrp80-2.c (revision 0) @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-tree-switch-conversion -fdump-tree-vrp1" } */ + +extern void vrp_keep (void); + +/* Test <<. */ + +void +f3 (int s, int b) +{ + if (s >> 3 == -2) + /* s in range [-16, -9]. */ + { + s += 17; + /* s in range [1, 8]. */ + b = (b & 1) + 1; + /* b in range [1, 2]. */ + b = b << s; + /* b in range [bmin << smin, bmax << smax], + == [1 << 1, 2 << 8] + == [2, 512]. */ + if (b == 2) + vrp_keep (); + if (b == 512) + vrp_keep (); + } +} + +int +main () +{ + return 0; +} + +/* { dg-final { scan-tree-dump-times "vrp_keep \\(" 2 "vrp1"} } */ +/* { dg-final { cleanup-tree-dump "vrp1" } } */ + +