re PR tree-optimization/50802 (FAIL: gcc.c-torture/execute/arith-rand-ll.c execution at -O2 and -Os)

PR tree-optimization/50802
        * tree-vrp.c (simplify_conversion_using_ranges): Rewrite test
        considering what happens to ranges during sign changes and/or
        intermediate narrowing conversions.

From-SVN: r181880
This commit is contained in:
Joern Rennecke 2011-12-01 14:25:24 +00:00 committed by Joern Rennecke
parent d7fb38e9ac
commit 6ebbd277eb
2 changed files with 46 additions and 21 deletions

View File

@ -1,3 +1,10 @@
2011-12-01 Joern Rennecke <joern.rennecke@embecosm.com>
PR tree-optimization/50802
* tree-vrp.c (simplify_conversion_using_ranges): Rewrite test
considering what happens to ranges during sign changes and/or
intermediate narrowing conversions.
2011-11-30 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR middle-end/50283

View File

@ -7284,7 +7284,9 @@ simplify_conversion_using_ranges (gimple stmt)
tree innerop, middleop, finaltype;
gimple def_stmt;
value_range_t *innervr;
double_int innermin, innermax, middlemin, middlemax;
bool inner_unsigned_p, middle_unsigned_p, final_unsigned_p;
unsigned inner_prec, middle_prec, final_prec;
double_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
finaltype = TREE_TYPE (gimple_assign_lhs (stmt));
if (!INTEGRAL_TYPE_P (finaltype))
@ -7309,33 +7311,49 @@ simplify_conversion_using_ranges (gimple stmt)
the middle conversion is removed. */
innermin = tree_to_double_int (innervr->min);
innermax = tree_to_double_int (innervr->max);
middlemin = double_int_ext (innermin, TYPE_PRECISION (TREE_TYPE (middleop)),
TYPE_UNSIGNED (TREE_TYPE (middleop)));
middlemax = double_int_ext (innermax, TYPE_PRECISION (TREE_TYPE (middleop)),
TYPE_UNSIGNED (TREE_TYPE (middleop)));
/* If the middle values are not equal to the original values fail.
But only if the inner cast truncates (thus we ignore differences
in extension to handle the case going from a range to an anti-range
and back). */
if ((TYPE_PRECISION (TREE_TYPE (innerop))
> TYPE_PRECISION (TREE_TYPE (middleop)))
&& (!double_int_equal_p (innermin, middlemin)
|| !double_int_equal_p (innermax, middlemax)))
inner_prec = TYPE_PRECISION (TREE_TYPE (innerop));
middle_prec = TYPE_PRECISION (TREE_TYPE (middleop));
final_prec = TYPE_PRECISION (finaltype);
/* If the first conversion is not injective, the second must not
be widening. */
if (double_int_cmp (double_int_sub (innermax, innermin),
double_int_mask (middle_prec), true) > 0
&& middle_prec < final_prec)
return false;
/* We also want a medium value so that we can track the effect that
narrowing conversions with sign change have. */
inner_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (innerop));
if (inner_unsigned_p)
innermed = double_int_rshift (double_int_mask (inner_prec),
1, inner_prec, false);
else
innermed = double_int_zero;
if (double_int_cmp (innermin, innermed, inner_unsigned_p) >= 0
|| double_int_cmp (innermed, innermax, inner_unsigned_p) >= 0)
innermed = innermin;
middle_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (middleop));
middlemin = double_int_ext (innermin, middle_prec, middle_unsigned_p);
middlemed = double_int_ext (innermed, middle_prec, middle_unsigned_p);
middlemax = double_int_ext (innermax, middle_prec, middle_unsigned_p);
/* Require that the final conversion applied to both the original
and the intermediate range produces the same result. */
final_unsigned_p = TYPE_UNSIGNED (finaltype);
if (!double_int_equal_p (double_int_ext (middlemin,
TYPE_PRECISION (finaltype),
TYPE_UNSIGNED (finaltype)),
final_prec, final_unsigned_p),
double_int_ext (innermin,
TYPE_PRECISION (finaltype),
TYPE_UNSIGNED (finaltype)))
final_prec, final_unsigned_p))
|| !double_int_equal_p (double_int_ext (middlemed,
final_prec, final_unsigned_p),
double_int_ext (innermed,
final_prec, final_unsigned_p))
|| !double_int_equal_p (double_int_ext (middlemax,
TYPE_PRECISION (finaltype),
TYPE_UNSIGNED (finaltype)),
final_prec, final_unsigned_p),
double_int_ext (innermax,
TYPE_PRECISION (finaltype),
TYPE_UNSIGNED (finaltype))))
final_prec, final_unsigned_p)))
return false;
gimple_assign_set_rhs1 (stmt, innerop);