Fix complex arithmetic and signed zeros

Joseph S. Myers joseph@codesourcery.com
Fri May 8 15:10:00 GMT 2009


I discovered some further optimizations that are incorrect for signed
zeros in complex arithmetic: folding for multiplication by 1.0 + 0.0i
and -1.0 + 0.0i; fixed by this patch.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
commit?

2009-05-08  Joseph Myers  <joseph@codesourcery.com>

	* fold-const.c (fold_binary): Do not fold multiplication by 1 or
	-1 for complex floating-point types if honoring signed zeros.

testsuite:
2009-05-08  Joseph Myers  <joseph@codesourcery.com>

	* gcc.dg/torture/complex-sign-mul-minus-one.c,
	gcc.dg/torture/complex-sign-mul-one.c: New tests.

Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 147281)
+++ gcc/fold-const.c	(working copy)
@@ -10647,13 +10647,18 @@ fold_binary (enum tree_code code, tree t
 	      && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
 	      && real_zerop (arg1))
 	    return omit_one_operand (type, arg1, arg0);
-	  /* In IEEE floating point, x*1 is not equivalent to x for snans.  */
+	  /* In IEEE floating point, x*1 is not equivalent to x for snans.
+	     Likewise for complex arithmetic with signed zeros.  */
 	  if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+	      && (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
+		  || !COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0)))
 	      && real_onep (arg1))
 	    return non_lvalue (fold_convert (type, arg0));
 
 	  /* Transform x * -1.0 into -x.  */
 	  if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+	      && (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
+		  || !COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0)))
 	      && real_minus_onep (arg1))
 	    return fold_convert (type, negate_expr (arg0));
 
Index: gcc/testsuite/gcc.dg/torture/complex-sign-mul-minus-one.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/complex-sign-mul-minus-one.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/complex-sign-mul-minus-one.c	(revision 0)
@@ -0,0 +1,61 @@
+/* Test complex arithmetic with signed zeros.  Pure complex
+   multiplication with -1.0 + 0.0i.  */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+#include "complex-sign.h"
+
+#define CHECK_MUL_INT(TYPE, COPY, ZERO, ZEROI, ONE, S1, S2, SR, SI)	\
+  do {									\
+    _Complex TYPE a1, b1, c1;						\
+    volatile _Complex TYPE a2, b2, c2;					\
+    a1 = ENCODE(ZERO, ZEROI, S1, S2);					\
+    CHECK_RES (a1, COPY, S1, S2);					\
+    b1 = -ONE + ZEROI;							\
+    c1 = a1 * b1;							\
+    CHECK_RES (c1, COPY, SR, SI);					\
+    c1 = a1 * (-ONE + ZEROI);						\
+    CHECK_RES (c1, COPY, SR, SI);					\
+    a2 = ENCODE(ZERO, ZEROI, S1, S2);					\
+    CHECK_RES (a2, COPY, S1, S2);					\
+    b2 = -ONE + ZEROI;							\
+    c2 = a2 * b2;							\
+    CHECK_RES (c2, COPY, SR, SI);					\
+    c2 = a2 * (-ONE + ZEROI);						\
+    CHECK_RES (c2, COPY, SR, SI);					\
+  } while (0)
+
+#define CHECK_MUL(TYPE, COPY, ZERO, ZEROI, ONE)			\
+  do {								\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, +, +, -, +);	\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, +, -, +, +);	\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, -, +, +, -);	\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, -, -, +, +);	\
+  } while (0)
+
+void
+check_mul_float (void)
+{
+  CHECK_MUL (float, __builtin_copysignf, 0.0f, 0.0if, 1.0f);
+}
+
+void
+check_mul_double (void)
+{
+  CHECK_MUL (double, __builtin_copysign, 0.0, 0.0i, 1.0);
+}
+
+void
+check_mul_long_double (void)
+{
+  CHECK_MUL (long double, __builtin_copysignl, 0.0l, 0.0il, 1.0l);
+}
+
+int
+main (void)
+{
+  check_mul_float ();
+  check_mul_double ();
+  check_mul_long_double ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/complex-sign-mul-one.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/complex-sign-mul-one.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/complex-sign-mul-one.c	(revision 0)
@@ -0,0 +1,61 @@
+/* Test complex arithmetic with signed zeros.  Pure complex
+   multiplication with 1.0 + 0.0i.  */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+#include "complex-sign.h"
+
+#define CHECK_MUL_INT(TYPE, COPY, ZERO, ZEROI, ONE, S1, S2, SR, SI)	\
+  do {									\
+    _Complex TYPE a1, b1, c1;						\
+    volatile _Complex TYPE a2, b2, c2;					\
+    a1 = ENCODE(ZERO, ZEROI, S1, S2);					\
+    CHECK_RES (a1, COPY, S1, S2);					\
+    b1 = ONE + ZEROI;							\
+    c1 = a1 * b1;							\
+    CHECK_RES (c1, COPY, SR, SI);					\
+    c1 = a1 * (ONE + ZEROI);						\
+    CHECK_RES (c1, COPY, SR, SI);					\
+    a2 = ENCODE(ZERO, ZEROI, S1, S2);					\
+    CHECK_RES (a2, COPY, S1, S2);					\
+    b2 = ONE + ZEROI;							\
+    c2 = a2 * b2;							\
+    CHECK_RES (c2, COPY, SR, SI);					\
+    c2 = a2 * (ONE + ZEROI);						\
+    CHECK_RES (c2, COPY, SR, SI);					\
+  } while (0)
+
+#define CHECK_MUL(TYPE, COPY, ZERO, ZEROI, ONE)			\
+  do {								\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, +, +, +, +);	\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, +, -, +, +);	\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, -, +, -, +);	\
+    CHECK_MUL_INT (TYPE, COPY, ZERO, ZEROI, ONE, -, -, +, -);	\
+  } while (0)
+
+void
+check_mul_float (void)
+{
+  CHECK_MUL (float, __builtin_copysignf, 0.0f, 0.0if, 1.0f);
+}
+
+void
+check_mul_double (void)
+{
+  CHECK_MUL (double, __builtin_copysign, 0.0, 0.0i, 1.0);
+}
+
+void
+check_mul_long_double (void)
+{
+  CHECK_MUL (long double, __builtin_copysignl, 0.0l, 0.0il, 1.0l);
+}
+
+int
+main (void)
+{
+  check_mul_float ();
+  check_mul_double ();
+  check_mul_long_double ();
+  exit (0);
+}

-- 
Joseph S. Myers
joseph@codesourcery.com



More information about the Gcc-patches mailing list