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]: fold cabs(x+xi) and (x,0)-(0,y)


This patch adds two bits of functionality.  First I add folding of
cabs(x+xi) -> fabs(x)*sqrt(2).  We already do the same for hypot(x,x). I
slightly reorganized fold_builtin_cabs to only check that TREE_CODE (arg)
== COMPLEX_EXPR one time.

Second I add folding of complex expressions like (x,0)-(0,y) into (x,-y)
and also (0,y)-(x,0) into (-x,y).  We already do a similar folding for the
analogous PLUS expression.

I also noticed two comment typos which I corrected below.

I'm doing these two seemingly unrelated functional bits together because
the testcases I came up with make use of both transformations in some
cases to resolve correctly.

Tested on sparc-sun-solaris2.10, no regressions.

Okay for mainline?

		Thanks,
		--Kaveh


2007-02-02  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* builtins.c (fold_builtin_cabs): Fold cabs(x+xi) into
	fabs(x)*sqrt(2).
	* fold-const.c (fold_binary): Fix comment typos.  Fold complex
	(x,0)-(0,y) into (x,-y).  Likewise (0,y)-(x,0) into (-x,y).

testsuite:
	* gcc.dg/builtins-54.c: Add more cases.

diff -rup orig/egcc-SVN20070202/gcc/builtins.c egcc-SVN20070202/gcc/builtins.c
--- orig/egcc-SVN20070202/gcc/builtins.c	2007-02-02 12:46:46.000000000 -0500
+++ egcc-SVN20070202/gcc/builtins.c	2007-02-02 14:35:16.628127104 -0500
@@ -7143,13 +7143,30 @@ fold_builtin_cabs (tree arglist, tree ty
 			      type, mpfr_hypot)))
     return res;

-  /* If either part is zero, cabs is fabs of the other.  */
-  if (TREE_CODE (arg) == COMPLEX_EXPR
-      && real_zerop (TREE_OPERAND (arg, 0)))
-    return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1));
-  if (TREE_CODE (arg) == COMPLEX_EXPR
-      && real_zerop (TREE_OPERAND (arg, 1)))
-    return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0));
+  if (TREE_CODE (arg) == COMPLEX_EXPR)
+    {
+      tree real = TREE_OPERAND (arg, 0);
+      tree imag = TREE_OPERAND (arg, 1);
+
+      /* If either part is zero, cabs is fabs of the other.  */
+      if (real_zerop (real))
+	return fold_build1 (ABS_EXPR, type, imag);
+      if (real_zerop (imag))
+	return fold_build1 (ABS_EXPR, type, real);
+
+      /* cabs(x+xi) -> fabs(x)*sqrt(2).  */
+      if (flag_unsafe_math_optimizations
+	  && operand_equal_p (real, imag, OEP_PURE_SAME))
+        {
+	  REAL_VALUE_TYPE sqrt2;
+
+	  real_sqrt (&sqrt2, TYPE_MODE (type), &dconst2);
+	  STRIP_NOPS (real);
+	  return fold_build2 (MULT_EXPR, type,
+			      fold_build1 (ABS_EXPR, type, real),
+			      build_real (type, sqrt2));
+	}
+    }

   /* Optimize cabs(-z) and cabs(conj(z)) as cabs(z).  */
   if (TREE_CODE (arg) == NEGATE_EXPR
diff -rup orig/egcc-SVN20070202/gcc/fold-const.c egcc-SVN20070202/gcc/fold-const.c
--- orig/egcc-SVN20070202/gcc/fold-const.c	2007-02-02 12:46:47.000000000 -0500
+++ egcc-SVN20070202/gcc/fold-const.c	2007-02-02 14:16:48.906222070 -0500
@@ -8923,7 +8923,7 @@ fold_binary (enum tree_code code, tree t

 	  /* Fold __complex__ ( x, 0 ) + __complex__ ( 0, y )
 	     to __complex__ ( x, y ).  This is not the same for SNaNs or
-	     if singed zeros are involved.  */
+	     if signed zeros are involved.  */
 	  if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
               && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
 	      && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0)))
