This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Handle all conversions possible in VRP
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 2 Apr 2008 22:58:12 +0200 (CEST)
- Subject: [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; }
+