Subject: [patch] Fix PR 22493 From: ja2morri at csclub dot uwaterloo dot ca (James A dot Morrison) Date: Sun, 24 Jul 2005 03:16:14 -0400 Hi, This patch fixes how extract_range_from_unary_expr deals with NEGATE_EXPRs and ABS_EXPRs for VR_ANTI_RANGEs and flag_wrapv. First we can't simply copy a VR_ANTI_RANGE for NEGATE_EXPRs since we could have an anti-range that is ~[2, 2], so we can only copy the anti-range when it is ~[-c, c]. vrp-1.c shows this problem. Similarily we have to be careful with anti-ranges and ABS_EXPRs, vrp-2.s shows how VRP used to mess up. Also for ABS_EXPRs we only want to switch the order of the min and max values in the range if both values are negative. vrp-3.c shows this. We used to generate turn the range [-15, 12] into [12, 15] instead of [0, 15]. The testcase in pr22493-1.c deals with flag_wrapv for NEGATE_EXPRs. I have a testcase for ABS_EXPRs as well, but it currently fails in the RTL optimizers. All of the testcases go in gcc.c-torture/execute. This patch has been bootstrapped and regtested on ia64-linux with no new regressions. However, very few of the libstdc++ tests actually ran. This version of the patch also fixes all the Divide_1 failures for java on ia64. Ok for mainline? Thanks, Jim 2005-07-24 James A. Morrison * tree-vrp.c (extract_range_from_unary_expr): Deal with -fwrapv and VR_ANTI_RANGEs properly for NEGATE_EXPRs and ABS_EXPRs. --- gcc/gcc/tree-vrp.c 20 Jul 2005 20:26:00 -0000 2.42 +++ gcc/gcc/tree-vrp.c 23 Jul 2005 22:25:10 -0000 @@ -1237,6 +1237,7 @@ extract_range_from_unary_expr (value_ran { enum tree_code code = TREE_CODE (expr); tree min, max, op0; + enum value_range_type vr_type; int cmp; value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }; @@ -1265,8 +1266,10 @@ extract_range_from_unary_expr (value_ran else set_value_range_to_varying (&vr0); + vr_type = vr0.type; + /* If VR0 is UNDEFINED, so is the result. */ - if (vr0.type == VR_UNDEFINED) + if (vr_type == VR_UNDEFINED) { set_value_range_to_undefined (vr); return; @@ -1276,7 +1279,7 @@ extract_range_from_unary_expr (value_ran operand is neither a pointer nor an integral type, set the resulting range to VARYING. TODO, in some cases we may be able to derive anti-ranges (like non-zero values). */ - if (vr0.type == VR_VARYING + if (vr_type == VR_VARYING || (!INTEGRAL_TYPE_P (TREE_TYPE (op0)) && !POINTER_TYPE_P (TREE_TYPE (op0))) || symbolic_range_p (&vr0)) @@ -1312,7 +1315,7 @@ extract_range_from_unary_expr (value_ran 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) + if (vr_type == VR_RANGE) { tree new_min, new_max; @@ -1353,27 +1356,64 @@ extract_range_from_unary_expr (value_ran if (code == NEGATE_EXPR && !TYPE_UNSIGNED (TREE_TYPE (expr))) { - /* Negating an anti-range doesn't really do anything to it. The - new range will also not take on the same range of values - excluded by the original anti-range. */ + /* Negating an anti-range doesn't really do anything to it if the max + value is equal to the min value. Then the new range will also not + take on the same range of values excluded by the original + anti-range. */ if (vr0.type == VR_ANTI_RANGE) { - copy_value_range (vr, &vr0); + tree neg_min = fold_unary_to_constant (code, TREE_TYPE (expr), + vr0.min); + if (operand_equal_p (vr0.max, neg_min, 0)) + copy_value_range (vr, &vr0); + else + set_value_range_to_varying (vr); return; } - /* NEGATE_EXPR flips the range around. */ - min = (vr0.max == TYPE_MAX_VALUE (TREE_TYPE (expr))) - ? TYPE_MIN_VALUE (TREE_TYPE (expr)) - : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max); + if (flag_wrapv && vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))) + { + tree one = build_int_cst (TREE_TYPE (expr), 1); - max = (vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))) - ? TYPE_MAX_VALUE (TREE_TYPE (expr)) - : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min); + vr_type = VR_ANTI_RANGE; + max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max); + max = int_const_binop (MINUS_EXPR, max, one, 0); + min = int_const_binop (PLUS_EXPR, vr0.min, one, 0); + } + else + { + /* NEGATE_EXPR flips the range around. */ + min = (vr0.max == TYPE_MAX_VALUE (TREE_TYPE (expr))) + ? TYPE_MIN_VALUE (TREE_TYPE (expr)) + : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max); + + max = (vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))) + ? TYPE_MAX_VALUE (TREE_TYPE (expr)) + : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min); + } } else if (code == ABS_EXPR - && !TYPE_UNSIGNED (TREE_TYPE (expr))) + && !(TYPE_UNSIGNED (TREE_TYPE (expr)))) { + int comp; + /* Deal with VR_ANTI_RANGEs in the same way we do for NEGATE_EXPRs. */ + if (vr_type == VR_ANTI_RANGE) + { + tree neg_min = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (expr), + vr0.min); + if (operand_equal_p (vr0.max, neg_min, 0)) + copy_value_range (vr, &vr0); + else + set_value_range_to_varying (vr); + return; + } + + if (flag_wrapv && vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))) + { + set_value_range_to_varying (vr); + return; + } + /* ABS_EXPR may flip the range around, if the original range included negative values. */ min = (vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))) @@ -1382,12 +1422,22 @@ extract_range_from_unary_expr (value_ran max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max); - /* If the range was reversed, swap MIN and MAX. */ - if (compare_values (min, max) == 1) + comp = compare_values (min, max); + if (tree_int_cst_sgn (vr0.min) == tree_int_cst_sgn (vr0.max)) + { + /* If the range was reversed, swap MIN and MAX. */ + if (comp == 1) + { + tree t = min; + min = max; + max = t; + } + } + else { - tree t = min; - min = max; - max = t; + if (comp == 1) + max = min; + min = build_int_cst (TREE_TYPE (expr), 0); } } else @@ -1406,7 +1456,7 @@ extract_range_from_unary_expr (value_ran set_value_range_to_varying (vr); } else - set_value_range (vr, vr0.type, min, max, NULL); + set_value_range (vr, vr_type, min, max, NULL); }