@@ -9231,6 +9231,43 @@ fold_binary (enum tree_code code, tree t
       else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
 	return negate_expr (fold_convert (type, arg1));

+      /* Fold __complex__ ( x, 0 ) - __complex__ ( 0, y ) to
+	 __complex__ ( x, -y ).  This is not the same for SNaNs or if
+	 signed zeros are involved.  */
+      if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+	  && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
+	  && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0)))
+        {
+	  tree rtype = TREE_TYPE (TREE_TYPE (arg0));
+	  tree arg0r = fold_unary (REALPART_EXPR, rtype, arg0);
+	  tree arg0i = fold_unary (IMAGPART_EXPR, rtype, arg0);
+	  bool arg0rz = false, arg0iz = false;
+	  if ((arg0r && (arg0rz = real_zerop (arg0r)))
+	      || (arg0i && (arg0iz = real_zerop (arg0i))))
+	    {
+	      tree arg1r = fold_unary (REALPART_EXPR, rtype, arg1);
+	      tree arg1i = fold_unary (IMAGPART_EXPR, rtype, arg1);
+	      if (arg0rz && arg1i && real_zerop (arg1i))
+	        {
+		  tree rp = fold_build1 (NEGATE_EXPR, rtype,
+					 arg1r ? arg1r
+					 : build1 (REALPART_EXPR, rtype, arg1));
+		  tree ip = arg0i ? arg0i
+		    : build1 (IMAGPART_EXPR, rtype, arg0);
+		  return fold_build2 (COMPLEX_EXPR, type, rp, ip);
+		}
+	      else if (arg0iz && arg1r && real_zerop (arg1r))
+	        {
+		  tree rp = arg0r ? arg0r
+		    : build1 (REALPART_EXPR, rtype, arg0);
+		  tree ip = fold_build1 (NEGATE_EXPR, rtype,
+					 arg1i ? arg1i
+					 : build1 (IMAGPART_EXPR, rtype, arg1));
+		  return fold_build2 (COMPLEX_EXPR, type, rp, ip);
+		}
+	    }
+	}
+
       /* Fold &x - &x.  This can happen from &x.foo - &x.
 	 This is unsafe for certain floats even in non-IEEE formats.
 	 In IEEE, it is unsafe because it does wrong for NaNs.
@@ -9410,7 +9447,7 @@ fold_binary (enum tree_code code, tree t
 	    }

 	  /* Fold z * +-I to __complex__ (-+__imag z, +-__real z).
-	     This is not the same for NaNs or if singed zeros are
+	     This is not the same for NaNs or if signed zeros are
 	     involved.  */
 	  if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
               && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
diff -rup orig/egcc-SVN20070202/gcc/testsuite/gcc.dg/builtins-54.c egcc-SVN20070202/gcc/testsuite/gcc.dg/builtins-54.c
--- orig/egcc-SVN20070202/gcc/testsuite/gcc.dg/builtins-54.c	2006-05-31 20:00:17.000000000 -0400
+++ egcc-SVN20070202/gcc/testsuite/gcc.dg/builtins-54.c	2007-02-02 14:29:28.791920612 -0500
@@ -1,44 +1,146 @@
 /* { dg-do link } */
 /* { dg-options "-O2 -ffast-math" } */

+double fabs(double);
+float fabsf(float);
+long double fabsl(long double);
 double cabs(__complex__ double);
 float cabsf(__complex__ float);
 long double cabsl(__complex__ long double);

 void link_error (void);

-void test(__complex__ double x)
+void test(__complex__ double x, double a, double b)
 {
   if (cabs(x) != cabs(-x))
     link_error();

   if (cabs(x) != cabs(~x))
     link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (a+a*1i))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (a*1i+a))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (-a+a*-1i))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (-a+-a*1i))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (-a-a*1i))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (a*-1i-a))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (-a*1i-a))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (a*-1i+-a))
+    link_error();
+
+  if (fabs(a) * __builtin_sqrt(2) != cabs (-a*1i+-a))
+    link_error();
+
+  if (fabs(a*b) * __builtin_sqrt(2) != cabs (a*b-(-b*a*1i)))
+    link_error();
+
+  if (fabs(a*b) * __builtin_sqrt(2) != cabs (a*b*1i-a*-b))
+    link_error();
 }

-void testf(__complex__ float x)
+void testf(__complex__ float x, float a, float b)
 {
   if (cabsf(x) != cabsf(-x))
     link_error();

   if (cabsf(x) != cabsf(~x))
     link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (a+a*1i))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (a*1i+a))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (-a+a*-1i))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (-a+-a*1i))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (-a-a*1i))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (a*-1i-a))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (-a*1i-a))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (a*-1i+-a))
+    link_error();
+
+  if (fabsf(a) * __builtin_sqrtf(2) != cabsf (-a*1i+-a))
+    link_error();
+
+  if (fabsf(a*b) * __builtin_sqrtf(2) != cabsf (a*b-(-b*a*1i)))
+    link_error();
+
+  if (fabsf(a*b) * __builtin_sqrtf(2) != cabsf (a*b*1i-a*-b))
+    link_error();
 }

-void testl(__complex__ long double x)
+void testl(__complex__ long double x, long double a, long double b)
 {
   if (cabsl(x) != cabsl(-x))
     link_error();

   if (cabsl(x) != cabsl(~x))
     link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (a+a*1i))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (a*1i+a))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (-a+a*-1i))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (-a+-a*1i))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (-a-a*1i))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (a*-1i-a))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (-a*1i-a))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (a*-1i+-a))
+    link_error();
+
+  if (fabsl(a) * __builtin_sqrtl(2) != cabsl (-a*1i+-a))
+    link_error();
+
+  if (fabsl(a*b) * __builtin_sqrtl(2) != cabsl (a*b-(-b*a*1i)))
+    link_error();
+
+  if (fabsl(a*b) * __builtin_sqrtl(2) != cabsl (a*b*1i-a*-b))
+    link_error();
 }

 int main()
 {
-  test(0.0);
-  testf(0.0);
-  testl(0.0);
+  test(0, 0, 0);
+  testf(0, 0, 0);
+  testl(0, 0, 0);
   return 0;
 }


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