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]

[Committed] PR23452: Optimize z*conj(z) for complex z


The following patch resolves PR tree-optimization/23452 by adding
code to fold_binary to recognize the common z*~z idiom and expand it
to (typeof(z))(realpart(z)*realpart(z) + imagpart(z)*imagpart(z)).
This is always safe for integral complex types, but can only
be applied to FP complex types with -ffast-math, as non-finite
imaginary components of z (such as Inf and NaN) mean that the
imaginary component of the result won't disappear to zero.

The following patch has been tested on x86_64-unknown-linux-gnu with
a full "make bootstrap", all default languages, and regression tested
with a top-level "make -k check" with no new failures.

Committed to mainline as revision 114246.



2006-05-30  Roger Sayle  <roger@eyesopen.com>

	PR tree-optimization/23452
	* fold-const.c (fold_mult_zconjz): New subroutine of fold_binary,
	to optimize z * conj(z) as realpart(z)^2 + imagpart(z)^2.
	(fold_binary) <MULT_EXPR>: Call fold_mult_zconjz for integral
	complex values and with -ffast-math for FP complex values.

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


Index: fold-const.c
===================================================================
*** fold-const.c	(revision 114206)
--- fold-const.c	(working copy)
*************** fold_comparison (enum tree_code code, tr
*** 8105,8110 ****
--- 8105,8148 ----
    return NULL_TREE;
  }

+
+ /* Subroutine of fold_binary.  Optimize complex multiplications of the
+    form z * conj(z), as pow(realpart(z),2) + pow(imagpart(z),2).  The
+    argument EXPR represents the expression "z" of type TYPE.  */
+
+ static tree
+ fold_mult_zconjz (tree type, tree expr)
+ {
+   tree itype = TREE_TYPE (type);
+   tree rpart, ipart, tem;
+
+   if (TREE_CODE (expr) == COMPLEX_EXPR)
+     {
+       rpart = TREE_OPERAND (expr, 0);
+       ipart = TREE_OPERAND (expr, 1);
+     }
+   else if (TREE_CODE (expr) == COMPLEX_CST)
+     {
+       rpart = TREE_REALPART (expr);
+       ipart = TREE_IMAGPART (expr);
+     }
+   else
+     {
+       expr = save_expr (expr);
+       rpart = fold_build1 (REALPART_EXPR, itype, expr);
+       ipart = fold_build1 (IMAGPART_EXPR, itype, expr);
+     }
+
+   rpart = save_expr (rpart);
+   ipart = save_expr (ipart);
+   tem = fold_build2 (PLUS_EXPR, itype,
+ 		     fold_build2 (MULT_EXPR, itype, rpart, rpart),
+ 		     fold_build2 (MULT_EXPR, itype, ipart, ipart));
+   return fold_build2 (COMPLEX_EXPR, type, tem,
+ 		      fold_convert (itype, integer_zero_node));
+ }
+
+
  /* Fold a binary expression of code CODE and type TYPE with operands
     OP0 and OP1.  Return the folded expression if folding is
     successful.  Otherwise, return NULL_TREE.  */
*************** fold_binary (enum tree_code code, tree t
*** 8768,8773 ****
--- 8806,8818 ----
  					     code, NULL_TREE)))
  	    return fold_convert (type, tem);

+ 	  /* Optimize z * conj(z) for integer complex numbers.  */
+ 	  if (TREE_CODE (arg0) == CONJ_EXPR
+ 	      && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+ 	    return fold_mult_zconjz (type, arg1);
+ 	  if (TREE_CODE (arg1) == CONJ_EXPR
+ 	      && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+ 	    return fold_mult_zconjz (type, arg0);
  	}
        else
  	{
*************** fold_binary (enum tree_code code, tree t
*** 8813,8818 ****
--- 8858,8875 ----
  		}
  	    }

+ 	  /* Optimize z * conj(z) for floating point complex numbers.
+ 	     Guarded by flag_unsafe_math_optimizations as non-finite
+ 	     imaginary components don't produce scalar results.  */
+ 	  if (flag_unsafe_math_optimizations
+ 	      && TREE_CODE (arg0) == CONJ_EXPR
+ 	      && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+ 	    return fold_mult_zconjz (type, arg1);
+ 	  if (flag_unsafe_math_optimizations
+ 	      && TREE_CODE (arg1) == CONJ_EXPR
+ 	      && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+ 	    return fold_mult_zconjz (type, arg0);
+
  	  if (flag_unsafe_math_optimizations)
  	    {
  	      enum built_in_function fcode0 = builtin_mathfn_code (arg0);


/* PR tree-optimization/23452 */
/* { dg-do compile } */
/* { dg-options "-O2 -ffast-math -fdump-tree-gimple" } */

_Complex double foo(_Complex double z)
{
  return z * ~z;
}

_Complex int bar(_Complex int z)
{
  return z * ~z;
}

/* { dg-final { scan-tree-dump-times "CONJ_EXPR" 0 "gimple" } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */



Roger
--


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