tree-complex.c (expand_complex_libcall): New.
authorRichard Henderson <rth@redhat.com>
Sat, 12 Feb 2005 00:26:57 +0000 (16:26 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Sat, 12 Feb 2005 00:26:57 +0000 (16:26 -0800)
        * tree-complex.c (expand_complex_libcall): New.
        (expand_complex_multiplication): Use it for c99 compliance.
        (expand_complex_division): Likewise.
        * fold-const.c (fold_complex_add, fold_complex_mult): New.
        (fold): Call them.
        * builtins.c (built_in_names): Remove const.
        * tree.c (build_common_builtin_nodes): Build complex arithmetic
        builtins.
        * tree.h (BUILT_IN_COMPLEX_MUL_MIN, BUILT_IN_COMPLEX_MUL_MAX): New.
        (BUILT_IN_COMPLEX_DIV_MIN, BUILT_IN_COMPLEX_DIV_MAX): New.
        (built_in_names): Remove const.
        * c-common.c (c_common_type_for_mode): Handle complex modes.
        * flags.h, toplev.c (flag_complex_method): Rename from
        flag_complex_divide_method.
        * libgcc2.c (__divsc3, __divdc3, __divxc3, __divtc3,
        __mulsc3, __muldc3, __mulxc3, __multc3): New.
        * libgcc2.h: Declare them.
        * libgcc-std.ver: Export them.
        * mklibgcc.in (lib2funcs): Build them.

From-SVN: r94909

13 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/c-common.c
gcc/flags.h
gcc/fold-const.c
gcc/libgcc-std.ver
gcc/libgcc2.c
gcc/libgcc2.h
gcc/mklibgcc.in
gcc/toplev.c
gcc/tree-complex.c
gcc/tree.c
gcc/tree.h

index f8348f343e8475238b18823d03c0a5accd9f653f..71e5b1510552df1d0f7827406d86068aa01eadfb 100644 (file)
@@ -1,3 +1,25 @@
+2005-02-11  Richard Henderson  <rth@redhat.com>
+
+       * tree-complex.c (expand_complex_libcall): New.
+       (expand_complex_multiplication): Use it for c99 compliance.
+       (expand_complex_division): Likewise.
+       * fold-const.c (fold_complex_add, fold_complex_mult): New.
+       (fold): Call them.
+       * builtins.c (built_in_names): Remove const.
+       * tree.c (build_common_builtin_nodes): Build complex arithmetic
+       builtins.
+       * tree.h (BUILT_IN_COMPLEX_MUL_MIN, BUILT_IN_COMPLEX_MUL_MAX): New.
+       (BUILT_IN_COMPLEX_DIV_MIN, BUILT_IN_COMPLEX_DIV_MAX): New.
+       (built_in_names): Remove const.
+       * c-common.c (c_common_type_for_mode): Handle complex modes.
+       * flags.h, toplev.c (flag_complex_method): Rename from
+       flag_complex_divide_method.
+       * libgcc2.c (__divsc3, __divdc3, __divxc3, __divtc3,
+       __mulsc3, __muldc3, __mulxc3, __multc3): New.
+       * libgcc2.h: Declare them.
+       * libgcc-std.ver: Export them.
+       * mklibgcc.in (lib2funcs): Build them.
+
 2005-02-11  Steven Bosscher  <stevenb@suse.de>
 
        PR tree-optimization/19876
index a20624015368e5ba88404c7a394871c0de983c31..420e5dee522f108b378e858a404472f1326186aa 100644 (file)
@@ -60,7 +60,7 @@ const char *const built_in_class_names[4]
   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
 
 #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X,
-const char *const built_in_names[(int) END_BUILTINS] =
+const char * built_in_names[(int) END_BUILTINS] =
 {
 #include "builtins.def"
 };
index 15f364800c6b2fdcc5070e6cc4b95b8332cb16d8..b414915bc872ca18bba608fa9343672c7e9dbdd2 100644 (file)
@@ -1611,7 +1611,27 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp)
   if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
     return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode);
 
