aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-vrp.c
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2012-08-10 08:33:57 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2012-08-10 08:33:57 +0000
commita28729836a7f1993a17eeca53a0165c31406b581 (patch)
tree43053999250c5d3d6737bf5f2ad532a3798eb474 /gcc/tree-vrp.c
parent70b5e7dc7356529b557b613c7dee032c9d89d035 (diff)
downloadgcc-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.c77
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;
}