From ce2157a1a98c1f01e18b0aaa4a50efd51fff8d5b Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Tue, 23 Sep 1997 12:35:51 -0600 Subject: [PATCH] fold-const.c (make_range): Correctly handle cases of converting from unsigned to signed type. * fold-const.c (make_range): Correctly handle cases of converting from unsigned to signed type. * fold-const.c (merge_ranges): Make sure that if one range is subset of another, it will always be the second range. Correct (+,-) case to account for this. Brought over from gcc2; fixes sparc bug. From-SVN: r15678 --- gcc/ChangeLog | 11 +++++ gcc/fold-const.c | 102 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 91 insertions(+), 22 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9eb883e9e53..6b7c8297735 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +Tue Sep 23 12:34:51 1997 Richard Kenner + + * fold-const.c (make_range): Correctly handle cases of converting + from unsigned to signed type. + +Tue Sep 23 12:34:51 1997 Bernd Schmidt + + * fold-const.c (merge_ranges): Make sure that if one range is subset + of another, it will always be the second range. Correct (+,-) case to + account for this. + Tue Sep 23 01:15:50 1997 David S. Miller * expmed.c (expand_divmod): If compute_mode is not the same as diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 10b13f33f7c..def96bfa627 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -2863,14 +2863,62 @@ make_range (exp, pin_p, plow, phigh) || (high != 0 && ! int_fits_type_p (high, type))) break; - if (low != 0) - low = convert (type, low); + n_low = low, n_high = high; - if (high != 0) - high = convert (type, high); + if (n_low != 0) + n_low = convert (type, n_low); + + if (n_high != 0) + n_high = convert (type, n_high); + + /* If we're converting from an unsigned to a signed type, + we will be doing the comparison as unsigned. The tests above + have already verified that LOW and HIGH are both positive. + + So we have to make sure that the original unsigned value will + be interpreted as positive. */ + if (TREE_UNSIGNED (type) && ! TREE_UNSIGNED (TREE_TYPE (exp))) + { + tree equiv_type = type_for_mode (TYPE_MODE (type), 1); + tree high_positive + = fold (build (RSHIFT_EXPR, type, + convert (type, + TYPE_MAX_VALUE (equiv_type)), + convert (type, integer_one_node))); + + /* If the low bound is specified, "and" the range with the + range for which the original unsigned value will be + positive. */ + if (low != 0) + { + if (! merge_ranges (&n_in_p, &n_low, &n_high, + 1, n_low, n_high, + 1, convert (type, integer_zero_node), + high_positive)) + break; + + in_p = (n_in_p == in_p); + } + else + { + /* Otherwise, "or" the range with the range of the input + that will be interpreted as negative. */ + if (! merge_ranges (&n_in_p, &n_low, &n_high, + 0, n_low, n_high, + 1, convert (type, integer_zero_node), + high_positive)) + break; + + in_p = (in_p != n_in_p); + } + } exp = arg0; + low = n_low, high = n_high; continue; + + default: + break; } break; @@ -2956,15 +3004,20 @@ merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, in1_p, low1, high1) tree tem; int in_p; tree low, high; + int lowequal = ((low0 == 0 && low1 == 0) + || integer_onep (range_binop (EQ_EXPR, integer_type_node, + low0, 0, low1, 0))); + int highequal = ((high0 == 0 && high1 == 0) + || integer_onep (range_binop (EQ_EXPR, integer_type_node, + high0, 1, high1, 1))); - /* Make range 0 be the range that starts first. Swap them if it isn't. */ + /* Make range 0 be the range that starts first, or ends last if they + start at the same value. Swap them if it isn't. */ if (integer_onep (range_binop (GT_EXPR, integer_type_node, low0, 0, low1, 0)) - || (((low0 == 0 && low1 == 0) - || integer_onep (range_binop (EQ_EXPR, integer_type_node, - low0, 0, low1, 0))) + || (lowequal && integer_onep (range_binop (GT_EXPR, integer_type_node, - high0, 1, high1, 1)))) + high1, 1, high0, 1)))) { temp = in0_p, in0_p = in1_p, in1_p = temp; tem = low0, low0 = low1, low1 = tem; @@ -2996,27 +3049,32 @@ merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, in1_p, low1, high1) else if (in0_p && ! in1_p) { - /* If they don't overlap, the result is the first range. If the - second range is a subset of the first, we can't describe this as - a single range unless both ranges end at the same place. If both - ranges start in the same place, then the result is false. - Otherwise, we go from the start of the first range to just before - the start of the second. */ + /* If they don't overlap, the result is the first range. If they are + equal, the result is false. If the second range is a subset of the + first, and the ranges begin at the same place, we go from just after + the end of the first range to the end of the second. If the second + range is not a subset of the first, or if it is a subset and both + ranges end at the same place, the range starts at the start of the + first range and ends just before the second range. + Otherwise, we can't describe this as a single range. */ if (no_overlap) in_p = 1, low = low0, high = high0; - else if (subset - && integer_zerop (range_binop (EQ_EXPR, integer_type_node, - high0, 1, high1, 0))) - return 0; - else if (integer_onep (range_binop (EQ_EXPR, integer_type_node, - low0, 0, low1, 0))) + else if (lowequal && highequal) in_p = 0, low = high = 0; - else + else if (subset && lowequal) + { + in_p = 1, high = high0; + low = range_binop (PLUS_EXPR, NULL_TREE, high1, 0, + integer_one_node, 0); + } + else if (! subset || highequal) { in_p = 1, low = low0; high = range_binop (MINUS_EXPR, NULL_TREE, low1, 0, integer_one_node, 0); } + else + return 0; } else if (! in0_p && in1_p)