-  if (VECTOR_MODE_P (mode))
+  if (COMPLEX_MODE_P (mode))
+    {
+      enum machine_mode inner_mode;
+      tree inner_type;
+
+      if (mode == TYPE_MODE (complex_float_type_node))
+       return complex_float_type_node;
+      if (mode == TYPE_MODE (complex_double_type_node))
+       return complex_double_type_node;
+      if (mode == TYPE_MODE (complex_long_double_type_node))
+       return complex_long_double_type_node;
+
+      if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+       return complex_integer_type_node;
+
+      inner_mode = GET_MODE_INNER (mode);
+      inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+      if (inner_type != NULL_TREE)
+       return build_complex_type (inner_type);
+    }
+  else if (VECTOR_MODE_P (mode))
     {
       enum machine_mode inner_mode = GET_MODE_INNER (mode);
       tree inner_type = c_common_type_for_mode (inner_mode, unsignedp);
index 91e719a0807ed95078c7a89afa026c5afea71d9f..cb8c100350ee5a1600b52c584632b787dc3c6b9e 100644 (file)
@@ -145,9 +145,9 @@ extern int flag_pcc_struct_return;
 
 /* 0 means straightforward implementation of complex divide acceptable.
    1 means wide ranges of inputs must work for complex divide.
-   2 means C99-like requirements for complex divide (not yet implemented).  */
+   2 means C99-like requirements for complex multiply and divide.  */
 
-extern int flag_complex_divide_method;
+extern int flag_complex_method;
 
 /* Nonzero means that we don't want inlining by virtue of -fno-inline,
    not just because the tree inliner turned us off.  */
index 0d732730426a4c22d5acce94ffea0fb6ae0b7f9a..5d6e5c5085467247c1f9f34607c811fce47de56a 100644 (file)
@@ -6306,6 +6306,168 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
   return fold (build2 (GE_EXPR, type, a, y));
 }
 
