tree-vrp.c (simplify_conversion_using_ranges): Manually translate the source value...
authorRichard Guenther <rguenther@suse.de>
Mon, 11 Jul 2011 14:27:04 +0000 (14:27 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 11 Jul 2011 14:27:04 +0000 (14:27 +0000)
2011-07-11  Richard Guenther  <rguenther@suse.de>

* tree-vrp.c (simplify_conversion_using_ranges): Manually
translate the source value-range through the conversion chain.

From-SVN: r176154

gcc/ChangeLog
gcc/tree-vrp.c

index e10d69d23d9cfc39c042a8735a8a9847e5418706..72611b797f2e9e404465d3ae334aca0e2b04db0f 100644 (file)
@@ -1,3 +1,8 @@
+2011-07-11  Richard Guenther  <rguenther@suse.de>
+
+       * tree-vrp.c (simplify_conversion_using_ranges): Manually
+       translate the source value-range through the conversion chain.
+
 2011-07-11  Richard Sandiford  <richard.sandiford@linaro.org>
 
        * expr.c (expand_expr_real_1): Use expand_insn for movmisalign.
index 68998b379919ea2aed8bcdc14050858fda843087..c975a5d0466d971e9b642e04893b09ab249106a1 100644 (file)
@@ -7347,30 +7347,55 @@ simplify_switch_using_ranges (gimple stmt)
 static bool
 simplify_conversion_using_ranges (gimple stmt)
 {
-  tree rhs1 = gimple_assign_rhs1 (stmt);
-  gimple def_stmt = SSA_NAME_DEF_STMT (rhs1);
-  value_range_t *final, *inner;
-
-  /* Obtain final and inner value-ranges for a conversion
-     sequence (final-type)(intermediate-type)inner-type.  */
-  final = get_value_range (gimple_assign_lhs (stmt));
-  if (final->type != VR_RANGE)
-    return false;
+  tree innerop, middleop, finaltype;
+  gimple def_stmt;
+  value_range_t *innervr;
+  double_int innermin, innermax, middlemin, middlemax;
+
+  finaltype = TREE_TYPE (gimple_assign_lhs (stmt));
+  middleop = gimple_assign_rhs1 (stmt);
+  def_stmt = SSA_NAME_DEF_STMT (middleop);
   if (!is_gimple_assign (def_stmt)
       || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
     return false;
-  rhs1 = gimple_assign_rhs1 (def_stmt);
-  if (TREE_CODE (rhs1) != SSA_NAME)
+  innerop = gimple_assign_rhs1 (def_stmt);
+  if (TREE_CODE (innerop) != SSA_NAME)
     return false;
-  inner = get_value_range (rhs1);
-  if (inner->type != VR_RANGE)
+
+  /* Get the value-range of the inner operand.  */
+  innervr = get_value_range (innerop);
+  if (innervr->type != VR_RANGE
+      || TREE_CODE (innervr->min) != INTEGER_CST
+      || TREE_CODE (innervr->max) != INTEGER_CST)
     return false;
-  /* If the value-range is preserved by the conversion sequence strip
-     the intermediate conversion.  */
-  if (!tree_int_cst_equal (final->min, inner->min)
-      || !tree_int_cst_equal (final->max, inner->max))
+
+  /* Simulate the conversion chain to check if the result is equal if
+     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 do not represent a proper range fail.  */
+  if (double_int_cmp (middlemin, middlemax,
+                     TYPE_UNSIGNED (TREE_TYPE (middleop))) > 0)
     return false;
-  gimple_assign_set_rhs1 (stmt, rhs1);
+  if (!double_int_equal_p (double_int_ext (middlemin,
+                                          TYPE_PRECISION (finaltype),
+                                          TYPE_UNSIGNED (finaltype)),
+                          double_int_ext (innermin,
+                                          TYPE_PRECISION (finaltype),
+                                          TYPE_UNSIGNED (finaltype)))
+      || !double_int_equal_p (double_int_ext (middlemax,
+                                             TYPE_PRECISION (finaltype),
+                                             TYPE_UNSIGNED (finaltype)),
+                             double_int_ext (innermax,
+                                             TYPE_PRECISION (finaltype),
+                                             TYPE_UNSIGNED (finaltype))))
+    return false;
+
+  gimple_assign_set_rhs1 (stmt, innerop);
   update_stmt (stmt);
   return true;
 }