diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2006-03-09 16:11:00 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2006-03-09 16:11:00 +0000 |
commit | f8fe05458d2116e5dcd2aa3eac9dff868be27cfb (patch) | |
tree | 5bedf0f0da9dcfb87f673767d4565f885cf8cb74 | |
parent | d56ee62bfe7847ec4a100f3773827c2e3697879a (diff) | |
download | gcc-f8fe05458d2116e5dcd2aa3eac9dff868be27cfb.zip gcc-f8fe05458d2116e5dcd2aa3eac9dff868be27cfb.tar.gz gcc-f8fe05458d2116e5dcd2aa3eac9dff868be27cfb.tar.bz2 |
fold-const.c (build_range_check): Make sure to use a valid type to apply the "(c>=low) && (c<=high) into...
* fold-const.c (build_range_check): Make sure to use a valid type to
apply the "(c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low)"
transformation.
(range_predecessor): New static function.
(range_successor): Likewise.
(merge_ranges): Use them to compute predecessors and successors of
range bounds.
From-SVN: r111866
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/fold-const.c | 143 |
2 files changed, 95 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5539174..5a138e2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2006-03-09 Eric Botcazou <ebotcazou@adacore.com> + + * fold-const.c (build_range_check): Make sure to use a valid type to + apply the "(c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low)" + transformation. + + (range_predecessor): New static function. + (range_successor): Likewise. + (merge_ranges): Use them to compute predecessors and successors of + range bounds. + 2006-03-09 Roger Sayle <roger@eyesopen.com> PR middle-end/26561 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index be0c461..582b496 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -108,6 +108,8 @@ static int all_ones_mask_p (tree, int); static tree sign_bit_p (tree, tree); static int simple_operand_p (tree); static tree range_binop (enum tree_code, tree, tree, int, tree, int); +static tree range_predecessor (tree); +static tree range_successor (tree); static tree make_range (tree, int *, tree *, tree *); static tree build_range_check (tree, tree, int, tree, tree); static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree, @@ -3722,6 +3724,32 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p, return constant_boolean_node (result, type); } +/* Return the predecessor of VAL in its type, handling the infinite case. */ + +static tree +range_predecessor (tree val) +{ + tree type = TREE_TYPE (val); + + if (INTEGRAL_TYPE_P (type) && val == TYPE_MIN_VALUE (type)) + return 0; + else + return range_binop (MINUS_EXPR, NULL_TREE, val, 0, integer_one_node, 0); +} + +/* Return the successor of VAL in its type, handling the infinite case. */ + +static tree +range_successor (tree val) +{ + tree type = TREE_TYPE (val); + + if (INTEGRAL_TYPE_P (type) && val == TYPE_MAX_VALUE (type)) + return 0; + else + return range_binop (PLUS_EXPR, NULL_TREE, val, 0, integer_one_node, 0); +} + /* Given EXP, a logical expression, set the range it is testing into variables denoted by PIN_P, PLOW, and PHIGH. Return the expression actually being tested. *PLOW and *PHIGH will be made of the same type @@ -4089,60 +4117,59 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high) } } - value = const_binop (MINUS_EXPR, high, low, 0); - if (value != 0 && (!flag_wrapv || TREE_OVERFLOW (value)) - && ! TYPE_UNSIGNED (etype)) + /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low). + This requires wrap-around arithmetics for the type of the expression. */ + switch (TREE_CODE (etype)) + { + case INTEGER_TYPE: + /* There is no requirement that LOW be within the range of ETYPE + if the latter is a subtype. It must, however, be within the base + type of ETYPE. So be sure we do the subtraction in that type. */ + if (TREE_TYPE (etype)) + etype = TREE_TYPE (etype); + break; + + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype), + TYPE_UNSIGNED (etype)); + break; + + default: + break; + } + + /* If we don't have wrap-around arithmetics upfront, try to force it. */ + if (TREE_CODE (etype) == INTEGER_TYPE + && !TYPE_UNSIGNED (etype) && !flag_wrapv) { tree utype, minv, maxv; /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN for the type in question, as we rely on this here. */ - switch (TREE_CODE (etype)) - { - case INTEGER_TYPE: - case ENUMERAL_TYPE: - /* There is no requirement that LOW be within the range of ETYPE - if the latter is a subtype. It must, however, be within the base - type of ETYPE. So be sure we do the subtraction in that type. */ - if (TREE_TYPE (etype)) - etype = TREE_TYPE (etype); - utype = lang_hooks.types.unsigned_type (etype); - maxv = fold_convert (utype, TYPE_MAX_VALUE (etype)); - maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1, - integer_one_node, 1); - minv = fold_convert (utype, TYPE_MIN_VALUE (etype)); - if (integer_zerop (range_binop (NE_EXPR, integer_type_node, - minv, 1, maxv, 1))) - { - etype = utype; - high = fold_convert (etype, high); - low = fold_convert (etype, low); - exp = fold_convert (etype, exp); - value = const_binop (MINUS_EXPR, high, low, 0); - } - break; - default: - break; - } + utype = lang_hooks.types.unsigned_type (etype); + maxv = fold_convert (utype, TYPE_MAX_VALUE (etype)); + maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1, + integer_one_node, 1); + minv = fold_convert (utype, TYPE_MIN_VALUE (etype)); + + if (integer_zerop (range_binop (NE_EXPR, integer_type_node, + minv, 1, maxv, 1))) + etype = utype; + else + return 0; } - if (value != 0 && ! TREE_OVERFLOW (value)) - { - /* There is no requirement that LOW be within the range of ETYPE - if the latter is a subtype. It must, however, be within the base - type of ETYPE. So be sure we do the subtraction in that type. */ - if (INTEGRAL_TYPE_P (etype) && TREE_TYPE (etype)) - { - etype = TREE_TYPE (etype); - exp = fold_convert (etype, exp); - low = fold_convert (etype, low); - value = fold_convert (etype, value); - } + high = fold_convert (etype, high); + low = fold_convert (etype, low); + exp = fold_convert (etype, exp); - return build_range_check (type, - fold_build2 (MINUS_EXPR, etype, exp, low), - 1, build_int_cst (etype, 0), value); - } + value = const_binop (MINUS_EXPR, high, low, 0); + + if (value != 0 && !TREE_OVERFLOW (value)) + return build_range_check (type, + fold_build2 (MINUS_EXPR, etype, exp, low), + 1, build_int_cst (etype, 0), value); return 0; } @@ -4208,7 +4235,7 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, /* 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 + the end of the second range to the end of the first. 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. @@ -4219,15 +4246,15 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, in_p = 0, low = high = 0; else if (subset && lowequal) { - in_p = 1, high = high0; - low = range_binop (PLUS_EXPR, NULL_TREE, high1, 0, - integer_one_node, 0); + low = range_successor (high1); + high = high0; + in_p = (low != 0); } else if (! subset || highequal) { - in_p = 1, low = low0; - high = range_binop (MINUS_EXPR, NULL_TREE, low1, 0, - integer_one_node, 0); + low = low0; + high = range_predecessor (low1); + in_p = (high != 0); } else return 0; @@ -4245,9 +4272,9 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, in_p = 0, low = high = 0; else { - in_p = 1, high = high1; - low = range_binop (PLUS_EXPR, NULL_TREE, high0, 1, - integer_one_node, 0); + low = range_successor (high0); + high = high1; + in_p = (low != 0); } } @@ -4262,9 +4289,7 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, if (no_overlap) { if (integer_onep (range_binop (EQ_EXPR, integer_type_node, - range_binop (PLUS_EXPR, NULL_TREE, - high0, 1, - integer_one_node, 1), + range_successor (high0), 1, low1, 0))) in_p = 0, low = low0, high = high1; else |