OSDN Git Service

Add declaration of ctime.
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index 433627e..a39aa3b 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 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -18,9 +18,10 @@ 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.  */
 
-/* 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.  */
 
@@ -31,7 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tconfig.h"
 #include "machmode.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.  */
@@ -115,6 +116,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)
@@ -640,6 +647,7 @@ __udivmoddi4 (n, d, rp)
 
 #ifdef L_divdi3
 UDItype __udivmoddi4 ();
+
 DItype
 __divdi3 (u, v)
      DItype u, v;
@@ -699,7 +707,7 @@ UDItype
 __umoddi3 (u, v)
      UDItype u, v;
 {
-  DItype w;
+  UDItype w;
 
   (void) __udivmoddi4 (u, v, &w);
 
@@ -1013,23 +1021,61 @@ __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)
+#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+#define DF_SIZE 53
+#define SF_SIZE 24
+#else
+#if TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#else
+#if TARGET_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+#define DF_SIZE 56
+#define SF_SIZE 24
+#else
+#define DF_SIZE 0
+#define SF_SIZE 0
+#endif
+#endif
+#endif
+
 
 SFtype
 __floatdisf (u)
      DItype u;
 {
-  SFtype f;
+  /* 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;
 
+  /* 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;
   f += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -f : f);
+  return (SFtype) (negate ? -f : f);
 }
 #endif
 
@@ -1179,6 +1225,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");
 
@@ -1216,6 +1329,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__
@@ -1251,10 +1365,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__ */
@@ -1282,44 +1399,214 @@ __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 provde 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
+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;
 
-__bb_init_func (blocks)
-       struct bb *blocks;
+/* 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;
 
-/* void * operator new (size_t sz) */
 void *
 __builtin_new (size_t sz)
 {
@@ -1329,13 +1616,33 @@ __builtin_new (size_t sz)
   if (sz == 0)
     sz = 1;
   p = (void *) malloc (sz);
-  if (p == 0)
-    (*__new_handler) ();
+  while (p == 0)
+    {
+      (*__new_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);
+
+void *
+__builtin_vec_new (size_t sz)
+{
+  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__.  */
@@ -1350,35 +1657,25 @@ __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 = __default_new_handler;
 
 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 ()
 {
   /* 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
@@ -1391,7 +1688,10 @@ 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. */
+
 void
 __builtin_delete (void *ptr)
 {
@@ -1399,6 +1699,22 @@ __builtin_delete (void *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 *);
+
+void
+__builtin_vec_delete (void *ptr)
+{
+  __builtin_delete (ptr);
+}
+#endif
+
+/* End of C++ free-store management functions */
 \f
 #ifdef L_shtab
 unsigned int __shtab[] = {
@@ -1422,6 +1738,9 @@ 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;
@@ -1520,6 +1839,7 @@ __clear_cache (beg, end)
 #endif /* just one plane */
 #endif /* Cache is large */
 #endif /* Cache exists */
+#endif /* CLEAR_INSN_CACHE */
 }
 
 #endif /* L_clear_cache */
@@ -1532,6 +1852,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.
@@ -1560,6 +1917,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.  */
@@ -1590,6 +1979,14 @@ __enable_execute_stack ()
 #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.  */
 
@@ -1599,21 +1996,9 @@ __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
 }
 
@@ -1649,7 +2034,7 @@ __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 int initialized = 0;
@@ -1698,7 +2083,7 @@ 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)