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
This commit is contained in:
Eric Botcazou 2006-03-09 16:11:00 +00:00 committed by Eric Botcazou
parent d56ee62bfe
commit f8fe05458d
2 changed files with 95 additions and 59 deletions

View File

@ -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

View File

@ -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