This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: Fix PR middle-end/30789, complex math folding via MPC


This patch fixes PR middle-end/30789, which deals with complex math
folding.  There are basically three problems noted in the PR:

1.  Getting "perfect" AKA "exact" results.
2.  Unnecessary overflow in complex division.
3.  C99 Annex G special cases.

Hooking fold into MPC fixes all three problems.  The first two are fixed
simply by virtue of using MPC which is meant specifically to handle
exactness and overflow.

The Annex G special cases only occur in cases where NaN is returned. Since
GCC's MPC infrastructure already backs out when encountering NaN values,
using MPC here means folding doesn't occur and the correct Annex G values
are calculated by libgcc at runtime.

Note GCC doesn't fold complex >int< division, regardles of my patch.  I
don't know why.  It seems like someone accidentally expected
TRUNC_DIV_EXPR handling in the RDIV_EXPR switch case.  Anyway, that's a
separate problem.  So my testcase only sanity checks runtime evaluation
for that.

Tested on x86_64-unknown-linux-gnu without MPC, with mpc-0.6 and with MPC
SVN.  No regressions, okay for mainline?

		Thanks,
		--Kaveh


2009-08-13  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	PR middle-end/30789

	* builtins.c (do_mpc_arg2): Make extern, define for any MPC
	version.  Move declaration...
	* real.h (do_mpc_arg2): ... here.
	* fold-const.c (const_binop): Use MPC for complex MULT_EXPR
	and RDIV_EXPR.

testsuite:
	* gcc.dg/torture/builtin-math-7.c: New.

diff -rup orig/egcc-SVN20090810/gcc/builtins.c egcc-SVN20090810/gcc/builtins.c
--- orig/egcc-SVN20090810/gcc/builtins.c	2009-07-18 02:00:56.000000000 +0200
+++ egcc-SVN20090810/gcc/builtins.c	2009-08-10 16:58:58.000000000 +0200
@@ -60,9 +60,6 @@ along with GCC; see the file COPYING3.
 #endif
 #ifdef HAVE_mpc
 static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t));
-#ifdef HAVE_mpc_pow
-static tree do_mpc_arg2 (tree, tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t));
-#endif
 #endif

 /* Define the names of the builtin function types and codes.  */
