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

2008-04-03  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.

From-SVN: r133866
This commit is contained in:
Richard Guenther 2008-04-03 09:33:27 +00:00 committed by Richard Biener
parent 2a7428c0c5
commit b47ee38692
6 changed files with 129 additions and 55 deletions

View File

@ -1,3 +1,8 @@
2008-04-03 Richard Guenther <rguenther@suse.de>
* tree-vrp.c (extract_range_from_unary_expr): Handle all
conversions. Simplify code.
2008-04-03 Kaz Kojima <kkojima@gcc.gnu.org> 2008-04-03 Kaz Kojima <kkojima@gcc.gnu.org>
* config/sh/sh.c (sh_output_mi_thunk): Free cfun. * config/sh/sh.c (sh_output_mi_thunk): Free cfun.

View File

@ -1,3 +1,9 @@
2008-04-03 Richard Guenther <rguenther@suse.de>
* 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 <jakub@redhat.com> 2008-04-03 Jakub Jelinek <jakub@redhat.com>
PR c++/35741 PR c++/35741

View File

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

View File

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

View File

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

View File

@ -2350,71 +2350,63 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
} }
/* Handle unary expressions on integer ranges. */ /* 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 inner_type = TREE_TYPE (op0);
tree outer_type = type; tree outer_type = type;
/* If VR0 represents a simple range, then try to convert /* Always use base-types here. This is important for the
the min and max values for the range to the same type correct signedness. */
as OUTER_TYPE. If the results compare equal to VR0's if (TREE_TYPE (inner_type))
min and max values and the new min is still less than inner_type = TREE_TYPE (inner_type);
or equal to the new max, then we can safely use the newly if (TREE_TYPE (outer_type))
computed range for EXPR. This allows us to compute outer_type = TREE_TYPE (outer_type);
accurate ranges through many casts. */
if ((vr0.type == VR_RANGE /* If VR0 is varying and we increase the type precision, assume
&& !overflow_infinity_range_p (&vr0)) a full range for the following transformation. */
|| (vr0.type == VR_VARYING if (vr0.type == VR_VARYING
&& TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type))) && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
{ {
tree new_min, new_max, orig_min, orig_max; vr0.type = VR_RANGE;
vr0.min = TYPE_MIN_VALUE (inner_type);
/* Convert the input operand min/max to OUTER_TYPE. If vr0.max = TYPE_MAX_VALUE (inner_type);
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 /* If VR0 is a constant range or anti-range and the conversion is
VARYING. Things like sign extensions and precision loss may not truncating we can convert the min and max values and
change the range. For instance, if x_3 is of type 'long long canonicalize the resulting range. Otherwise we can do the
int' and 'y_5 = (unsigned short) x_3', if x_3 is ~[0, 0], it conversion if the size of the range is less than what the
is impossible to know at compile time whether y_5 will be precision of the target type can represent and the range is
~[0, 0]. */ not an anti-range. */
if (TYPE_SIZE (inner_type) != TYPE_SIZE (outer_type) if ((vr0.type == VR_RANGE
|| TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type)) || 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; return;
} }
set_value_range_to_varying (vr);
return;
} }
/* Conversion of a VR_VARYING value to a wider type can result /* Conversion of a VR_VARYING value to a wider type can result