OSDN Git Service

Declare __fixunsxfdi.
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index ce693ed..4dd2843 100644 (file)
@@ -28,99 +28,141 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    compiled for the target, and hence definitions concerning only the host
    do not apply.  */
 
-#include "tm.h"
+#include "tconfig.h"
+#include "machmode.h"
+#ifndef L_trampoline
 #include "gstddef.h"
+#endif
 
 /* Don't use `fancy_abort' here even if config.h says to use it.  */
 #ifdef abort
 #undef abort
 #endif
 
-/* Need to undef this because LONG_TYPE_SIZE may rely upon GCC's
-   internal `target_flags' variable.  */
-#undef LONG_TYPE_SIZE
-
-#define LONG_TYPE_SIZE (sizeof (long) * BITS_PER_UNIT)
+/* In the first part of this file, we are interfacing to calls generated
+   by the compiler itself.  These calls pass values into these routines
+   which have very specific modes (rather than very specific types), and
+   these compiler-generated calls also expect any return values to have
+   very specific modes (rather than very specific types).  Thus, we need
+   to avoid using regular C language type names in this part of the file
+   because the sizes for those types can be configured to be anything.
+   Instead we use the following special type names.  */
+
+typedef unsigned int UQItype   __attribute__ ((mode (QI)));
+typedef         int SItype     __attribute__ ((mode (SI)));
+typedef unsigned int USItype   __attribute__ ((mode (SI)));
+typedef                 int DItype     __attribute__ ((mode (DI)));
+typedef unsigned int UDItype   __attribute__ ((mode (DI)));
+typedef        float SFtype    __attribute__ ((mode (SF)));
+typedef                float DFtype    __attribute__ ((mode (DF)));
+#if LONG_DOUBLE_TYPE_SIZE == 96
+typedef                float XFtype    __attribute__ ((mode (XF)));
+#endif
+#if LONG_DOUBLE_TYPE_SIZE == 128
+typedef                float TFtype    __attribute__ ((mode (TF)));
+#endif
 
-#ifndef SItype
-#define SItype long int
+#if BITS_PER_WORD==16
+typedef int word_type __attribute__ ((mode (HI)));
+#endif
+#if BITS_PER_WORD==32
+typedef int word_type __attribute__ ((mode (SI)));
 #endif
+#if BITS_PER_WORD==64
+typedef int word_type __attribute__ ((mode (DI)));
+#endif
+
+/* Make sure that we don't accidentally use any normal C language built-in
+   type names in the first part of this file.  Instead we want to use *only*
+   the type names defined above.  The following macro definitions insure
+   that if we *do* accidentally use some normal C language built-in type name,
+   we will get a syntax error.  */
+
+#define char bogus_type
+#define short bogus_type
+#define int bogus_type
+#define long bogus_type
+#define unsigned bogus_type
+#define float bogus_type
+#define double bogus_type
+
+#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 
-/* long long ints are pairs of long ints in the order determined by
+/* DIstructs are pairs of SItype values in the order determined by
    WORDS_BIG_ENDIAN.  */
 
 #if WORDS_BIG_ENDIAN
-  struct longlong {long high, low;};
+  struct DIstruct {SItype high, low;};
 #else
-  struct longlong {long low, high;};
+  struct DIstruct {SItype low, high;};
 #endif
 
-/* We need this union to unpack/pack longlongs, since we don't have
-   any arithmetic yet.  Incoming long long parameters are stored
-   into the `ll' field, and the unpacked result is read from the struct
-   longlong.  */
+/* We need this union to unpack/pack DImode values, since we don't have
+   any arithmetic yet.  Incoming DImode parameters are stored into the
+   `ll' field, and the unpacked result is read from the struct `s'.  */
 
 typedef union
 {
-  struct longlong s;
-  long long ll;
-} long_long;
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
 
-#if defined (L_udivmoddi4) || defined (L_muldi3)
+#if defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)
 
 #include "longlong.h"
 
 #endif /* udiv or mul */
 
-extern long long __fixunssfdi (float a);
-extern long long __fixunsdfdi (double a);
+extern DItype __fixunssfdi (SFtype a);
+extern DItype __fixunsdfdi (DFtype a);
+extern DItype __fixunsxfdi (XFtype a);
 \f
 #if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
 #if defined (L_divdi3) || defined (L_moddi3)
 static inline
 #endif
-long long
+DItype
 __negdi2 (u)
-     long long u;
+     DItype u;
 {
-  long_long w;
-  long_long uu;
+  DIunion w;
+  DIunion uu;
 
   uu.ll = u;
 
   w.s.low = -uu.s.low;
-  w.s.high = -uu.s.high - ((unsigned long) w.s.low > 0);
+  w.s.high = -uu.s.high - ((USItype) w.s.low > 0);
 
   return w.ll;
 }
 #endif
 \f
 #ifdef L_lshldi3
-long long
+DItype
 __lshldi3 (u, b)
