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;
+ }

Reply via email to