OSDN Git Service

(fold, associate): If -ffast-math, associate FP mults.
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Mar 1994 11:18:52 +0000 (11:18 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Mar 1994 11:18:52 +0000 (11:18 +0000)
(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

gcc/fold-const.c

index 57d866b..8195163 100644 (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: