Blob Blame History Raw
2007-01-05  Jakub Jelinek  <jakub@redhat.com>

	PR c/30360
	* libgcc2.c (__divdc3): Compare c and d against 0.0 instead of
	denom against 0.0.

2005-11-22  Joseph S. Myers  <joseph@codesourcery.com>

	* libgcc-std.ver (GCC_4.2.0): New version.
	* libgcc2.c (__floatundixf, __floatunditf, __floatundidf,
	__floatundisf): New functions.
	* libgcc2.h (__floatundixf, __floatunditf, __floatundidf,
	__floatundisf): Declare.
	* mklibgcc.in (lib2funcs): Add _floatundidf, _floatundisf,
	_floatundixf, and _floatunditf.

2005-03-30 Fariborz Jahanian <fjahanian@apple.com>

	* libgcc2.h (__powisf2, __powidf2, __powixf2, __powitf2): Change
	2nd argument type to int.
	* libgcc2.c: Change prototype of __powi* functions to use
	int.

2005-02-11  Richard Henderson  <rth@redhat.com>

	* 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-09  Richard Guenther  <rguenth@gcc.gnu.org>

	PR middle-end/19402
	* libgcc2.h: Add prototypes for __builtin_powi[lf].
	* libgcc2.c: Add __builtin_powi[lf] implementation.
	* mklibgcc.in: Add __builtin_powi[lf] to lib2funcs.

--- gcc/libgcc-std.ver.jj	2007-03-02 09:27:16.000000000 +0100
+++ gcc/libgcc-std.ver	2007-03-02 10:32:27.000000000 +0100
@@ -235,7 +235,39 @@ GCC_3.4.4 {
   __subvti3
 }
 
-%inherit GCC_4.2.0 GCC_3.4.4
+%inherit GCC_4.0.0 GCC_3.4.4
+GCC_4.0.0 {
+  # libgcc2 __builtin_powi helpers.
+  __powisf2
+  __powidf2
+  __powixf2
+  __powitf2
+
+  # c99 compliant complex arithmetic
+  __divsc3
+  __divdc3
+  __divxc3
+  __divtc3
+  __mulsc3
+  __muldc3
+  __mulxc3
+  __multc3
+}
+
+%inherit GCC_4.2.0 GCC_4.0.0
 GCC_4.2.0 {
+  # unsigned-to-floating conversions
+  __floatunsisf
+  __floatunsidf
+  __floatunsixf
+  __floatunsitf
+  __floatundidf
+  __floatundisf
+  __floatundixf
+  __floatunditf
+  __floatuntidf
+  __floatuntisf
+  __floatuntixf
+  __floatuntitf
   _Unwind_GetIPInfo
 }
--- gcc/libgcc2.h.jj	2006-10-05 00:37:01.000000000 +0200
+++ gcc/libgcc2.h	2007-03-02 11:26:31.000000000 +0100
@@ -88,12 +88,16 @@ typedef unsigned int UTItype	__attribute
 
 typedef 	float SFtype	__attribute__ ((mode (SF)));
 typedef		float DFtype	__attribute__ ((mode (DF)));
+typedef _Complex float SCtype;
+typedef _Complex double DCtype;
 
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 typedef		float XFtype	__attribute__ ((mode (XF)));
+typedef _Complex long double XCtype;
 #endif
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 typedef		float TFtype	__attribute__ ((mode (TF)));
+typedef _Complex long double TCtype;
 #endif
 
 #else /* BITS_PER_UNIT != 8 */