+/* Fold complex addition when both components are accessible by parts.
+   Return non-null if successful.  CODE should be PLUS_EXPR for addition,
+   or MINUS_EXPR for subtraction.  */
+
+static tree
+fold_complex_add (tree type, tree ac, tree bc, enum tree_code code)
+{
+  tree ar, ai, br, bi, rr, ri, inner_type;
+
+  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);
+
+  rr = fold (build2 (code, inner_type, ar, br));  
+  ri = fold (build2 (code, inner_type, ai, bi));  
+
+  return fold (build2 (COMPLEX_EXPR, type, rr, ri));
+}
+
+/* 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 ar, ai, br, bi, 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;
+
+  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 && br0 && bi1)
+    {
+      rr = zero;
+      ri = ar;
+    }
+  else if (ai0 && bi0)
+    {
+      rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
+      ri = zero;
+    }
+  else if (ai0 && br0)
+    {
+      rr = zero;
+      ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
+    }
+  else if (ar0 && bi0)
+    {
+      rr = zero;
+      ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
+    }
+  else if (ar0 && br0)
+    {
+      rr = fold (build2 (MULT_EXPR, inner_type, ai, br));
+      rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
+      ri = zero;
+    }
+  else if (bi0)
+    {
+      rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
+      ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
+    }
+  else if (ai0)
+    {
+      rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
+      ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
+    }
+  else if (br0)
+    {
+      rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
+      rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
+      ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
+    }
+  else if (ar0)
+    {
+      rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
+      rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
+      ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
+    }
+  else
+    return NULL;
+
+  return fold (build2 (COMPLEX_EXPR, type, rr, ri));
+}
+
 /* 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.
@@ -6833,6 +6995,14 @@ fold (tree expr)
       if (TREE_CODE (arg0) == NEGATE_EXPR
          && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
        return fold (build2 (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
+
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+       {
+         tem = fold_complex_add (type, arg0, arg1, PLUS_EXPR);
+         if (tem)
+           return tem;
+       }
+
       if (! FLOAT_TYPE_P (type))
        {
          if (integer_zerop (arg1))
@@ -7264,6 +7434,13 @@ fold (tree expr)
        return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
                             TREE_OPERAND (arg0, 0)));
 
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+       {
+         tem = fold_complex_add (type, arg0, arg1, MINUS_EXPR);
+         if (tem)
+           return tem;
+       }
+
       if (! FLOAT_TYPE_P (type))
        {
          if (! wins && integer_zerop (arg0))
@@ -7392,6 +7569,13 @@ fold (tree expr)
                             negate_expr (arg0),
                             TREE_OPERAND (arg1, 0)));
 
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+       {
+         tem = fold_complex_mult (type, arg0, arg1);
+         if (tem)
+           return tem;
+       }
+
       if (! FLOAT_TYPE_P (type))
        {
          if (integer_zerop (arg1))
index b701fcf95339291e7e843f736a8f654e4fbde688..341cf7a481bc27029905899882fe3e2db11ef4c0 100644 (file)
@@ -241,4 +241,14 @@ GCC_4.0.0 {
   __powidf2
   __powixf2
   __powitf2
-}
\ No newline at end of file
+
+  # c99 compliant complex arithmetic
+  __divsc3
+  __divdc3
+  __divxc3
+  __divtc3
+  __mulsc3
+  __muldc3
+  __mulxc3
+  __multc3
+}
index 9d12d32c5eb288d7bdc00c8aea4eb61d983659d2..df2ecb7a4e536d94dfb235798c94b485d7c19130 100644 (file)
@@ -1501,6 +1501,208 @@ NAME (TYPE x, Wtype m)
 
 #endif
 \f
+#if defined(L_mulsc3) || defined(L_divsc3) \
+    || defined(L_muldc3) || defined(L_divdc3) \
+    || (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80 \
+       && (defined(L_mulxc3) || defined(L_divxc3))) \
+    || (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128 \
+       && (defined(L_multc3) || defined(L_divtc3)))
+
+#undef float
+#undef double
+#undef long
+
+#if defined(L_mulsc3) || defined(L_divsc3)
+# define MTYPE SFtype
+# define CTYPE SCtype
+# define MODE  sc
+# define CEXT  f
+# define NOTRUNC __FLT_EVAL_METHOD__ == 0
+#elif defined(L_muldc3) || defined(L_divdc3)
+# define MTYPE DFtype
+# define CTYPE DCtype
+# define MODE  dc
+# if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 64
+#  define CEXT l
+#  define NOTRUNC 1
+# else
+#  define CEXT
+#  define NOTRUNC __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1
+# endif
+#elif defined(L_mulxc3) || defined(L_divxc3)
+# define MTYPE XFtype
+# define CTYPE XCtype
+# define MODE  xc
+# define CEXT  l
+# define NOTRUNC 1
+#elif defined(L_multc3) || defined(L_divtc3)
+# define MTYPE TFtype
+# define CTYPE TCtype
+# define MODE  tc
+# define CEXT  l
+# define NOTRUNC 1
+#else
+# error
+#endif
+
+#define CONCAT3(A,B,C) _CONCAT3(A,B,C)
+#define _CONCAT3(A,B,C)        A##B##C
+
+#define CONCAT2(A,B)   _CONCAT2(A,B)
+#define _CONCAT2(A,B)  A##B
+
+/* All of these would be present in a full C99 implementation of <math.h>
+   and <complex.h>.  Our problem is that only a few systems have such full
+   implementations.  Further, libgcc_s.so isn't currenly linked against
+   libm.so, and even for systems that do provide full C99, the extra overhead
+   of all programs using libgcc having to link against libm.  So avoid it.  */
+
+#define isnan(x)       __builtin_expect ((x) != (x), 0)
+#define isfinite(x)    __builtin_expect (!isnan((x) - (x)), 1)
+#define isinf(x)       __builtin_expect (!isnan(x) & !isfinite(x), 0)
+
+#define INFINITY       CONCAT2(__builtin_inf, CEXT) ()
+#define I              1i
+
+/* Helpers to make the following code slightly less gross.  */
+#define COPYSIGN       CONCAT2(__builtin_copysign, CEXT)
+#define FABS           CONCAT2(__builtin_fabs, CEXT)
+
+/* Verify that MTYPE matches up with CEXT.  */
+extern void *compile_type_assert[sizeof(INFINITY) == sizeof(MTYPE) ? 1 : -1];
+
+/* Ensure that we've lost any extra precision.  */
+#if NOTRUNC
+# define TRUNC(x)
+#else
+# define TRUNC(x)      __asm__ ("" : "=m"(x) : "m"(x))
+#endif
+
+#if defined(L_mulsc3) || defined(L_muldc3) \
+    || defined(L_mulxc3) || defined(L_multc3)
+
+CTYPE
+CONCAT3(__mul,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d)
+{
+  MTYPE ac, bd, ad, bc, x, y;
+
+  ac = a * c;
+  bd = b * d;
+  ad = a * d;
+  bc = b * c;
+
+  TRUNC (ac);
+  TRUNC (bd);
+  TRUNC (ad);
+  TRUNC (bc);
+
+  x = ac - bd;
+  y = ad + bc;
+
+  if (isnan (x) && isnan (y))
+    {
+      /* Recover infinities that computed as NaN + iNaN.  */
+      _Bool recalc = 0;
+      if (isinf (a) || isinf (b))
+       {
+         /* z is infinite.  "Box" the infinity and change NaNs in
+            the other factor to 0.  */
+         a = COPYSIGN (isinf (a) ? 1 : 0, a);
+         b = COPYSIGN (isinf (b) ? 1 : 0, b);
+         if (isnan (c)) c = COPYSIGN (0, c);
+         if (isnan (d)) d = COPYSIGN (0, d);
+          recalc = 1;
+       }
+     if (isinf (c) || isinf (d))
+       {
+         /* w is infinite.  "Box" the infinity and change NaNs in
+            the other factor to 0.  */
+         c = COPYSIGN (isinf (c) ? 1 : 0, c);
+         d = COPYSIGN (isinf (d) ? 1 : 0, d);
+         if (isnan (a)) a = COPYSIGN (0, a);
+         if (isnan (b)) b = COPYSIGN (0, b);
+         recalc = 1;
+       }
+     if (!recalc
+         && (isinf (ac) || isinf (bd)
+             || isinf (ad) || isinf (bc)))
+       {
+         /* Recover infinities from overflow by changing NaNs to 0.  */
+         if (isnan (a)) a = COPYSIGN (0, a);
+         if (isnan (b)) b = COPYSIGN (0, b);
+         if (isnan (c)) c = COPYSIGN (0, c);
+         if (isnan (d)) d = COPYSIGN (0, d);
+         recalc = 1;
+       }
+      if (recalc)
+       {
+         x = INFINITY * (a * c - b * d);
+         y = INFINITY * (a * d + b * c);
+       }
+    }
+
+  return x + I * y;
+}
+#endif /* complex multiply */
+
+#if defined(L_divsc3) || defined(L_divdc3) \
+    || defined(L_divxc3) || defined(L_divtc3)
+
+CTYPE
+CONCAT3(__div,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d)
+{
+  MTYPE denom, ratio, x, y;
+
+  /* ??? We can get better behaviour from logrithmic scaling instead of 
+     the division.  But that would mean starting to link libgcc against
+     libm.  We could implement something akin to ldexp/frexp as gcc builtins
+     fairly easily...  */
+  if (FABS (c) < FABS (d))
+    {
+      ratio = c / d;
+      denom = (c * ratio) + d;
+      x = ((a * ratio) + b) / denom;
+      y = ((b * ratio) - a) / denom;
+    }
+  else
+    {
+      ratio = d / c;
+      denom = (d * ratio) + c;
+      x = ((b * ratio) + a) / denom;
+      y = (b - (a * ratio)) / denom;
+    }
+
+  /* Recover infinities and zeros that computed as NaN+iNaN; the only cases
+     are non-zero/zero, infinite/finite, and finite/infinite.  */
+  if (isnan (x) && isnan (y))
+    {
+      if (denom == 0.0 && (!isnan (a) || !isnan (b)))
+       {
+         x = COPYSIGN (INFINITY, c) * a;
+         y = COPYSIGN (INFINITY, c) * b;
+       }
+      else if ((isinf (a) || isinf (b)) && isfinite (c) && isfinite (d))
+       {
+         a = COPYSIGN (isinf (a) ? 1 : 0, a);
+         b = COPYSIGN (isinf (b) ? 1 : 0, b);
+         x = INFINITY * (a * c + b * d);
+         y = INFINITY * (b * c - a * d);
+       }
+      else if ((isinf (c) || isinf (d)) && isfinite (a) && isfinite (b))
+       {
+         c = COPYSIGN (isinf (c) ? 1 : 0, c);
+         d = COPYSIGN (isinf (d) ? 1 : 0, d);
+         x = 0.0 * (a * c + b * d);
+         y = 0.0 * (b * c - a * d);
+       }
+    }
+
+  return x + I * y;
+}
+#endif /* complex divide */
+
+#endif /* all complex float routines */
+\f
 /* From here on down, the routines use normal data types.  */
 
 #define SItype bogus_type
