]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
fold-const.c (fold <PLUS_EXPR>): Transform x+x into x*2.0.
authorRoger Sayle <roger@eyesopen.com>
Mon, 4 Aug 2003 23:42:48 +0000 (23:42 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Mon, 4 Aug 2003 23:42:48 +0000 (23:42 +0000)
* fold-const.c (fold <PLUS_EXPR>): Transform x+x into x*2.0.
Optimize x*c+x and x+x*c into x*(c+1) and x*c1+x*c2 into x*(c1+c2)
for floating point expressions with -ffast-math.
(fold <MULT_EXPR>): Don't transform x*2.0 into x+x.
* expmed.c (expand_mult): Wrap long line.  Expand x*2.0 as x+x.

* gcc.dg/20030804-1.c: New test case.

From-SVN: r70158

gcc/ChangeLog
gcc/expmed.c
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/20030804-1.c [new file with mode: 0644]

index 60a391c45ec5088cb6885a9cbf4e777f567289c9..daf0bec3424e173396bbcf0d962b31839bcc515e 100644 (file)
@@ -1,3 +1,11 @@
+2003-08-04  Roger Sayle  <roger@eyesopen.com>
+
+       * fold-const.c (fold <PLUS_EXPR>): Transform x+x into x*2.0.
+       Optimize x*c+x and x+x*c into x*(c+1) and x*c1+x*c2 into x*(c1+c2)
+       for floating point expressions with -ffast-math.
+       (fold <MULT_EXPR>): Don't transform x*2.0 into x+x.
+       * expmed.c (expand_mult): Wrap long line.  Expand x*2.0 as x+x.
+
 2003-08-04  Roger Sayle  <roger@eyesopen.com>
 
        * c-common.c (flag_noniso_default_format_attributes): Delete.
index 68163e9ba2b0627533b8ed2a43265fff69e3a543..89ecd0c198255e2bcff851e9a0085686593670fc 100644 (file)
@@ -2300,7 +2300,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
    you should swap the two operands if OP0 would be constant.  */
 
 rtx
-expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, int unsignedp)
+expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+            int unsignedp)
 {
   rtx const_op1 = op1;
 
@@ -2514,6 +2515,28 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, int unsignedp
        }
     }
 
+  if (GET_CODE (op0) == CONST_DOUBLE)
+    {
+      rtx temp = op0;
+      op0 = op1;
+      op1 = temp;
+    }
+
+  /* Expand x*2.0 as x+x.  */
+  if (GET_CODE (op1) == CONST_DOUBLE
+      && GET_MODE_CLASS (mode) == MODE_FLOAT)
+    {
+      REAL_VALUE_TYPE d;
+      REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
+
+      if (REAL_VALUES_EQUAL (d, dconst2))
+       {
+         op0 = force_reg (GET_MODE (op0), op0);
+         return expand_binop (mode, add_optab, op0, op0,
+                              target, unsignedp, OPTAB_LIB_WIDEN);
+       }
+    }
+
   /* This used to use umul_optab if unsigned, but for non-widening multiply
      there is no difference between signed and unsigned.  */
   op0 = expand_binop (mode,
index c4faf075d0d77584feb547538b32092e959d91b2..4dd606f68bf569248b39a711486dfa0faa8638fa 100644 (file)
@@ -5659,14 +5659,72 @@ fold (tree expr)
                                    same));
            }
        }
