fold-const.c (int_const_binop): Return NULL_TREE when an expression can't be evaluated at compile-time (instead...

* fold-const.c (int_const_binop): Return NULL_TREE when an expression
	can't be evaluated at compile-time (instead of calling abort).
	Return NULL_TREE for division (and modulus) by zero.
	(const_binop):  Return NULL_TREE for floating point operators that
	aren't handled by real_arithmetic.
	(fold_binary):  Eliminate "wins" variable, and "binary" label, by
	folding operators with constant operands early.  Assert that
	operands are non-NULL.

From-SVN: r109088
This commit is contained in:
Roger Sayle 2005-12-27 23:27:34 +00:00 committed by Roger Sayle
parent 5156c0c3a7
commit fd6c76f462
2 changed files with 89 additions and 92 deletions

View File

@ -1,3 +1,14 @@
2005-12-27 Roger Sayle <roger@eyesopen.com>
* fold-const.c (int_const_binop): Return NULL_TREE when an expression
can't be evaluated at compile-time (instead of calling abort).
Return NULL_TREE for division (and modulus) by zero.
(const_binop): Return NULL_TREE for floating point operators that
aren't handled by real_arithmetic.
(fold_binary): Eliminate "wins" variable, and "binary" label, by
folding operators with constant operands early. Assert that
operands are non-NULL.
2005-12-27 Kazu Hirata <kazu@codesourcery.com>
* tree-vrp.c (extract_range_from_binary_expr): Use

View File

@ -1345,7 +1345,8 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type)
}
/* Combine two integer constants ARG1 and ARG2 under operation CODE
to produce a new constant.
to produce a new constant. Return NULL_TREE if we don't know how
to evaluate CODE at compile-time.
If NOTRUNC is nonzero, do not truncate the result to fit the data type. */
@ -1434,6 +1435,8 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
/* ... fall through ... */
case ROUND_DIV_EXPR:
if (int2h == 0 && int2l == 0)
return NULL_TREE;
if (int2h == 0 && int2l == 1)
{
low = int1l, hi = int1h;
@ -1466,6 +1469,8 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
/* ... fall through ... */
case ROUND_MOD_EXPR:
if (int2h == 0 && int2l == 0)
return NULL_TREE;
overflow = div_and_round_double (code, uns,
int1l, int1h, int2l, int2h,
&garbagel, &garbageh, &low, &hi);
@ -1490,7 +1495,7 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
break;
default:
gcc_unreachable ();
return NULL_TREE;
}
t = build_int_cst_wide (TREE_TYPE (arg1), low, hi);
@ -1546,6 +1551,21 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
bool inexact;
tree t, type;
/* The following codes are handled by real_arithmetic. */
switch (code)
{
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
case RDIV_EXPR:
case MIN_EXPR:
case MAX_EXPR:
break;
default:
return NULL_TREE;
}
d1 = TREE_REAL_CST (arg1);
d2 = TREE_REAL_CST (arg2);
@ -1605,6 +1625,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
| TREE_CONSTANT_OVERFLOW (arg2);
return t;
}
if (TREE_CODE (arg1) == COMPLEX_CST)
{
tree type = TREE_TYPE (arg1);
@ -1680,11 +1701,11 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
break;
default:
gcc_unreachable ();
return NULL_TREE;
}
return t;
}
return 0;
return NULL_TREE;
}
/* Create a size type INT_CST node with NUMBER sign extended. KIND
@ -7171,80 +7192,57 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
tree arg0 = NULL_TREE, arg1 = NULL_TREE;
enum tree_code_class kind = TREE_CODE_CLASS (code);
/* WINS will be nonzero when the switch is done
if all operands are constant. */
int wins = 1;
gcc_assert (IS_EXPR_CODE_CLASS (kind)
&& TREE_CODE_LENGTH (code) == 2);
&& TREE_CODE_LENGTH (code) == 2
&& op0 != NULL_TREE
&& op1 != NULL_TREE);
arg0 = op0;
arg1 = op1;
if (arg0)
/* Strip any conversions that don't change the mode. This is
safe for every expression, except for a comparison expression
because its signedness is derived from its operands. So, in
the latter case, only strip conversions that don't change the
signedness.
Note that this is done as an internal manipulation within the
constant folder, in order to find the simplest representation
of the arguments so that their form can be studied. In any
cases, the appropriate type conversions should be put back in
the tree that will get out of the constant folder. */
if (kind == tcc_comparison)
{
tree subop;
/* Strip any conversions that don't change the mode. This is
safe for every expression, except for a comparison expression
because its signedness is derived from its operands. So, in
the latter case, only strip conversions that don't change the
signedness.
Note that this is done as an internal manipulation within the
constant folder, in order to find the simplest representation
of the arguments so that their form can be studied. In any
cases, the appropriate type conversions should be put back in
the tree that will get out of the constant folder. */
if (kind == tcc_comparison)
STRIP_SIGN_NOPS (arg0);
else
STRIP_NOPS (arg0);
if (TREE_CODE (arg0) == COMPLEX_CST)
subop = TREE_REALPART (arg0);
else
subop = arg0;
if (TREE_CODE (subop) != INTEGER_CST
&& TREE_CODE (subop) != REAL_CST)
/* Note that TREE_CONSTANT isn't enough:
static var addresses are constant but we can't
do arithmetic on them. */
wins = 0;
STRIP_SIGN_NOPS (arg0);
STRIP_SIGN_NOPS (arg1);
}
else
{
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
}
if (arg1)
/* Note that TREE_CONSTANT isn't enough: static var addresses are
constant but we can't do arithmetic on them. */
if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
|| (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
|| (TREE_CODE (arg0) == COMPLEX_CST && TREE_CODE (arg1) == COMPLEX_CST)
|| (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST))
{
tree subop;
/* Strip any conversions that don't change the mode. This is
safe for every expression, except for a comparison expression
because its signedness is derived from its operands. So, in
the latter case, only strip conversions that don't change the
signedness.
Note that this is done as an internal manipulation within the
constant folder, in order to find the simplest representation
of the arguments so that their form can be studied. In any
cases, the appropriate type conversions should be put back in
the tree that will get out of the constant folder. */
if (kind == tcc_comparison)
STRIP_SIGN_NOPS (arg1);
if (kind == tcc_binary)
tem = const_binop (code, arg0, arg1, 0);
else if (kind == tcc_comparison)
tem = fold_relational_const (code, type, arg0, arg1);
else
STRIP_NOPS (arg1);
tem = NULL_TREE;
if (TREE_CODE (arg1) == COMPLEX_CST)
subop = TREE_REALPART (arg1);
else
subop = arg1;
if (TREE_CODE (subop) != INTEGER_CST
&& TREE_CODE (subop) != REAL_CST)
/* Note that TREE_CONSTANT isn't enough:
static var addresses are constant but we can't
do arithmetic on them. */
wins = 0;
if (tem != NULL_TREE)
{
if (TREE_TYPE (tem) != type)
tem = fold_convert (type, tem);
return tem;
}
}
/* If this is a commutative operation, and ARG0 is a constant, move it
@ -7253,9 +7251,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& tree_swap_operands_p (arg0, arg1, true))
return fold_build2 (code, type, op1, op0);
/* Now WINS is set as described above,
ARG0 is the first operand of EXPR,
and ARG1 is the second operand (if it has more than one operand).
/* ARG0 is the first operand of EXPR, and ARG1 is the second operand.
First check for cases where an arithmetic operation is applied to a
compound, conditional, or comparison operation. Push the arithmetic
@ -7577,8 +7573,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
don't associate floats at all, unless the user has specified
-funsafe-math-optimizations. */
if (! wins
&& (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
{
tree var0, con0, lit0, minus_lit0;
tree var1, con1, lit1, minus_lit1;
@ -7652,18 +7647,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
}
}
binary:
if (wins)
t1 = const_binop (code, arg0, arg1, 0);
if (t1 != NULL_TREE)
{
/* The return value should always have
the same type as the original expression. */
if (TREE_TYPE (t1) != type)
t1 = fold_convert (type, t1);
return t1;
}
return NULL_TREE;
case MINUS_EXPR:
@ -7691,7 +7674,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
if (! FLOAT_TYPE_P (type))
{
if (! wins && integer_zerop (arg0))
if (integer_zerop (arg0))
return negate_expr (fold_convert (type, arg1));
if (integer_zerop (arg1))
return non_lvalue (fold_convert (type, arg0));
@ -7739,7 +7722,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
/* (ARG0 - ARG1) is the same as (-ARG1 + ARG0). So check whether
ARG0 is zero and X + ARG0 reduces to X, since that would mean
(-ARG1 + ARG0) reduces to -ARG1. */
else if (!wins && fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
return negate_expr (fold_convert (type, arg1));
/* Fold &x - &x. This can happen from &x.foo - &x.
@ -7753,7 +7736,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return fold_convert (type, integer_zero_node);
/* A - B -> A + (-B) if B is easily negatable. */
if (!wins && negate_expr_p (arg1)
if (negate_expr_p (arg1)
&& ((FLOAT_TYPE_P (type)
/* Avoid this transformation if B is a positive REAL_CST. */
&& (TREE_CODE (arg1) != REAL_CST
@ -8488,7 +8471,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return fold_build2 (MULT_EXPR, type, arg0, arg1);
}
}
goto binary;
return NULL_TREE;
case TRUNC_DIV_EXPR:
case ROUND_DIV_EXPR:
@ -8533,7 +8516,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
return fold_convert (type, tem);
goto binary;
return NULL_TREE;
case CEIL_MOD_EXPR:
case FLOOR_MOD_EXPR:
@ -8613,7 +8596,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
return fold_convert (type, tem);
goto binary;
return NULL_TREE;
case LROTATE_EXPR:
case RROTATE_EXPR:
@ -8727,7 +8710,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
== (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
return TREE_OPERAND (arg0, 0);
goto binary;
return NULL_TREE;
case MIN_EXPR:
if (operand_equal_p (arg0, arg1, 0))
@ -9998,7 +9981,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return pedantic_non_lvalue (tem);
case COMPLEX_EXPR:
if (wins)
if ((TREE_CODE (arg0) == REAL_CST
&& TREE_CODE (arg1) == REAL_CST)
|| (TREE_CODE (arg0) == INTEGER_CST
&& TREE_CODE (arg1) == INTEGER_CST))
return build_complex (type, arg0, arg1);
return NULL_TREE;