@@ -1772,4 +1974,3 @@ func_ptr __DTOR_LIST__[2];
 #endif
 #endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
 #endif /* L_ctors */
-
index fb6d91485b70a9860bdc9577bedb86f0713838e4..165787316364e970491a751a9b8e514276f699d4 100644 (file)
@@ -92,12 +92,16 @@ typedef unsigned int UTItype        __attribute__ ((mode (TI)));
 
 typedef        float SFtype    __attribute__ ((mode (SF)));
 typedef                float DFtype    __attribute__ ((mode (DF)));
+typedef _Complex float SCtype  __attribute__ ((mode (SC)));
+typedef _Complex float DCtype  __attribute__ ((mode (DC)));
 
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80
 typedef                float XFtype    __attribute__ ((mode (XF)));
+typedef _Complex float XCtype  __attribute__ ((mode (XC)));
 #endif
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 typedef                float TFtype    __attribute__ ((mode (TF)));
+typedef _Complex float TCtype  __attribute__ ((mode (TC)));
 #endif
 
 #else /* BITS_PER_UNIT != 8 */
@@ -308,12 +312,19 @@ extern DWtype __fixunssfDI (SFtype);
 extern SFtype __powisf2 (SFtype, Wtype);
 extern DFtype __powidf2 (DFtype, Wtype);
 
+extern SCtype __divsc3 (SFtype, SFtype, SFtype, SFtype);
+extern SCtype __mulsc3 (SFtype, SFtype, SFtype, SFtype);
+extern DCtype __divdc3 (DFtype, DFtype, DFtype, DFtype);
+extern DCtype __muldc3 (DFtype, DFtype, DFtype, DFtype);
+
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80
 extern DWtype __fixxfdi (XFtype);
 extern DWtype __fixunsxfDI (XFtype);
 extern XFtype __floatdixf (DWtype);
 extern UWtype __fixunsxfSI (XFtype);
 extern XFtype __powixf2 (XFtype, Wtype);
+extern XCtype __divxc3 (XFtype, XFtype, XFtype, XFtype);
+extern XCtype __mulxc3 (XFtype, XFtype, XFtype, XFtype);
 #endif
 
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
@@ -321,6 +332,8 @@ extern DWtype __fixunstfDI (TFtype);
 extern DWtype __fixtfdi (TFtype);
 extern TFtype __floatditf (DWtype);
 extern TFtype __powitf2 (TFtype, Wtype);
+extern TCtype __divtc3 (TFtype, TFtype, TFtype, TFtype);
+extern TCtype __multc3 (TFtype, TFtype, TFtype, TFtype);
 #endif
 #endif /* BITS_PER_UNIT == 8 */
 
index 7ac1dbf24de0ad03f38e53eb16314ee9a9a2dee1..c88fca98186cb4fc1c8345e24d7c2714a49441ef 100644 (file)
@@ -62,7 +62,8 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
        _addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
        _ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
        _popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
