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]

fix middle-end/19953


I suspect this may in fact generate better code for flag_complex_method = 2
than flag_complex_method = 1, due to being able to delay expanding to 
scalar operations until after tree-level cse has been able to propagate
zeros to where we can see them.

For 4.1, we should look into delaying complex expansion with optimization
until after at least the first dom pass.

Tested on i686-linux.


r~



        PR middle-end/19953
        * builtins.c (fold_builtin_complex_mul, fold_builtin_complex_div): New.
        (fold_builtin_1): Call them.
        * fold-const.c (fold_complex_mult_parts): Split out from ...
        (fold_complex_mult): ... here.  Fix typo in both imaginary case.
        (fold_complex_div_parts, fold_complex_div): New.
        (fold): Use them.
        * tree.h (fold_complex_mult_parts, fold_complex_div_parts): Declare.

Index: gcc/builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.425
diff -u -p -d -r1.425 builtins.c
--- gcc/builtins.c	20 Feb 2005 17:01:14 -0000	1.425
+++ gcc/builtins.c	24 Feb 2005 19:50:01 -0000
@@ -7843,6 +7843,44 @@ fold_builtin_unordered_cmp (tree exp,
 		       fold (build2 (code, type, arg0, arg1))));
 }
 
+/* Fold a call to one of the external complex multiply libcalls.  */
+
+static tree
+fold_builtin_complex_mul (tree type, tree arglist)
+{
+  tree ar, ai, br, bi;
+
+  if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, REAL_TYPE,
+			 REAL_TYPE, VOID_TYPE))
+    return NULL;
+
+  ar = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
+  ai = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
+  br = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
+  bi = TREE_VALUE (arglist);
+
+  return fold_complex_mult_parts (type, ar, ai, br, bi);
+}
+
+/* Fold a call to one of the external complex division libcalls.  */
+
+static tree
+fold_builtin_complex_div (tree type, tree arglist)
+{
+  tree ar, ai, br, bi;
+
+  if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, REAL_TYPE,
+			 REAL_TYPE, VOID_TYPE))
+    return NULL;
+
+  ar = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
+  ai = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
+  br = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
+  bi = TREE_VALUE (arglist);
+
+  return fold_complex_div_parts (type, ar, ai, br, bi, RDIV_EXPR);
+}
+
 /* Used by constant folding to simplify calls to builtin functions.  EXP is
    the CALL_EXPR of a call to a builtin function.  IGNORE is true if the
    result of the function call is ignored.  This function returns NULL_TREE
@@ -7854,11 +7892,13 @@ fold_builtin_1 (tree exp, bool ignore)
   tree fndecl = get_callee_fndecl (exp);
   tree arglist = TREE_OPERAND (exp, 1);
   tree type = TREE_TYPE (TREE_TYPE (fndecl));
+  enum built_in_function fcode;
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
     return targetm.fold_builtin (exp, ignore);
 
-  switch (DECL_FUNCTION_CODE (fndecl))
+  fcode = DECL_FUNCTION_CODE (fndecl);
+  switch (fcode)
     {
     case BUILT_IN_FPUTS:
       return fold_builtin_fputs (arglist, ignore, false, NULL_TREE);
@@ -8188,6 +8228,12 @@ fold_builtin_1 (tree exp, bool ignore)
       break;
 
     default:
+      if (fcode >= BUILT_IN_COMPLEX_MUL_MIN
+	  && fcode <= BUILT_IN_COMPLEX_MUL_MAX)
+	return fold_builtin_complex_mul (type, arglist);
+      if (fcode >= BUILT_IN_COMPLEX_DIV_MIN
+	  && fcode <= BUILT_IN_COMPLEX_DIV_MAX)
+	return fold_builtin_complex_div (type, arglist);
       break;
     }
 
Index: gcc/fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.516
diff -u -p -d -r1.516 fold-const.c
--- gcc/fold-const.c	18 Feb 2005 21:44:18 -0000	1.516
+++ gcc/fold-const.c	24 Feb 2005 19:50:04 -0000
@@ -6336,26 +6336,12 @@ fold_complex_add (tree type, tree ac, tr
 /* Perform some simplifications of complex multiplication when one or more
    of the components are constants or zeros.  Return non-null if successful.  */
 