+      else
+       {
+         /* See if ARG1 is zero and X + ARG1 reduces to X.  */
+         if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
+           return non_lvalue (convert (type, arg0));
 
-      /* See if ARG1 is zero and X + ARG1 reduces to X.  */
-      else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
-       return non_lvalue (convert (type, arg0));
+         /* Likewise if the operands are reversed.  */
+         if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+           return non_lvalue (convert (type, arg1));
 
-      /* Likewise if the operands are reversed.  */
-      else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
-       return non_lvalue (convert (type, arg1));
+         /* Convert x+x into x*2.0.  */
+         if (operand_equal_p (arg0, arg1, 0))
+           return fold (build (MULT_EXPR, type, arg0,
+                               build_real (type, dconst2)));
+
+         /* Convert x*c+x into x*(c+1).  */
+         if (flag_unsafe_math_optimizations
+             && TREE_CODE (arg0) == MULT_EXPR
+             && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
+             && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+           {
+             REAL_VALUE_TYPE c;
+
+             c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+             real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+             return fold (build (MULT_EXPR, type, arg1,
+                                 build_real (type, c)));
+           }
+
+         /* Convert x+x*c into x*(c+1).  */
+         if (flag_unsafe_math_optimizations
+             && TREE_CODE (arg1) == MULT_EXPR
+             && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
+             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
+             && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
+           {
+             REAL_VALUE_TYPE c;
+
+             c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+             real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+             return fold (build (MULT_EXPR, type, arg0,
+                                 build_real (type, c)));
+           }
+
+         /* Convert x*c1+x*c2 into x*(c1+c2).  */
+         if (flag_unsafe_math_optimizations
+             && TREE_CODE (arg0) == MULT_EXPR
+             && TREE_CODE (arg1) == MULT_EXPR
+             && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
+             && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
+             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
+             && operand_equal_p (TREE_OPERAND (arg0, 0),
+                                 TREE_OPERAND (arg1, 0), 0))
+           {
+             REAL_VALUE_TYPE c1, c2;
+
+             c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+             c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+             real_arithmetic (&c1, PLUS_EXPR, &c1, &c2);
+             return fold (build (MULT_EXPR, type,
+                                 TREE_OPERAND (arg0, 0),
+                                 build_real (type, c1)));
+           }
+       }
 
      bit_rotate:
       /* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A
@@ -5954,15 +6012,6 @@ fold (tree expr)
              && real_minus_onep (arg1))
            return fold (build1 (NEGATE_EXPR, type, arg0));
 
-         /* x*2 is x+x */
-         if (! wins && real_twop (arg1)
-             && (*lang_hooks.decls.global_bindings_p) () == 0
-             && ! CONTAINS_PLACEHOLDER_P (arg0))
-           {
-             tree arg = save_expr (arg0);
-             return fold (build (PLUS_EXPR, type, arg, arg));
-           }
-
          if (flag_unsafe_math_optimizations)
            {
              enum built_in_function fcode0 = builtin_mathfn_code (arg0);
index 862280a104df70c4578c105226d9eb6cf64a4770..ba19bc89283a4f04ab185fe94c2fda447fbc6d78 100644 (file)
@@ -1,3 +1,7 @@
+2003-08-04  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/20030804-1.c: New test case.
+
 2003-08-04  Alexandre Oliva  <aoliva@redhat.com>
 
        * gcc.dg/cpp/separate-1.c: New test.
diff --git a/gcc/testsuite/gcc.dg/20030804-1.c b/gcc/testsuite/gcc.dg/20030804-1.c
new file mode 100644 (file)
index 0000000..cbc6647
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (C) 2003 Free Software Foundation.
+
+   Check that constant folding of mathematical expressions doesn't
+   break anything.
+
+   Written by Roger Sayle, 3rd August 2003.  */
+
+/* { dg-do link } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern void link_error(void);
+
+void test(double x)
+{
+  if (x+x != 2.0*x)
+    link_error ();
+  if (x+x != x*2.0)
+    link_error ();
+
+  if (x+x+x != 3.0*x)
+    link_error ();
+  if (x+x+x != x*3.0)
+    link_error ();
+
+  if ((x+x)+x != 3.0*x)
+    link_error ();
+  if ((x+x)+x != x*3.0)
+    link_error ();
+
+  if (x+(x+x) != 3.0*x)
+    link_error ();
+  if (x+(x+x) != x*3.0)
+    link_error ();
+
+  if (x+4.0*x != 5.0*x)
+    link_error ();
+  if (x+4.0*x != x*5.0)
+    link_error ();
+  if (x+x*4.0 != 5.0*x)
+    link_error ();
+  if (x+x*4.0 != x*5.0)
+    link_error ();
+  if (4.0*x+x != 5.0*x)
+    link_error ();
+  if (4.0*x+x != x*5.0)
+    link_error ();
+  if (x*4.0+x != 5.0*x)
+    link_error ();
+  if (x*4.0+x != x*5.0)
+    link_error ();
+
+  if (3.0*x + 5.0*x != 8.0*x)
+    link_error ();
+  if (3.0*x + 5.0*x != x*8.0)
+    link_error ();
+  if (x*3.0 + 5.0*x != 8.0*x)
+    link_error ();
+  if (x*3.0 + 5.0*x != x*8.0)
+    link_error ();
+  if (3.0*x + x*5.0 != 8.0*x)
+    link_error ();
+  if (3.0*x + x*5.0 != x*8.0)
+    link_error ();
+  if (x*3.0 + x*5.0 != 8.0*x)
+    link_error ();
+  if (x*3.0 + x*5.0 != x*8.0)
+    link_error ();
+}
+
+int main()
+{
+  test(2.0);
+  return 0;
+}
+