Commit 1baa375f by Richard Kenner Committed by Richard Kenner

fold-const.c (negate_expr, [...]): New.

	* fold-const.c (negate_expr, associate_trees, extract_muldiv): New.
	(split_tree): Completely rework to make more general.
	(make_range, fold): Call negate_expr.
	(fold, case NEGATE_EXPR): Simplify -(a-b) is -ffast-math.
	(fold, associate): Call new split_tree and associate_trees.
	(fold, case MULT_EXPR, case *_{DIV,MOD}_EXPR): Call extract_muldiv.

From-SVN: r30673
parent a8b64d6c
Sat Nov 27 08:38:26 1999 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* fold-const.c (negate_expr, associate_trees, extract_muldiv): New.
(split_tree): Completely rework to make more general.
(make_range, fold): Call negate_expr.
(fold, case NEGATE_EXPR): Simplify -(a-b) is -ffast-math.
(fold, associate): Call new split_tree and associate_trees.
(fold, case MULT_EXPR, case *_{DIV,MOD}_EXPR): Call extract_muldiv.
1999-11-26 Bernd Schmidt <bernds@cygnus.co.uk> 1999-11-26 Bernd Schmidt <bernds@cygnus.co.uk>
* loop.c (try_copy_prop): Avoid GNU C extension. * loop.c (try_copy_prop): Avoid GNU C extension.
......
...@@ -61,8 +61,10 @@ int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT, ...@@ -61,8 +61,10 @@ int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT *, HOST_WIDE_INT, HOST_WIDE_INT *,
HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *,
HOST_WIDE_INT *)); HOST_WIDE_INT *));
static int split_tree PROTO((tree, enum tree_code, tree *, static tree negate_expr PROTO((tree));
tree *, int *)); static tree split_tree PROTO((tree, enum tree_code, tree *, tree *,
int));
static tree associate_trees PROTO((tree, tree, enum tree_code, tree));
static tree int_const_binop PROTO((enum tree_code, tree, tree, int, int)); static tree int_const_binop PROTO((enum tree_code, tree, tree, int, int));
static tree const_binop PROTO((enum tree_code, tree, tree, int)); static tree const_binop PROTO((enum tree_code, tree, tree, int));
static tree fold_convert PROTO((tree, tree)); static tree fold_convert PROTO((tree, tree));
...@@ -93,6 +95,7 @@ static tree fold_range_test PROTO((tree)); ...@@ -93,6 +95,7 @@ static tree fold_range_test PROTO((tree));
static tree unextend PROTO((tree, int, int, tree)); static tree unextend PROTO((tree, int, int, tree));
static tree fold_truthop PROTO((enum tree_code, tree, tree, tree)); static tree fold_truthop PROTO((enum tree_code, tree, tree, tree));
static tree optimize_minmax_comparison PROTO((tree)); static tree optimize_minmax_comparison PROTO((tree));
static tree extract_muldiv PROTO((tree, tree, enum tree_code, tree));
static tree strip_compound_expr PROTO((tree, tree)); static tree strip_compound_expr PROTO((tree, tree));
static int multiple_of_p PROTO((tree, tree, tree)); static int multiple_of_p PROTO((tree, tree, tree));
static tree constant_boolean_node PROTO((int, tree)); static tree constant_boolean_node PROTO((int, tree));
...@@ -1199,93 +1202,181 @@ real_hex_to_f (s, mode) ...@@ -1199,93 +1202,181 @@ real_hex_to_f (s, mode)
#endif /* no REAL_ARITHMETIC */ #endif /* no REAL_ARITHMETIC */
/* Split a tree IN into a constant and a variable part /* Given T, an expression, return the negation of T. Allow for T to be
that could be combined with CODE to make IN. null, in which case return null. */
CODE must be a commutative arithmetic operation.
Store the constant part into *CONP and the variable in &VARP.
Return 1 if this was done; zero means the tree IN did not decompose
this way.
If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. static tree
Therefore, we must tell the caller whether the variable part negate_expr (t)
was subtracted. We do this by storing 1 or -1 into *VARSIGNP. tree t;
The value stored is the coefficient for the variable term. {
The constant term we return should always be added; tree type;
we negate it if necessary. */ tree tem;
static int if (t == 0)
split_tree (in, code, varp, conp, varsignp) return 0;
type = TREE_TYPE (t);
STRIP_SIGN_NOPS (t);
switch (TREE_CODE (t))
{
case INTEGER_CST:
case REAL_CST:
if (! TREE_UNSIGNED (type)
&& 0 != (tem = fold (build1 (NEGATE_EXPR, type, t)))
&& ! TREE_OVERFLOW (tem))
return tem;
break;
case NEGATE_EXPR:
return convert (type, TREE_OPERAND (t, 0));
case MINUS_EXPR:
/* - (A - B) -> B - A */
if (! FLOAT_TYPE_P (type) || flag_fast_math)
return convert (type,
fold (build (MINUS_EXPR, TREE_TYPE (t),
TREE_OPERAND (t, 1),
TREE_OPERAND (t, 0))));
break;
default:
break;
}
return convert (type, build1 (NEGATE_EXPR, TREE_TYPE (t), t));
}
/* Split a tree IN into a constant, literal and variable parts that could be
combined with CODE to make IN. "constant" means an expression with
TREE_CONSTANT but that isn't an actual constant. CODE must be a
commutative arithmetic operation. Store the constant part into *CONP,
the literal in &LITP and return the variable part. If a part isn't
present, set it to null. If the tree does not decompose in this way,
return the entire tree as the variable part and the other parts as null.
If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. In that
case, we negate an operand that was subtracted. If NEGATE_P is true, we
are negating all of IN.
If IN is itself a literal or constant, return it as appropriate.
Note that we do not guarantee that any of the three values will be the
same type as IN, but they will have the same signedness and mode. */
static tree
split_tree (in, code, conp, litp, negate_p)
tree in; tree in;
enum tree_code code; enum tree_code code;
tree *varp, *conp; tree *conp, *litp;
int *varsignp; int negate_p;
{ {
register tree outtype = TREE_TYPE (in); tree orig_in = in;
*varp = 0; tree type = TREE_TYPE (in);
tree var = 0;
*conp = 0; *conp = 0;
*litp = 0;
/* Strip any conversions that don't change the machine mode. */ /* Strip any conversions that don't change the machine mode or signedness. */
while ((TREE_CODE (in) == NOP_EXPR STRIP_SIGN_NOPS (in);
|| TREE_CODE (in) == CONVERT_EXPR)
&& (TYPE_MODE (TREE_TYPE (in)) if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST)
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (in, 0))))) *litp = in;
in = TREE_OPERAND (in, 0); else if (TREE_CONSTANT (in))
*conp = in;
if (TREE_CODE (in) == code else if (TREE_CODE (in) == code
|| (! FLOAT_TYPE_P (TREE_TYPE (in)) || (! FLOAT_TYPE_P (TREE_TYPE (in))
/* We can associate addition and subtraction together /* We can associate addition and subtraction together (even
(even though the C standard doesn't say so) though the C standard doesn't say so) for integers because
for integers because the value is not affected. the value is not affected. For reals, the value might be
For reals, the value might be affected, so we can't. */ affected, so we can't. */
&& ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR) && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
|| (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR)))) || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR))))
{ {
enum tree_code code = TREE_CODE (TREE_OPERAND (in, 0)); tree op0 = TREE_OPERAND (in, 0);
if (code == INTEGER_CST) tree op1 = TREE_OPERAND (in, 1);
{ int neg1_p = TREE_CODE (in) == MINUS_EXPR;
*conp = TREE_OPERAND (in, 0); int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0;
*varp = TREE_OPERAND (in, 1);
if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) /* First see if either of the operands is a literal, then a constant. */
&& TREE_TYPE (*varp) != outtype) if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)
*varp = convert (outtype, *varp); *litp = op0, op0 = 0;
*varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1; else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST)
return 1; *litp = op1, neg_litp_p = neg1_p, op1 = 0;
}
if (TREE_CONSTANT (TREE_OPERAND (in, 1))) if (op0 != 0 && TREE_CONSTANT (op0))
{ *conp = op0, op0 = 0;
*conp = TREE_OPERAND (in, 1); else if (op1 != 0 && TREE_CONSTANT (op1))
*varp = TREE_OPERAND (in, 0); *conp = op1, neg_conp_p = neg1_p, op1 = 0;
*varsignp = 1;
if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) /* If we haven't dealt with either operand, this is not a case we can
&& TREE_TYPE (*varp) != outtype) decompose. Otherwise, VAR is either of the ones remaining, if any. */
*varp = convert (outtype, *varp); if (op0 != 0 && op1 != 0)
if (TREE_CODE (in) == MINUS_EXPR) var = in;
{ else if (op0 != 0)
/* If operation is subtraction and constant is second, var = op0;
must negate it to get an additive constant.
And this cannot be done unless it is a manifest constant.
It could also be the address of a static variable.
We cannot negate that, so give up. */
if (TREE_CODE (*conp) == INTEGER_CST)
/* Subtracting from integer_zero_node loses for long long. */
*conp = fold (build1 (NEGATE_EXPR, TREE_TYPE (*conp), *conp));
else else
return 0; var = op1, neg_var_p = neg1_p;
}
return 1; /* Now do any needed negations. */
if (neg_litp_p) *litp = negate_expr (*litp);
if (neg_conp_p) *conp = negate_expr (*conp);
if (neg_var_p) var = negate_expr (var);
} }
if (TREE_CONSTANT (TREE_OPERAND (in, 0))) else
var = in;
if (negate_p)
{ {
*conp = TREE_OPERAND (in, 0); var = negate_expr (var);
*varp = TREE_OPERAND (in, 1); *conp = negate_expr (*conp);
if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) *litp = negate_expr (*litp);
&& TREE_TYPE (*varp) != outtype)
*varp = convert (outtype, *varp);
*varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1;
return 1;
} }
return var;
}
/* Re-associate trees split by the above function. T1 and T2 are either
expressions to associate or null. Return the new expression, if any. If
we build an operation, do it in TYPE and with CODE, except if CODE is a
MINUS_EXPR, in which case we use PLUS_EXPR since split_tree will already
have taken care of the negations. */
static tree
associate_trees (t1, t2, code, type)
tree t1, t2;
enum tree_code code;
tree type;
{
tree tem;
if (t1 == 0)
return t2;
else if (t2 == 0)
return t1;
if (code == MINUS_EXPR)
code = PLUS_EXPR;
/* If either input is CODE, a PLUS_EXPR, or a MINUS_EXPR, don't
try to fold this since we will have infinite recursion. But do
deal with any NEGATE_EXPRs. */
if (TREE_CODE (t1) == code || TREE_CODE (t2) == code
|| TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR)
{
if (TREE_CODE (t1) == NEGATE_EXPR)
return build (MINUS_EXPR, type, convert (type, t2),
convert (type, TREE_OPERAND (t1, 0)));
else if (TREE_CODE (t2) == NEGATE_EXPR)
return build (MINUS_EXPR, type, convert (type, t1),
convert (type, TREE_OPERAND (t2, 0)));
else
return build (code, type, convert (type, t1), convert (type, t2));
} }
return 0;
return fold (build (code, type, convert (type, t1), convert (type, t2)));
} }
/* Combine two integer constants ARG1 and ARG2 under operation CODE /* Combine two integer constants ARG1 and ARG2 under operation CODE
...@@ -3249,7 +3340,7 @@ make_range (exp, pin_p, plow, phigh) ...@@ -3249,7 +3340,7 @@ make_range (exp, pin_p, plow, phigh)
case BIT_NOT_EXPR: case BIT_NOT_EXPR:
/* ~ X -> -X - 1 */ /* ~ X -> -X - 1 */
exp = build (MINUS_EXPR, type, build1 (NEGATE_EXPR, type, arg0), exp = build (MINUS_EXPR, type, negate_expr (arg0),
convert (type, integer_one_node)); convert (type, integer_one_node));
continue; continue;
...@@ -4154,6 +4245,213 @@ optimize_minmax_comparison (t) ...@@ -4154,6 +4245,213 @@ optimize_minmax_comparison (t)
} }
} }
/* T is an integer expression that is being multiplied, divided, or taken a
modulus (CODE says which and what kind of divide or modulus) by a
constant C. See if we can eliminate that operation by folding it with
other operations already in T. WIDE_TYPE, if non-null, is a type that
should be used for the computation if wider than our type.
For example, if we are dividing (X * 8) + (Y + 16) by 4, we can return
(X * 2) + (Y + 4). We also canonicalize (X + 7) * 4 into X * 4 + 28
in the hope that either the machine has a multiply-accumulate insn
or that this is part of an addressing calculation.
If we return a non-null expression, it is an equivalent form of the
original computation, but need not be in the original type. */
static tree
extract_muldiv (t, c, code, wide_type)
tree t;
tree c;
enum tree_code code;
tree wide_type;
{
tree type = TREE_TYPE (t);
enum tree_code tcode = TREE_CODE (t);
tree ctype = (wide_type != 0 && (GET_MODE_SIZE (TYPE_MODE (wide_type))
> GET_MODE_SIZE (TYPE_MODE (type)))
? wide_type : type);
tree t1, t2;
int same_p = tcode == code;
int cancel_p
= (code == MULT_EXPR && tcode == EXACT_DIV_EXPR) || tcode == MULT_EXPR;
tree op0, op1;
/* Don't deal with constants of zero here; they confuse the code below. */
if (integer_zerop (c))
return 0;
if (TREE_CODE_CLASS (tcode) == '1')
op0 = TREE_OPERAND (t, 0);
if (TREE_CODE_CLASS (tcode) == '2')
op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1);
/* Note that we need not handle conditional operations here since fold
already handles those cases. So just do arithmetic here. */
switch (tcode)
{
case INTEGER_CST:
/* For a constant, we can always simplify if we are a multiply
or (for divide and modulus) if it is a multiple of our constant. */
if (code == MULT_EXPR
|| integer_zerop (const_binop (TRUNC_MOD_EXPR, t, c, 0)))
return const_binop (code, convert (ctype, t), convert (ctype, c), 0);
break;
case CONVERT_EXPR: case NON_LVALUE_EXPR: case NOP_EXPR:
/* Pass the constant down and see if we can make a simplification. If
we can, replace this expression with a conversion of that result to
our type. */
if (0 != (t1 = extract_muldiv (op0, convert (TREE_TYPE (op0), c), code,
code == MULT_EXPR ? ctype : NULL_TREE)))
return t1;
break;
case NEGATE_EXPR: case ABS_EXPR:
if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
return fold (build1 (tcode, ctype, convert (ctype, t1)));
break;
case MIN_EXPR: case MAX_EXPR:
/* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */
if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0
&& (t2 = extract_muldiv (op1, c, code, wide_type)) != 0)
return fold (build (tcode, ctype, convert (ctype, t1),
convert (ctype, t2)));
break;
case WITH_RECORD_EXPR:
if ((t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code, wide_type)) != 0)
return build (WITH_RECORD_EXPR, TREE_TYPE (t1), t1,
TREE_OPERAND (t, 1));
break;
case SAVE_EXPR:
/* If this has not been evaluated, we can see if we can do
something inside it and make a new one. */
if (SAVE_EXPR_RTL (t) == 0
&& 0 != (t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code,
wide_type)))
return save_expr (t1);
break;
case LSHIFT_EXPR: case RSHIFT_EXPR:
/* If the second operand is constant, this is a multiplication
or floor division, by a power of two, so we can treat it that
way unless the multiplier or divisor overflows. */
if (TREE_CODE (op1) == INTEGER_CST
&& 0 != (t1 = convert (ctype,
const_binop (LSHIFT_EXPR, size_one_node,
op1, 0)))
&& ! TREE_OVERFLOW (t1))
return extract_muldiv (build (tcode == LSHIFT_EXPR
? MULT_EXPR : FLOOR_DIV_EXPR,
ctype, convert (ctype, op0), t1),
c, code, wide_type);
break;
case PLUS_EXPR: case MINUS_EXPR:
/* See if we can eliminate the operation on both sides. If we can, we
can return a new PLUS or MINUS. If we can't, the only remaining
cases where we can do anything are if the second operand is a
constant. */
t1 = extract_muldiv (op0, c, code, wide_type);
t2 = extract_muldiv (op1, c, code, wide_type);
if (t1 != 0 && t2 != 0)
return fold (build (tcode, ctype, convert (ctype, t1),
convert (ctype, t2)));
else if (TREE_CODE (op1) != INTEGER_CST)
break;
/* If we were able to eliminate our operation from the first side,
apply our operation to the second side and reform the PLUS or
MINUS. */
if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR)
&& 0 != (t2 = const_binop (code, convert (ctype, op1),
convert (ctype, c), 0))
&& ! TREE_OVERFLOW (t2))
return fold (build (tcode, ctype, convert (ctype, t1), t2));
/* The last case is if we are a multiply. In that case, we can
apply the distributive law to commute the multiply and addition
if the multiplication of the constants doesn't overflow. */
if (code == MULT_EXPR
&& 0 != (t1 = const_binop (code, convert (ctype, op1),
convert (ctype, c), 0))
&& ! TREE_OVERFLOW (t1))
return fold (build (tcode, ctype, fold (build (code, ctype,
convert (ctype, op0),
convert (ctype, c))),
t1));
break;
case MULT_EXPR:
/* We have a special case here if we are doing something like
(C * 8) % 4 since we know that's zero. */
if ((code == TRUNC_MOD_EXPR || code == CEIL_MOD_EXPR
|| code == FLOOR_MOD_EXPR || code == ROUND_MOD_EXPR)
&& TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST
&& integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
return omit_one_operand (type, integer_zero_node, op0);
/* ... fall through ... */
case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR: case EXACT_DIV_EXPR:
/* If we can extract our operation from the LHS, do so and return a
new operation. Likewise for the RHS from a MULT_EXPR. Otherwise,
do something only if the second operand is a constant. */
if (same_p
&& (t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
return fold (build (tcode, ctype, convert (ctype, t1),
convert (ctype, op1)));
else if (tcode == MULT_EXPR && code == MULT_EXPR
&& (t1 = extract_muldiv (op1, c, code, wide_type)) != 0)
return fold (build (tcode, ctype, convert (ctype, op0),
convert (ctype, t1)));
else if (TREE_CODE (op1) != INTEGER_CST)
return 0;
/* If these are the same operation types, we can associate them
assuming no overflow. */
if (tcode == code
&& 0 != (t1 = const_binop (MULT_EXPR, convert (ctype, op1),
convert (ctype, c), 0))
&& ! TREE_OVERFLOW (t1))
return fold (build (tcode, ctype, convert (ctype, op0), t1));
/* If these operations "cancel" each other, we have the main
optimizations of this pass, which occur when either constant is a
multiple of the other, in which case we replace this with either an
operation or CODE or TCODE. */
if ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
|| (tcode == MULT_EXPR
&& code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
&& code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR))
{
if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
return fold (build (tcode, ctype, convert (ctype, op0),
convert (ctype,
const_binop (TRUNC_DIV_EXPR,
op1, c, 0))));
else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0)))
return fold (build (code, ctype, convert (ctype, op0),
convert (ctype,
const_binop (TRUNC_DIV_EXPR,
c, op1, 0))));
}
break;
default:
break;
}
return 0;
}
/* If T contains a COMPOUND_EXPR which was inserted merely to evaluate /* If T contains a COMPOUND_EXPR which was inserted merely to evaluate
S, a SAVE_EXPR, return the expression actually being evaluated. Note S, a SAVE_EXPR, return the expression actually being evaluated. Note
that we may sometimes modify the tree. */ that we may sometimes modify the tree. */
...@@ -4772,7 +5070,8 @@ fold (expr) ...@@ -4772,7 +5070,8 @@ fold (expr)
return TREE_OPERAND (arg0, 0); return TREE_OPERAND (arg0, 0);
/* Convert - (a - b) to (b - a) for non-floating-point. */ /* Convert - (a - b) to (b - a) for non-floating-point. */
else if (TREE_CODE (arg0) == MINUS_EXPR && ! FLOAT_TYPE_P (type)) else if (TREE_CODE (arg0) == MINUS_EXPR
&& (! FLOAT_TYPE_P (type) || flag_fast_math))
return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1), return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1),
TREE_OPERAND (arg0, 0)); TREE_OPERAND (arg0, 0));
...@@ -4816,14 +5115,10 @@ fold (expr) ...@@ -4816,14 +5115,10 @@ fold (expr)
else if (TREE_CODE (arg0) == COMPLEX_EXPR) else if (TREE_CODE (arg0) == COMPLEX_EXPR)
return build (COMPLEX_EXPR, TREE_TYPE (arg0), return build (COMPLEX_EXPR, TREE_TYPE (arg0),
TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 0),
fold (build1 (NEGATE_EXPR, negate_expr (TREE_OPERAND (arg0, 1)));
TREE_TYPE (TREE_TYPE (arg0)),
TREE_OPERAND (arg0, 1))));
else if (TREE_CODE (arg0) == COMPLEX_CST) else if (TREE_CODE (arg0) == COMPLEX_CST)
return build_complex (type, TREE_OPERAND (arg0, 0), return build_complex (type, TREE_OPERAND (arg0, 0),
fold (build1 (NEGATE_EXPR, negate_expr (TREE_OPERAND (arg0, 1)));
TREE_TYPE (TREE_TYPE (arg0)),
TREE_OPERAND (arg0, 1))));
else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR) else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
return fold (build (TREE_CODE (arg0), type, return fold (build (TREE_CODE (arg0), type,
fold (build1 (CONJ_EXPR, type, fold (build1 (CONJ_EXPR, type,
...@@ -5047,109 +5342,41 @@ fold (expr) ...@@ -5047,109 +5342,41 @@ fold (expr)
} }
} }
associate:
/* In most languages, can't associate operations on floats
through parentheses. Rather than remember where the parentheses
were, we don't associate floats at all. It shouldn't matter much.
However, associating multiplications is only very slightly
inaccurate, so do that if -ffast-math is specified. */
if (FLOAT_TYPE_P (type)
&& ! (flag_fast_math && code == MULT_EXPR))
goto binary;
/* The varsign == -1 cases happen only for addition and subtraction. associate:
It says that the arg that was split was really CON minus VAR. /* In most languages, can't associate operations on floats through
The rest of the code applies to all associative operations. */ parentheses. Rather than remember where the parentheses were, we
if (!wins) don't associate floats at all. It shouldn't matter much. However,
{ associating multiplications is only very slightly inaccurate, so do
tree var, con; that if -ffast-math is specified. */
int varsign;
if (split_tree (arg0, code, &var, &con, &varsign))
{
if (varsign == -1)
{
/* EXPR is (CON-VAR) +- ARG1. */
/* If it is + and VAR==ARG1, return just CONST. */
if (code == PLUS_EXPR && operand_equal_p (var, arg1, 0))
return convert (TREE_TYPE (t), con);
/* If ARG0 is a constant, don't change things around;
instead keep all the constant computations together. */
if (TREE_CONSTANT (arg0))
return t;
/* Otherwise return (CON +- ARG1) - VAR. */ if (! wins
t = build (MINUS_EXPR, type, && (! FLOAT_TYPE_P (type)
fold (build (code, type, con, arg1)), var); || (flag_fast_math && code != MULT_EXPR)))
}
else
{ {
/* EXPR is (VAR+CON) +- ARG1. */ tree var0, con0, lit0, var1, con1, lit1;
/* If it is - and VAR==ARG1, return just CONST. */
if (code == MINUS_EXPR && operand_equal_p (var, arg1, 0))
return convert (TREE_TYPE (t), con);
/* If ARG0 is a constant, don't change things around;
instead keep all the constant computations together. */
if (TREE_CONSTANT (arg0))
return t;
/* Otherwise return VAR +- (ARG1 +- CON). */ /* Split both trees into variables, constants, and literals. Then
tem = fold (build (code, type, arg1, con)); associate each group together, the constants with literals,
t = build (code, type, var, tem); then the result with variables. This increases the chances of
literals being recombined later and of generating relocatable
expressions for the sum of a constant and literal. */
var0 = split_tree (arg0, code, &con0, &lit0, 0);
var1 = split_tree (arg1, code, &con1, &lit1, code == MINUS_EXPR);
if (integer_zerop (tem) /* Only do something if we found more than two objects. Otherwise,
&& (code == PLUS_EXPR || code == MINUS_EXPR)) nothing has changed and we risk infinite recursion. */
return convert (type, var); if (2 < ((var0 != 0) + (var1 != 0) + (con0 != 0) + (con1 != 0)
/* If we have x +/- (c - d) [c an explicit integer] + (lit0 != 0) + (lit1 != 0)))
change it to x -/+ (d - c) since if d is relocatable
then the latter can be a single immediate insn
and the former cannot. */
if (TREE_CODE (tem) == MINUS_EXPR
&& TREE_CODE (TREE_OPERAND (tem, 0)) == INTEGER_CST)
{ {
tree tem1 = TREE_OPERAND (tem, 1); var0 = associate_trees (var0, var1, code, type);
TREE_OPERAND (tem, 1) = TREE_OPERAND (tem, 0); con0 = associate_trees (con0, con1, code, type);
TREE_OPERAND (tem, 0) = tem1; lit0 = associate_trees (lit0, lit1, code, type);
TREE_SET_CODE (t, con0 = associate_trees (con0, lit0, code, type);
(code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR)); return convert (type, associate_trees (var0, con0, code, type));
}
}
return t;
} }
if (split_tree (arg1, code, &var, &con, &varsign))
{
if (TREE_CONSTANT (arg1))
return t;
if (varsign == -1)
TREE_SET_CODE (t,
(code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR));
/* EXPR is ARG0 +- (CON +- VAR). */
if (TREE_CODE (t) == MINUS_EXPR
&& operand_equal_p (var, arg0, 0))
{
/* If VAR and ARG0 cancel, return just CON or -CON. */
if (code == PLUS_EXPR)
return convert (TREE_TYPE (t), con);
return fold (build1 (NEGATE_EXPR, TREE_TYPE (t),
convert (TREE_TYPE (t), con)));
} }
t = build (TREE_CODE (t), type,
fold (build (code, TREE_TYPE (t), arg0, con)), var);
if (integer_zerop (TREE_OPERAND (t, 0))
&& TREE_CODE (t) == PLUS_EXPR)
return convert (TREE_TYPE (t), var);
return t;
}
}
binary: binary:
#if defined (REAL_IS_NOT_DOUBLE) && ! defined (REAL_ARITHMETIC) #if defined (REAL_IS_NOT_DOUBLE) && ! defined (REAL_ARITHMETIC)
if (TREE_CODE (arg1) == REAL_CST) if (TREE_CODE (arg1) == REAL_CST)
...@@ -5183,7 +5410,7 @@ fold (expr) ...@@ -5183,7 +5410,7 @@ fold (expr)
if (! FLOAT_TYPE_P (type)) if (! FLOAT_TYPE_P (type))
{ {
if (! wins && integer_zerop (arg0)) if (! wins && integer_zerop (arg0))
return build1 (NEGATE_EXPR, type, arg1); return negate_expr (arg1);
if (integer_zerop (arg1)) if (integer_zerop (arg1))
return non_lvalue (convert (type, arg0)); return non_lvalue (convert (type, arg0));
...@@ -5206,7 +5433,7 @@ fold (expr) ...@@ -5206,7 +5433,7 @@ fold (expr)
{ {
/* Except with IEEE floating point, 0-x equals -x. */ /* Except with IEEE floating point, 0-x equals -x. */
if (! wins && real_zerop (arg0)) if (! wins && real_zerop (arg0))
return build1 (NEGATE_EXPR, type, arg1); return negate_expr (arg1);
/* Except with IEEE floating point, x-0 equals x. */ /* Except with IEEE floating point, x-0 equals x. */
if (real_zerop (arg1)) if (real_zerop (arg1))
return non_lvalue (convert (type, arg0)); return non_lvalue (convert (type, arg0));
...@@ -5237,14 +5464,6 @@ fold (expr) ...@@ -5237,14 +5464,6 @@ fold (expr)
if (integer_onep (arg1)) if (integer_onep (arg1))
return non_lvalue (convert (type, arg0)); return non_lvalue (convert (type, arg0));
/* ((A / C) * C) is A if the division is an
EXACT_DIV_EXPR. Since C is normally a constant,
just check for one of the four possibilities. */
if (TREE_CODE (arg0) == EXACT_DIV_EXPR
&& operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
return TREE_OPERAND (arg0, 0);
/* (a * (1 << b)) is (a << b) */ /* (a * (1 << b)) is (a << b) */
if (TREE_CODE (arg1) == LSHIFT_EXPR if (TREE_CODE (arg1) == LSHIFT_EXPR
&& integer_onep (TREE_OPERAND (arg1, 0))) && integer_onep (TREE_OPERAND (arg1, 0)))
...@@ -5254,6 +5473,12 @@ fold (expr) ...@@ -5254,6 +5473,12 @@ fold (expr)
&& integer_onep (TREE_OPERAND (arg0, 0))) && integer_onep (TREE_OPERAND (arg0, 0)))
return fold (build (LSHIFT_EXPR, type, arg1, return fold (build (LSHIFT_EXPR, type, arg1,
TREE_OPERAND (arg0, 1))); TREE_OPERAND (arg0, 1)));
if (TREE_CODE (arg1) == INTEGER_CST
&& 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
code, NULL_TREE)))
return convert (type, tem);
} }
else else
{ {
...@@ -5455,129 +5680,10 @@ fold (expr) ...@@ -5455,129 +5680,10 @@ fold (expr)
&& multiple_of_p (type, arg0, arg1)) && multiple_of_p (type, arg0, arg1))
return fold (build (EXACT_DIV_EXPR, type, arg0, arg1)); return fold (build (EXACT_DIV_EXPR, type, arg0, arg1));
/* If we have ((a / C1) / C2) where both division are the same type, try
to simplify. First see if C1 * C2 overflows or not. */
if (TREE_CODE (arg0) == code && TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
tree new_divisor;
new_divisor = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 1), arg1, 0);
tem = const_binop (FLOOR_DIV_EXPR, new_divisor, arg1, 0);
if (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_LOW (tem)
&& TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_HIGH (tem))
{
/* If no overflow, divide by C1*C2. */
return fold (build (code, type, TREE_OPERAND (arg0, 0), new_divisor));
}
}
/* Look for ((a * C1) / C3) or (((a * C1) + C2) / C3),
where C1 % C3 == 0 or C3 % C1 == 0. We can simplify these
expressions, which often appear in the offsets or sizes of
objects with a varying size. Only deal with positive divisors
and multiplicands. If C2 is negative, we must have C2 % C3 == 0.
Look for NOPs and SAVE_EXPRs inside. */
if (TREE_CODE (arg1) == INTEGER_CST if (TREE_CODE (arg1) == INTEGER_CST
&& tree_int_cst_sgn (arg1) >= 0) && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
{ code, NULL_TREE)))
int have_save_expr = 0; return convert (type, tem);
tree c2 = integer_zero_node;
tree xarg0 = arg0;
if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
STRIP_NOPS (xarg0);
/* Look inside the dividend and simplify using EXACT_DIV_EXPR
if possible. */
if (TREE_CODE (xarg0) == MULT_EXPR
&& multiple_of_p (type, TREE_OPERAND (xarg0, 0), arg1))
{
tree t;
t = fold (build (MULT_EXPR, type,
fold (build (EXACT_DIV_EXPR, type,
TREE_OPERAND (xarg0, 0), arg1)),
TREE_OPERAND (xarg0, 1)));
if (have_save_expr)
t = save_expr (t);
return t;
}
if (TREE_CODE (xarg0) == MULT_EXPR
&& multiple_of_p (type, TREE_OPERAND (xarg0, 1), arg1))
{
tree t;
t = fold (build (MULT_EXPR, type,
fold (build (EXACT_DIV_EXPR, type,
TREE_OPERAND (xarg0, 1), arg1)),
TREE_OPERAND (xarg0, 0)));
if (have_save_expr)
t = save_expr (t);
return t;
}
if (TREE_CODE (xarg0) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST)
c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0);
else if (TREE_CODE (xarg0) == MINUS_EXPR
&& TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
/* If we are doing this computation unsigned, the negate
is incorrect. */
&& ! TREE_UNSIGNED (type))
{
c2 = fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (xarg0, 1)));
xarg0 = TREE_OPERAND (xarg0, 0);
}
if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
STRIP_NOPS (xarg0);
if (TREE_CODE (xarg0) == MULT_EXPR
&& TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
&& tree_int_cst_sgn (TREE_OPERAND (xarg0, 1)) >= 0
&& (integer_zerop (const_binop (TRUNC_MOD_EXPR,
TREE_OPERAND (xarg0, 1), arg1, 1))
|| integer_zerop (const_binop (TRUNC_MOD_EXPR, arg1,
TREE_OPERAND (xarg0, 1), 1)))
&& (tree_int_cst_sgn (c2) >= 0
|| integer_zerop (const_binop (TRUNC_MOD_EXPR, c2,
arg1, 1))))
{
tree outer_div = integer_one_node;
tree c1 = TREE_OPERAND (xarg0, 1);
tree c3 = arg1;
/* If C3 > C1, set them equal and do a divide by
C3/C1 at the end of the operation. */
if (tree_int_cst_lt (c1, c3))
outer_div = const_binop (code, c3, c1, 0), c3 = c1;
/* The result is A * (C1/C3) + (C2/C3). */
t = fold (build (PLUS_EXPR, type,
fold (build (MULT_EXPR, type,
TREE_OPERAND (xarg0, 0),
const_binop (code, c1, c3, 1))),
const_binop (code, c2, c3, 1)));
if (! integer_onep (outer_div))
t = fold (build (code, type, t, convert (type, outer_div)));
if (have_save_expr)
t = save_expr (t);
return t;
}
}
goto binary; goto binary;
...@@ -5590,39 +5696,10 @@ fold (expr) ...@@ -5590,39 +5696,10 @@ fold (expr)
if (integer_zerop (arg1)) if (integer_zerop (arg1))
return t; return t;
/* Look for ((a * C1) % C3) or (((a * C1) + C2) % C3),
where C1 % C3 == 0. Handle similarly to the division case,
but don't bother with SAVE_EXPRs. */
if (TREE_CODE (arg1) == INTEGER_CST if (TREE_CODE (arg1) == INTEGER_CST
&& ! integer_zerop (arg1)) && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
{ code, NULL_TREE)))
tree c2 = integer_zero_node; return convert (type, tem);
tree xarg0 = arg0;
if (TREE_CODE (xarg0) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST)
c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0);
else if (TREE_CODE (xarg0) == MINUS_EXPR
&& TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
&& ! TREE_UNSIGNED (type))
{
c2 = fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (xarg0, 1)));
xarg0 = TREE_OPERAND (xarg0, 0);
}
STRIP_NOPS (xarg0);
if (TREE_CODE (xarg0) == MULT_EXPR
&& TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
&& integer_zerop (const_binop (TRUNC_MOD_EXPR,
TREE_OPERAND (xarg0, 1),
arg1, 1))
&& tree_int_cst_sgn (c2) >= 0)
/* The result is (C2%C3). */
return omit_one_operand (type, const_binop (code, c2, arg1, 1),
TREE_OPERAND (xarg0, 0));
}
goto binary; goto binary;
...@@ -6046,8 +6123,7 @@ fold (expr) ...@@ -6046,8 +6123,7 @@ fold (expr)
else if ((code == EQ_EXPR || code == NE_EXPR) else if ((code == EQ_EXPR || code == NE_EXPR)
&& TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg0) == NEGATE_EXPR
&& TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST
&& 0 != (tem = fold (build1 (NEGATE_EXPR, TREE_TYPE (arg1), && 0 != (tem = negate_expr (arg1))
arg1)))
&& TREE_CODE (tem) == INTEGER_CST && TREE_CODE (tem) == INTEGER_CST
&& ! TREE_CONSTANT_OVERFLOW (tem)) && ! TREE_CONSTANT_OVERFLOW (tem))
return fold (build (code, type, TREE_OPERAND (arg0, 0), tem)); return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
...@@ -6086,17 +6162,14 @@ fold (expr) ...@@ -6086,17 +6162,14 @@ fold (expr)
and a comparison, and is probably faster. */ and a comparison, and is probably faster. */
else if (code == LE_EXPR && TREE_CODE (arg1) == INTEGER_CST else if (code == LE_EXPR && TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (arg0) == ABS_EXPR && TREE_CODE (arg0) == ABS_EXPR
&& ! TREE_SIDE_EFFECTS (arg0)) && ! TREE_SIDE_EFFECTS (arg0)
{ && (0 != (tem = negate_expr (arg1)))
tree inner = TREE_OPERAND (arg0, 0); && TREE_CODE (tem) == INTEGER_CST
tem = fold (build1 (NEGATE_EXPR, TREE_TYPE (arg1), arg1));
if (TREE_CODE (tem) == INTEGER_CST
&& ! TREE_CONSTANT_OVERFLOW (tem)) && ! TREE_CONSTANT_OVERFLOW (tem))
return fold (build (TRUTH_ANDIF_EXPR, type, return fold (build (TRUTH_ANDIF_EXPR, type,
build (GE_EXPR, type, inner, tem), build (GE_EXPR, type, TREE_OPERAND (arg0, 0), tem),
build (LE_EXPR, type, inner, arg1))); build (LE_EXPR, type,
} TREE_OPERAND (arg0, 0), arg1)));
/* If this is an EQ or NE comparison with zero and ARG0 is /* If this is an EQ or NE comparison with zero and ARG0 is
(1 << foo) & bar, convert it to (bar >> foo) & 1. Both require (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require
...@@ -6635,8 +6708,7 @@ fold (expr) ...@@ -6635,8 +6708,7 @@ fold (expr)
switch (comp_code) switch (comp_code)
{ {
case EQ_EXPR: case EQ_EXPR:
return pedantic_non_lvalue return pedantic_non_lvalue (negate_expr (arg1));
(fold (build1 (NEGATE_EXPR, type, arg1)));
case NE_EXPR: case NE_EXPR:
return pedantic_non_lvalue (convert (type, arg1)); return pedantic_non_lvalue (convert (type, arg1));
case GE_EXPR: case GE_EXPR:
...@@ -6651,11 +6723,10 @@ fold (expr) ...@@ -6651,11 +6723,10 @@ fold (expr)
if (TREE_UNSIGNED (TREE_TYPE (arg1))) if (TREE_UNSIGNED (TREE_TYPE (arg1)))
arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1); arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1);
return pedantic_non_lvalue return pedantic_non_lvalue
(fold (build1 (NEGATE_EXPR, type, (negate_expr (convert (type,
convert (type,
fold (build1 (ABS_EXPR, fold (build1 (ABS_EXPR,
TREE_TYPE (arg1), TREE_TYPE (arg1),
arg1)))))); arg1)))));
default: default:
abort (); abort ();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment