diff options
author | Richard Guenther <rguenther@suse.de> | 2012-08-10 08:33:57 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2012-08-10 08:33:57 +0000 |
commit | a28729836a7f1993a17eeca53a0165c31406b581 (patch) | |
tree | 43053999250c5d3d6737bf5f2ad532a3798eb474 /gcc/tree-vrp.c | |
parent | 70b5e7dc7356529b557b613c7dee032c9d89d035 (diff) | |
download | gcc-a28729836a7f1993a17eeca53a0165c31406b581.zip gcc-a28729836a7f1993a17eeca53a0165c31406b581.tar.gz gcc-a28729836a7f1993a17eeca53a0165c31406b581.tar.bz2 |
re PR tree-optimization/54027 (possible mis-optimization of signed left shift in c89 mode)
2012-08-10 Richard Guenther <rguenther@suse.de>
PR tree-optimization/54027
* tree-vrp.c (extract_range_from_binary_expr_1): Merge RSHIFT_EXPR
and LSHIFT_EXPR handling, force -fwrapv for the multiplication used
to handle LSHIFT_EXPR with a constant.
* gcc.dg/torture/pr54027.c: New testcase.
From-SVN: r190286
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 77 |
1 files changed, 34 insertions, 43 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 5f7734f..a5b583b 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -2726,57 +2726,48 @@ extract_range_from_binary_expr_1 (value_range_t *vr, extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1); return; } - else if (code == RSHIFT_EXPR) + else if (code == RSHIFT_EXPR + || code == LSHIFT_EXPR) { /* If we have a RSHIFT_EXPR with any shift values outside [0..prec-1], then drop to VR_VARYING. Outside of this range we get undefined behavior from the shift operation. We cannot even trust SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl shifts, and the operation at the tree level may be widened. */ - if (vr1.type != VR_RANGE - || !value_range_nonnegative_p (&vr1) - || TREE_CODE (vr1.max) != INTEGER_CST - || compare_tree_int (vr1.max, TYPE_PRECISION (expr_type) - 1) == 1) - { - set_value_range_to_varying (vr); - return; - } - - extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1); - return; - } - else if (code == LSHIFT_EXPR) - { - /* If we have a LSHIFT_EXPR with any shift values outside [0..prec-1], - then drop to VR_VARYING. Outside of this range we get undefined - behavior from the shift operation. We cannot even trust - SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl - shifts, and the operation at the tree level may be widened. */ - if (vr1.type != VR_RANGE - || !value_range_nonnegative_p (&vr1) - || TREE_CODE (vr1.max) != INTEGER_CST - || compare_tree_int (vr1.max, TYPE_PRECISION (expr_type) - 1) == 1) + if (range_int_cst_p (&vr1) + && compare_tree_int (vr1.min, 0) >= 0 + && compare_tree_int (vr1.max, TYPE_PRECISION (expr_type)) == -1) { - set_value_range_to_varying (vr); - return; - } - - /* We can map shifts by constants to MULT_EXPR handling. */ - if (range_int_cst_singleton_p (&vr1)) - { - value_range_t vr1p = VR_INITIALIZER; - vr1p.type = VR_RANGE; - vr1p.min - = double_int_to_tree (expr_type, - double_int_lshift (double_int_one, - TREE_INT_CST_LOW (vr1.min), - TYPE_PRECISION (expr_type), - false)); - vr1p.max = vr1p.min; - extract_range_from_multiplicative_op_1 (vr, MULT_EXPR, &vr0, &vr1p); - return; + if (code == RSHIFT_EXPR) + { + extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1); + return; + } + /* We can map lshifts by constants to MULT_EXPR handling. */ + else if (code == LSHIFT_EXPR + && range_int_cst_singleton_p (&vr1)) + { + bool saved_flag_wrapv; + value_range_t vr1p = VR_INITIALIZER; + vr1p.type = VR_RANGE; + vr1p.min + = double_int_to_tree (expr_type, + double_int_lshift + (double_int_one, + TREE_INT_CST_LOW (vr1.min), + TYPE_PRECISION (expr_type), + false)); + vr1p.max = vr1p.min; + /* We have to use a wrapping multiply though as signed overflow + on lshifts is implementation defined in C89. */ + saved_flag_wrapv = flag_wrapv; + flag_wrapv = 1; + extract_range_from_binary_expr_1 (vr, MULT_EXPR, expr_type, + &vr0, &vr1p); + flag_wrapv = saved_flag_wrapv; + return; + } } - set_value_range_to_varying (vr); return; } |