(fold, associate): If -ffast-math, associate FP mults.

(fold, case RDIV_EXPR): Split case; ignore division by 1.
If -ffast-math, convert to multply by reciprocal.
(fold, case *_DIV_EXPR): Simplify A/C1/C2.

From-SVN: r6780
This commit is contained in:
Richard Kenner 1994-03-14 06:18:52 -05:00
parent d0cb4c6591
commit e9aaa5a553

View File

@ -3666,9 +3666,13 @@ 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. */
if (FLOAT_TYPE_P (type))
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.
It says that the arg that was split was really CON minus VAR.
The rest of the code applies to all associative operations. */
@ -3958,17 +3962,80 @@ fold (expr)
}
goto binary;
case RDIV_EXPR:
/* In most cases, do nothing with a divide by zero. */
#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
#ifndef REAL_INFINITY
if (TREE_CODE (arg1) == REAL_CST && real_zerop (arg1))
return t;
#endif
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
/* In IEEE floating point, x/1 is not equivalent to x for snans.
However, ANSI says we can drop signals, so we can do this anyway. */
if (real_onep (arg1))
return non_lvalue (convert (type, arg0));
/* If ARG1 is a constant, we can convert this to a multiply by the
reciprocal. This does not have the same rounding properties,
so only do this if -ffast-math. We can actually always safely
do it if ARG1 is a power of two, but it's hard to tell if it is
or not in a portable manner. */
if (TREE_CODE (arg1) == REAL_CST && flag_fast_math
&& 0 != (tem = const_binop (code, build_real (type, dconst1),
arg1, 0)))
return fold (build (MULT_EXPR, type, arg0, tem));
goto binary;
case TRUNC_DIV_EXPR:
case ROUND_DIV_EXPR:
case FLOOR_DIV_EXPR:
case CEIL_DIV_EXPR:
case EXACT_DIV_EXPR:
case RDIV_EXPR:
if (integer_onep (arg1))
return non_lvalue (convert (type, arg0));
if (integer_zerop (arg1))
return t;
/* If we have ((a / C1) / C2) where both division are the same type, tr
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)
{
tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 1), arg1, 0);
/* If it overflows, the result is +/- 1 or zero, depending on
the signs of the two constants and the division operation. */
if (TREE_OVERFLOW (tem))
{
switch (code)
{
case EXACT_DIV_EXPR:
case TRUNC_DIV_EXPR:
tem = integer_zero_node;
break;
case FLOOR_DIV_EXPR:
/* -1 if signs disagree, else 0. */
tem = (((tree_int_cst_sgn (TREE_OPERAND (arg0, 1)) < 0)
!= (tree_int_cst_sgn (arg1) < 0))
? build_int_2 (-1, -1) : integer_zero_node);
break;
case CEIL_DIV_EXPR:
/* 1 if signs agree, else 0. */
tem = (((tree_int_cst_sgn (TREE_OPERAND (arg0, 1)) < 0)
== (tree_int_cst_sgn (arg1) < 0))
? integer_one_node : integer_zero_node);
break;
}
return omit_one_operand (type, tem, TREE_OPERAND (arg0, 0));
}
else
/* If no overflow, divide by C1*C2. */
return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
}
/* 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
@ -4044,14 +4111,6 @@ fold (expr)
}
}
#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
#ifndef REAL_INFINITY
if (TREE_CODE (arg1) == REAL_CST
&& real_zerop (arg1))
return t;
#endif
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
goto binary;
case CEIL_MOD_EXPR: