On Tue, 2006-03-21 at 10:14 +0100, Duncan Sands wrote:

> Hi Jeff, on the subject of seeing through typecasts, I was playing around
> with VRP and noticed that the following "if" statement is not eliminated:
> 
> int u (unsigned char c) {
>         int i = c;
> 
>         if (i < 0 || i > 255)
>                 return -1; /* never taken */
>         else
>                 return 0;
> }
> 
> Is it supposed to be?
Fixed thusly.  Bootstrapped and regression tested on i686-pc-linux-gnu.


        * tree-vrp.c (extract_range_from_unary_expr): Derive ranges for
        type conversions of a VR_VARYING source to a wider type.

        * gcc.dg/tree-ssa/vrp28.c: New test.

Index: tree-vrp.c
===================================================================
*** tree-vrp.c  (revision 112250)
--- tree-vrp.c  (working copy)
*************** extract_range_from_unary_expr (value_ran
*** 1641,1654 ****
        return;
      }
  
!   /* Refuse to operate on varying and symbolic ranges.  Also, if the
!      operand is neither a pointer nor an integral type, set the
!      resulting range to VARYING.  TODO, in some cases we may be able
!      to derive anti-ranges (like nonzero values).  */
!   if (vr0.type == VR_VARYING
!       || (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
!         && !POINTER_TYPE_P (TREE_TYPE (op0)))
!       || symbolic_range_p (&vr0))
      {
        set_value_range_to_varying (vr);
        return;
--- 1641,1652 ----
        return;
      }
  
!   /* Refuse to operate on symbolic ranges, or if neither operand is
!      a pointer or integral type.  */
!   if ((!INTEGRAL_TYPE_P (TREE_TYPE (op0))
!        && !POINTER_TYPE_P (TREE_TYPE (op0)))
!       || (vr0.type != VR_VARYING
!         && symbolic_range_p (&vr0)))
      {
        set_value_range_to_varying (vr);
        return;
*************** extract_range_from_unary_expr (value_ran
*** 1681,1700 ****
         or equal to the new max, then we can safely use the newly
         computed range for EXPR.  This allows us to compute
         accurate ranges through many casts.  */
!       if (vr0.type == VR_RANGE)
!       {
!         tree new_min, new_max;
  
!         /* Convert VR0's min/max to OUTER_TYPE.  */
!         new_min = fold_convert (outer_type, vr0.min);
!         new_max = fold_convert (outer_type, vr0.max);
  
          /* Verify the new min/max values are gimple values and
!            that they compare equal to VR0's min/max values.  */
          if (is_gimple_val (new_min)
              && is_gimple_val (new_max)
!             && tree_int_cst_equal (new_min, vr0.min)
!             && tree_int_cst_equal (new_max, vr0.max)
              && compare_values (new_min, new_max) <= 0
              && compare_values (new_min, new_max) >= -1)
            {
--- 1679,1714 ----
         or equal to the new max, then we can safely use the newly
         computed range for EXPR.  This allows us to compute
         accurate ranges through many casts.  */
!       if (vr0.type == VR_RANGE
!         || (vr0.type == VR_VARYING
!             && TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type)))
!       {
!         tree new_min, new_max, orig_min, orig_max;
! 
!         /* Convert the input operand min/max to OUTER_TYPE.   If
!            the input has no range information, then use the min/max
!            for the input's type.  */
!         if (vr0.type == VR_RANGE)
!           {
!             orig_min = vr0.min;
!             orig_max = vr0.max;
!           }
!         else
!           {
!             orig_min = TYPE_MIN_VALUE (inner_type);
!             orig_max = TYPE_MAX_VALUE (inner_type);
!           }
  
!         new_min = fold_convert (outer_type, orig_min);
!         new_max = fold_convert (outer_type, orig_max);
  
          /* Verify the new min/max values are gimple values and
!            that they compare equal to the orignal input's
!            min/max values.  */
          if (is_gimple_val (new_min)
              && is_gimple_val (new_max)
!             && tree_int_cst_equal (new_min, orig_min)
!             && tree_int_cst_equal (new_max, orig_max)
              && compare_values (new_min, new_max) <= 0
              && compare_values (new_min, new_max) >= -1)
            {
*************** extract_range_from_unary_expr (value_ran
*** 1717,1722 ****
--- 1731,1746 ----
        }
      }
  
+   /* Conversion of a VR_VARYING value to a wider type can result
+      in a usable range.  So wait until after we've handled conversions
+      before dropping the result to VR_VARYING if we had a source
+      operand that is VR_VARYING.  */
+   if (vr0.type == VR_VARYING)
+     {
+       set_value_range_to_varying (vr);
+       return;
+     }
+ 
    /* Apply the operation to each end of the range and see what we end
       up with.  */
    if (code == NEGATE_EXPR
Index: testsuite/gcc.dg/tree-ssa/vrp28.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/vrp28.c   (revision 0)
--- testsuite/gcc.dg/tree-ssa/vrp28.c   (revision 0)
***************
*** 0 ****
--- 1,32 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-vrp1" } */
+ 
+ int f(_Bool a)
+ {
+   int t = a;
+   if (t != 2)
+    return 0;
+   return 1;
+ }
+ 
+ int f1(unsigned char a)
+ {
+   int t = a;
+   if (t != 256)
+    return 0;
+   return 1;
+ }
+ 
+ int f3 (unsigned char c)
+ {
+   int i = c;
+   if (i < 0 || i > 255)
+     return -1;
+   else
+     return 0;
+ }
+ 
+ /* { dg-final { scan-tree-dump-times "if " 0 "vrp1" } } * /
+ /* { dg-final { cleanup-tree-dump "vrp1" } } */
+ 
+ 

Reply via email to