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 <rguent...@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; + }