This fixes PR53922 - we failed to handle "don't know" return from value_inside_range inside range_includes_zero_p. Fixed and re-structured the code to not have the strage range/anti-range issue.
Bootstrapped and tested on x86_64-unknown-linxu-gnu, applied. Richard. 2012-07-13 Richard Guenther <rguent...@suse.de> PR tree-optimization/53922 * tree-vrp.c (value_inside_range): Change prototype to take min/max instead of value-range. (range_includes_zero_p): Likewise. Return the result from value_inside_range. (extract_range_from_binary_expr_1): Adjust to handle dont-know return value from range_includes_zero_p. (extract_range_from_unary_expr_1): Likewise. (compare_range_with_value): Likewise. (vrp_meet_1): Likewise. * gcc.dg/torture/pr53922.c: New testcase. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c (revision 189451) --- gcc/tree-vrp.c (working copy) *************** compare_values (tree val1, tree val2) *** 1339,1379 **** } ! /* Return 1 if VAL is inside value range VR (VR->MIN <= VAL <= VR->MAX), ! 0 if VAL is not inside VR, -2 if we cannot tell either way. - FIXME, the current semantics of this functions are a bit quirky - when taken in the context of VRP. In here we do not care - about VR's type. If VR is the anti-range ~[3, 5] the call - value_inside_range (4, VR) will return 1. - - This is counter-intuitive in a strict sense, but the callers - currently expect this. They are calling the function - merely to determine whether VR->MIN <= VAL <= VR->MAX. The - callers are applying the VR_RANGE/VR_ANTI_RANGE semantics - themselves. - - This also applies to value_ranges_intersect_p and - range_includes_zero_p. The semantics of VR_RANGE and - VR_ANTI_RANGE should be encoded here, but that also means - adapting the users of these functions to the new semantics. - Benchmark compile/20001226-1.c compilation time after changing this function. */ static inline int ! value_inside_range (tree val, value_range_t * vr) { int cmp1, cmp2; ! cmp1 = operand_less_p (val, vr->min); if (cmp1 == -2) return -2; if (cmp1 == 1) return 0; ! cmp2 = operand_less_p (vr->max, val); if (cmp2 == -2) return -2; --- 1339,1363 ---- } ! /* Return 1 if VAL is inside value range MIN <= VAL <= MAX, ! 0 if VAL is not inside [MIN, MAX], -2 if we cannot tell either way. Benchmark compile/20001226-1.c compilation time after changing this function. */ static inline int ! value_inside_range (tree val, tree min, tree max) { int cmp1, cmp2; ! cmp1 = operand_less_p (val, min); if (cmp1 == -2) return -2; if (cmp1 == 1) return 0; ! cmp2 = operand_less_p (max, val); if (cmp2 == -2) return -2; *************** value_ranges_intersect_p (value_range_t *** 1402,1424 **** } ! /* Return true if VR includes the value zero, false otherwise. FIXME, ! currently this will return false for an anti-range like ~[-4, 3]. ! This will be wrong when the semantics of value_inside_range are ! modified (currently the users of this function expect these ! semantics). */ ! static inline bool ! range_includes_zero_p (value_range_t *vr) { ! tree zero; ! ! gcc_assert (vr->type != VR_UNDEFINED ! && vr->type != VR_VARYING ! && !symbolic_range_p (vr)); ! ! zero = build_int_cst (TREE_TYPE (vr->min), 0); ! return (value_inside_range (zero, vr) == 1); } /* Return true if *VR is know to only contain nonnegative values. */ --- 1386,1399 ---- } ! /* Return 1 if [MIN, MAX] includes the value zero, 0 if it does not ! include the value zero, -2 if we cannot tell. */ ! static inline int ! range_includes_zero_p (tree min, tree max) { ! tree zero = build_int_cst (TREE_TYPE (min), 0); ! return value_inside_range (zero, min, max); } /* Return true if *VR is know to only contain nonnegative values. */ *************** extract_range_from_binary_expr_1 (value_ *** 2641,2647 **** gives [min / 4, max / 4] range. */ if (vr1.type == VR_RANGE && !symbolic_range_p (&vr1) ! && !range_includes_zero_p (&vr1)) { vr0.type = type = VR_RANGE; vr0.min = vrp_val_min (expr_type); --- 2616,2622 ---- gives [min / 4, max / 4] range. */ if (vr1.type == VR_RANGE && !symbolic_range_p (&vr1) ! && range_includes_zero_p (vr1.min, vr1.max) == 0) { vr0.type = type = VR_RANGE; vr0.min = vrp_val_min (expr_type); *************** extract_range_from_binary_expr_1 (value_ *** 2658,2665 **** not eliminate a division by zero. */ if (cfun->can_throw_non_call_exceptions && (vr1.type != VR_RANGE ! || symbolic_range_p (&vr1) ! || range_includes_zero_p (&vr1))) { set_value_range_to_varying (vr); return; --- 2633,2639 ---- not eliminate a division by zero. */ if (cfun->can_throw_non_call_exceptions && (vr1.type != VR_RANGE ! || range_includes_zero_p (vr1.min, vr1.max) != 0)) { set_value_range_to_varying (vr); return; *************** extract_range_from_binary_expr_1 (value_ *** 2670,2677 **** include 0. */ if (vr0.type == VR_RANGE && (vr1.type != VR_RANGE ! || symbolic_range_p (&vr1) ! || range_includes_zero_p (&vr1))) { tree zero = build_int_cst (TREE_TYPE (vr0.min), 0); int cmp; --- 2644,2650 ---- include 0. */ if (vr0.type == VR_RANGE && (vr1.type != VR_RANGE ! || range_includes_zero_p (vr1.min, vr1.max) != 0)) { tree zero = build_int_cst (TREE_TYPE (vr0.min), 0); int cmp; *************** extract_range_from_binary_expr_1 (value_ *** 2723,2730 **** else if (code == TRUNC_MOD_EXPR) { if (vr1.type != VR_RANGE ! || symbolic_range_p (&vr1) ! || range_includes_zero_p (&vr1) || vrp_val_is_min (vr1.min)) { set_value_range_to_varying (vr); --- 2696,2702 ---- else if (code == TRUNC_MOD_EXPR) { if (vr1.type != VR_RANGE ! || range_includes_zero_p (vr1.min, vr1.max) != 0 || vrp_val_is_min (vr1.min)) { set_value_range_to_varying (vr); *************** extract_range_from_unary_expr_1 (value_r *** 3159,3165 **** ~[-INF, min(MIN, MAX)]. */ if (vr0.type == VR_ANTI_RANGE) { ! if (range_includes_zero_p (&vr0)) { /* Take the lower of the two values. */ if (cmp != 1) --- 3131,3137 ---- ~[-INF, min(MIN, MAX)]. */ if (vr0.type == VR_ANTI_RANGE) { ! if (range_includes_zero_p (vr0.min, vr0.max) == 1) { /* Take the lower of the two values. */ if (cmp != 1) *************** extract_range_from_unary_expr_1 (value_r *** 3210,3216 **** /* If the range contains zero then we know that the minimum value in the range will be zero. */ ! else if (range_includes_zero_p (&vr0)) { if (cmp == 1) max = min; --- 3182,3188 ---- /* If the range contains zero then we know that the minimum value in the range will be zero. */ ! else if (range_includes_zero_p (vr0.min, vr0.max) == 1) { if (cmp == 1) max = min; *************** compare_range_with_value (enum tree_code *** 3812,3818 **** return NULL_TREE; /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2. */ ! if (value_inside_range (val, vr) == 1) return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node; return NULL_TREE; --- 3784,3790 ---- return NULL_TREE; /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2. */ ! if (value_inside_range (val, vr->min, vr->max) == 1) return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node; return NULL_TREE; *************** vrp_meet_1 (value_range_t *vr0, value_ra *** 7548,7559 **** anti-range. FIXME, all this nonsense about distinguishing anti-ranges from ranges is necessary because of the odd semantics of range_includes_zero_p and friends. */ ! if (!symbolic_range_p (&saved) ! && ((saved.type == VR_RANGE && !range_includes_zero_p (&saved)) ! || (saved.type == VR_ANTI_RANGE && range_includes_zero_p (&saved))) ! && !symbolic_range_p (vr1) ! && ((vr1->type == VR_RANGE && !range_includes_zero_p (vr1)) ! || (vr1->type == VR_ANTI_RANGE && range_includes_zero_p (vr1)))) { set_value_range_to_nonnull (vr0, TREE_TYPE (saved.min)); --- 7520,7533 ---- anti-range. FIXME, all this nonsense about distinguishing anti-ranges from ranges is necessary because of the odd semantics of range_includes_zero_p and friends. */ ! if (((saved.type == VR_RANGE ! && range_includes_zero_p (saved.min, saved.max) == 0) ! || (saved.type == VR_ANTI_RANGE ! && range_includes_zero_p (saved.min, saved.max) == 1)) ! && ((vr1->type == VR_RANGE ! && range_includes_zero_p (vr1->min, vr1->max) == 0) ! || (vr1->type == VR_ANTI_RANGE ! && range_includes_zero_p (vr1->min, vr1->max) == 1))) { set_value_range_to_nonnull (vr0, TREE_TYPE (saved.min)); Index: gcc/testsuite/gcc.dg/torture/pr53922.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr53922.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr53922.c (working copy) *************** *** 0 **** --- 1,22 ---- + /* { dg-do run } */ + /* { dg-require-weak "" } */ + + int x(int a) + { + return a; + } + int y(int a) __attribute__ ((weak)); + int g = 0; + int main() + { + int (*scan_func)(int); + if (g) + scan_func = x; + else + scan_func = y; + + if (scan_func) + g = scan_func(10); + + return 0; + }