-       _powixf2 _powitf2'
+       _powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3
+       _divxc3 _divtc3'
 
 # Disable SHLIB_LINK if shared libgcc not enabled.
 if [ "@enable_shared@" = "no" ]; then
index 2659997a9418078ef2d2bfe332fd54288df135d4..99704a4309053134360d2c114ee1785afda98c0f 100644 (file)
@@ -267,9 +267,9 @@ int flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN;
 
 /* 0 means straightforward implementation of complex divide acceptable.
    1 means wide ranges of inputs must work for complex divide.
-   2 means C99-like requirements for complex divide (not yet implemented).  */
+   2 means C99-like requirements for complex multiply and divide.  */
 
-int flag_complex_divide_method = 0;
+int flag_complex_method = 0;
 
 /* Nonzero means that we don't want inlining by virtue of -fno-inline,
    not just because the tree inliner turned us off.  */
index 3373326aad9190355b1a0fc84738cd8b9751a056..a5708f39a8e186f275a78392cfe26bf336a2132b 100644 (file)
@@ -105,6 +105,40 @@ expand_complex_addition (block_stmt_iterator *bsi, tree inner_type,
   update_complex_assignment (bsi, rr, ri);
 }
 
+/* Expand a complex multiplication or division to a libcall to the c99
+   compliant routines.  */
+
+static void
+expand_complex_libcall (block_stmt_iterator *bsi, tree ar, tree ai,
+                       tree br, tree bi, enum tree_code code)
+{
+  enum machine_mode mode;
+  enum built_in_function bcode;
+  tree args, fn, stmt, type;
+
+  args = tree_cons (NULL, bi, NULL);
+  args = tree_cons (NULL, br, args);
+  args = tree_cons (NULL, ai, args);
+  args = tree_cons (NULL, ar, args);
+
+  stmt = bsi_stmt (*bsi);
+  type = TREE_TYPE (TREE_OPERAND (stmt, 1));
+
+  mode = TYPE_MODE (type);
+  gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
+  if (code == MULT_EXPR)
+    bcode = BUILT_IN_COMPLEX_MUL_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
+  else if (code == RDIV_EXPR)
+    bcode = BUILT_IN_COMPLEX_DIV_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
+  else
+    gcc_unreachable ();
+  fn = built_in_decls[bcode];
+
+  TREE_OPERAND (stmt, 1)
+    = build3 (CALL_EXPR, type, build_fold_addr_expr (fn), args, NULL);
+  modify_stmt (stmt);
+}
+
 /* Expand complex multiplication to scalars:
        a * b = (ar*br - ai*bi) + i(ar*bi + br*ai)
 */
@@ -115,6 +149,12 @@ expand_complex_multiplication (block_stmt_iterator *bsi, tree inner_type,
 {
   tree t1, t2, t3, t4, rr, ri;
 
+  if (flag_complex_method == 2 && SCALAR_FLOAT_TYPE_P (inner_type))
+    {
+      expand_complex_libcall (bsi, ar, ai, br, bi, MULT_EXPR);
+      return;
+    }
+
   t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, br);
   t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, bi);
   t3 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, bi);
@@ -311,18 +351,27 @@ expand_complex_division (block_stmt_iterator *bsi, tree inner_type,
                         tree ar, tree ai, tree br, tree bi,
                         enum tree_code code)
 {
-  switch (flag_complex_divide_method)
+  switch (flag_complex_method)
     {
     case 0:
       /* straightforward implementation of complex divide acceptable.  */
       expand_complex_div_straight (bsi, inner_type, ar, ai, br, bi, code);
       break;
+
+    case 2:
+      if (SCALAR_FLOAT_TYPE_P (inner_type))
+       {
+         expand_complex_libcall (bsi, ar, ai, br, bi, code);
+         return;
+       }
+      /* FALLTHRU */
+
     case 1:
       /* wide ranges of inputs must work for complex divide.  */
       expand_complex_div_wide (bsi, inner_type, ar, ai, br, bi, code);
       break;
+
     default:
-      /* C99-like requirements for complex divide (not yet implemented).  */
       gcc_unreachable ();
     }
 }
