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>
* 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>
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. */
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