tree.c (real_minus_onep): New function to test for -1.0.
authorRoger Sayle <roger@eyesopen.com>
Sat, 1 Jun 2002 16:56:08 +0000 (16:56 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Sat, 1 Jun 2002 16:56:08 +0000 (16:56 +0000)
* tree.c (real_minus_onep): New function to test for -1.0.
* fold-const.c (fold) [MULT_EXPR]:  Optimize -1.0*x into -x.

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

From-SVN: r54149

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/fnegate-1.c [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 0dd65f30b66a24c58279b7426bd7cd79ae5a3861..9a4a44b4e62d571a46b1f7f52969b206deb1d99a 100644 (file)
@@ -1,3 +1,8 @@
+2002-06-01  Roger Sayle  <roger@eyesopen.com>
+
+       * tree.c (real_minus_onep): New function to test for -1.0.
+       * fold-const.c (fold) [MULT_EXPR]:  Optimize -1.0*x into -x.
+
 2002-06-01  Roger Sayle  <roger@eyesopen.com>
 
        * fold-const.c (fold_truthop): Transform "a || b" into "(a|b) != 0"
index 0998a93aa2e433e8e761b92be7dace7ebaecf64f..947d575dd9398442d5faab5fe6eea3f204f7dbf4 100644 (file)
@@ -5370,6 +5370,14 @@ fold (expr)
             so we can do this anyway.  */
          if (real_onep (arg1))
            return non_lvalue (convert (type, arg0));
+
+         /* Transform x * -1.0 into -x.  This should be safe for NaNs,
+            signed zeros and signed infinities, but is currently
+            restricted to "unsafe math optimizations" just in case.  */
+         if (flag_unsafe_math_optimizations
+             && 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
index 8e063176cafce3c193a1dd946b7d5dbf12b0eb28..5f2d0b7b9a761ea652fd68854a727312764a1df7 100644 (file)
@@ -1,3 +1,7 @@
+2002-06-01  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/fnegate-1.c: New test case.
+
 2002-05-30  Osku Salerma  <osku@iki.fi>
 
        * gcc.c-torture/execute/mayalias-1.c: New file.
diff --git a/gcc/testsuite/gcc.dg/fnegate-1.c b/gcc/testsuite/gcc.dg/fnegate-1.c
new file mode 100644 (file)
index 0000000..ad0f4e0
--- /dev/null
@@ -0,0 +1,113 @@
+/* Copyright (C) 2002 Free Software Foundation.
+  
+   Test floating point negation produces the expected results.
+  
+   Written by Roger Sayle, 21st May 2002.  */
+
+/* { dg-do run } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern void abort ();
+
+
+double
+dneg (double x)
+{
+  return -x;
+}
+
+double
+dmult (double x)
+{
+  return -1.0 * x;
+}
+
+double
+ddiv (double x)
+{
+  return x / -1.0;
+}
+
+
+float
+fneg (float x)
+{
+  return -x;
+}
+
+float
+fmult (float x)
+{
+  return -1.0f * x;
+}
+
+float
+fdiv (float x)
+{
+  return x / -1.0f;
+}
+
+
+void
+ftest(float src, float dst)
+{
+  if (fneg (src) != dst)
+    abort ();
+
+  if (src != fneg (dst))
+    abort ();
+
+  if (fmult (src) != dst)
+    abort ();
+
+  if (src != fmult (dst))
+    abort ();
+
+  if (fdiv (src) != dst)
+    abort ();
+
+  if (src != fdiv(dst))
+    abort ();
+}
+
+void
+dtest(double src, double dst)
+{
+  if (dneg (src) != dst)
+    abort ();
+
+  if (src != dneg (dst))
+    abort ();
+
+  if (dmult (src) != dst)
+    abort ();
+
+  if (src != dmult (dst))
+    abort ();
+
+  if (ddiv (src) != dst)
+    abort ();
+
+  if (src != ddiv(dst))
+    abort ();
+}
+
+
+int
+main ()
+{
+  ftest (1.0f, -1.0f);
+  ftest (2.0f, -2.0f);
+  ftest (-3.0f, 3.0f);
+  ftest (0.0f, -0.0f);
+  ftest (-0.0f, 0.0f);
+
+  dtest (1.0, -1.0);
+  dtest (2.0, -2.0);
+  dtest (-3.0, 3.0);
+  dtest (0.0, -0.0);
+  dtest (-0.0, 0.0);
+
+  return 0;
+}
+
index 15f156aea0a511c8dc8ebe3f4d060b0cf691654a..04ae6ce53480bae19a8b3546e69f8952a25bf3d6 100644 (file)
@@ -892,6 +892,22 @@ real_twop (expr)
              && real_zerop (TREE_IMAGPART (expr))));
 }
 
+/* Return 1 if EXPR is the real constant minus one.  */
+
+int
+real_minus_onep (expr)
+     tree expr;
+{
+  STRIP_NOPS (expr);
+
+  return ((TREE_CODE (expr) == REAL_CST
+          && ! TREE_CONSTANT_OVERFLOW (expr)
+          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1))
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && real_minus_onep (TREE_REALPART (expr))
+             && real_zerop (TREE_IMAGPART (expr))));
+}
+
 /* Nonzero if EXP is a constant or a cast of a constant.  */
 
 int
index fffad7a4bb0940518914867e21836fa9d69924fd..34385da1c73c3b8d009f04196cde004b8cd669fa 100644 (file)
@@ -2850,6 +2850,7 @@ extern void expand_pending_sizes        PARAMS ((tree));
 
 extern int real_onep                   PARAMS ((tree));
 extern int real_twop                   PARAMS ((tree));
+extern int real_minus_onep             PARAMS ((tree));
 extern void gcc_obstack_init           PARAMS ((struct obstack *));
 extern void init_obstacks              PARAMS ((void));
 extern void build_common_tree_nodes    PARAMS ((int));