This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Handle all conversions possible in VRP


This patch cleans up the range propagation through (integral) conversions
and makes it handle all cases that can be handled (all cases that would
not fall back to effectively varying).

Bootstrapped and tested on x86_64-unknown-linux-gnu, I'll apply this
after I fixed the fallout from the last VRP patch.

Thanks,
Richard.

2008-04-02  Richard Guenther  <rguenther@suse.de>

	* tree-vrp.c (extract_range_from_unary_expr): Handle all
	conversions.  Simplify code.

	* gcc.dg/tree-ssa/vrp43.c: New testcase.
	* gcc.dg/tree-ssa/vrp44.c: Likewise.
	* gcc.dg/tree-ssa/vrp45.c: Likewise.

Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c.orig	2008-04-02 11:51:06.000000000 +0200
--- gcc/tree-vrp.c	2008-04-02 13:06:49.000000000 +0200
*************** extract_range_from_unary_expr (value_ran
*** 2340,2410 ****
      }
  
    /* Handle unary expressions on integer ranges.  */
!   if (code == NOP_EXPR || code == CONVERT_EXPR)
      {
        tree inner_type = TREE_TYPE (op0);
        tree outer_type = type;
  
!       /* If VR0 represents a simple range, then try to convert
! 	 the min and max values for the range to the same type
! 	 as OUTER_TYPE.  If the results compare equal to VR0's
! 	 min and max values and the new min is still less than
! 	 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
! 	   && !overflow_infinity_range_p (&vr0))
! 	  || (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 original 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)
! 	      && (!is_overflow_infinity (new_min)
! 		  || !is_overflow_infinity (new_max))
! 	      && (cmp = compare_values (new_min, new_max)) <= 0
! 	      && cmp >= -1)
! 	    {
! 	      set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
! 	      return;
! 	    }
! 	}
! 
!       /* When converting types of different sizes, set the result to
! 	 VARYING.  Things like sign extensions and precision loss may
! 	 change the range.  For instance, if x_3 is of type 'long long
! 	 int' and 'y_5 = (unsigned short) x_3', if x_3 is ~[0, 0], it
! 	 is impossible to know at compile time whether y_5 will be
! 	 ~[0, 0].  */
!       if (TYPE_SIZE (inner_type) != TYPE_SIZE (outer_type)
! 	  || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
! 	{
! 	  set_value_range_to_varying (vr);
  	  return;
  	}
      }
  
    /* Conversion of a VR_VARYING value to a wider type can result
--- 2340,2402 ----
      }
  
    /* Handle unary expressions on integer ranges.  */
!   if ((code == NOP_EXPR
!        || code == CONVERT_EXPR)
!       && INTEGRAL_TYPE_P (type)
!       && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
      {
        tree inner_type = TREE_TYPE (op0);
        tree outer_type = type;
  
!       /* Always use base-types here.  This is important for the
! 	 correct signedness.  */
!       if (TREE_TYPE (inner_type))
! 	inner_type = TREE_TYPE (inner_type);
!       if (TREE_TYPE (outer_type))
! 	outer_type = TREE_TYPE (outer_type);
! 
!       /* If VR0 is varying and we increase the type precision, assume
! 	 a full range for the following transformation.  */
!       if (vr0.type == VR_VARYING
! 	  && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
! 	{
! 	  vr0.type = VR_RANGE;
! 	  vr0.min = TYPE_MIN_VALUE (inner_type);
! 	  vr0.max = TYPE_MAX_VALUE (inner_type);
! 	}
! 
!       /* If VR0 is a constant range or anti-range and the conversion is
! 	 not truncating we can convert the min and max values and
! 	 canonicalize the resulting range.  Otherwise we can do the
! 	 conversion if the size of the range is less than what the
! 	 precision of the target type can represent and the range is
! 	 not an anti-range.  */
        if ((vr0.type == VR_RANGE
! 	   || vr0.type == VR_ANTI_RANGE)
! 	  && TREE_CODE (vr0.min) == INTEGER_CST
! 	  && TREE_CODE (vr0.max) == INTEGER_CST
! 	  && !is_overflow_infinity (vr0.min)
! 	  && !is_overflow_infinity (vr0.max)
! 	  && (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type)
! 	      || (vr0.type == VR_RANGE
! 		  && integer_zerop (int_const_binop (RSHIFT_EXPR,
! 		       int_const_binop (MINUS_EXPR, vr0.max, vr0.min, 0),
! 		         size_int (TYPE_PRECISION (outer_type)), 0)))))
! 	{
! 	  tree new_min, new_max;
! 	  new_min = force_fit_type_double (outer_type,
! 					   TREE_INT_CST_LOW (vr0.min),
! 					   TREE_INT_CST_HIGH (vr0.min), 0, 0);
! 	  new_max = force_fit_type_double (outer_type,
! 					   TREE_INT_CST_LOW (vr0.max),
! 					   TREE_INT_CST_HIGH (vr0.max), 0, 0);
! 	  set_and_canonicalize_value_range (vr, vr0.type,
! 					    new_min, new_max, NULL);
  	  return;
  	}
+ 
+       set_value_range_to_varying (vr);
+       return;
      }
  
    /* Conversion of a VR_VARYING value to a wider type can result
Index: gcc/testsuite/gcc.dg/tree-ssa/vrp43.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/vrp43.c	2008-04-02 11:53:59.000000000 +0200
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do run } */
+ /* { dg-options "-O2" } */
+ 
+ int __attribute__((noinline))
+ foo(int i)
+ {
+   if (i != 0)
+     {
+       char c = (char)i;
+       return c != 0;
+     }
+   return 0;
+ }
+ 
+ extern void abort (void);
+ 
+ int main()
+ {
+   if (foo(0xff00))
+     abort ();
+   return 0;
+ }
Index: gcc/testsuite/gcc.dg/tree-ssa/vrp44.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/vrp44.c	2008-04-02 11:53:59.000000000 +0200
***************
*** 0 ****
--- 1,30 ----
+ /* { dg-do link } */
+ /* { dg-options "-O2" } */
+ 
+ extern void link_error (void);
+ 
+ void test1(int i)
+ {
+   if (i >= -5 && i <= 8)
+     {
+       unsigned int j = i + 1;
+       if (j == -5)
+ 	link_error ();
+       if (j == 10)
+ 	link_error ();
+     }
+ }
+ 
+ void test2(unsigned int i)
+ {
+   if (i >= -5 || i <= 8)
+     {
+       int j = i;
+       if (j == -6)
+ 	link_error ();
+       if (j == 9)
+ 	link_error ();
+     }
+ }
+ 
+ int main() { return 0; }
Index: gcc/testsuite/gcc.dg/tree-ssa/vrp45.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/vrp45.c	2008-04-02 13:09:18.000000000 +0200
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do link } */
+ /* { dg-options "-O2" } */
+ 
+ extern void link_error (void);
+ 
+ void foo (int i)
+ {
+   if (i > -128 && i < 127)
+     {
+       unsigned char k = i;
+       if (k == 0x80)
+         link_error ();
+       if (k == 0x7f)
+         link_error ();
+     }
+ }
+ 
+ int main() { return 0; }
+ 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]