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]: optimize builtin cproj


Up until very recently, the implementation of cproj in GLIBC used an
algorithm very much at odds with the C standard.
http://sourceware.org/bugzilla/show_bug.cgi?id=10401
If you "man cproj" on linux-gnu, it says: "NOTE The glibc implementation
is broken and does something entirely different." :-)

I had held off optimizing builtin cproj in GCC until that was fixed.  Now
that it's been done I've gone ahead with the GCC side.

First, we can change the builtin attributes on cproj to
ATTR_CONST_NOTHROW_LIST because (like cimag and creal) cproj does not
raise any floating point exceptions.  The old (incorrect) GLIBC
implementation did some calculations which might have invoked some FP
rounding.  The correct C implementation does no math so the attribute can
be changed.

Next we can optimize cproj when the argument is constant, or when there
are no infinities on the supplied mode.  Other opts may follow, for now
here's what I have.

Tested on x86_64-unknown-linux-gnu, no regressions.  Okay for mainline?

		Thanks,
		--Kaveh


2010-04-09  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* builtins.c (build_complex_cproj, fold_builtin_cproj): New.
	(fold_builtin_1): Fold builtin cproj.
	* builtins.def (BUILT_IN_CPROJ, BUILT_IN_CPROJF, BUILT_IN_CPROJL):
	Use ATTR_CONST_NOTHROW_LIST.

testsuite:
	* gcc.dg/torture/builtin-cproj-1.c: New.
	* gcc.dg/torture/builtin-cproj-2.c: New.

diff -rup orig/egcc-SVN20100409/gcc/builtins.c egcc-SVN20100409/gcc/builtins.c
--- orig/egcc-SVN20100409/gcc/builtins.c	2010-03-23 02:01:51.000000000 +0100
+++ egcc-SVN20100409/gcc/builtins.c	2010-04-09 18:58:42.000000000 +0200
@@ -6955,6 +6955,50 @@ fold_builtin_cabs (location_t loc, tree
   return NULL_TREE;
 }

+/* Build a complex (inf +- 0i) for the result of cproj.  TYPE is the
+   complex tree type of the result.  If NEG is true, the imaginary
+   zero is negative.  */
+
+static tree
+build_complex_cproj (tree type, bool neg)
+{
+  REAL_VALUE_TYPE rinf, rzero = dconst0;
+
+  real_inf (&rinf);
+  rzero.sign = neg;
+  return build_complex (type, build_real (TREE_TYPE (type), rinf),
+			build_real (TREE_TYPE (type), rzero));
+}
+
+/* Fold call to builtin cproj, cprojf or cprojl with argument ARG.  TYPE is the
+   return type.  Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_cproj (location_t loc, tree arg, tree type)
+{
+  if (!validate_arg (arg, COMPLEX_TYPE)
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+    return NULL_TREE;
+
+  /* If there are no infinities, return arg.  */
+  if (! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (type))))
+    return non_lvalue_loc (loc, arg);
+
+  /* Calculate the result when the argument is a constant.  */
+  if (TREE_CODE (arg) == COMPLEX_CST)
+    {
+      const REAL_VALUE_TYPE *real = TREE_REAL_CST_PTR (TREE_REALPART (arg));
+      const REAL_VALUE_TYPE *imag = TREE_REAL_CST_PTR (TREE_IMAGPART (arg));
+
+      if (real_isinf (real) || real_isinf (imag))
+	return build_complex_cproj (type, imag->sign);
+      else
+	return arg;
+    }
+
+  return NULL_TREE;
+}
+
 /* Fold a builtin function call to sqrt, sqrtf, or sqrtl with argument ARG.
    Return NULL_TREE if no simplification can be made.  */

@@ -9712,6 +9756,9 @@ fold_builtin_1 (location_t loc, tree fnd
     CASE_FLT_FN (BUILT_IN_CCOSH):
       return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ true);