-     long long u;
-     int b;
+     DItype u;
+     SItype b;
 {
-  long_long w;
-  long bm;
-  long_long uu;
+  DIunion w;
+  SItype bm;
+  DIunion uu;
 
   if (b == 0)
     return u;
 
   uu.ll = u;
 
-  bm = (sizeof (long) * BITS_PER_UNIT) - b;
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
   if (bm <= 0)
     {
       w.s.low = 0;
-      w.s.high = (unsigned long)uu.s.low << -bm;
+      w.s.high = (USItype)uu.s.low << -bm;
     }
   else
     {
-      unsigned long carries = (unsigned long)uu.s.low >> bm;
-      w.s.low = (unsigned long)uu.s.low << b;
-      w.s.high = ((unsigned long)uu.s.high << b) | carries;
+      USItype carries = (USItype)uu.s.low >> bm;
+      w.s.low = (USItype)uu.s.low << b;
+      w.s.high = ((USItype)uu.s.high << b) | carries;
     }
 
   return w.ll;
@@ -128,31 +170,31 @@ __lshldi3 (u, b)
 #endif
 
 #ifdef L_lshrdi3
-long long
+DItype
 __lshrdi3 (u, b)
-     long long u;
-     int b;
+     DItype u;
+     SItype b;
 {
-  long_long w;
-  long bm;
-  long_long uu;
+  DIunion w;
+  SItype bm;
+  DIunion uu;
 
   if (b == 0)
     return u;
 
   uu.ll = u;
 
-  bm = (sizeof (long) * BITS_PER_UNIT) - b;
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
   if (bm <= 0)
     {
       w.s.high = 0;
-      w.s.low = (unsigned long)uu.s.high >> -bm;
+      w.s.low = (USItype)uu.s.high >> -bm;
     }
   else
     {
-      unsigned long carries = (unsigned long)uu.s.high << bm;
-      w.s.high = (unsigned long)uu.s.high >> b;
-      w.s.low = ((unsigned long)uu.s.low >> b) | carries;
+      USItype carries = (USItype)uu.s.high << bm;
+      w.s.high = (USItype)uu.s.high >> b;
+      w.s.low = ((USItype)uu.s.low >> b) | carries;
     }
 
   return w.ll;
@@ -160,31 +202,31 @@ __lshrdi3 (u, b)
 #endif
 
 #ifdef L_ashldi3
-long long
+DItype
 __ashldi3 (u, b)
-     long long u;
-     int b;
+     DItype u;
+     SItype b;
 {
-  long_long w;
-  long bm;
-  long_long uu;
+  DIunion w;
+  SItype bm;
+  DIunion uu;
 
   if (b == 0)
     return u;
 
   uu.ll = u;
 
-  bm = (sizeof (long) * BITS_PER_UNIT) - b;
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
   if (bm <= 0)
     {
       w.s.low = 0;
-      w.s.high = (unsigned long)uu.s.low << -bm;
+      w.s.high = (USItype)uu.s.low << -bm;
     }
   else
     {
-      unsigned long carries = (unsigned long)uu.s.low >> bm;
-      w.s.low = (unsigned long)uu.s.low << b;
-      w.s.high = ((unsigned long)uu.s.high << b) | carries;
+      USItype carries = (USItype)uu.s.low >> bm;
+      w.s.low = (USItype)uu.s.low << b;
+      w.s.high = ((USItype)uu.s.high << b) | carries;
     }
 
   return w.ll;
@@ -192,59 +234,180 @@ __ashldi3 (u, b)
 #endif
 
 #ifdef L_ashrdi3
-long long
+DItype
 __ashrdi3 (u, b)
-     long long u;
-     int b;
+     DItype u;
+     SItype b;
 {
-  long_long w;
-  long bm;
-  long_long uu;
+  DIunion w;
+  SItype bm;
+  DIunion uu;
 
   if (b == 0)
     return u;
 
   uu.ll = u;
 
-  bm = (sizeof (long) * BITS_PER_UNIT) - b;
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
   if (bm <= 0)
     {
       /* w.s.high = 1..1 or 0..0 */
-      w.s.high = uu.s.high >> (sizeof (long) * BITS_PER_UNIT - 1);
+      w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
       w.s.low = uu.s.high >> -bm;
     }
   else
     {
-      unsigned long carries = (unsigned long)uu.s.high << bm;
+      USItype carries = (USItype)uu.s.high << bm;
       w.s.high = uu.s.high >> b;
-      w.s.low = ((unsigned long)uu.s.low >> b) | carries;
+      w.s.low = ((USItype)uu.s.low >> b) | carries;
     }
 
   return w.ll;
 }
 #endif
 \f
+#ifdef L_ffsdi2
+DItype
+__ffsdi2 (u)
+     DItype u;
+{
+  DIunion uu, w;
+  uu.ll = u;
+  w.s.high = 0;
+  w.s.low = ffs (uu.s.low);
+  if (w.s.low != 0)
+    return w.ll;
+  w.s.low = ffs (uu.s.high);
+  if (w.s.low != 0)
+    {
+      w.s.low += BITS_PER_UNIT * sizeof (SItype);
+      return w.ll;
+    }
+  return w.ll;
+}
+#endif
+\f
 #ifdef L_muldi3
-long long
+DItype
 __muldi3 (u, v)
-     long long u, v;
+     DItype u, v;
 {
-  long_long w;
-  long_long uu, vv;
+  DIunion w;
+  DIunion uu, vv;
 
   uu.ll = u,
   vv.ll = v;
 
   w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((unsigned long) uu.s.low * (unsigned long) vv.s.high
-              + (unsigned long) uu.s.high * (unsigned long) vv.s.low);
+  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+              + (USItype) uu.s.high * (USItype) vv.s.low);
 
   return w.ll;
 }
 #endif
 \f
+#ifdef L_udiv_w_sdiv
+USItype
+__udiv_w_sdiv (rp, a1, a0, d)
+     USItype *rp, a1, a0, d;
+{
+  USItype q, r;
+  USItype c0, c1, b1;
+
+  if ((SItype) d >= 0)
+    {
+      if (a1 < d - a1 - (a0 >> (SI_TYPE_SIZE - 1)))
+       {
+         /* dividend, divisor, and quotient are nonnegative */
+         sdiv_qrnnd (q, r, a1, a0, d);
+       }
+      else
+       {
+         /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
+         sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (SI_TYPE_SIZE - 1));
+         /* Divide (c1*2^32 + c0) by d */
+         sdiv_qrnnd (q, r, c1, c0, d);
+         /* Add 2^31 to quotient */
+         q += (USItype) 1 << (SI_TYPE_SIZE - 1);
+       }
+    }
+  else
+    {
+      b1 = d >> 1;                     /* d/2, between 2^30 and 2^31 - 1 */
+      c1 = a1 >> 1;                    /* A/2 */
+      c0 = (a1 << (SI_TYPE_SIZE - 1)) + (a0 >> 1);
+
+      if (a1 < b1)                     /* A < 2^32*b1, so A/2 < 2^31*b1 */
+       {
+         sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+         r = 2*r + (a0 & 1);           /* Remainder from A/(2*b1) */
+         if ((d & 1) != 0)
+           {
+             if (r >= q)
+               r = r - q;
+             else if (q - r <= d)
+               {
+                 r = r - q + d;
+                 q--;
+               }
+             else
+               {
+                 r = r - q + 2*d;
+                 q -= 2;
+               }
+           }
+       }
+      else if (c1 < b1)                        /* So 2^31 <= (A/2)/b1 < 2^32 */
+       {
+         c1 = (b1 - 1) - c1;
+         c0 = ~c0;                     /* logical NOT */
+
+         sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+         q = ~q;                       /* (A/2)/b1 */
+         r = (b1 - 1) - r;
+
+         r = 2*r + (a0 & 1);           /* A/(2*b1) */
+
+         if ((d & 1) != 0)
+           {
+             if (r >= q)
+               r = r - q;
+             else if (q - r <= d)
+               {
+                 r = r - q + d;
+                 q--;
+               }
+             else
+               {
+                 r = r - q + 2*d;
+                 q -= 2;
+               }
+           }
+       }
+      else                             /* Implies c1 = b1 */
+       {                               /* Hence a1 = d - 1 = 2*b1 - 1 */
+         if (a0 >= -d)
+           {
+             q = -1;
+             r = a0 + d;
+           }
+         else
+           {
+             q = -2;
+             r = a0 + 2*d;
+           }
+       }
+    }
+
+  *rp = r;
+  return q;
+}
+#endif
+\f
 #ifdef L_udivmoddi4
-static const unsigned char __clz_tab[] =
+static const UQItype __clz_tab[] =
 {
   0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
@@ -256,17 +419,17 @@ static const unsigned char __clz_tab[] =
   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
 };
 
-unsigned long long
+UDItype
 __udivmoddi4 (n, d, rp)
-     unsigned long long n, d;
-     unsigned long long int *rp;
+     UDItype n, d;
+     UDItype *rp;
 {
-  long_long ww;
-  long_long nn, dd;
-  long_long rr;
-  unsigned long d0, d1, n0, n1, n2;
-  unsigned long q0, q1;
-  unsigned b, bm;
+  DIunion ww;
+  DIunion nn, dd;
+  DIunion rr;
+  USItype d0, d1, n0, n1, n2;
+  USItype q0, q1;
+  USItype b, bm;
 
   nn.ll = n;
   dd.ll = d;
@@ -325,7 +488,7 @@ __udivmoddi4 (n, d, rp)
                 denominator set.  */
 
              d0 = d0 << bm;
-             n1 = (n1 << bm) | (n0 >> (LONG_TYPE_SIZE - bm));
+             n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
              n0 = n0 << bm;
            }
 
@@ -350,7 +513,7 @@ __udivmoddi4 (n, d, rp)
                 leading quotient digit q1 = 1).
 
                 This special case is necessary, not an optimization.
