From 0d27ac1e87ddc24c2059c4a379d2400471527ce5 Mon Sep 17 00:00:00 2001 From: rguenth Date: Thu, 3 Apr 2008 09:33:27 +0000 Subject: [PATCH] 2008-04-03 Richard Guenther * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@133866 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 5 ++ gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/gcc.dg/tree-ssa/vrp43.c | 22 ++++++++ gcc/testsuite/gcc.dg/tree-ssa/vrp44.c | 30 ++++++++++ gcc/testsuite/gcc.dg/tree-ssa/vrp45.c | 19 +++++++ gcc/tree-vrp.c | 102 ++++++++++++++++------------------ 6 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp43.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp44.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp45.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 764c6fc..321dfb0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2008-04-03 Richard Guenther + + * tree-vrp.c (extract_range_from_unary_expr): Handle all + conversions. Simplify code. + 2008-04-03 Kaz Kojima * config/sh/sh.c (sh_output_mi_thunk): Free cfun. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e291072..59bc95a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2008-04-03 Richard Guenther + + * gcc.dg/tree-ssa/vrp43.c: New testcase. + * gcc.dg/tree-ssa/vrp44.c: Likewise. + * gcc.dg/tree-ssa/vrp45.c: Likewise. + 2008-04-03 Jakub Jelinek PR c++/35741 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp43.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp43.c new file mode 100644 index 0000000..f475354 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp43.c @@ -0,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; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp44.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp44.c new file mode 100644 index 0000000..a2df852 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp44.c @@ -0,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; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp45.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp45.c new file mode 100644 index 0000000..7916d2d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp45.c @@ -0,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; } + diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 6563528..9741262 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -2350,71 +2350,63 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code, } /* Handle unary expressions on integer ranges. */ - if (code == NOP_EXPR || code == CONVERT_EXPR) + 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; - /* 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))) + /* 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)) { - 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; - } + vr0.type = VR_RANGE; + vr0.min = TYPE_MIN_VALUE (inner_type); + vr0.max = TYPE_MAX_VALUE (inner_type); } - /* 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)) + /* 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))))) { - set_value_range_to_varying (vr); + 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 -- 2.7.4