diff options
author | Tom de Vries <tom@codesourcery.com> | 2012-09-15 21:00:33 +0000 |
---|---|---|
committer | Tom de Vries <vries@gcc.gnu.org> | 2012-09-15 21:00:33 +0000 |
commit | b25d9e22e47f47935cd28c5df552d7bea4a45581 (patch) | |
tree | 8016b093f8efa67a0b865e63857661f6a988f589 /gcc | |
parent | 583aa11c6bacdaa2be9d47226ec925ad24db76c2 (diff) | |
download | gcc-b25d9e22e47f47935cd28c5df552d7bea4a45581.zip gcc-b25d9e22e47f47935cd28c5df552d7bea4a45581.tar.gz gcc-b25d9e22e47f47935cd28c5df552d7bea4a45581.tar.bz2 |
tree-vrp.c (extract_range_from_binary_expr_1): Fix bug in handling of LSHIFT_EXPR with shift range.
2012-09-15 Tom de Vries <tom@codesourcery.com>
* tree-vrp.c (extract_range_from_binary_expr_1): Fix bug in handling of
LSHIFT_EXPR with shift range. Handle more LSHIFT_EXPR cases with shift
range.
From-SVN: r191351
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/tree-vrp.c | 59 |
2 files changed, 57 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a5e3018..a5106a9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2012-09-15 Tom de Vries <tom@codesourcery.com> + + * tree-vrp.c (extract_range_from_binary_expr_1): Fix bug in handling of + LSHIFT_EXPR with shift range. Handle more LSHIFT_EXPR cases with shift + range. + 2012-09-15 Georg-Johann Lay <avr@gjlay.de> PR target/54222 diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 291d899..34f1d1a 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -2766,20 +2766,63 @@ extract_range_from_binary_expr_1 (value_range_t *vr, else if (code == LSHIFT_EXPR && range_int_cst_p (&vr0)) { - int overflow_pos = TYPE_PRECISION (expr_type); + int prec = TYPE_PRECISION (expr_type); + int overflow_pos = prec; int bound_shift; - double_int bound; + double_int bound, complement, low_bound, high_bound; + bool uns = TYPE_UNSIGNED (expr_type); + bool in_bounds = false; - if (!TYPE_UNSIGNED (expr_type)) + if (!uns) 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)) + /* If bound_shift == HOST_BITS_PER_DOUBLE_INT, the llshift can + overflow. However, for that to happen, vr1.max needs to be + zero, which means vr1 is a singleton range of zero, which + means it should be handled by the previous LSHIFT_EXPR + if-clause. */ + bound = double_int_one.llshift (bound_shift, prec); + complement = ~(bound - double_int_one); + + if (uns) + { + low_bound = bound; + high_bound = complement.zext (prec); + if (tree_to_double_int (vr0.max).ult (low_bound)) + { + /* [5, 6] << [1, 2] == [10, 24]. */ + /* We're shifting out only zeroes, the value increases + monotonically. */ + in_bounds = true; + } + else if (high_bound.ult (tree_to_double_int (vr0.min))) + { + /* [0xffffff00, 0xffffffff] << [1, 2] + == [0xfffffc00, 0xfffffffe]. */ + /* We're shifting out only ones, the value decreases + monotonically. */ + in_bounds = true; + } + } + else + { + /* [-1, 1] << [1, 2] == [-4, 4]. */ + low_bound = complement.sext (prec); + high_bound = bound; + if (tree_to_double_int (vr0.max).slt (high_bound) + && low_bound.slt (tree_to_double_int (vr0.min))) + { + /* For non-negative numbers, we're shifting out only + zeroes, the value increases monotonically. + For negative numbers, we're shifting out only ones, the + value decreases monotomically. */ + in_bounds = true; + } + } + + if (in_bounds) { - /* In the absense of overflow, (a << b) is equivalent - to (a * 2^b). */ extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1); return; } |