-                (Shifts counts of LONG_TYPE_SIZE are undefined.)  */
+                (Shifts counts of SI_TYPE_SIZE are undefined.)  */
 
              n1 -= d0;
              q1 = 1;
@@ -359,7 +522,7 @@ __udivmoddi4 (n, d, rp)
            {
              /* Normalize.  */
 
-             b = LONG_TYPE_SIZE - bm;
+             b = SI_TYPE_SIZE - bm;
 
              d0 = d0 << bm;
              n2 = n1 >> b;
@@ -436,10 +599,10 @@ __udivmoddi4 (n, d, rp)
            }
          else
            {
-             unsigned long m1, m0;
+             USItype m1, m0;
              /* Normalize.  */
 
-             b = LONG_TYPE_SIZE - bm;
+             b = SI_TYPE_SIZE - bm;
 
              d1 = (d1 << bm) | (d0 >> b);
              d0 = d0 << bm;
@@ -477,14 +640,15 @@ __udivmoddi4 (n, d, rp)
 #endif
 
 #ifdef L_divdi3
-unsigned long long __udivmoddi4 ();
-long long
+UDItype __udivmoddi4 ();
+
+DItype
 __divdi3 (u, v)
-     long long u, v;
+     DItype u, v;
 {
-  int c = 0;
-  long_long uu, vv;
-  long long w;
+  SItype c = 0;
+  DIunion uu, vv;
+  DItype w;
 
   uu.ll = u;
   vv.ll = v;
@@ -496,7 +660,7 @@ __divdi3 (u, v)
     c = ~c,
     vv.ll = __negdi2 (vv.ll);
 
-  w = __udivmoddi4 (uu.ll, vv.ll, (unsigned long long *) 0);
+  w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0);
   if (c)
     w = __negdi2 (w);
 
@@ -505,14 +669,14 @@ __divdi3 (u, v)
 #endif
 
 #ifdef L_moddi3
-unsigned long long __udivmoddi4 ();
-long long
+UDItype __udivmoddi4 ();
+DItype
 __moddi3 (u, v)
-     long long u, v;
+     DItype u, v;
 {
-  int c = 0;
-  long_long uu, vv;
-  long long w;
+  SItype c = 0;
+  DIunion uu, vv;
+  DItype w;
 
   uu.ll = u;
   vv.ll = v;
@@ -532,12 +696,12 @@ __moddi3 (u, v)
 #endif
 
 #ifdef L_umoddi3
-unsigned long long __udivmoddi4 ();
-unsigned long long
+UDItype __udivmoddi4 ();
+UDItype
 __umoddi3 (u, v)
-     unsigned long long u, v;
+     UDItype u, v;
 {
-  long long w;
+  DItype w;
 
   (void) __udivmoddi4 (u, v, &w);
 
@@ -546,21 +710,21 @@ __umoddi3 (u, v)
 #endif
 
 #ifdef L_udivdi3
-unsigned long long __udivmoddi4 ();
-unsigned long long
+UDItype __udivmoddi4 ();
+UDItype
 __udivdi3 (n, d)
-     unsigned long long n, d;
+     UDItype n, d;
 {
-  return __udivmoddi4 (n, d, (unsigned long long *) 0);
+  return __udivmoddi4 (n, d, (UDItype *) 0);
 }
 #endif
 \f
 #ifdef L_cmpdi2
-SItype
+word_type
 __cmpdi2 (a, b)
-     long long a, b;
+     DItype a, b;
 {
-  long_long au, bu;
+  DIunion au, bu;
 
   au.ll = a, bu.ll = b;
 
@@ -568,72 +732,160 @@ __cmpdi2 (a, b)
     return 0;
   else if (au.s.high > bu.s.high)
     return 2;
-  if ((unsigned long) au.s.low < (unsigned long) bu.s.low)
+  if ((USItype) au.s.low < (USItype) bu.s.low)
     return 0;
-  else if ((unsigned long) au.s.low > (unsigned long) bu.s.low)
+  else if ((USItype) au.s.low > (USItype) bu.s.low)
     return 2;
   return 1;
 }
 #endif
 
 #ifdef L_ucmpdi2
-SItype
+word_type
 __ucmpdi2 (a, b)
-     long long a, b;
+     DItype a, b;
 {
-  long_long au, bu;
+  DIunion au, bu;
 
   au.ll = a, bu.ll = b;
 
-  if ((unsigned long) au.s.high < (unsigned long) bu.s.high)
+  if ((USItype) au.s.high < (USItype) bu.s.high)
     return 0;
-  else if ((unsigned long) au.s.high > (unsigned long) bu.s.high)
+  else if ((USItype) au.s.high > (USItype) bu.s.high)
     return 2;
-  if ((unsigned long) au.s.low < (unsigned long) bu.s.low)
+  if ((USItype) au.s.low < (USItype) bu.s.low)
     return 0;
-  else if ((unsigned long) au.s.low > (unsigned long) bu.s.low)
+  else if ((USItype) au.s.low > (USItype) bu.s.low)
     return 2;
   return 1;
 }
 #endif
 \f
+#if defined(L_fixunstfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+
+DItype
+__fixunstfdi (a)
+     TFtype a;
+{
+  TFtype b;
+  UDItype v;
+
+  if (a < 0)
+    return 0;
+
+  /* Compute high word of result, as a flonum.  */
+  b = (a / HIGH_WORD_COEFF);
+  /* Convert that to fixed (but not to DItype!),
+     and shift it into the high word.  */
+  v = (USItype) b;
+  v <<= WORD_SIZE;
+  /* Remove high part from the TFtype, leaving the low part as flonum.  */
+  a -= (TFtype)v;
+  /* Convert that to fixed (but not to DItype!) and add it in.
+     Sometimes A comes out negative.  This is significant, since
+     A has more bits than a long int does.  */
+  if (a < 0)
+    v -= (USItype) (- a);
+  else
+    v += (USItype) a;
+  return v;
+}
+#endif
+
+#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
+DItype
+__fixtfdi (a)
+     TFtype a;
+{
+  if (a < 0)
+    return - __fixunstfdi (-a);
+  return __fixunstfdi (a);
+}
+#endif
+
+#if defined(L_fixunsxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+
+DItype
+__fixunsxfdi (a)
+     XFtype a;
+{
+  XFtype b;
+  UDItype v;
+
+  if (a < 0)
+    return 0;
+
+  /* Compute high word of result, as a flonum.  */
+  b = (a / HIGH_WORD_COEFF);
+  /* Convert that to fixed (but not to DItype!),
+     and shift it into the high word.  */
+  v = (USItype) b;
+  v <<= WORD_SIZE;
+  /* Remove high part from the XFtype, leaving the low part as flonum.  */
+  a -= (XFtype)v;
+  /* Convert that to fixed (but not to DItype!) and add it in.
+     Sometimes A comes out negative.  This is significant, since
+     A has more bits than a long int does.  */
+  if (a < 0)
+    v -= (USItype) (- a);
+  else
+    v += (USItype) a;
+  return v;
+}
+#endif
+
+#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+DItype
+__fixxfdi (a)
+     XFtype a;
+{
+  if (a < 0)
+    return - __fixunsxfdi (-a);
+  return __fixunsxfdi (a);
+}
+#endif
+
 #ifdef L_fixunsdfdi
-#define WORD_SIZE (sizeof (long) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((long long) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
-long long
+DItype
 __fixunsdfdi (a)
-     double a;
+     DFtype a;
 {
-  double b;
-  unsigned long long v;
+  DFtype b;
+  UDItype v;
 
   if (a < 0)
     return 0;
 
   /* Compute high word of result, as a flonum.  */
   b = (a / HIGH_WORD_COEFF);
-  /* Convert that to fixed (but not to long long!),
+  /* Convert that to fixed (but not to DItype!),
      and shift it into the high word.  */
-  v = (unsigned long int) b;
+  v = (USItype) b;
   v <<= WORD_SIZE;
-  /* Remove high part from the double, leaving the low part as flonum.  */
-  a -= (double)v;
-  /* Convert that to fixed (but not to long long!) and add it in.
+  /* Remove high part from the DFtype, leaving the low part as flonum.  */
+  a -= (DFtype)v;
+  /* Convert that to fixed (but not to DItype!) and add it in.
      Sometimes A comes out negative.  This is significant, since
      A has more bits than a long int does.  */
   if (a < 0)
-    v -= (unsigned long int) (- a);
+    v -= (USItype) (- a);
   else
-    v += (unsigned long int) a;
+    v += (USItype) a;
   return v;
 }
 #endif
 
 #ifdef L_fixdfdi
-long long
+DItype
 __fixdfdi (a)
-     double a;
+     DFtype a;
 {
   if (a < 0)
     return - __fixunsdfdi (-a);
@@ -642,44 +894,44 @@ __fixdfdi (a)
 #endif
 
 #ifdef L_fixunssfdi
-#define WORD_SIZE (sizeof (long) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((long long) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
-long long
-__fixunssfdi (float original_a)
+DItype
+__fixunssfdi (SFtype original_a)
 {
-  /* Convert the float to a double, because that is surely not going
+  /* Convert the SFtype to a DFtype, because that is surely not going
      to lose any bits.  Some day someone else can write a faster version
-     that avoids converting to double, and verify it really works right.  */
-  double a = original_a;
-  double b;
-  unsigned long long v;
+     that avoids converting to DFtype, and verify it really works right.  */
+  DFtype a = original_a;
+  DFtype b;
+  UDItype v;
 
   if (a < 0)
     return 0;
 
   /* Compute high word of result, as a flonum.  */
   b = (a / HIGH_WORD_COEFF);
-  /* Convert that to fixed (but not to long long!),
+  /* Convert that to fixed (but not to DItype!),
      and shift it into the high word.  */
-  v = (unsigned long int) b;
+  v = (USItype) b;
   v <<= WORD_SIZE;
-  /* Remove high part from the double, leaving the low part as flonum.  */
-  a -= (double)v;
-  /* Convert that to fixed (but not to long long!) and add it in.
+  /* Remove high part from the DFtype, leaving the low part as flonum.  */
+  a -= (DFtype)v;
+  /* Convert that to fixed (but not to DItype!) and add it in.
      Sometimes A comes out negative.  This is significant, since
      A has more bits than a long int does.  */
   if (a < 0)
-    v -= (unsigned long int) (- a);
+    v -= (USItype) (- a);
   else
-    v += (unsigned long int) a;
+    v += (USItype) a;
   return v;
 }
 #endif
 
 #ifdef L_fixsfdi
-long long
-__fixsfdi (float a)
+DItype
+__fixsfdi (SFtype a)
 {
   if (a < 0)
     return - __fixunssfdi (-a);
@@ -687,88 +939,196 @@ __fixsfdi (float a)
 }
 #endif
 
+#if defined(L_floatdixf) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+
+XFtype
+__floatdixf (u)
+     DItype u;
+{
+  XFtype d;
+  SItype negate = 0;
+
+  if (u < 0)
+    u = -u, negate = 1;
+
+  d = (USItype) (u >> WORD_SIZE);
+  d *= HIGH_HALFWORD_COEFF;
+  d *= HIGH_HALFWORD_COEFF;
+  d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+
+  return (negate ? -d : d);
+}
+#endif
+
+#if defined(L_floatditf) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+
+TFtype
+__floatditf (u)
+     DItype u;
+{
+  TFtype d;
+  SItype negate = 0;
+
+  if (u < 0)
+    u = -u, negate = 1;
+
+  d = (USItype) (u >> WORD_SIZE);
+  d *= HIGH_HALFWORD_COEFF;
+  d *= HIGH_HALFWORD_COEFF;
+  d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+
+  return (negate ? -d : d);
+}
+#endif
+
 #ifdef L_floatdidf
-#define WORD_SIZE (sizeof (long) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((long long) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((long long) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
-double
+DFtype
 __floatdidf (u)
-     long long u;
+     DItype u;
 {
-  double d;
-  int negate = 0;
+  DFtype d;
+  SItype negate = 0;
 
   if (u < 0)
     u = -u, negate = 1;
 
-  d = (unsigned int) (u >> WORD_SIZE);
+  d = (USItype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
-  d += (unsigned int) (u & (HIGH_WORD_COEFF - 1));
+  d += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
   return (negate ? -d : d);
 }
 #endif
 
 #ifdef L_floatdisf
-#define WORD_SIZE (sizeof (long) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((long long) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((long long) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
-float
+SFtype
 __floatdisf (u)
-     long long u;
+     DItype u;
 {
-  float f;
-  int negate = 0;
+  /* Do the calculation in DFmode
+     so that we don't lose any of the precision of the high word
+     while multiplying it.  */
+  DFtype f;
+  SItype negate = 0;
 
   if (u < 0)
     u = -u, negate = 1;
 
-  f = (unsigned int) (u >> WORD_SIZE);
+  f = (USItype) (u >> WORD_SIZE);
   f *= HIGH_HALFWORD_COEFF;
   f *= HIGH_HALFWORD_COEFF;
-  f += (unsigned int) (u & (HIGH_WORD_COEFF - 1));
+  f += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -f : f);
+  return (SFtype) (negate ? -f : f);
+}
+#endif
+
+#if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
+#include "glimits.h"
+
+USItype
+__fixunsxfsi (a)
+     XFtype a;
+{
+  if (a >= - (DFtype) LONG_MIN)
+    return (SItype) (a + LONG_MIN) - LONG_MIN;
+  return (SItype) a;
 }
 #endif
 
 #ifdef L_fixunsdfsi
-#include "limits.h"
+#include "glimits.h"
 
-unsigned SItype
+USItype
 __fixunsdfsi (a)
-     double a;
+     DFtype a;
 {
-  if (a >= - (double) LONG_MIN)
+  if (a >= - (DFtype) LONG_MIN)
     return (SItype) (a + LONG_MIN) - LONG_MIN;
   return (SItype) a;
 }
 #endif
 
 #ifdef L_fixunssfsi
-#include "limits.h"
+#include "glimits.h"
 
-unsigned SItype
-__fixunssfsi (float a)
+USItype
+__fixunssfsi (SFtype a)
 {
-  if (a >= - (float) LONG_MIN)
+  if (a >= - (SFtype) LONG_MIN)
     return (SItype) (a + LONG_MIN) - LONG_MIN;
   return (SItype) a;
 }
 #endif
 \f
+/* From here on down, the routines use normal data types.  */
+
+#define SItype bogus_type
+#define USItype bogus_type
+#define DItype bogus_type
+#define UDItype bogus_type
+#define SFtype bogus_type
+#define DFtype bogus_type
+
+#undef char
+#undef short
+#undef int
+#undef long
+#undef unsigned
+#undef float
+#undef double
+\f
+#ifdef L__gcc_bcmp
+
+/* Like bcmp except the sign is meaningful.
+   Reult is negative if S1 is less than S2,
+   positive if S1 is greater, 0 if S1 and S2 are equal.  */
+
+int
+__gcc_bcmp (s1, s2, size)
+     unsigned char *s1, *s2;
+     size_t size;
+{
+  while (size > 0)
+    {
+      unsigned char c1 = *s1++, c2 = *s2++;
+      if (c1 != c2)
+       return c1 - c2;
+      size--;
+    }
+  return 0;
+}
+
+#endif
+\f\f
 #ifdef L_varargs
 #ifdef __i860__
-#ifdef SVR4
+#if defined(__svr4__) || defined(__alliant__)
        asm ("  .text");
        asm ("  .align  4");
 
+/* The Alliant needs the added underscore.  */
        asm (".globl    __builtin_saveregs");
 asm ("__builtin_saveregs:");
-       asm ("  andnot  0x0f,%sp,%sp"); /* round down to 16-byte boundary */
+       asm (".globl    ___builtin_saveregs");
+asm ("___builtin_saveregs:");
+
+        asm (" andnot  0x0f,%sp,%sp"); /* round down to 16-byte boundary */
        asm ("  adds    -96,%sp,%sp");  /* allocate stack space for reg save
                                           area and also for a new va_list
                                           structure */
@@ -823,7 +1183,7 @@ asm ("__builtin_saveregs:");
        asm ("  bri     %r1");          /* delayed return */
        asm ("  st.l    %r28,12(%r16)"); /* pointer to overflow args */
 
-#else /* not SVR4 */
+#else /* not __svr4__ */
        asm ("  .text");
        asm ("  .align  4");
 
@@ -861,11 +1221,16 @@ asm ("__builtin_saveregs:");
        asm ("  mov     r30,sp");
                                /* recover stack and pass address to start 
                                   of data.  */
-#endif /* not SVR4 */
+#endif /* not __svr4__ */
 #else /* not __i860__ */
 #ifdef __sparc__
+       asm (".global __builtin_saveregs");
+       asm ("__builtin_saveregs:");
        asm (".global ___builtin_saveregs");
        asm ("___builtin_saveregs:");
+#ifdef NEED_PROC_COMMAND
+       asm (".proc 020");
+#endif
        asm ("st %i0,[%fp+68]");
        asm ("st %i1,[%fp+72]");
        asm ("st %i2,[%fp+76]");
@@ -873,6 +1238,10 @@ asm ("__builtin_saveregs:");
        asm ("st %i4,[%fp+84]");
        asm ("retl");
        asm ("st %i5,[%fp+88]");
+#ifdef NEED_TYPE_COMMAND
+       asm (".type __builtin_saveregs,#function");
+       asm (".size __builtin_saveregs,.-__builtin_saveregs");
+#endif
 #else /* not __sparc__ */
 #if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
 
@@ -897,102 +1266,264 @@ __builtin_saveregs ()
 #endif
 \f
 #ifdef L_eprintf
+#ifndef inhibit_libc
+
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
 #include <stdio.h>
 /* This is used by the `assert' macro.  */
 void
 __eprintf (string, expression, line, filename)
-     char *string;
-     char *expression;
+     const char *string;
+     const char *expression;
      int line;
-     char *filename;
+     const char *filename;
 {
   fprintf (stderr, string, expression, line, filename);
   fflush (stderr);
   abort ();
 }
+
+#endif
 #endif
 
 #ifdef L_bb
-/* Avoid warning from ranlib about empty object file.  */
-void
-__bb_avoid_warning ()
-{}
 
-#if defined (__sun__) && defined (__mc68000__)
+/* Structure emitted by -a  */
 struct bb
 {
-  int initialized;
-  char *filename;
-  int *counts;
-  int ncounts;
-  int zero_word;
-  int *addresses;
+  long zero_word;
+  const char *filename;
+  long *counts;
+  long ncounts;
+  struct bb *next;
+  const unsigned long *addresses;
+
+  /* Older GCC's did not emit these fields.  */
+  long nwords;
+  const char **functions;
+  const long *line_nums;
+  const char **filenames;
 };
 
-extern int ___tcov_init;
+#ifdef BLOCK_PROFILER_CODE
+BLOCK_PROFILER_CODE
+#else
 
-__bb_init_func (blocks)
-       struct bb *blocks;
+/* Simple minded basic block profiling output dumper for
+   systems that don't provde tcov support.  At present,
+   it requires atexit and stdio.  */
+
+#include <stdio.h>
+
+#ifdef HAVE_ATEXIT
+extern void atexit (void (*) (void));
+#define ON_EXIT(FUNC,ARG) atexit ((FUNC))
+#else
+#ifdef sun
+extern void on_exit (void*, void*);
+#define ON_EXIT(FUNC,ARG) on_exit ((FUNC), (ARG))
+#endif
+#endif
+
+static struct bb *bb_head = (struct bb *)0;
+
+/* Return the number of digits needed to print a value */
+/* __inline__ */ static int num_digits (long value, int base)
 {
-  if (! ___tcov_init)
-    ___tcov_init_func ();
+  int minus = (value < 0 && base != 16);
+  unsigned long v = (minus) ? -value : value;
+  int ret = minus;
+
+  do
+    {
+      v /= base;
+      ret++;
+    }
+  while (v);
 
-  ___bb_link (blocks->filename, blocks->counts, blocks->ncounts);
+  return ret;
 }
 
+void
+__bb_exit_func (void)
+{
+  FILE *file = fopen ("bb.out", "a");
+  long time_value;
+
+  if (!file)
+    perror ("bb.out");
+
+  else
+    {
+      struct bb *ptr;
+
+      /* This is somewhat type incorrect, but it avoids worrying about
+        exactly where time.h is included from.  It should be ok unless
+        a void * differs from other pointer formats, or if sizeof(long)
+        is < sizeof (time_t).  It would be nice if we could assume the
+        use of rationale standards here.  */
+
+      time((void *) &time_value);
+      fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
+
+      /* We check the length field explicitly in order to allow compatibility
+        with older GCC's which did not provide it.  */
+
+      for (ptr = bb_head; ptr != (struct bb *)0; ptr = ptr->next)
+       {
+         int i;
+         int func_p    = (ptr->nwords >= sizeof (struct bb) && ptr->nwords <= 1000);
+         int line_p    = (func_p && ptr->line_nums);
+         int file_p    = (func_p && ptr->filenames);
+         long ncounts  = ptr->ncounts;
+         long cnt_max  = 0;
+         long line_max = 0;
+         long addr_max = 0;
+         int file_len  = 0;
+         int func_len  = 0;
+         int blk_len   = num_digits (ncounts, 10);
+         int cnt_len;
+         int line_len;
+         int addr_len;
+
+         fprintf (file, "File %s, %ld basic blocks \n\n",
+                  ptr->filename, ncounts);
+
+         /* Get max values for each field.  */
+         for (i = 0; i < ncounts; i++)
+           {
+             const char *p;
+             int len;
+
+             if (cnt_max < ptr->counts[i])
+               cnt_max = ptr->counts[i];
+
+             if (addr_max < ptr->addresses[i])
+               addr_max = ptr->addresses[i];
+
+             if (line_p && line_max < ptr->line_nums[i])
+               line_max = ptr->line_nums[i];
+
+             if (func_p)
+               {
+                 p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
+                 len = strlen (p);
+                 if (func_len < len)
+                   func_len = len;
+               }
+
+             if (file_p)
+               {
+                 p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
+                 len = strlen (p);
+                 if (file_len < len)
+                   file_len = len;
+               }
+           }
+
+         addr_len = num_digits (addr_max, 16);
+         cnt_len  = num_digits (cnt_max, 10);
+         line_len = num_digits (line_max, 10);
+
+         /* Now print out the basic block information.  */
+         for (i = 0; i < ncounts; i++)
+           {
+             fprintf (file,
+                      "    Block #%*d: executed %*ld time(s) address= 0x%.*lx",
+                      blk_len, i+1,
+                      cnt_len, ptr->counts[i],
+                      addr_len, ptr->addresses[i]);
+
+             if (func_p)
+               fprintf (file, " function= %-*s", func_len,
+                        (ptr->functions[i]) ? ptr->functions[i] : "<none>");
+
+             if (line_p)
+               fprintf (file, " line= %*d", line_len, ptr->line_nums[i]);
+
+             if (file_p)
+               fprintf (file, " file= %s",
+                        (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
+
+             fprintf (file, "\n");
+           }
+
+         fprintf (file, "\n");
+         fflush (file);
+       }
+
+      fprintf (file, "\n\n");
+      fclose (file);
+    }
+}
+
+void
+__bb_init_func (struct bb *blocks)
+{
+  /* User is supposed to check whether the first word is non-0,
+     but just in case.... */
+
+  if (blocks->zero_word)
+    return;
+
+#ifdef ON_EXIT
+  /* Initialize destructor.  */
+  if (!bb_head)
+    ON_EXIT (__bb_exit_func, 0);
 #endif
-#endif
+
+  /* Set up linked list.  */
+  blocks->zero_word = 1;
+  blocks->next = bb_head;
+  bb_head = blocks;
+}
+
+#endif /* !BLOCK_PROFILER_CODE */
+#endif /* L_bb */
 \f
 /* frills for C++ */
 
-#ifdef L_builtin_new
+#ifdef L_op_new
 typedef void (*vfp)(void);
 
 extern vfp __new_handler;
 
+/* void * operator new (size_t sz) */
 void *
-__builtin_new (sz)
-     long sz;
+__builtin_new (size_t sz)
 {
   void *p;
 
+  /* malloc (0) is unpredictable; avoid it.  */
+  if (sz == 0)
+    sz = 1;
   p = (void *) malloc (sz);
   if (p == 0)
     (*__new_handler) ();
   return p;
 }
-#endif
-
-#ifdef L_builtin_New
-typedef void (*vfp)(void);
+#endif /* L_op_new */
 
-static void default_new_handler ();
+#ifdef L_new_handler
 
-vfp __new_handler = default_new_handler;
-
-void *
-__builtin_vec_new (p, maxindex, size, ctor)
-     void *p;
-     int maxindex, size;
-     void (*ctor)(void *);
-{
-  int i, nelts = maxindex + 1;
-  void *rval;
+#ifndef inhibit_libc
+/* This gets us __GNU_LIBRARY__.  */
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
 
-  if (p == 0)
-    p = (void *)__builtin_new (nelts * size);
+#ifdef __GNU_LIBRARY__
+  /* Avoid forcing the library's meaning of `write' on the user program
+     by using the "internal" name (for use within the library)  */
+#define write(fd, buf, n)      __write((fd), (buf), (n))
+#endif
+#endif /* inhibit_libc */
 
-  rval = p;
+typedef void (*vfp)(void);
 
-  for (i = 0; i < nelts; i++)
-    {
-      (*ctor) (p);
-      p += size;
-    }
+extern void *__builtin_new (size_t);
+static void default_new_handler (void);
 
-  return rval;
-}
+vfp __new_handler = default_new_handler;
 
 vfp
 __set_new_handler (handler)
@@ -1013,54 +1544,31 @@ set_new_handler (handler)
   return __set_new_handler (handler);
 }
 
+#define MESSAGE "Virtual memory exceeded in `new'\n"
+
 static void
 default_new_handler ()
 {
   /* don't use fprintf (stderr, ...) because it may need to call malloc.  */
   /* This should really print the name of the program, but that is hard to
      do.  We need a standard, clean way to get at the name.  */
-  write (2, "Virtual memory exceeded in `new'\n", 33);
+  write (2, MESSAGE, sizeof (MESSAGE));
   /* don't call exit () because that may call global destructors which
      may cause a loop.  */
   _exit (-1);
 }
 #endif
-\f
-#ifdef L_builtin_del
-typedef void (*vfp)(void);
 
+#ifdef L_op_delete
+/* void operator delete (void *ptr) */
 void
-__builtin_delete (ptr)
-     void *ptr;
+__builtin_delete (void *ptr)
 {
   if (ptr)
     free (ptr);
 }
-
-void
-__builtin_vec_delete (ptr, maxindex, size, dtor, auto_delete_vec, auto_delete)
-     void *ptr;
-     int maxindex, size;
-     void (*dtor)();
-     int auto_delete;
-{
-  int i, nelts = maxindex + 1;
-  void *p = ptr;
-
-  ptr += nelts * size;
-
-  for (i = 0; i < nelts; i++)
-    {
-      ptr -= size;
-      (*dtor) (ptr, auto_delete);
-    }
-
-  if (auto_delete_vec)
-    __builtin_delete (p);
-}
-
 #endif
-
+\f
 #ifdef L_shtab
 unsigned int __shtab[] = {
     0x00000001, 0x00000002, 0x00000004, 0x00000008,
@@ -1087,7 +1595,8 @@ __clear_cache (beg, end)
   static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
   static int initialized = 0;
   int offset;
-  unsigned int start_addr, end_addr;
+  void *start_addr
+  void *end_addr;
   typedef (*function_ptr) ();
 
 #if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
@@ -1219,11 +1728,45 @@ __enable_execute_stack ()
   asm ("pich");
 }
 #endif /* __convex__ */
+
+#ifdef __pyr__
+
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/vmmac.h>
+
+/* Modified from the convex -code above.
+   mremap promises to clear the i-cache. */
+
+void
+__enable_execute_stack ()
+{
+  int fp;
+  if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
+               PROT_READ|PROT_WRITE|PROT_EXEC))
+    {
+      perror ("mprotect in __enable_execute_stack");
+      fflush (stderr);
+      abort ();
+    }
+}
+#endif /* __pyr__ */
 #endif /* L_trampoline */
 \f
 #ifdef L__main
 
 #include "gbl-ctors.h"
+/* Some systems use __main in a way incompatible with its use in gcc, in these
+   cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
+   give the same symbol without quotes for an alternative entry point.  You
+   must define both, or niether. */
+#ifndef NAME__MAIN
+#define NAME__MAIN "__main"
+#define SYMBOL__MAIN __main
+#endif
 
 /* Run all the global destructors on exit from the program.  */
 
@@ -1233,8 +1776,8 @@ __do_global_dtors ()
 #ifdef DO_GLOBAL_DTORS_BODY
   DO_GLOBAL_DTORS_BODY;
 #else
-  int nptrs = *(int *)__DTOR_LIST__;
-  int i;
+  unsigned nptrs = (unsigned HOST_WIDE_INT) __DTOR_LIST__[0];
+  unsigned i;
 
   /* Some systems place the number of pointers
      in the first word of the table.
@@ -1254,7 +1797,7 @@ __do_global_dtors ()
 #ifndef INIT_SECTION_ASM_OP
 /* Run all the global constructors on entry to the program.  */
 
-#ifndef ON_EXIT /* DO_GLOBAL_CTORS_BODY uses ON_EXIT */
+#ifndef ON_EXIT
 #define ON_EXIT(a, b)
 #else
 /* Make sure the exit routine is pulled in to define the globals as
@@ -1269,8 +1812,11 @@ void
 __do_global_ctors ()
 {
   DO_GLOBAL_CTORS_BODY;
+  ON_EXIT (__do_global_dtors, 0);
 }
+#endif /* no INIT_SECTION_ASM_OP */
 
+#if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
 /* Subroutine called automatically by `main'.
    Compiling a global function named `main'
    produces an automatic call to this function at the beginning.
@@ -1280,21 +1826,21 @@ __do_global_ctors ()
    to run __do_global_ctors, so we need not do anything here.  */
 
 void
-__main ()
+SYMBOL__MAIN ()
 {
   /* Support recursive calls to `main': run initializers just once.  */
-  static initialized = 0;
+  static int initialized = 0;
   if (! initialized)
     {
       initialized = 1;
       __do_global_ctors ();
     }
 }
-#endif /* no INIT_SECTION_ASM_OP */
+#endif /* no INIT_SECTION_ASM_OP or INVOKE__main */
 
 #endif /* L__main */
 \f
-#ifdef L_exit
+#ifdef L_ctors
 
 #include "gbl-ctors.h"
 
@@ -1305,10 +1851,21 @@ __main ()
 
 /* We declare the lists here with two elements each,
    so that they are valid empty lists if no other definition is loaded.  */
-#ifndef INIT_SECTION_ASM_OP
+#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
+#ifdef __NeXT__
+/* After 2.3, try this definition on all systems.  */
+func_ptr __CTOR_LIST__[2] = {0, 0};
+func_ptr __DTOR_LIST__[2] = {0, 0};
+#else
 func_ptr __CTOR_LIST__[2];
 func_ptr __DTOR_LIST__[2];
-#endif /* INIT_SECTION_ASM_OP */
+#endif
+#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
+#endif /* L_ctors */
+\f
+#ifdef L_exit
+
+#include "gbl-ctors.h"
 
 #ifndef ON_EXIT
 
@@ -1318,7 +1875,7 @@ func_ptr __DTOR_LIST__[2];
 
 extern void __do_global_dtors ();
 extern void _cleanup ();
-extern void _exit ();
+extern volatile void _exit ();
 
 void 
 exit (status)