aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoern Rennecke <joern.rennecke@embecosm.com>2011-12-01 14:25:24 +0000
committerJoern Rennecke <amylaar@gcc.gnu.org>2011-12-01 14:25:24 +0000
commit6ebbd277eb93778fbb0a7750216ef3d22c27c71c (patch)
tree9c045f2198b517ada893ae1f831c1eaf793c2d2b
parentd7fb38e9ac62b51cf64ac901c8424c8cffc17907 (diff)
downloadgcc-6ebbd277eb93778fbb0a7750216ef3d22c27c71c.zip
gcc-6ebbd277eb93778fbb0a7750216ef3d22c27c71c.tar.gz
gcc-6ebbd277eb93778fbb0a7750216ef3d22c27c71c.tar.bz2
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
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/tree-vrp.c60
2 files changed, 46 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index addee39..1020e90 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 5cbc25f..494cdd3 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -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);