summaryrefslogtreecommitdiffstats
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1994-03-14 11:18:52 +0000
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1994-03-14 11:18:52 +0000
commit0f586b9b834cc4e3724604891729a89c3cc00e47 (patch)
tree3e385c029e541846ca154d3500d1b98cb73b0c57 /gcc/fold-const.c
parent5e394bead3862531be946ffdd479363f643f2707 (diff)
downloadppe42-gcc-0f586b9b834cc4e3724604891729a89c3cc00e47.tar.gz
ppe42-gcc-0f586b9b834cc4e3724604891729a89c3cc00e47.zip
(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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@6780 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c81
1 files changed, 70 insertions, 11 deletions
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:
OpenPOWER on IntegriCloud