index 3d41e114342cfef172dd74cfb06057ec543c3f16..3a0054c507e76d1d6a5397af6a3959e46748ea72 100644 (file)
@@ -5903,6 +5903,48 @@ build_common_builtin_nodes (void)
                        BUILT_IN_PROFILE_FUNC_ENTER, "profile_func_enter", 0);
   local_define_builtin ("__builtin_profile_func_exit", ftype,
                        BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit", 0);
+
+  /* Complex multiplication and division.  These are handled as builtins
+     rather than optabs because emit_library_call_value doesn't support
+     complex.  Further, we can do slightly better with folding these 
+     beasties if the real and complex parts of the arguments are separate.  */
+  {
+    enum machine_mode mode;
+
+    for (mode = MIN_MODE_COMPLEX_FLOAT; mode <= MAX_MODE_COMPLEX_FLOAT; ++mode)
+      {
+       char mode_name_buf[4], *q;
+       const char *p;
+       enum built_in_function mcode, dcode;
+       tree type, inner_type;
+
+       type = lang_hooks.types.type_for_mode (mode, 0);
+       if (type == NULL)
+         continue;
+       inner_type = TREE_TYPE (type);
+
+       tmp = tree_cons (NULL_TREE, inner_type, void_list_node);
+       tmp = tree_cons (NULL_TREE, inner_type, tmp);
+       tmp = tree_cons (NULL_TREE, inner_type, tmp);
+       tmp = tree_cons (NULL_TREE, inner_type, tmp);
+       ftype = build_function_type (type, tmp);
+
+        mcode = BUILT_IN_COMPLEX_MUL_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
+        dcode = BUILT_IN_COMPLEX_DIV_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
+
+        for (p = GET_MODE_NAME (mode), q = mode_name_buf; *p; p++, q++)
+         *q = TOLOWER (*p);
+       *q = '\0';
+
+       built_in_names[mcode] = concat ("__mul", mode_name_buf, "3", NULL);
+        local_define_builtin (built_in_names[mcode], ftype, mcode,
+                             built_in_names[mcode], ECF_CONST | ECF_NOTHROW);
+
+       built_in_names[dcode] = concat ("__div", mode_name_buf, "3", NULL);
+        local_define_builtin (built_in_names[dcode], ftype, dcode,
+                             built_in_names[dcode], ECF_CONST | ECF_NOTHROW);
+      }
+  }
 }
 
 /* HACK.  GROSS.  This is absolutely disgusting.  I wish there was a
index 4b14d3fdfe3b9b369fd3875b58bbfdd27ad8e8c2..dea3136e009bb67ed1ec2805e1328ae8bd02aed2 100644 (file)
@@ -187,13 +187,27 @@ enum built_in_function
 {
 #include "builtins.def"
 
+  /* Complex division routines in libgcc.  These are done via builtins
+     because emit_library_call_value can't handle complex values.  */
+  BUILT_IN_COMPLEX_MUL_MIN,
+  BUILT_IN_COMPLEX_MUL_MAX
+    = BUILT_IN_COMPLEX_MUL_MIN
+      + MAX_MODE_COMPLEX_FLOAT
+      - MIN_MODE_COMPLEX_FLOAT,
+
+  BUILT_IN_COMPLEX_DIV_MIN,
+  BUILT_IN_COMPLEX_DIV_MAX
+    = BUILT_IN_COMPLEX_DIV_MIN
+      + MAX_MODE_COMPLEX_FLOAT
+      - MIN_MODE_COMPLEX_FLOAT,
+
   /* Upper bound on non-language-specific builtins.  */
   END_BUILTINS
 };
 #undef DEF_BUILTIN
 
 /* Names for the above.  */
-extern const char *const built_in_names[(int) END_BUILTINS];
+extern const char * built_in_names[(int) END_BUILTINS];
 
 /* Helper macros for math builtins.  */