OSDN Git Service

PR middle-end/19953
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 24 Feb 2005 20:00:09 +0000 (20:00 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 24 Feb 2005 20:00:09 +0000 (20:00 +0000)
        * 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@95511 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/builtins.c
gcc/fold-const.c
gcc/testsuite/gcc.dg/tree-ssa/complex-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/complex-2.c [new file with mode: 0644]
gcc/tree.h

index 7677cf8..3e2bcb4 100644 (file)
@@ -1,3 +1,14 @@
+2005-02-24  Richard Henderson  <rth@redhat.com>
+
+       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.
+
 2005-02-24  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
 
        * tree-ssa-ccp.c (visit_assignment): Verify that result of
index f0dd878..078edc3 100644 (file)
@@ -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 a75ccdc..5c3139c 100644 (file)
@@ -6336,26 +6336,12 @@ fold_complex_add (tree type, tree ac, tree bc, enum tree_code code)
 /* 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, tree bc)
     }
   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, tree bc)
   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:
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/complex-1.c b/gcc/testsuite/gcc.dg/tree-ssa/complex-1.c
new file mode 100644 (file)
index 0000000..7dff01c
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/complex-2.c b/gcc/testsuite/gcc.dg/tree-ssa/complex-2.c
new file mode 100644 (file)
index 0000000..ce72eb2
--- /dev/null
@@ -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 62e9bb3..81992f9 100644 (file)
@@ -3549,6 +3549,9 @@ extern tree build_fold_indirect_ref (tree);
 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);