+    CASE_FLT_FN (BUILT_IN_CPROJ):
+      return fold_builtin_cproj(loc, arg0, type);
+
     CASE_FLT_FN (BUILT_IN_CSIN):
       if (validate_arg (arg0, COMPLEX_TYPE)
 	  && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
diff -rup orig/egcc-SVN20100409/gcc/builtins.def egcc-SVN20100409/gcc/builtins.def
--- orig/egcc-SVN20100409/gcc/builtins.def	2009-11-26 02:01:36.000000000 +0100
+++ egcc-SVN20100409/gcc/builtins.def	2010-04-09 18:54:03.000000000 +0200
@@ -479,9 +479,9 @@ DEF_C99_BUILTIN        (BUILT_IN_CONJL,
 DEF_C99_BUILTIN        (BUILT_IN_CPOW, "cpow", BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE_COMPLEX_DOUBLE, ATTR_MATHFN_FPROUNDING)
 DEF_C99_BUILTIN        (BUILT_IN_CPOWF, "cpowf", BT_FN_COMPLEX_FLOAT_COMPLEX_FLOAT_COMPLEX_FLOAT, ATTR_MATHFN_FPROUNDING)
 DEF_C99_BUILTIN        (BUILT_IN_CPOWL, "cpowl", BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE, ATTR_MATHFN_FPROUNDING)
-DEF_C99_BUILTIN        (BUILT_IN_CPROJ, "cproj", BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE, ATTR_MATHFN_FPROUNDING)
-DEF_C99_BUILTIN        (BUILT_IN_CPROJF, "cprojf", BT_FN_COMPLEX_FLOAT_COMPLEX_FLOAT, ATTR_MATHFN_FPROUNDING)
-DEF_C99_BUILTIN        (BUILT_IN_CPROJL, "cprojl", BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE, ATTR_MATHFN_FPROUNDING)
+DEF_C99_BUILTIN        (BUILT_IN_CPROJ, "cproj", BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE, ATTR_CONST_NOTHROW_LIST)
+DEF_C99_BUILTIN        (BUILT_IN_CPROJF, "cprojf", BT_FN_COMPLEX_FLOAT_COMPLEX_FLOAT, ATTR_CONST_NOTHROW_LIST)
+DEF_C99_BUILTIN        (BUILT_IN_CPROJL, "cprojl", BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE, ATTR_CONST_NOTHROW_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_CREAL, "creal", BT_FN_DOUBLE_COMPLEX_DOUBLE, ATTR_CONST_NOTHROW_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_CREALF, "crealf", BT_FN_FLOAT_COMPLEX_FLOAT, ATTR_CONST_NOTHROW_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_CREALL, "creall", BT_FN_LONGDOUBLE_COMPLEX_LONGDOUBLE, ATTR_CONST_NOTHROW_LIST)
diff -rup orig/egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-1.c egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-1.c
--- orig/egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-1.c	2010-04-09 19:18:45.000000000 +0200
+++ egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-1.c	2010-04-09 19:16:02.000000000 +0200
@@ -0,0 +1,88 @@
+/* Copyright (C) 2010  Free Software Foundation.
+
+   Verify that folding of built-in cproj is correctly performed by the
+   compiler.
+
+   Origin: Kaveh R. Ghazi,  April 9, 2010.  */
+
+/* { dg-do link } */
+
+/* All references to link_error should go away at compile-time.  The
+   argument is the __LINE__ number.  It appears in the tree dump file
+   and aids in debugging should any of the tests fail.  */
+extern void link_error(int);
+
+#define CPROJ(X) __builtin_cproj(X)
+#define CPROJF(X) __builtin_cprojf(X)
+#define CPROJL(X) __builtin_cprojl(X)
+#define INF __builtin_inff()
+#define I 1i
+#define CPSGN(X,Y) __builtin_copysignf((X),(Y))
+#define CIMAG(X) __builtin_cimagf(X)
+#define CREAL(X) __builtin_crealf(X)
+
+/* Check that the signs of the real and/or imaginary parts of two
+   complex numbers match.  */
+#define CKSGN(X,Y) (CKSGN_R(X,Y) || CKSGN_I(X,Y))
+#define CKSGN_R(X,Y) (CPSGN(1,CREAL(X)) != CPSGN(1,CREAL(Y)))
+#define CKSGN_I(X,Y) (CPSGN(1,CIMAG(X)) != CPSGN(1,CIMAG(Y)))
+
+/* Test that (cproj(X) == ZERO+Inf) and that the signs of the
+   imaginary parts match.  ZERO is +/- 0i.  */
+#define TEST_CST_INF(X,ZERO) do { \
+  if (CPROJF(X) != ZERO+INF || CKSGN_I(CPROJF(X),ZERO+INF)) \
+    link_error(__LINE__); \
+  if (CPROJ(X) != ZERO+INF || CKSGN_I(CPROJ(X),ZERO+INF)) \
+    link_error(__LINE__); \
+  if (CPROJL(X) != ZERO+INF || CKSGN_I(CPROJL(X),ZERO+INF)) \
+    link_error(__LINE__); \
+} while (0)
+
+/* Test that (cproj(X) == X) for all finite (X).  */
+#define TEST_CST(X) do { \
+  if (CPROJF(X) != (X) || CKSGN(CPROJF(X),(X))) \
+    link_error(__LINE__); \
+} while (0)
+
+void foo (void)
+{
+  TEST_CST_INF (INF+0I, 0);
+  TEST_CST_INF (INF-0I, -0.FI);
+  TEST_CST_INF (INF+4I, 0);
+  TEST_CST_INF (INF-4I, -0.FI);
+  TEST_CST_INF (-INF+0I, 0);
+  TEST_CST_INF (-INF-0I, -0.FI);
+  TEST_CST_INF (-INF+4I, 0);
+  TEST_CST_INF (-INF-4I, -0.FI);
+
+  TEST_CST_INF (0+I*INF, 0);
+  TEST_CST_INF (0-I*INF, -0.FI);
+  TEST_CST_INF (23+I*INF, 0);
+  TEST_CST_INF (23-I*INF, -0.FI);
+  TEST_CST_INF (-0.F+I*INF, 0);
+  TEST_CST_INF (-0.F-I*INF, -0.FI);
+  TEST_CST_INF (-23+I*INF, 0);
+  TEST_CST_INF (-23-I*INF, -0.FI);
+
+  TEST_CST_INF (INF+I*INF, 0);
+  TEST_CST_INF (INF-I*INF, -0.FI);
+  TEST_CST_INF (-INF+I*INF, 0);
+  TEST_CST_INF (-INF-I*INF, -0.FI);
+
+  TEST_CST (0);
+  TEST_CST (-0.F);
+  TEST_CST (0-0.FI);
+  TEST_CST (-0.F-0.FI);
+
+  TEST_CST (22+3I);
+  TEST_CST (22-3I);
+  TEST_CST (-22+3I);
+  TEST_CST (-22-3I);
+
+  return;
+}
+
+int main (void)
+{
+  return 0;
+}
diff -rup orig/egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-2.c egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-2.c
--- orig/egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-2.c	2010-04-09 19:36:38.000000000 +0200
+++ egcc-SVN20100409/gcc/testsuite/gcc.dg/torture/builtin-cproj-2.c	2010-04-09 19:35:05.000000000 +0200
@@ -0,0 +1,46 @@
+/* Copyright (C) 2010  Free Software Foundation.
+
+   Verify that folding of built-in cproj is correctly performed by the
+   compiler.  With -ffinite-math-only all cproj calls should be
+   eliminated regardless of what the argument is, or what is known
+   about it.
+
+   Origin: Kaveh R. Ghazi,  April 9, 2010.  */
+
+/* { dg-do link } */
+/* { dg-options "-ffinite-math-only" } */
+
+/* All references to link_error should go away at compile-time.  The
+   argument is the __LINE__ number.  It appears in the tree dump file
+   and aids in debugging should any of the tests fail.  */
+extern void link_error(int);
+
+#define CPROJ(X) __builtin_cproj(X)
+#define CPROJF(X) __builtin_cprojf(X)
+#define CPROJL(X) __builtin_cprojl(X)
+
+/* Test that the supplied expressions eliminte the cproj call.  */
+#define TEST_EXPRS(LD_EXPR, D_EXPR, F_EXPR) do { \
+  if (CPROJF(F_EXPR) != (F_EXPR)) \
+    link_error (__LINE__); \
+  if (CPROJ(D_EXPR) != (D_EXPR)) \
+    link_error (__LINE__); \
+  if (CPROJL(LD_EXPR) != (LD_EXPR)) \
+    link_error (__LINE__); \
+} while (0)
+
+void foo (_Complex long double cld, _Complex double cd, _Complex float cf)
+{
+#ifdef __OPTIMIZE__
+  TEST_EXPRS (cld, cd, cf);
+  TEST_EXPRS (cld*2, cd*2, cf*2);
+  TEST_EXPRS (cld*cld, cd*cd, cf*cf);
+#endif
+
+  return;
+}
+
+int main (void)
+{
+  return 0;
+}


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