OSDN Git Service

(__udiv_w_sdiv): If we don't have sdiv_qrnnd, define dummy variant of
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index c4f35c8..3d9637c 100644 (file)
@@ -1,6 +1,6 @@
 /* More subroutines needed by GCC output code on some machines.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -16,11 +16,13 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
-/* As a special exception, if you link this library with files
-   compiled with GCC to produce an executable, this does not cause
-   the resulting executable to be covered by the GNU General Public License.
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
    This exception does not however invalidate any other reasons why
    the executable file might be covered by the GNU General Public License.  */
 
@@ -30,8 +32,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "tconfig.h"
 #include "machmode.h"
+#include "defaults.h" 
 #ifndef L_trampoline
-#include "gstddef.h"
+#include <stddef.h>
 #endif
 
 /* Don't use `fancy_abort' here even if config.h says to use it.  */
@@ -39,6 +42,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #undef abort
 #endif
 
+#if (SUPPORTS_WEAK == 1) && defined (ASM_OUTPUT_DEF)
+#define WEAK_ALIAS
+#endif
+
+/* Permit the tm.h file to select the endianness to use just for this
+   file.  This is used when the endianness is determined when the
+   compiler is run.  */
+
+#ifndef LIBGCC2_WORDS_BIG_ENDIAN
+#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
+#endif
+
 /* 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
@@ -53,8 +68,10 @@ 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
@@ -62,15 +79,7 @@ typedef              float XFtype    __attribute__ ((mode (XF)));
 typedef                float TFtype    __attribute__ ((mode (TF)));
 #endif
 
-#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
+typedef int word_type __attribute__ ((mode (__word__)));
 
 /* 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*
@@ -89,9 +98,9 @@ typedef int word_type __attribute__ ((mode (DI)));
 #define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 
 /* DIstructs are pairs of SItype values in the order determined by
-   WORDS_BIG_ENDIAN.  */
+   LIBGCC2_WORDS_BIG_ENDIAN.  */
 
-#if WORDS_BIG_ENDIAN
+#if LIBGCC2_WORDS_BIG_ENDIAN
   struct DIstruct {SItype high, low;};
 #else
   struct DIstruct {SItype low, high;};
@@ -107,7 +116,9 @@ typedef union
   DItype ll;
 } DIunion;
 
-#if defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)
+#if (defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)\
+     || defined (L_divdi3) || defined (L_udivdi3) \
+     || defined (L_moddi3) || defined (L_umoddi3))
 
 #include "longlong.h"
 
@@ -115,6 +126,12 @@ typedef union
 
 extern DItype __fixunssfdi (SFtype a);
 extern DItype __fixunsdfdi (DFtype a);
+#if LONG_DOUBLE_TYPE_SIZE == 96
+extern DItype __fixunsxfdi (XFtype a);
+#endif
+#if LONG_DOUBLE_TYPE_SIZE == 128
+extern DItype __fixunstfdi (TFtype a);
+#endif
 \f
 #if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
 #if defined (L_divdi3) || defined (L_moddi3)
@@ -136,46 +153,14 @@ __negdi2 (u)
 }
 #endif
 \f
