From: Richard Kenner Date: Mon, 14 Mar 1994 11:18:52 +0000 (-0500) Subject: (fold, associate): If -ffast-math, associate FP mults. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e9aaa5a55313f9248eeba1e93907d18a5614d2ee;p=gcc.git (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 --- diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 57d866bbb7a..8195163d8b1 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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: