summaryrefslogtreecommitdiff
path: root/gcc/tree-vrp.c
diff options
context:
space:
mode:
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2011-07-11 14:27:04 +0000
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2011-07-11 14:27:04 +0000
commitb3b0dcace63b2119501a4cb01066773b5eb5b35f (patch)
treebafcbf8cbeddfaf7f813f266159b82dd6a444b62 /gcc/tree-vrp.c
parent2b27de00bcdb20744d7407f02f9deef85150ca34 (diff)
downloadgcc-b3b0dcace63b2119501a4cb01066773b5eb5b35f.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@176154 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r--gcc/tree-vrp.c61
1 files changed, 43 insertions, 18 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 68998b37991..c975a5d0466 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -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;
}