@@ -216,6 +220,10 @@ typedef int word_type __attribute__ ((mo
 #define __floatditf	__NDW(float,tf)
 #define __floatdidf	__NDW(float,df)
 #define __floatdisf	__NDW(float,sf)
+#define __floatundixf	__NDW(floatun,xf)
+#define __floatunditf	__NDW(floatun,tf)
+#define __floatundidf	__NDW(floatun,df)
+#define __floatundisf	__NDW(floatun,sf)
 #define __fixunsxfSI	__NW(fixunsxf,)
 #define __fixunstfSI	__NW(fixunstf,)
 #define __fixunsdfSI	__NW(fixunsdf,)
@@ -293,27 +301,47 @@ extern SItype __negvsi2 (SItype);
 #endif /* COMPAT_SIMODE_TRAPPING_ARITHMETIC */
 
 #if BITS_PER_UNIT == 8
+#undef int
 extern DWtype __fixdfdi (DFtype);
 extern DWtype __fixsfdi (SFtype);
 extern DFtype __floatdidf (DWtype);
 extern SFtype __floatdisf (DWtype);
+extern DFtype __floatundidf (UDWtype);
+extern SFtype __floatundisf (UDWtype);
 extern UWtype __fixunsdfSI (DFtype);
 extern UWtype __fixunssfSI (SFtype);
 extern DWtype __fixunsdfDI (DFtype);
 extern DWtype __fixunssfDI (SFtype);
+extern SFtype __powisf2 (SFtype, int);
+extern DFtype __powidf2 (DFtype, int);
+
+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 == 96
 extern DWtype __fixxfdi (XFtype);
 extern DWtype __fixunsxfDI (XFtype);
 extern XFtype __floatdixf (DWtype);
+extern XFtype __floatundixf (UDWtype);
 extern UWtype __fixunsxfSI (XFtype);
+extern XFtype __powixf2 (XFtype, int);
+extern XCtype __divxc3 (XFtype, XFtype, XFtype, XFtype);
+extern XCtype __mulxc3 (XFtype, XFtype, XFtype, XFtype);
 #endif
 
 #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 extern DWtype __fixunstfDI (TFtype);
 extern DWtype __fixtfdi (TFtype);
 extern TFtype __floatditf (DWtype);
+extern TFtype __floatunditf (UDWtype);
+extern TFtype __powitf2 (TFtype, int);
+extern TCtype __divtc3 (TFtype, TFtype, TFtype, TFtype);
+extern TCtype __multc3 (TFtype, TFtype, TFtype, TFtype);
 #endif
+
+#define int bogus_type
 #endif /* BITS_PER_UNIT == 8 */
 
 /* DWstructs are pairs of Wtype values in the order determined by
--- gcc/mklibgcc.in.jj	2006-10-05 00:37:01.000000000 +0200
+++ gcc/mklibgcc.in	2007-03-02 10:31:58.000000000 +0100
@@ -58,7 +58,9 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ash
 	_enable_execute_stack _trampoline __main _absvsi2 _absvdi2 _addvsi3
 	_addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
 	_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
-	_popcountsi2 _popcountdi2 _paritysi2 _paritydi2'
+	_popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
+	_powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3
+	_divxc3 _divtc3 _floatundidf _floatundisf _floatundixf _floatunditf'
 
 # Disable SHLIB_LINK if shared libgcc not enabled.
 if [ "@enable_shared@" = "no" ]; then
--- gcc/libgcc2.c.jj	2006-10-05 00:37:01.000000000 +0200
+++ gcc/libgcc2.c	2007-03-02 10:58:07.000000000 +0100
@@ -1331,6 +1331,23 @@ __floatdixf (DWtype u)
 }
 #endif
 
+#if defined(L_floatundixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
+
+XFtype
+__floatundixf (UDWtype u)
+{
+  XFtype d = (UWtype) (u >> WORD_SIZE);
+  d *= HIGH_HALFWORD_COEFF;
+  d *= HIGH_HALFWORD_COEFF;
+  d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
+
+  return d;
+}
+#endif
+
 #if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
 #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
 #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
@@ -1348,6 +1365,23 @@ __floatditf (DWtype u)
 }
 #endif
 
+#if defined(L_floatunditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
+
+TFtype
+__floatunditf (UDWtype u)
+{
+  TFtype d = (UWtype) (u >> WORD_SIZE);
+  d *= HIGH_HALFWORD_COEFF;
+  d *= HIGH_HALFWORD_COEFF;
+  d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
+
+  return d;
+}
+#endif
+
 #ifdef L_floatdidf
 #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
 #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
@@ -1365,6 +1399,23 @@ __floatdidf (DWtype u)
 }
 #endif
 
+#ifdef L_floatundidf
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
+
+DFtype
+__floatundidf (UDWtype u)
+{
+  DFtype d = (UWtype) (u >> WORD_SIZE);
+  d *= HIGH_HALFWORD_COEFF;
+  d *= HIGH_HALFWORD_COEFF;
+  d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
+
+  return d;
+}
+#endif
+
 #ifdef L_floatdisf
 #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
 #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
@@ -1409,6 +1460,49 @@ __floatdisf (DWtype u)
 }
 #endif
 
+#ifdef L_floatundisf
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
+
+#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
+#define DF_SIZE DBL_MANT_DIG
+#define SF_SIZE FLT_MANT_DIG
+
+SFtype
+__floatundisf (UDWtype u)
+{
+  /* Protect against double-rounding error.
+     Represent any low-order bits, that might be truncated in DFmode,
+     by a bit that won't be lost.  The bit can go in anywhere below the
+     rounding position of the SFmode.  A fixed mask and bit position
+     handles all usual configurations.  It doesn't handle the case
+     of 128-bit DImode, however.  */
+  if (DF_SIZE < DI_SIZE
+      && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
+    {
+#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
+      if (u >= ((UDWtype) 1 << DF_SIZE))
+	{
+	  if ((UDWtype) u & (REP_BIT - 1))
+	    {
+	      u &= ~ (REP_BIT - 1);
+	      u |= REP_BIT;
+	    }
+	}
+    }
+  /* Do the calculation in DFmode
+     so that we don't lose any of the precision of the high word
+     while multiplying it.  */
+  DFtype f = (UWtype) (u >> WORD_SIZE);
+  f *= HIGH_HALFWORD_COEFF;
+  f *= HIGH_HALFWORD_COEFF;
+  f += (UWtype) (u & (HIGH_WORD_COEFF - 1));
+
+  return (SFtype) f;
+}
+#endif
+
 #if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 /* Reenable the normal types, in case limits.h needs them.  */
 #undef char
@@ -1475,6 +1569,246 @@ __fixunssfSI (SFtype a)
 }
 #endif
 
+/* Integer power helper used from __builtin_powi for non-constant
+   exponents.  */
+
+#if defined(L_powisf2) || defined(L_powidf2) \
+    || (defined(L_powixf2) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96) \
+    || (defined(L_powitf2) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+# if defined(L_powisf2)
+#  define TYPE SFtype
+#  define NAME __powisf2
+# elif defined(L_powidf2)
+#  define TYPE DFtype
+#  define NAME __powidf2
+# elif defined(L_powixf2)
+#  define TYPE XFtype
+#  define NAME __powixf2
+# elif defined(L_powitf2)
+#  define TYPE TFtype
+#  define NAME __powitf2
+# endif
+
+#undef int
+#undef unsigned
+TYPE
+NAME (TYPE x, int m)
+{
+  unsigned int n = m < 0 ? -m : m;
+  TYPE y = n % 2 ? x : 1;
+  while (n >>= 1)
+    {
+      x = x * x;
+      if (n % 2)
+	y = y * x;
+    }
+  return m < 0 ? 1/y : y;
+}
+
+#endif
+
+#if defined(L_mulsc3) || defined(L_divsc3) \
+    || defined(L_muldc3) || defined(L_divdc3) \
+    || (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96 \
+	&& (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 currently 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 behavior from logarithmic 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 nonzero/zero, infinite/finite, and finite/infinite.  */
+  if (isnan (x) && isnan (y))
+    {
+      if (c == 0.0 && d == 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 */
+
 /* From here on down, the routines use normal data types.  */
 
 #define SItype bogus_type