@@ -13825,8 +13822,8 @@ do_mpc_arg1 (tree arg, tree type, int (*
    TYPE.  We assume that function FUNC returns zero if the result
    could be calculated exactly within the requested precision.  */

-#ifdef HAVE_mpc_pow
-static tree
+#ifdef HAVE_mpc
+tree
 do_mpc_arg2 (tree arg0, tree arg1, tree type,
 	     int (*func)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t))
 {
diff -rup orig/egcc-SVN20090810/gcc/fold-const.c egcc-SVN20090810/gcc/fold-const.c
--- orig/egcc-SVN20090810/gcc/fold-const.c	2009-07-17 02:00:25.000000000 +0200
+++ egcc-SVN20090810/gcc/fold-const.c	2009-08-13 21:59:39.000000000 +0200
@@ -1972,6 +1972,11 @@ const_binop (enum tree_code code, tree a
 	  break;

 	case MULT_EXPR:
+#ifdef HAVE_mpc
+	  if (COMPLEX_FLOAT_TYPE_P (type))
+	    return do_mpc_arg2 (arg1, arg2, type, mpc_mul);
+#endif
+
 	  real = const_binop (MINUS_EXPR,
 			      const_binop (MULT_EXPR, r1, r2, notrunc),
 			      const_binop (MULT_EXPR, i1, i2, notrunc),
@@ -1983,6 +1988,11 @@ const_binop (enum tree_code code, tree a
 	  break;

 	case RDIV_EXPR:
+#ifdef HAVE_mpc
+	  if (COMPLEX_FLOAT_TYPE_P (type))
+	    return do_mpc_arg2 (arg1, arg2, type, mpc_div);
+#endif
+
 	  {
 	    tree magsquared
 	      = const_binop (PLUS_EXPR,
diff -rup orig/egcc-SVN20090810/gcc/real.h egcc-SVN20090810/gcc/real.h
--- orig/egcc-SVN20090810/gcc/real.h	2009-07-16 19:48:33.000000000 +0200
+++ egcc-SVN20090810/gcc/real.h	2009-08-10 17:16:17.000000000 +0200
@@ -26,6 +26,9 @@
 #include <mpfr.h>
 #ifdef HAVE_mpc
 #include <mpc.h>
+# ifdef HAVE_mpc
+extern tree do_mpc_arg2 (tree, tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t));
+# endif
 # if MPC_VERSION >= MPC_VERSION_NUM(0,6,1)
 #  define HAVE_mpc_pow
 # endif
diff -rup orig/egcc-SVN20090810/gcc/testsuite/gcc.dg/torture/builtin-math-7.c egcc-SVN20090810/gcc/testsuite/gcc.dg/torture/builtin-math-7.c
--- orig/egcc-SVN20090810/gcc/testsuite/gcc.dg/torture/builtin-math-7.c	2009-08-13 22:03:35.000000000 +0200
+++ egcc-SVN20090810/gcc/testsuite/gcc.dg/torture/builtin-math-7.c	2009-08-13 22:09:17.000000000 +0200
@@ -0,0 +1,75 @@
+/* Copyright (C) 2009  Free Software Foundation.
+
+   Verify that folding of complex mul and div work correctly.
+
+   Origin: Kaveh R. Ghazi,  August 13, 2009.  */
+
+/* { dg-do run } */
+/* { dg-require-effective-target mpc } */
+
+extern void link_error(int);
+
+/* Evaluate this expression at compile-time.  */
+#define COMPILETIME_TESTIT(TYPE,X,OP,Y,RES) do { \
+  if ((_Complex TYPE)(X) OP (_Complex TYPE)(Y) != (_Complex TYPE)(RES)) \
+    link_error(__LINE__); \
+} while (0)
+
+/* Evaluate this expression at runtime.  */
+#define RUNTIME_TESTIT(TYPE,X,OP,Y,RES) do { \
+  volatile _Complex TYPE foo = (_Complex TYPE)(X); \
+  foo OP##= (_Complex TYPE)(Y); \
+  if (foo != (_Complex TYPE)(RES)) __builtin_printf ("(%f %f) != (%f %f)\n", (double)__real foo, (double)__imag foo, (double)__real (RES), (double)__imag (RES)); \
+  if (foo != (_Complex TYPE)(RES)) __builtin_abort(); \
+} while (0)
+
+/* Evaluate this expression at compile-time and runtime.  */
+#define TESTIT(TYPE,X,OP,Y,RES) do { \
+  COMPILETIME_TESTIT(TYPE,X,OP,Y,RES); \
+  RUNTIME_TESTIT(TYPE,X,OP,Y,RES); \
+} while (0)
+
+/* Either the real or imaginary parts should be infinity.  */
+#define TEST_ONE_PART_INF(VAL) do { \
+  if (! __builtin_isinf(__real (VAL)) \
+      && ! __builtin_isinf(__imag (VAL))) \
+    __builtin_abort(); \
+} while (0)
+
+int main()
+{
+  /* Test some regular finite values.  */
+  TESTIT (double, 3.+4.i, *, 2, 6+8i);
+  TESTIT (double, 3.+4.i, /, 2, 1.5+2i);
+  TESTIT (int, 3+4i, *, 2, 6+8i);
+  RUNTIME_TESTIT (int, 3+4i, /, 2, 1+2i);
+
+  TESTIT (double, 3.+4.i, *, 2+5i, -14+23i);
+  TESTIT (double, 3.+4.i, /, 5i, .8-.6i);
+  TESTIT (int, 3+4i, *, 2+5i, -14+23i);
+  RUNTIME_TESTIT (int, 30+40i, /, 5i, 8-6i);
+
+  /* Test that we don't overflow.  */
+  TESTIT (double,
+	  (__DBL_MAX__ * 0.5 + __DBL_MAX__ * 0.5i),
+	  /,
+	  (__DBL_MAX__ * 0.25 + __DBL_MAX__ * 0.25i),
+	  2);
+
+  /* Test for accuracy.  */
+  COMPILETIME_TESTIT (double,
+		      (1 + __DBL_EPSILON__ + 1i),
+		      *,
+		      (1 - __DBL_EPSILON__ + 1i),
+		      -4.93038065763132378382330353301741393545754021943139377981e-32+2i);
+
+  /* This becomes (NaN + iInf).  */
+#define VAL1 ((_Complex double)__builtin_inf() * 1i)
+
+  /* Test some C99 Annex G special cases.  */
+  TEST_ONE_PART_INF ((VAL1) * (VAL1));
+  TEST_ONE_PART_INF ((_Complex double)1 / (_Complex double)0);
+  TEST_ONE_PART_INF ((VAL1) / (_Complex double)1);
+
+  return 0;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]