-static tree
-fold_complex_mult (tree type, tree ac, tree bc)
+tree
+fold_complex_mult_parts (tree type, tree ar, tree ai, tree br, tree bi)
 {
-  tree ar, ai, br, bi, rr, ri, inner_type, zero;
+  tree rr, ri, inner_type, zero;
   bool ar0, ai0, br0, bi0, bi1;
 
-  if (TREE_CODE (ac) == COMPLEX_EXPR)
-    ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
-  else if (TREE_CODE (ac) == COMPLEX_CST)
-    ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
-  else
-    return NULL;
-
-  if (TREE_CODE (bc) == COMPLEX_EXPR)
-    br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
-  else if (TREE_CODE (bc) == COMPLEX_CST)
-    br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
-  else
-    return NULL;
-
   inner_type = TREE_TYPE (type);
   zero = NULL;
 
@@ -6432,7 +6418,7 @@ fold_complex_mult (tree type, tree ac, t
     }
   else if (ar0 && br0)
     {
-      rr = fold (build2 (MULT_EXPR, inner_type, ai, br));
+      rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
       rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
       ri = zero;
     }
@@ -6464,6 +6450,152 @@ fold_complex_mult (tree type, tree ac, t
   return fold (build2 (COMPLEX_EXPR, type, rr, ri));
 }
 
+static tree
+fold_complex_mult (tree type, tree ac, tree bc)
+{
+  tree ar, ai, br, bi;
+
+  if (TREE_CODE (ac) == COMPLEX_EXPR)
+    ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
+  else if (TREE_CODE (ac) == COMPLEX_CST)
+    ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
+  else
+    return NULL;
+
+  if (TREE_CODE (bc) == COMPLEX_EXPR)
+    br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
+  else if (TREE_CODE (bc) == COMPLEX_CST)
+    br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
+  else
+    return NULL;
+
+  return fold_complex_mult_parts (type, ar, ai, br, bi);
+}
+
+/* Perform some simplifications of complex division when one or more of
+   the components are constants or zeros.  Return non-null if successful.  */
+
+tree
+fold_complex_div_parts (tree type, tree ar, tree ai, tree br, tree bi,
+			enum tree_code code)
+{
+  tree rr, ri, inner_type, zero;
+  bool ar0, ai0, br0, bi0, bi1;
+
+  inner_type = TREE_TYPE (type);
+  zero = NULL;
+
+  if (SCALAR_FLOAT_TYPE_P (inner_type))
+    {
+      ar0 = ai0 = br0 = bi0 = bi1 = false;
+
+      /* We're only interested in +0.0 here, thus we don't use real_zerop.  */
+
+      if (TREE_CODE (ar) == REAL_CST
+	  && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ar), dconst0))
+	ar0 = true, zero = ar;
+
+      if (TREE_CODE (ai) == REAL_CST
+	  && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ai), dconst0))
+	ai0 = true, zero = ai;
+
+      if (TREE_CODE (br) == REAL_CST
+	  && REAL_VALUES_IDENTICAL (TREE_REAL_CST (br), dconst0))
+	br0 = true, zero = br;
+
+      if (TREE_CODE (bi) == REAL_CST)
+	{
+	  if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst0))
+	    bi0 = true, zero = bi;
+	  else if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst1))
+	    bi1 = true;
+	}
+    }
+  else
+    {
+      ar0 = integer_zerop (ar);
+      if (ar0)
+	zero = ar;
+      ai0 = integer_zerop (ai);
+      if (ai0)
+	zero = ai;
+      br0 = integer_zerop (br);
+      if (br0)
+	zero = br;
+      bi0 = integer_zerop (bi);
+      if (bi0)
+	{
+	  zero = bi;
+	  bi1 = false;
+	}
+      else
+	bi1 = integer_onep (bi);
+    }
+
+  /* We won't optimize anything below unless something is zero.  */
+  if (zero == NULL)
+    return NULL;
+
+  if (ai0 && bi0)
+    {
+      rr = fold (build2 (code, inner_type, ar, br));
+      ri = zero;
+    }
+  else if (ai0 && br0)
+    {
+      rr = zero;
+      ri = fold (build2 (code, inner_type, ar, bi));
+      ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
+    }
+  else if (ar0 && bi0)
+    {
+      rr = zero;
+      ri = fold (build2 (code, inner_type, ai, br));
+    }
+  else if (ar0 && br0)
+    {
+      rr = fold (build2 (code, inner_type, ai, bi));
+      ri = zero;
+    }
+  else if (bi0)
+    {
+      rr = fold (build2 (code, inner_type, ar, br));
+      ri = fold (build2 (code, inner_type, ai, br));
+    }
+  else if (br0)
+    {
+      rr = fold (build2 (code, inner_type, ai, bi));
+      ri = fold (build2 (code, inner_type, ar, bi));
+      ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
+    }
+  else
+    return NULL;
+
+  return fold (build2 (COMPLEX_EXPR, type, rr, ri));
+}
+
+static tree
+fold_complex_div (tree type, tree ac, tree bc, enum tree_code code)
+{
+  tree ar, ai, br, bi;
+
+  if (TREE_CODE (ac) == COMPLEX_EXPR)
+    ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
+  else if (TREE_CODE (ac) == COMPLEX_CST)
+    ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
+  else
+    return NULL;
+
+  if (TREE_CODE (bc) == COMPLEX_EXPR)
+    br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
+  else if (TREE_CODE (bc) == COMPLEX_CST)
+    br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
+  else
+    return NULL;
+
+  return fold_complex_div_parts (type, ar, ai, br, bi, code);
+}
+
 /* Perform constant folding and related simplification of EXPR.
    The related simplifications include x*1 => x, x*0 => 0, etc.,
    and application of the associative law.
@@ -8042,6 +8174,13 @@ fold (tree expr)
 				 TREE_OPERAND (arg1, 0)));
 	}
 
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+	{
+	  tem = fold_complex_div (type, arg0, arg1, code);
+	  if (tem)
+	    return tem;
+	}
+
       if (flag_unsafe_math_optimizations)
 	{
 	  enum built_in_function fcode = builtin_mathfn_code (arg1);
@@ -8166,6 +8305,12 @@ fold (tree expr)
 					 code, NULL_TREE)))
 	return fold_convert (type, tem);
 
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+	{
+	  tem = fold_complex_div (type, arg0, arg1, code);
+	  if (tem)
+	    return tem;
+	}
       goto binary;
 
     case CEIL_MOD_EXPR:
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.692
diff -u -p -d -r1.692 tree.h
--- gcc/tree.h	14 Feb 2005 16:07:16 -0000	1.692
+++ gcc/tree.h	24 Feb 2005 19:50:04 -0000
@@ -3549,6 +3549,9 @@ extern tree build_fold_indirect_ref (tre
 extern tree fold_indirect_ref (tree);
 extern tree constant_boolean_node (int, tree);
 extern tree build_low_bits_mask (tree, unsigned);
+extern tree fold_complex_mult_parts (tree, tree, tree, tree, tree);
+extern tree fold_complex_div_parts (tree, tree, tree, tree, tree,
+				    enum tree_code);
 
 extern bool tree_swap_operands_p (tree, tree, bool);
 extern enum tree_code swap_tree_comparison (enum tree_code);
Index: gcc/testsuite/gcc.dg/tree-ssa/complex-1.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/tree-ssa/complex-1.c
diff -N gcc/testsuite/gcc.dg/tree-ssa/complex-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/tree-ssa/complex-1.c	24 Feb 2005 19:50:04 -0000
@@ -0,0 +1,12 @@
+/* Verify that we don't libcall for complex * real.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -O -fdump-tree-optimized" } */
+
+typedef _Complex float C;
+
+C foo(C x, float y)
+{
+  return x * y;
+}
+
+/* { dg-final { scan-tree-dump-times "__mul" 0 "optimized" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/complex-2.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/tree-ssa/complex-2.c
diff -N gcc/testsuite/gcc.dg/tree-ssa/complex-2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/tree-ssa/complex-2.c	24 Feb 2005 19:50:04 -0000
@@ -0,0 +1,12 @@
+/* Verify that we don't libcall for complex / real.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -O -fdump-tree-optimized" } */
+
+typedef _Complex float C;
+
+C foo(C x, float y)
+{
+  return x / y;
+}
+
+/* { dg-final { scan-tree-dump-times "__div" 0 "optimized" } } */


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