This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR54027
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 9 Aug 2012 15:46:10 +0200 (CEST)
- Subject: [PATCH] Fix PR54027
This fixes PR54027, VRP treating overflow in signed left-shifts undefined.
Bootstrap and regtest pending on x86_64-unknown-linux-gnu.
Richard.
2012-08-09 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.
Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c (revision 190252)
--- gcc/tree-vrp.c (working copy)
*************** extract_range_from_binary_expr_1 (value_
*** 2726,2782 ****
extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
return;
}
! else if (code == RSHIFT_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)
- {
- 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;
- }
-
set_value_range_to_varying (vr);
return;
}
--- 2726,2773 ----
extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
return;
}
! 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 (range_int_cst_p (&vr1)
! && compare_tree_int (vr1.min, 0) >= 0
! && compare_tree_int (vr1.max, TYPE_PRECISION (expr_type)) == -1)
{
! 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;
}
Index: gcc/testsuite/gcc.dg/torture/pr54027.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr54027.c (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr54027.c (working copy)
***************
*** 0 ****
--- 1,9 ----
+ /* { dg-do run } */
+
+ int main (void)
+ {
+ int x = 1;
+ while (x)
+ x <<= 1;
+ return x;
+ }