-#ifdef L_lshldi3
-DItype
-__lshldi3 (u, b)
-     DItype u;
-     SItype b;
-{
-  DIunion w;
-  SItype bm;
-  DIunion uu;
-
-  if (b == 0)
-    return u;
-
-  uu.ll = u;
-
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
-  if (bm <= 0)
-    {
-      w.s.low = 0;
-      w.s.high = (USItype)uu.s.low << -bm;
-    }
-  else
-    {
-      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;
-}
-#endif
-
 #ifdef L_lshrdi3
 DItype
 __lshrdi3 (u, b)
      DItype u;
-     SItype b;
+     word_type b;
 {
   DIunion w;
-  SItype bm;
+  word_type bm;
   DIunion uu;
 
   if (b == 0)
@@ -204,10 +189,10 @@ __lshrdi3 (u, b)
 DItype
 __ashldi3 (u, b)
      DItype u;
-     SItype b;
+     word_type b;
 {
   DIunion w;
-  SItype bm;
+  word_type bm;
   DIunion uu;
 
   if (b == 0)
@@ -236,10 +221,10 @@ __ashldi3 (u, b)
 DItype
 __ashrdi3 (u, b)
      DItype u;
-     SItype b;
+     word_type b;
 {
   DIunion w;
-  SItype bm;
+  word_type bm;
   DIunion uu;
 
   if (b == 0)
@@ -306,6 +291,7 @@ __muldi3 (u, v)
 #endif
 \f
 #ifdef L_udiv_w_sdiv
+#if defined (sdiv_qrnnd)
 USItype
 __udiv_w_sdiv (rp, a1, a0, d)
      USItype *rp, a1, a0, d;
@@ -403,8 +389,20 @@ __udiv_w_sdiv (rp, a1, a0, d)
   *rp = r;
   return q;
 }
+#else
+/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
+USItype
+__udiv_w_sdiv (rp, a1, a0, d)
+     USItype *rp, a1, a0, d;
+{}
+#endif
 #endif
 \f
+#if (defined (L_udivdi3) || defined (L_divdi3) || \
+     defined (L_umoddi3) || defined (L_moddi3))
+#define L_udivmoddi4
+#endif
+
 #ifdef L_udivmoddi4
 static const UQItype __clz_tab[] =
 {
@@ -418,6 +416,10 @@ static const UQItype __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,
 };
 
+#if (defined (L_udivdi3) || defined (L_divdi3) || \
+     defined (L_umoddi3) || defined (L_moddi3))
+static inline
+#endif
 UDItype
 __udivmoddi4 (n, d, rp)
      UDItype n, d;
@@ -640,11 +642,12 @@ __udivmoddi4 (n, d, rp)
 
 #ifdef L_divdi3
 UDItype __udivmoddi4 ();
+
 DItype
 __divdi3 (u, v)
      DItype u, v;
 {
-  SItype c = 0;
+  word_type c = 0;
   DIunion uu, vv;
   DItype w;
 
@@ -672,7 +675,7 @@ DItype
 __moddi3 (u, v)
      DItype u, v;
 {
-  SItype c = 0;
+  word_type c = 0;
   DIunion uu, vv;
   DItype w;
 
@@ -699,7 +702,7 @@ UDItype
 __umoddi3 (u, v)
      UDItype u, v;
 {
-  DItype w;
+  UDItype w;
 
   (void) __udivmoddi4 (u, v, &w);
 
@@ -1013,6 +1016,35 @@ __floatdidf (u)
 #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)
+#define DI_SIZE (sizeof (DItype) * BITS_PER_UNIT)
+
+/* Define codes for all the float formats that we know of.  Note
+   that this is copied from real.h.  */
+   
+#define UNKNOWN_FLOAT_FORMAT 0
+#define IEEE_FLOAT_FORMAT 1
+#define VAX_FLOAT_FORMAT 2
+#define IBM_FLOAT_FORMAT 3
+
+/* Default to IEEE float if not specified.  Nearly all machines use it.  */
+#ifndef HOST_FLOAT_FORMAT
+#define        HOST_FLOAT_FORMAT       IEEE_FLOAT_FORMAT
+#endif
+
+#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+#define DF_SIZE 53
+#define SF_SIZE 24
+#endif
+
+#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#endif
+
+#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#endif
 
 SFtype
 __floatdisf (u)
@@ -1027,6 +1059,22 @@ __floatdisf (u)
   if (u < 0)
     u = -u, negate = 1;
 
+  /* 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 ((USItype) 1 << (DI_SIZE - DF_SIZE))
+      if (u >= ((UDItype) 1 << DF_SIZE))
+       {
+         if ((USItype) u & (REP_BIT - 1))
+           u |= REP_BIT;
+       }
+    }
   f = (USItype) (u >> WORD_SIZE);
   f *= HIGH_HALFWORD_COEFF;
   f *= HIGH_HALFWORD_COEFF;
@@ -1037,7 +1085,15 @@ __floatdisf (u)
 #endif
 
 #if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
-#include "glimits.h"
+/* Reenable the normal types, in case limits.h needs them.  */
+#undef char
+#undef short
+#undef int
+#undef long
+#undef unsigned
+#undef float
+#undef double
+#include <limits.h>
 
 USItype
 __fixunsxfsi (a)
@@ -1050,7 +1106,15 @@ __fixunsxfsi (a)
 #endif
 
 #ifdef L_fixunsdfsi
-#include "glimits.h"
+/* Reenable the normal types, in case limits.h needs them.  */
+#undef char
+#undef short
+#undef int
+#undef long
+#undef unsigned
+#undef float
+#undef double
+#include <limits.h>
 
 USItype
 __fixunsdfsi (a)
@@ -1063,7 +1127,15 @@ __fixunsdfsi (a)
 #endif
 
 #ifdef L_fixunssfsi
-#include "glimits.h"
+/* Reenable the normal types, in case limits.h needs them.  */
+#undef char
+#undef short
+#undef int
+#undef long
+#undef unsigned
+#undef float
+#undef double
+#include <limits.h>
 
 USItype
 __fixunssfsi (SFtype a)
@@ -1094,7 +1166,7 @@ __fixunssfsi (SFtype a)
 #ifdef L__gcc_bcmp
 
 /* Like bcmp except the sign is meaningful.
-   Reult is negative if S1 is less than S2,
+   Result is negative if S1 is less than S2,
    positive if S1 is greater, 0 if S1 and S2 are equal.  */
 
 int
@@ -1182,6 +1254,73 @@ asm ("___builtin_saveregs:");
        asm ("  st.l    %r28,12(%r16)"); /* pointer to overflow args */
 
 #else /* not __svr4__ */
+#if defined(__PARAGON__)
+       /*
+        *      we'll use SVR4-ish varargs but need SVR3.2 assembler syntax,
+        *      and we stand a better chance of hooking into libraries
+        *      compiled by PGI.  [andyp@ssd.intel.com]
+        */
+       asm ("  .text");
+       asm ("  .align  4");
+       asm (".globl    __builtin_saveregs");
+asm ("__builtin_saveregs:");
+       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 */
+       /* Save all argument registers in the arg reg save area.  The
+          arg reg save area must have the following layout (according
+          to the svr4 ABI):
+
+               struct {
+                 union  {
+                   float freg[8];
+                   double dreg[4];
+                 } float_regs;
+                 long  ireg[12];
+               };
+       */
+
+       asm ("  fst.q   f8,  0(sp)");
+       asm ("  fst.q   f12,16(sp)"); 
+       asm ("  st.l    r16,32(sp)");
+       asm ("  st.l    r17,36(sp)"); 
+       asm ("  st.l    r18,40(sp)");
+       asm ("  st.l    r19,44(sp)");
+       asm ("  st.l    r20,48(sp)");
+       asm ("  st.l    r21,52(sp)");
+       asm ("  st.l    r22,56(sp)");
+       asm ("  st.l    r23,60(sp)");
+       asm ("  st.l    r24,64(sp)");
+       asm ("  st.l    r25,68(sp)");
+       asm ("  st.l    r26,72(sp)");
+       asm ("  st.l    r27,76(sp)");
+
+       asm ("  adds    80,sp,r16");  /* compute the address of the new
+                                          va_list structure.  Put in into
+                                          r16 so that it will be returned
+                                          to the caller.  */
+
+       /* Initialize all fields of the new va_list structure.  This
+          structure looks like:
+
+               typedef struct {
+                   unsigned long       ireg_used;
+                   unsigned long       freg_used;
+                   long                *reg_base;
+                   long                *mem_ptr;
+               } va_list;
+       */
+
+       asm ("  st.l    r0, 0(r16)"); /* nfixed */
+       asm ("  st.l    r0, 4(r16)"); /* nfloating */
+       asm ("  st.l    sp, 8(r16)"); /* __va_ctl points to __va_struct.  */
+       asm ("  bri     r1");           /* delayed return */
+       asm ("   st.l   r28,12(r16)"); /* pointer to overflow args */
+#else /* not __PARAGON__ */
        asm ("  .text");
        asm ("  .align  4");
 
@@ -1219,6 +1358,7 @@ asm ("___builtin_saveregs:");
        asm ("  mov     r30,sp");
                                /* recover stack and pass address to start 
                                   of data.  */
+#endif /* not __PARAGON__ */
 #endif /* not __svr4__ */
 #else /* not __i860__ */
 #ifdef __sparc__
@@ -1254,10 +1394,13 @@ asm ("___builtin_saveregs:");
   asm ("       j       $31");
   asm ("       .end __builtin_saveregs");
 #else /* not __mips__, etc. */
+
+void *
 __builtin_saveregs ()
 {
   abort ();
 }
+
 #endif /* not __mips__ */
 #endif /* not __sparc__ */
 #endif /* not __i860__ */
@@ -1285,60 +1428,270 @@ __eprintf (string, expression, line, filename)
 #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
+#ifndef inhibit_libc
+
+/* Simple minded basic block profiling output dumper for
+   systems that don't provide tcov support.  At present,
+   it requires atexit and stdio.  */
+
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
+char *ctime ();
+
+#ifdef HAVE_ATEXIT
+#ifdef WINNT
+extern int atexit (void (*) (void));
+#else
+extern void atexit (void (*) (void));
+#endif
+#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
 
-__bb_init_func (blocks)
-       struct bb *blocks;
+static struct bb *bb_head;
+
+/* 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= %*ld", 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 /* not inhibit_libc */
+#endif /* not BLOCK_PROFILER_CODE */
+#endif /* L_bb */
 \f
-/* frills for C++ */
+/* Default free-store management functions for C++, per sections 12.5 and
+   17.3.3 of the Working Paper. */
 
 #ifdef L_op_new
-typedef void (*vfp)(void);
+/* operator new (size_t), described in 17.3.3.5.  This function is used by
+   C++ programs to allocate a block of memory to hold a single object. */
 
+typedef void (*vfp)(void);
 extern vfp __new_handler;
+extern void __default_new_handler (void);
 
-/* void * operator new (size_t sz) */
+#ifdef WEAK_ALIAS
+void * __builtin_new (size_t sz)
+     __attribute__ ((weak, alias ("___builtin_new")));
+void *
+___builtin_new (size_t sz)
+#else
 void *
 __builtin_new (size_t sz)
+#endif
 {
   void *p;
+  vfp handler = (__new_handler) ? __new_handler : __default_new_handler;
 
   /* malloc (0) is unpredictable; avoid it.  */
   if (sz == 0)
     sz = 1;
   p = (void *) malloc (sz);
-  if (p == 0)
-    (*__new_handler) ();
+  while (p == 0)
+    {
+      (*handler) ();
+      p = (void *) malloc (sz);
+    }
+  
   return p;
 }
 #endif /* L_op_new */
 
+#ifdef L_op_vnew
+/* void * operator new [] (size_t), described in 17.3.3.6.  This function
+   is used by C++ programs to allocate a block of memory for an array.  */
+
+extern void * __builtin_new (size_t);
+
+#ifdef WEAK_ALIAS
+void * __builtin_vec_new (size_t sz)
+     __attribute__ ((weak, alias ("___builtin_vec_new")));
+void *
+___builtin_vec_new (size_t sz)
+#else
+void *
+__builtin_vec_new (size_t sz)
+#endif
+{
+  return __builtin_new (sz);
+}
+#endif /* L_op_vnew */
+
 #ifdef L_new_handler
+/* set_new_handler (fvoid_t *) and the default new handler, described in
+   17.3.3.2 and 17.3.3.5.  These functions define the result of a failure
+   to allocate the amount of memory requested from operator new or new []. */
 
 #ifndef inhibit_libc
 /* This gets us __GNU_LIBRARY__.  */
@@ -1353,40 +1706,32 @@ __builtin_new (size_t sz)
 #endif /* inhibit_libc */
 
 typedef void (*vfp)(void);
+void __default_new_handler (void);
 
-extern void *__builtin_new (size_t);
-static void default_new_handler (void);
-
-vfp __new_handler = default_new_handler;
+vfp __new_handler = (vfp)0;
 
 vfp
-__set_new_handler (handler)
-     vfp handler;
+set_new_handler (vfp handler)
 {
   vfp prev_handler;
 
   prev_handler = __new_handler;
-  if (handler == 0) handler = default_new_handler;
+  if (handler == 0) handler = __default_new_handler;
   __new_handler = handler;
   return prev_handler;
 }
 
-vfp
-set_new_handler (handler)
-     vfp handler;
-{
-  return __set_new_handler (handler);
-}
-
 #define MESSAGE "Virtual memory exceeded in `new'\n"
 
-static void
-default_new_handler ()
+void
+__default_new_handler ()
 {
+#ifndef inhibit_libc
   /* 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, MESSAGE, sizeof (MESSAGE));
+#endif
   /* don't call exit () because that may call global destructors which
      may cause a loop.  */
   _exit (-1);
@@ -1394,14 +1739,47 @@ default_new_handler ()
 #endif
 
 #ifdef L_op_delete
-/* void operator delete (void *ptr) */
+/* operator delete (void *), described in 17.3.3.3.  This function is used
+   by C++ programs to return to the free store a block of memory allocated
+   as a single object. */
+
+#ifdef WEAK_ALIAS
+void __builtin_delete (void *ptr)
+     __attribute__ ((weak, alias ("___builtin_delete")));
+void
+___builtin_delete (void *ptr)
+#else
 void
 __builtin_delete (void *ptr)
+#endif
 {
   if (ptr)
     free (ptr);
 }
 #endif
+
+#ifdef L_op_vdel
+/* operator delete [] (void *), described in 17.3.3.4.  This function is
+   used by C++ programs to return to the free store a block of memory
+   allocated as an array. */
+
+extern void __builtin_delete (void *);
+
+#ifdef WEAK_ALIAS
+void __builtin_vec_delete (void *ptr)
+     __attribute__ ((weak, alias ("___builtin_vec_delete")));
+void
+___builtin_vec_delete (void *ptr)
+#else
+void
+__builtin_vec_delete (void *ptr)
+#endif
+{
+  __builtin_delete (ptr);
+}
+#endif
+
+/* End of C++ free-store management functions */
 \f
 #ifdef L_shtab
 unsigned int __shtab[] = {
@@ -1425,9 +1803,12 @@ void
 __clear_cache (beg, end)
      char *beg, *end;
 {
+#ifdef CLEAR_INSN_CACHE 
+  CLEAR_INSN_CACHE (beg, end);
+#else
 #ifdef INSN_CACHE_SIZE
   static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
-  static int initialized = 0;
+  static int initialized;
   int offset;
   void *start_addr
   void *end_addr;
@@ -1523,6 +1904,7 @@ __clear_cache (beg, end)
 #endif /* just one plane */
 #endif /* Cache is large */
 #endif /* Cache exists */
+#endif /* CLEAR_INSN_CACHE */
 }
 
 #endif /* L_clear_cache */
@@ -1535,6 +1917,43 @@ __clear_cache (beg, end)
 TRANSFER_FROM_TRAMPOLINE 
 #endif
 
+#if defined (NeXT) && defined (__MACH__)
+
+/* Make stack executable so we can call trampolines on stack.
+   This is called from INITIALIZE_TRAMPOLINE in next.h.  */
+#ifdef NeXTStep21
+ #include <mach.h>
+#else
+ #include <mach/mach.h>
+#endif
+
+void
+__enable_execute_stack (addr)
+     char *addr;
+{
+  kern_return_t r;
+  char *eaddr = addr + TRAMPOLINE_SIZE;
+  vm_address_t a = (vm_address_t) addr;
+
+  /* turn on execute access on stack */
+  r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL);
+  if (r != KERN_SUCCESS)
+    {
+      mach_error("vm_protect VM_PROT_ALL", r);
+      exit(1);
+    }
+
+  /* We inline the i-cache invalidation for speed */
+
+#ifdef CLEAR_INSN_CACHE
+  CLEAR_INSN_CACHE (addr, eaddr);
+#else
+  __clear_cache ((int) addr, (int) eaddr);
+#endif
+} 
+
+#endif /* defined (NeXT) && defined (__MACH__) */
+
 #ifdef __convex__
 
 /* Make stack executable so we can call trampolines on stack.
@@ -1563,6 +1982,38 @@ __enable_execute_stack ()
 }
 #endif /* __convex__ */
 
+#ifdef __DOLPHIN__
+
+/* Modified from the convex -code above. */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <sys/m88kbcs.h>
+
+void
+__enable_execute_stack ()
+{
+  int save_errno;
+  static unsigned long lowest = USRSTACK;
+  unsigned long current = (unsigned long) &save_errno & -NBPC;
+  
+  /* Ignore errno being set. memctl sets errno to EINVAL whenever the
+     address is seen as 'negative'. That is the case with the stack.   */
+
+  save_errno=errno;
+  if (lowest > current)
+    {
+      unsigned len=lowest-current;
+      memctl(current,len,MCT_TEXT);
+      lowest = current;
+    }
+  else
+    memctl(current,NBPC,MCT_TEXT);
+  errno=save_errno;
+}
+
+#endif /* __DOLPHIN__ */
+
 #ifdef __pyr__
 
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
@@ -1596,12 +2047,13 @@ __enable_execute_stack ()
 /* 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. */
+   must define both, or neither. */
 #ifndef NAME__MAIN
 #define NAME__MAIN "__main"
 #define SYMBOL__MAIN __main
 #endif
 
+#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
 /* Run all the global destructors on exit from the program.  */
 
 void
@@ -1610,23 +2062,12 @@ __do_global_dtors ()
 #ifdef DO_GLOBAL_DTORS_BODY
   DO_GLOBAL_DTORS_BODY;
 #else
-  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.
-     On other systems, that word is -1.
-     In all cases, the table is null-terminated.  */
-
-  /* If the length is not recorded, count up to the null.  */
-  if (nptrs == -1)
-    for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++);
-
-  /* GNU LD format.  */
-  for (i = nptrs; i >= 1; i--)
-    __DTOR_LIST__[i] ();
+  func_ptr *p;
+  for (p = __DTOR_LIST__ + 1; *p; )
+    (*p++) ();
 #endif
 }
+#endif
 
 #ifndef INIT_SECTION_ASM_OP
 /* Run all the global constructors on entry to the program.  */
@@ -1663,7 +2104,7 @@ void
 SYMBOL__MAIN ()
 {
   /* Support recursive calls to `main': run initializers just once.  */
-  static int initialized = 0;
+  static int initialized;
   if (! initialized)
     {
       initialized = 1;
@@ -1709,13 +2150,15 @@ func_ptr __DTOR_LIST__[2];
 
 extern void __do_global_dtors ();
 extern void _cleanup ();
-extern volatile void _exit ();
+extern void _exit () __attribute__ ((noreturn));
 
 void 
 exit (status)
      int status;
 {
+#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
   __do_global_dtors ();
+#endif
 #ifdef EXIT_BODY
   EXIT_BODY;
 #else
@@ -1730,37 +2173,245 @@ int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
 
 #endif /* L_exit */
 \f
-/* In a.out systems, we need to have these dummy constructor and destructor
-   lists in the library.
-
-   When using `collect', the first link will resolve __CTOR_LIST__
-   and __DTOR_LIST__ to these symbols.  We will then run "nm" on the
-   result, build the correct __CTOR_LIST__ and __DTOR_LIST__, and relink.
-   Since we don't do the second link if no constructors existed, these
-   dummies must be fully functional empty lists.
-
-   When using `gnu ld', these symbols will be used if there are no
-   constructors.  If there are constructors, the N_SETV symbol defined
-   by the linker from the N_SETT's in input files will define __CTOR_LIST__
-   and __DTOR_LIST__ rather than its being allocated as common storage
-   by the definitions below.
-
-   When using a linker that supports constructor and destructor segments,
-   these definitions will not be used, since crtbegin.o and crtend.o
-   (from crtstuff.c) will have already defined __CTOR_LIST__ and
-    __DTOR_LIST__.  The crt*.o files are passed directly to the linker
-   on its command line, by gcc.  */
-
-/* The list needs two elements:  one is ignored (the old count); the
-   second is the terminating zero.  Since both values are zero, this
-   declaration is not initialized, and it becomes `common'.  */
-
-#ifdef L_ctor_list
-#include "gbl-ctors.h"
-func_ptr __CTOR_LIST__[2];
+#ifdef L_eh
+typedef struct {
+  void *start;
+  void *end;
+  void *exception_handler;
+} exception_table;
+
+struct exception_table_node {
+  exception_table *table;
+  void *start;
+  void *end;
+  struct exception_table_node *next;
+};
+
+static int except_table_pos;
+static void *except_pc;
+static struct exception_table_node *exception_table_list;
+
+static exception_table *
+find_exception_table (pc)
+     void* pc;
+{
+  register struct exception_table_node *table = exception_table_list;
+  for ( ; table != 0; table = table->next)
+    {
+      if (table->start <= pc && table->end > pc)
+       return table->table;
+    }
+  return 0;
+}
+
+/* this routine takes a pc, and the address of the exception handler associated
+   with the closest exception table handler entry associated with that PC,
+   or 0 if there are no table entries the PC fits in.  The algorithm works
+   something like this:
+
+    while(current_entry exists) {
+        if(current_entry.start < pc )
+            current_entry = next_entry;
+        else {
+            if(prev_entry.start <= pc && prev_entry.end > pc) {
+                save pointer to prev_entry;
+                return prev_entry.exception_handler;
+             }
+            else return 0;
+         }
+     }
+    return 0;
+
+   Assuming a correctly sorted table (ascending order) this routine should
+   return the tightest match...
+
+   In the advent of a tie, we have to give the last entry, as it represents
+   an inner block.
+ */
+
+
+void *
+__find_first_exception_table_match(pc)
+void *pc;
+{
+  exception_table *table = find_exception_table (pc);
+  int pos = 0;
+  int best = 0;
+  if (table == 0)
+    return (void*)0;
+#if 0
+  printf("find_first_exception_table_match(): pc = %x!\n",pc);
 #endif
 
-#ifdef L_dtor_list
-#include "gbl-ctors.h"
-func_ptr __DTOR_LIST__[2];
+  except_pc = pc;
+
+#if 0
+  /* We can't do this yet, as we don't know that the table is sorted.  */
+  do {
+    ++pos;
+    if (table[pos].start > except_pc)
+      /* found the first table[pos].start > except_pc, so the previous
+        entry better be the one we want! */
+      break;
+  } while(table[pos].exception_handler != (void*)-1);
+
+  --pos;
+  if (table[pos].start <= except_pc && table[pos].end > except_pc)
+    {
+      except_table_pos = pos;
+#if 0
+      printf("find_first_eh_table_match(): found match: %x\n",table[pos].exception_handler);
+#endif
+      return table[pos].exception_handler;
+    }
+#else
+  while (table[++pos].exception_handler != (void*)-1) {
+    if (table[pos].start <= except_pc && table[pos].end > except_pc)
+      {
+       /* This can apply.  Make sure it is better or as good as the previous
+          best.  */
+       /* The best one ends first. */
+       if (best == 0 || (table[pos].end <= table[best].end
+                         /* The best one starts last.  */
+                         && table[pos].start >= table[best].start))
+         best = pos;
+      }
+  }
+  if (best != 0)
+    return table[best].exception_handler;
+#endif
+
+#if 0
+  printf("find_first_eh_table_match(): else: returning NULL!\n");
+#endif
+  return (void*)0;
+}
+
+void *
+__throw_type_match (void *catch_type, void *throw_type, void* obj)
+{
+#if 0
+ printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
+       catch_type, throw_type);
+#endif
+ if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
+   return obj;
+ return 0;
+}
+
+void
+__register_exceptions (exception_table *table)
+{
+  struct exception_table_node *node;
+  exception_table *range = table + 1;
+
+  if (range->start == (void*)-1)
+    return;
+
+  node = (struct exception_table_node*)
+    malloc (sizeof (struct exception_table_node));
+  node->table = table;
+
+  /* This look can be optimized away either if the table
+     is sorted, or if we pass in extra parameters. */
+  node->start = range->start;
+  node->end = range->end;
+  for (range++ ; range->start != (void*)(-1); range++)
+    {
+      if (range->start < node->start)
+       node->start = range->start;
+      if (range->end > node->end)
+       node->end = range->end;
+    }
+
+  node->next = exception_table_list;
+  exception_table_list = node;
+}
+
+#if #machine(i386)
+void
+__unwind_function(void *ptr)
+{
+  asm("movl 8(%esp),%ecx");
+  /* Undo current frame */
+  asm("movl %ebp,%esp");
+  asm("popl %ebp");
+  /* like ret, but stay here */
+  asm("addl $4,%esp");
+  
+  /* Now, undo previous frame. */
+  /* This is a test routine, as we have to dynamically probe to find out
+     what to pop for certain, this is just a guess. */
+  asm("leal -16(%ebp),%esp");
+  asm("pop %eax"); /* really for popl %ebx */
+  asm("pop %eax"); /* really for popl %esi */
+  asm("pop %eax"); /* really for popl %edi */
+  asm("movl %ebp,%esp");
+  asm("popl %ebp");
+
+  asm("movl %ecx,0(%esp)");
+  asm("ret");
+}
+#endif
+
+#if #machine(rs6000)
+__unwind_function(void *ptr)
+{
+  asm("mr 31,1");
+  asm("l 1,0(1)");
+  asm("l 31,-4(1)");
+  asm("# br");
+
+  asm("mr 31,1");
+  asm("l 1,0(1)");
+  /* use 31 as a scratch register to restore the link register. */
+  asm("l 31, 8(1);mtlr 31 # l lr,8(1)");
+  asm("l 31,-4(1)");
+  asm("# br");
+  asm("mtctr 3;bctr # b 3");
+}
+#endif /* rs6000 */
+
+#if #machine(powerpc)
+__unwind_function(void *ptr)
+{
+  asm("mr 31,1");
+  asm("lwz 1,0(1)");
+  asm("lwz 31,-4(1)");
+  asm("# br");
+
+  asm("mr 31,1");
+  asm("lwz 1,0(1)");
+  /* use 31 as a scratch register to restore the link register. */
+  asm("lwz 31, 8(1);mtlr 31 # l lr,8(1)");
+  asm("lwz 31,-4(1)");
+  asm("# br");
+  asm("mtctr 3;bctr # b 3");
+}
+#endif /* powerpc */
+#endif /* L_eh */
+\f
+#ifdef L_pure
+#ifndef inhibit_libc
+/* This gets us __GNU_LIBRARY__.  */
+#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+#include <stdio.h>
+
+#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 */
+
+#define MESSAGE "pure virtual method called\n"
+
+void
+__pure_virtual ()
+{
+#ifndef inhibit_libc
+  write (2, MESSAGE, sizeof (MESSAGE) - 1);
+#endif
+  _exit (-1);
+}
 #endif