This fixes PR50729, so much for not implementing it by using value-ranges ... opens up the door for more bugs ;)
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2011-10-17 Richard Guenther <rguent...@suse.de> PR tree-optimization/50729 * tree-vrp.c (extract_range_from_unary_expr_1): Remove redundant test. (simplify_conversion_using_ranges): Properly test the intermediate result. * gcc.dg/torture/pr50729.c: New testcase. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c (revision 180077) --- gcc/tree-vrp.c (working copy) *************** extract_range_from_unary_expr_1 (value_r *** 2913,2927 **** determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). */ if (POINTER_TYPE_P (type)) { ! if (CONVERT_EXPR_CODE_P (code)) ! { ! if (range_is_nonnull (&vr0)) ! set_value_range_to_nonnull (vr, type); ! else if (range_is_null (&vr0)) ! set_value_range_to_null (vr, type); ! else ! set_value_range_to_varying (vr); ! } else set_value_range_to_varying (vr); return; --- 2913,2922 ---- determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). */ if (POINTER_TYPE_P (type)) { ! if (range_is_nonnull (&vr0)) ! set_value_range_to_nonnull (vr, type); ! else if (range_is_null (&vr0)) ! set_value_range_to_null (vr, type); else set_value_range_to_varying (vr); return; *************** simplify_conversion_using_ranges (gimple *** 7288,7297 **** TYPE_UNSIGNED (TREE_TYPE (middleop))); middlemax = double_int_ext (innermax, TYPE_PRECISION (TREE_TYPE (middleop)), TYPE_UNSIGNED (TREE_TYPE (middleop))); ! /* If the middle values do not represent a proper range fail. */ ! if (double_int_cmp (middlemin, middlemax, ! TYPE_UNSIGNED (TREE_TYPE (middleop))) > 0) return false; if (!double_int_equal_p (double_int_ext (middlemin, TYPE_PRECISION (finaltype), TYPE_UNSIGNED (finaltype)), --- 7283,7299 ---- TYPE_UNSIGNED (TREE_TYPE (middleop))); middlemax = double_int_ext (innermax, TYPE_PRECISION (TREE_TYPE (middleop)), TYPE_UNSIGNED (TREE_TYPE (middleop))); ! /* If the middle values are not equal to the original values fail. ! But only if the inner cast truncates (thus we ignore differences ! in extension to handle the case going from a range to an anti-range ! and back). */ ! if ((TYPE_PRECISION (TREE_TYPE (innerop)) ! > TYPE_PRECISION (TREE_TYPE (middleop))) ! && (!double_int_equal_p (innermin, middlemin) ! || !double_int_equal_p (innermax, middlemax))) return false; + /* Require that the final conversion applied to both the original + and the intermediate range produces the same result. */ if (!double_int_equal_p (double_int_ext (middlemin, TYPE_PRECISION (finaltype), TYPE_UNSIGNED (finaltype)), Index: gcc/testsuite/gcc.dg/torture/pr50729.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr50729.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr50729.c (revision 0) *************** *** 0 **** --- 1,20 ---- + /* { dg-do run } */ + /* { dg-require-effective-target int32plus } */ + + extern void abort (void); + unsigned short __attribute__((noinline)) + foo (int i) + { + if (i >= 0 + && i <= 0x400000) + return (unsigned short)(signed char)i; + return i; + } + int main() + { + int i; + for (i = 0; i < 0xffff; ++i) + if (foo(i) != (unsigned short)(signed char) i) + abort (); + return 0; + }