/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
-/* Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
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 other files,
some of which are compiled with GCC, to produce an executable,
#include "tconfig.h"
#include "machmode.h"
+#include "defaults.h"
#ifndef L_trampoline
#include <stddef.h>
#endif
#undef abort
#endif
+#if (SUPPORTS_WEAK == 1) && (defined (ASM_OUTPUT_DEF) || defined (ASM_OUTPUT_WEAK_ALIAS))
+#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. */
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
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*
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"
static inline
#endif
DItype
-__negdi2 (u)
- DItype u;
+__negdi2 (DItype u)
{
DIunion w;
DIunion uu;
}
#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
-
+/* Unless shift functions are defined whith full ANSI prototypes,
+ parameter b will be promoted to int if word_type is smaller than an int. */
#ifdef L_lshrdi3
DItype
-__lshrdi3 (u, b)
- DItype u;
- SItype b;
+__lshrdi3 (DItype u, word_type b)
{
DIunion w;
- SItype bm;
+ word_type bm;
DIunion uu;
if (b == 0)
#ifdef L_ashldi3
DItype
-__ashldi3 (u, b)
- DItype u;
- SItype b;
+__ashldi3 (DItype u, word_type b)
{
DIunion w;
- SItype bm;
+ word_type bm;
DIunion uu;
if (b == 0)
#ifdef L_ashrdi3
DItype
-__ashrdi3 (u, b)
- DItype u;
- SItype b;
+__ashrdi3 (DItype u, word_type b)
{
DIunion w;
- SItype bm;
+ word_type bm;
DIunion uu;
if (b == 0)
\f
#ifdef L_ffsdi2
DItype
-__ffsdi2 (u)
- DItype u;
+__ffsdi2 (DItype u)
{
DIunion uu, w;
uu.ll = u;
\f
#ifdef L_muldi3
DItype
-__muldi3 (u, v)
- DItype u, v;
+__muldi3 (DItype u, DItype v)
{
DIunion w;
DIunion uu, vv;
#endif
\f
#ifdef L_udiv_w_sdiv
+#if defined (sdiv_qrnnd)
USItype
-__udiv_w_sdiv (rp, a1, a0, d)
- USItype *rp, a1, a0, d;
+__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
{
USItype q, r;
USItype c0, c1, b1;
*rp = r;
return q;
}
+#else
+/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv. */
+USItype
+__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype 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[] =
{
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;
- UDItype *rp;
+__udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
{
DIunion ww;
DIunion nn, dd;
udiv_qrnnd (q1, n1, n2, n1, d0);
}
- /* n1 != d0... */
+ /* n1 != d0... */
udiv_qrnnd (q0, n0, n1, n0, d0);
UDItype __udivmoddi4 ();
DItype
-__divdi3 (u, v)
- DItype u, v;
+__divdi3 (DItype u, DItype v)
{
- SItype c = 0;
+ word_type c = 0;
DIunion uu, vv;
DItype w;
#ifdef L_moddi3
UDItype __udivmoddi4 ();
DItype
-__moddi3 (u, v)
- DItype u, v;
+__moddi3 (DItype u, DItype v)
{
- SItype c = 0;
+ word_type c = 0;
DIunion uu, vv;
DItype w;
#ifdef L_umoddi3
UDItype __udivmoddi4 ();
UDItype
-__umoddi3 (u, v)
- UDItype u, v;
+__umoddi3 (UDItype u, UDItype v)
{
UDItype w;
#ifdef L_udivdi3
UDItype __udivmoddi4 ();
UDItype
-__udivdi3 (n, d)
- UDItype n, d;
+__udivdi3 (UDItype n, UDItype d)
{
return __udivmoddi4 (n, d, (UDItype *) 0);
}
\f
#ifdef L_cmpdi2
word_type
-__cmpdi2 (a, b)
- DItype a, b;
+__cmpdi2 (DItype a, DItype b)
{
DIunion au, bu;
#ifdef L_ucmpdi2
word_type
-__ucmpdi2 (a, b)
- DItype a, b;
+__ucmpdi2 (DItype a, DItype b)
{
DIunion au, bu;
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DItype
-__fixunstfdi (a)
- TFtype a;
+__fixunstfdi (TFtype a)
{
TFtype b;
UDItype v;
#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
DItype
-__fixtfdi (a)
- TFtype a;
+__fixtfdi (TFtype a)
{
if (a < 0)
return - __fixunstfdi (-a);
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DItype
-__fixunsxfdi (a)
- XFtype a;
+__fixunsxfdi (XFtype a)
{
XFtype b;
UDItype v;
#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
DItype
-__fixxfdi (a)
- XFtype a;
+__fixxfdi (XFtype a)
{
if (a < 0)
return - __fixunsxfdi (-a);
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DItype
-__fixunsdfdi (a)
- DFtype a;
+__fixunsdfdi (DFtype a)
{
DFtype b;
UDItype v;
#ifdef L_fixdfdi
DItype
-__fixdfdi (a)
- DFtype a;
+__fixdfdi (DFtype a)
{
if (a < 0)
return - __fixunsdfdi (-a);
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
XFtype
-__floatdixf (u)
- DItype u;
+__floatdixf (DItype u)
{
XFtype d;
SItype negate = 0;
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
TFtype
-__floatditf (u)
- DItype u;
+__floatditf (DItype u)
{
TFtype d;
SItype negate = 0;
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DFtype
-__floatdidf (u)
- DItype u;
+__floatdidf (DItype u)
{
DFtype d;
SItype negate = 0;
#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 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
-#else
-#if TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT
+#endif
+
+#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
#define DF_SIZE 56
#define SF_SIZE 24
-#else
-#if TARGET_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+#endif
+
+#if HOST_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;
+__floatdisf (DItype u)
{
/* Do the calculation in DFmode
so that we don't lose any of the precision of the high word
#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
+#undef MIN
+#undef MAX
+#include <limits.h>
USItype
-__fixunsxfsi (a)
- XFtype a;
+__fixunsxfsi (XFtype a)
{
if (a >= - (DFtype) LONG_MIN)
return (SItype) (a + LONG_MIN) - LONG_MIN;
#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
+#undef MIN
+#undef MAX
+#include <limits.h>
USItype
-__fixunsdfsi (a)
- DFtype a;
+__fixunsdfsi (DFtype a)
{
if (a >= - (DFtype) LONG_MIN)
return (SItype) (a + LONG_MIN) - LONG_MIN;
#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
+#undef MIN
+#undef MAX
+#include <limits.h>
USItype
__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
-__gcc_bcmp (s1, s2, size)
- unsigned char *s1, *s2;
- size_t size;
+__gcc_bcmp (unsigned char *s1, unsigned char *s2, size_t size)
{
while (size > 0)
{
#endif
\f\f
+#ifdef L__dummy
+void
+__dummy () {}
+#endif
+
#ifdef L_varargs
#ifdef __i860__
#if defined(__svr4__) || defined(__alliant__)
asm (" sw $7,12($30)");
asm (" j $31");
asm (" .end __builtin_saveregs");
-#else /* not __mips__, etc. */
+#else /* not __mips__, etc. */
void *
__builtin_saveregs ()
#include <stdio.h>
/* This is used by the `assert' macro. */
void
-__eprintf (string, expression, line, filename)
- const char *string;
- const char *expression;
- int line;
- const char *filename;
+__eprintf (const char *string, const char *expression,
+ int line, const char *filename)
{
fprintf (stderr, string, expression, line, filename);
fflush (stderr);
const char **functions;
const long *line_nums;
const char **filenames;
+ char *flags;
};
#ifdef BLOCK_PROFILER_CODE
#ifndef inhibit_libc
/* Simple minded basic block profiling output dumper for
- systems that don't provde tcov support. At present,
+ 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
-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
+#include "gbl-ctors.h"
+#include "gcov-io.h"
-static struct bb *bb_head = (struct bb *)0;
+static struct bb *bb_head;
/* Return the number of digits needed to print a value */
/* __inline__ */ static int num_digits (long value, int base)
void
__bb_exit_func (void)
{
- FILE *file = fopen ("bb.out", "a");
+ FILE *da_file, *file;
long time_value;
+ int i;
+
+ if (bb_head == 0)
+ return;
+
+ i = strlen (bb_head->filename) - 3;
+
+ if (!strcmp (bb_head->filename+i, ".da"))
+ {
+ /* Must be -fprofile-arcs not -a.
+ Dump data in a form that gcov expects. */
+
+ struct bb *ptr;
+
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ {
+ /* If the file exists, and the number of counts in it is the same,
+ then merge them in. */
+
+ if ((da_file = fopen (ptr->filename, "r")) != 0)
+ {
+ long n_counts = 0;
+ unsigned char tmp;
+ int i;
+ int ret = 0;
+
+
+ if (__read_long (&n_counts, da_file, 8) != 0)
+ {
+ fprintf (stderr, "arc profiling: Can't read output file %s.\n",
+ ptr->filename);
+ continue;
+ }
+
+ if (n_counts == ptr->ncounts)
+ {
+ int i;
+
+ for (i = 0; i < n_counts; i++)
+ {
+ long v = 0;
+ unsigned char tmp;
+ int j;
+ int ret = 0;
+
+ if (__read_long (&v, da_file, 8) != 0)
+ {
+ fprintf (stderr, "arc profiling: Can't read output file %s.\n",
+ ptr->filename);
+ break;
+ }
+ ptr->counts[i] += v;
+ }
+ }
+
+ if (fclose (da_file) == EOF)
+ fprintf (stderr, "arc profiling: Error closing output file %s.\n",
+ ptr->filename);
+ }
+ if ((da_file = fopen (ptr->filename, "w")) < 0)
+ {
+ fprintf (stderr, "arc profiling: Can't open output file %s.\n",
+ ptr->filename);
+ continue;
+ }
+
+ /* ??? Should first write a header to the file. Perferably, a 4 byte
+ magic number, 4 bytes containing the time the program was
+ compiled, 4 bytes containing the last modification time of the
+ source file, and 4 bytes indicating the compiler options used.
+
+ That way we can easily verify that the proper source/executable/
+ data file combination is being used from gcov. */
+
+ if (__write_long (ptr->ncounts, da_file, 8) != 0)
+ {
+
+ fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ }
+ else
+ {
+ int j;
+ long *count_ptr = ptr->counts;
+ int ret = 0;
+ for (j = ptr->ncounts; j > 0; j--)
+ {
+ if (__write_long (*count_ptr, da_file, 8) != 0)
+ {
+ ret=1;
+ break;
+ }
+ count_ptr++;
+ }
+ if (ret)
+ fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ }
+
+ if (fclose (da_file) == EOF)
+ fprintf (stderr, "arc profiling: Error closing output file %s.\n",
+ ptr->filename);
+ }
+
+ return;
+ }
+
+ /* Must be basic block profiling. Emit a human readable output file. */
+
+ file = fopen ("bb.out", "a");
if (!file)
perror ("bb.out");
/* 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)
+ 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);
+ 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)
+ 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 func_p = (ptr->nwords >= sizeof (struct bb)
+ && ptr->nwords <= 1000
+ && ptr->functions);
int line_p = (func_p && ptr->line_nums);
int file_p = (func_p && ptr->filenames);
+ int addr_p = (ptr->addresses != 0);
long ncounts = ptr->ncounts;
long cnt_max = 0;
long line_max = 0;
if (cnt_max < ptr->counts[i])
cnt_max = ptr->counts[i];
- if (addr_max < ptr->addresses[i])
+ if (addr_p && addr_max < ptr->addresses[i])
addr_max = ptr->addresses[i];
if (line_p && line_max < ptr->line_nums[i])
for (i = 0; i < ncounts; i++)
{
fprintf (file,
- " Block #%*d: executed %*ld time(s) address= 0x%.*lx",
+ " Block #%*d: executed %*ld time(s)",
blk_len, i+1,
- cnt_len, ptr->counts[i],
- addr_len, ptr->addresses[i]);
+ cnt_len, ptr->counts[i]);
+
+ if (addr_p)
+ fprintf (file, " address= 0x%.*lx", addr_len,
+ ptr->addresses[i]);
if (func_p)
fprintf (file, " function= %-*s", func_len,
__bb_init_func (struct bb *blocks)
{
/* User is supposed to check whether the first word is non-0,
- but just in case.... */
+ but just in case.... */
if (blocks->zero_word)
return;
bb_head = blocks;
}
-#endif /* not inhibit_libc */
-#endif /* not BLOCK_PROFILER_CODE */
-#endif /* L_bb */
-\f
-/* Default free-store management functions for C++, per sections 12.5 and
- 17.3.3 of the Working Paper. */
+#ifndef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID)
+#endif
+#ifndef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID)
+#endif
-#ifdef L_op_new
-/* 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. */
+#include <string.h>
-typedef void (*vfp)(void);
-extern vfp __new_handler;
+/* Number of buckets in hashtable of basic block addresses. */
-void *
-__builtin_new (size_t sz)
-{
- void *p;
+#define BB_BUCKETS 311
- /* malloc (0) is unpredictable; avoid it. */
- if (sz == 0)
- sz = 1;
- p = (void *) malloc (sz);
- while (p == 0)
- {
- (*__new_handler) ();
- p = (void *) malloc (sz);
- }
-
- return p;
-}
-#endif /* L_op_new */
+/* Maximum length of string in file bb.in. */
-#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. */
+#define BBINBUFSIZE 500
-extern void * __builtin_new (size_t);
+/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
+ "BBINBUFSIZE" but want to avoid trouble with preprocessors. */
-void *
-__builtin_vec_new (size_t sz)
+#define BBINBUFSIZESTR "499"
+
+struct bb_edge
{
- return __builtin_new (sz);
-}
-#endif /* L_op_vnew */
+ struct bb_edge *next;
+ unsigned long src_addr;
+ unsigned long dst_addr;
+ unsigned long count;
+};
-#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 []. */
+enum bb_func_mode
+{
+ TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
+};
-#ifndef inhibit_libc
-/* This gets us __GNU_LIBRARY__. */
-#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
-#include <stdio.h>
+struct bb_func
+{
+ struct bb_func *next;
+ char *funcname;
+ char *filename;
+ enum bb_func_mode mode;
+};
-#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 */
+/* This is the connection to the outside world.
+ The BLOCK_PROFILER macro must set __bb.blocks
+ and __bb.blockno. */
-typedef void (*vfp)(void);
-void __default_new_handler (void);
+struct {
+ unsigned long blockno;
+ struct bb *blocks;
+} __bb;
-vfp __new_handler = __default_new_handler;
+/* Vars to store addrs of source and destination basic blocks
+ of a jump. */
-vfp
-set_new_handler (vfp handler)
-{
- vfp prev_handler;
+static unsigned long bb_src = 0;
+static unsigned long bb_dst = 0;
- prev_handler = __new_handler;
- if (handler == 0) handler = __default_new_handler;
- __new_handler = handler;
- return prev_handler;
-}
+static FILE *bb_tracefile = (FILE *) 0;
+static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
+static struct bb_func *bb_func_head = (struct bb_func *) 0;
+static unsigned long bb_callcount = 0;
+static int bb_mode = 0;
-#define MESSAGE "Virtual memory exceeded in `new'\n"
+static unsigned long *bb_stack = (unsigned long *) 0;
+static size_t bb_stacksize = 0;
-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, MESSAGE, sizeof (MESSAGE));
- /* don't call exit () because that may call global destructors which
- may cause a loop. */
- _exit (-1);
-}
-#endif
+static int reported = 0;
-#ifdef L_op_delete
-/* 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. */
+/* Trace modes:
+Always : Print execution frequencies of basic blocks
+ to file bb.out.
+bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
+bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
+bb_mode & 4 != 0 : Cut call instructions from basic block flow.
+bb_mode & 8 != 0 : Insert return instructions in basic block flow.
+*/
-void
-__builtin_delete (void *ptr)
+#ifdef HAVE_POPEN
+
+/*#include <sys/types.h>*/
+#include <sys/stat.h>
+/*#include <malloc.h>*/
+
+/* Commands executed by gopen. */
+
+#define GOPENDECOMPRESS "gzip -cd "
+#define GOPENCOMPRESS "gzip -c >"
+
+/* Like fopen but pipes through gzip. mode may only be "r" or "w".
+ If it does not compile, simply replace gopen by fopen and delete
+ '.gz' from any first parameter to gopen. */
+
+static FILE *
+gopen (char *fn, char *mode)
{
- if (ptr)
- free (ptr);
-}
-#endif
+ int use_gzip;
+ char *p;
-#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. */
+ if (mode[1])
+ return (FILE *) 0;
-extern void __builtin_delete (void *);
+ if (mode[0] != 'r' && mode[0] != 'w')
+ return (FILE *) 0;
-void
-__builtin_vec_delete (void *ptr)
+ p = fn + strlen (fn)-1;
+ use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
+ || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
+
+ if (use_gzip)
+ {
+ if (mode[0]=='r')
+ {
+ FILE *f;
+ char *s = (char *) malloc (sizeof (char) * strlen (fn)
+ + sizeof (GOPENDECOMPRESS));
+ strcpy (s, GOPENDECOMPRESS);
+ strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
+ f = popen (s, mode);
+ free (s);
+ return f;
+ }
+
+ else
+ {
+ FILE *f;
+ char *s = (char *) malloc (sizeof (char) * strlen (fn)
+ + sizeof (GOPENCOMPRESS));
+ strcpy (s, GOPENCOMPRESS);
+ strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
+ if (!(f = popen (s, mode)))
+ f = fopen (s, mode);
+ free (s);
+ return f;
+ }
+ }
+
+ else
+ return fopen (fn, mode);
+}
+
+static int
+gclose (FILE *f)
{
- __builtin_delete (ptr);
+ struct stat buf;
+
+ if (f != 0)
+ {
+ if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
+ return pclose (f);
+
+ return fclose (f);
+ }
+ return 0;
}
-#endif
-/* End of C++ free-store management functions */
-\f
-#ifdef L_shtab
-unsigned int __shtab[] = {
- 0x00000001, 0x00000002, 0x00000004, 0x00000008,
- 0x00000010, 0x00000020, 0x00000040, 0x00000080,
- 0x00000100, 0x00000200, 0x00000400, 0x00000800,
- 0x00001000, 0x00002000, 0x00004000, 0x00008000,
- 0x00010000, 0x00020000, 0x00040000, 0x00080000,
- 0x00100000, 0x00200000, 0x00400000, 0x00800000,
- 0x01000000, 0x02000000, 0x04000000, 0x08000000,
- 0x10000000, 0x20000000, 0x40000000, 0x80000000
- };
-#endif
-\f
-#ifdef L_clear_cache
-/* Clear part of an instruction cache. */
+#endif /* HAVE_POPEN */
-#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
+/* Called once per program. */
-void
-__clear_cache (beg, end)
- char *beg, *end;
+static void
+__bb_exit_trace_func ()
{
-#ifdef CLEAR_INSN_CACHE
- CLEAR_INSN_CACHE (beg, end);
+ FILE *file = fopen ("bb.out", "a");
+ struct bb_func *f;
+ struct bb_edge *e;
+ struct bb *b;
+
+ if (!file)
+ perror ("bb.out");
+
+ if (bb_mode & 1)
+ {
+ if (!bb_tracefile)
+ perror ("bbtrace");
+ else
+#ifdef HAVE_POPEN
+ gclose (bb_tracefile);
+#else
+ fclose (bb_tracefile);
+#endif /* HAVE_POPEN */
+ }
+
+ /* Check functions in `bb.in'. */
+
+ if (file)
+ {
+ long time_value;
+ const struct bb_func *p;
+ int printed_something = 0;
+ struct bb *ptr;
+ long blk;
+
+ /* This is somewhat type incorrect. */
+ time ((void *) &time_value);
+
+ for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
+ {
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ {
+ if (!ptr->filename || p->filename != (char *) 0 && strcmp (p->filename, ptr->filename))
+ continue;
+ for (blk = 0; blk < ptr->ncounts; blk++)
+ {
+ if (!strcmp (p->funcname, ptr->functions[blk]))
+ goto found;
+ }
+ }
+
+ if (!printed_something)
+ {
+ fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
+ printed_something = 1;
+ }
+
+ fprintf (file, "\tFunction %s", p->funcname);
+ if (p->filename)
+ fprintf (file, " of file %s", p->filename);
+ fprintf (file, "\n" );
+
+found: ;
+ }
+
+ if (printed_something)
+ fprintf (file, "\n");
+
+ }
+
+ if (bb_mode & 2)
+ {
+ if (!bb_hashbuckets)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ return;
+ }
+
+ else if (file)
+ {
+ long time_value;
+ int i;
+ unsigned long addr_max = 0;
+ unsigned long cnt_max = 0;
+ int cnt_len;
+ int addr_len;
+
+ /* 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 jump tracing");
+
+ switch (bb_mode & 12)
+ {
+ case 0:
+ fprintf (file, " (with call)");
+ break;
+
+ case 4:
+ /* Print nothing. */
+ break;
+
+ case 8:
+ fprintf (file, " (with call & ret)");
+ break;
+
+ case 12:
+ fprintf (file, " (with ret)");
+ break;
+ }
+
+ fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
+
+ for (i = 0; i < BB_BUCKETS; i++)
+ {
+ struct bb_edge *bucket = bb_hashbuckets[i];
+ for ( ; bucket; bucket = bucket->next )
+ {
+ if (addr_max < bucket->src_addr)
+ addr_max = bucket->src_addr;
+ if (addr_max < bucket->dst_addr)
+ addr_max = bucket->dst_addr;
+ if (cnt_max < bucket->count)
+ cnt_max = bucket->count;
+ }
+ }
+ addr_len = num_digits (addr_max, 16);
+ cnt_len = num_digits (cnt_max, 10);
+
+ for ( i = 0; i < BB_BUCKETS; i++)
+ {
+ struct bb_edge *bucket = bb_hashbuckets[i];
+ for ( ; bucket; bucket = bucket->next )
+ {
+ fprintf (file, "Jump from block 0x%.*lx to "
+ "block 0x%.*lx executed %*d time(s)\n",
+ addr_len, bucket->src_addr,
+ addr_len, bucket->dst_addr,
+ cnt_len, bucket->count);
+ }
+ }
+
+ fprintf (file, "\n");
+
+ }
+ }
+
+ if (file)
+ fclose (file);
+
+ /* Free allocated memory. */
+
+ f = bb_func_head;
+ while (f)
+ {
+ struct bb_func *old = f;
+
+ f = f->next;
+ if (old->funcname) free (old->funcname);
+ if (old->filename) free (old->filename);
+ free (old);
+ }
+
+ if (bb_stack)
+ free (bb_stack);
+
+ if (bb_hashbuckets)
+ {
+ int i;
+
+ for (i = 0; i < BB_BUCKETS; i++)
+ {
+ struct bb_edge *old, *bucket = bb_hashbuckets[i];
+
+ while (bucket)
+ {
+ old = bucket;
+ bucket = bucket->next;
+ free (old);
+ }
+ }
+ free (bb_hashbuckets);
+ }
+
+ for (b = bb_head; b; b = b->next)
+ if (b->flags) free (b->flags);
+}
+
+/* Called once per program. */
+
+static void
+__bb_init_prg ()
+{
+
+ FILE *file;
+ char buf[BBINBUFSIZE];
+ const char *p;
+ const char *pos;
+ enum bb_func_mode m;
+
+#ifdef ON_EXIT
+ /* Initialize destructor. */
+ ON_EXIT (__bb_exit_func, 0);
+#endif
+
+ if (!(file = fopen ("bb.in", "r")))
+ return;
+
+ while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF)
+ {
+ p = buf;
+ if (*p == '-')
+ {
+ m = TRACE_OFF;
+ p++;
+ }
+ else
+ {
+ m = TRACE_ON;
+ }
+ if (!strcmp (p, "__bb_trace__"))
+ bb_mode |= 1;
+ else if (!strcmp (p, "__bb_jumps__"))
+ bb_mode |= 2;
+ else if (!strcmp (p, "__bb_hidecall__"))
+ bb_mode |= 4;
+ else if (!strcmp (p, "__bb_showret__"))
+ bb_mode |= 8;
+ else
+ {
+ struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
+ if (f)
+ {
+ unsigned long l;
+ f->next = bb_func_head;
+ if (pos = strchr (p, ':'))
+ {
+ if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
+ continue;
+ strcpy (f->funcname, pos+1);
+ l = pos-p;
+ if ((f->filename = (char *) malloc (l+1)))
+ {
+ strncpy (f->filename, p, l);
+ f->filename[l] = '\0';
+ }
+ else
+ f->filename = (char *) 0;
+ }
+ else
+ {
+ if (!(f->funcname = (char *) malloc (strlen (p)+1)))
+ continue;
+ strcpy (f->funcname, p);
+ f->filename = (char *) 0;
+ }
+ f->mode = m;
+ bb_func_head = f;
+ }
+ }
+ }
+ fclose (file);
+
+#ifdef HAVE_POPEN
+
+ if (bb_mode & 1)
+ bb_tracefile = gopen ("bbtrace.gz", "w");
+
+#else
+
+ if (bb_mode & 1)
+ bb_tracefile = fopen ("bbtrace", "w");
+
+#endif /* HAVE_POPEN */
+
+ if (bb_mode & 2)
+ {
+ bb_hashbuckets = (struct bb_edge **)
+ malloc (BB_BUCKETS * sizeof (struct bb_edge *));
+ if (bb_hashbuckets)
+ bzero ((char *) bb_hashbuckets, BB_BUCKETS);
+ }
+
+ if (bb_mode & 12)
+ {
+ bb_stacksize = 10;
+ bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
+ }
+
+#ifdef ON_EXIT
+ /* Initialize destructor. */
+ ON_EXIT (__bb_exit_trace_func, 0);
+#endif
+
+}
+
+/* Called upon entering a basic block. */
+
+void
+__bb_trace_func ()
+{
+ struct bb_edge *bucket;
+
+ MACHINE_STATE_SAVE("1")
+
+ if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
+ goto skip;
+
+ bb_dst = __bb.blocks->addresses[__bb.blockno];
+ __bb.blocks->counts[__bb.blockno]++;
+
+ if (bb_tracefile)
+ {
+ fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
+ }
+
+ if (bb_hashbuckets)
+ {
+ struct bb_edge **startbucket, **oldnext;
+
+ oldnext = startbucket
+ = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
+ bucket = *startbucket;
+
+ for (bucket = *startbucket; bucket;
+ oldnext = &(bucket->next), bucket = *oldnext)
+ {
+ if (bucket->src_addr == bb_src
+ && bucket->dst_addr == bb_dst)
+ {
+ bucket->count++;
+ *oldnext = bucket->next;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ goto ret;
+ }
+ }
+
+ bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
+
+ if (!bucket)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ }
+
+ else
+ {
+ bucket->src_addr = bb_src;
+ bucket->dst_addr = bb_dst;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ bucket->count = 1;
+ }
+ }
+
+ret:
+ bb_src = bb_dst;
+
+skip:
+ ;
+
+ MACHINE_STATE_RESTORE("1")
+
+}
+
+/* Called when returning from a function and `__bb_showret__' is set. */
+
+static void
+__bb_trace_func_ret ()
+{
+ struct bb_edge *bucket;
+
+ if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
+ goto skip;
+
+ if (bb_hashbuckets)
+ {
+ struct bb_edge **startbucket, **oldnext;
+
+ oldnext = startbucket
+ = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
+ bucket = *startbucket;
+
+ for (bucket = *startbucket; bucket;
+ oldnext = &(bucket->next), bucket = *oldnext)
+ {
+ if (bucket->src_addr == bb_dst
+ && bucket->dst_addr == bb_src)
+ {
+ bucket->count++;
+ *oldnext = bucket->next;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ goto ret;
+ }
+ }
+
+ bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
+
+ if (!bucket)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ }
+
+ else
+ {
+ bucket->src_addr = bb_dst;
+ bucket->dst_addr = bb_src;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ bucket->count = 1;
+ }
+ }
+
+ret:
+ bb_dst = bb_src;
+
+skip:
+ ;
+
+}
+
+/* Called upon entering the first function of a file. */
+
+static void
+__bb_init_file (struct bb *blocks)
+{
+
+ const struct bb_func *p;
+ long blk, ncounts = blocks->ncounts;
+ const char **functions = blocks->functions;
+
+ /* Set up linked list. */
+ blocks->zero_word = 1;
+ blocks->next = bb_head;
+ bb_head = blocks;
+
+ blocks->flags = 0;
+ if (!bb_func_head
+ || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
+ return;
+
+ for (blk = 0; blk < ncounts; blk++)
+ blocks->flags[blk] = 0;
+
+ for (blk = 0; blk < ncounts; blk++)
+ {
+ for (p = bb_func_head; p; p = p->next)
+ {
+ if (!strcmp (p->funcname, functions[blk])
+ && (!p->filename || !strcmp (p->filename, blocks->filename)))
+ {
+ blocks->flags[blk] |= p->mode;
+ }
+ }
+ }
+
+}
+
+/* Called when exiting from a function. */
+
+void
+__bb_trace_ret ()
+{
+
+ MACHINE_STATE_SAVE("2")
+
+ if (bb_callcount)
+ {
+ if ((bb_mode & 12) && bb_stacksize > bb_callcount)
+ {
+ bb_src = bb_stack[bb_callcount];
+ if (bb_mode & 8)
+ __bb_trace_func_ret ();
+ }
+
+ bb_callcount -= 1;
+ }
+
+ MACHINE_STATE_RESTORE("2")
+
+}
+
+/* Called when entering a function. */
+
+void
+__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
+{
+ static int trace_init = 0;
+
+ MACHINE_STATE_SAVE("3")
+
+ if (!blocks->zero_word)
+ {
+ if (!trace_init)
+ {
+ trace_init = 1;
+ __bb_init_prg ();
+ }
+ __bb_init_file (blocks);
+ }
+
+ if (bb_callcount)
+ {
+
+ bb_callcount += 1;
+
+ if (bb_mode & 12)
+ {
+ if (bb_callcount >= bb_stacksize)
+ {
+ size_t newsize = bb_callcount + 100;
+
+ bb_stack = (unsigned long *) realloc (bb_stack, newsize);
+ if (! bb_stack)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ bb_stacksize = 0;
+ goto stack_overflow;
+ }
+ bb_stacksize = newsize;
+ }
+ bb_stack[bb_callcount] = bb_src;
+
+ if (bb_mode & 4)
+ bb_src = 0;
+
+ }
+
+stack_overflow:;
+
+ }
+
+ else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
+ {
+ bb_callcount = 1;
+ bb_src = 0;
+
+ if (bb_stack)
+ bb_stack[bb_callcount] = bb_src;
+ }
+
+ MACHINE_STATE_RESTORE("3")
+}
+
+#endif /* not inhibit_libc */
+#endif /* not BLOCK_PROFILER_CODE */
+#endif /* L_bb */
+\f
+/* Default free-store management functions for C++, per sections 12.5 and
+ 17.3.3 of the Working Paper. */
+
+#ifdef L_op_new
+/* 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);
+
+#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);
+ 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__. */
+#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 */
+
+typedef void (*vfp)(void);
+void __default_new_handler (void);
+
+vfp __new_handler = (vfp) 0;
+
+vfp
+set_new_handler (vfp handler)
+{
+ vfp prev_handler;
+
+ prev_handler = __new_handler;
+ if (handler == 0) handler = __default_new_handler;
+ __new_handler = handler;
+ return prev_handler;
+}
+
+#define MESSAGE "Virtual memory exceeded in `new'\n"
+
+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);
+}
+#endif
+
+#ifdef L_op_delete
+/* 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[] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000
+ };
+#endif
+\f
+#ifdef L_clear_cache
+/* Clear part of an instruction cache. */
+
+#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
+
+void
+__clear_cache (char *beg, char *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;
= JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
ptr += INSN_CACHE_LINE_WIDTH;
}
- *(INSTRUCTION_TYPE *)(ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
+ *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
initialized = 1;
}
/* Jump to a trampoline, loading the static chain address. */
+#ifdef WINNT
+
+long getpagesize()
+{
+#ifdef _ALPHA_
+ return 8192;
+#else
+ return 4096;
+#endif
+}
+
+int mprotect(char *addr, int len, int prot)
+{
+ int np, op;
+
+ if (prot == 7) np = 0x40;
+ else if (prot == 5) np = 0x20;
+ else if (prot == 4) np = 0x10;
+ else if (prot == 3) np = 0x04;
+ else if (prot == 1) np = 0x02;
+ else if (prot == 0) np = 0x01;
+
+ if (VirtualProtect (addr, len, np, &op))
+ return 0;
+ else
+ return -1;
+
+}
+
+#endif
+
#ifdef TRANSFER_FROM_TRAMPOLINE
TRANSFER_FROM_TRAMPOLINE
#endif
#endif
void
-__enable_execute_stack (addr)
- char *addr;
+__enable_execute_stack (char *addr)
{
kern_return_t r;
char *eaddr = addr + TRAMPOLINE_SIZE;
lowest = current;
}
- /* Clear instruction cache in case an old trampoline is in it. */
+ /* Clear instruction cache in case an old trampoline is in it. */
asm ("pich");
}
#endif /* __convex__ */
#ifdef __DOLPHIN__
-/* Modified from the convex -code above. */
+/* Modified from the convex -code above. */
#include <sys/param.h>
#include <errno.h>
#include <sys/vmmac.h>
/* Modified from the convex -code above.
- mremap promises to clear the i-cache. */
+ mremap promises to clear the i-cache. */
void
__enable_execute_stack ()
}
}
#endif /* __pyr__ */
+
+#if defined (sony_news) && defined (SYSTYPE_BSD)
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <syscall.h>
+#include <machine/sysnews.h>
+
+/* cacheflush function for NEWS-OS 4.2.
+ This function is called from trampoline-initialize code
+ defined in config/mips/mips.h. */
+
+void
+cacheflush (char *beg, int size, int flag)
+{
+ if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
+ {
+ perror ("cache_flush");
+ fflush (stderr);
+ abort ();
+ }
+}
+
+#endif /* sony_news */
#endif /* L_trampoline */
\f
#ifdef L__main
/* 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)
+#ifdef INIT_SECTION_ASM_OP
+#undef HAS_INIT_SECTION
+#define HAS_INIT_SECTION
+#endif
+
+#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
/* Run all the global destructors on exit from the program. */
void
#ifdef DO_GLOBAL_DTORS_BODY
DO_GLOBAL_DTORS_BODY;
#else
- func_ptr *p;
- for (p = __DTOR_LIST__ + 1; *p; )
- (*p++) ();
+ static func_ptr *p = __DTOR_LIST__ + 1;
+ while (*p)
+ {
+ p++;
+ (*(p-1)) ();
+ }
#endif
}
#endif
-#ifndef INIT_SECTION_ASM_OP
+#ifndef HAS_INIT_SECTION
/* Run all the global constructors on entry to the program. */
#ifndef ON_EXIT
DO_GLOBAL_CTORS_BODY;
ON_EXIT (__do_global_dtors, 0);
}
-#endif /* no INIT_SECTION_ASM_OP */
+#endif /* no HAS_INIT_SECTION */
-#if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
+#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
/* Subroutine called automatically by `main'.
Compiling a global function named `main'
produces an automatic call to this function at the beginning.
SYMBOL__MAIN ()
{
/* Support recursive calls to `main': run initializers just once. */
- static int initialized = 0;
+ static int initialized;
if (! initialized)
{
initialized = 1;
__do_global_ctors ();
}
}
-#endif /* no INIT_SECTION_ASM_OP or INVOKE__main */
+#endif /* no HAS_INIT_SECTION or INVOKE__main */
#endif /* L__main */
\f
/* We declare the lists here with two elements each,
so that they are valid empty lists if no other definition is loaded. */
#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
-#ifdef __NeXT__
+#if defined(__NeXT__) || defined(_AIX)
/* After 2.3, try this definition on all systems. */
func_ptr __CTOR_LIST__[2] = {0, 0};
func_ptr __DTOR_LIST__[2] = {0, 0};
#include "gbl-ctors.h"
+#ifdef NEED_ATEXIT
+# ifdef ON_EXIT
+# undef ON_EXIT
+# endif
+int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
+#endif
+
#ifndef ON_EXIT
+#ifdef NEED_ATEXIT
+# include <errno.h>
+
+static func_ptr *atexit_chain = 0;
+static long atexit_chain_length = 0;
+static volatile long last_atexit_chain_slot = -1;
+
+int atexit (func_ptr func)
+{
+ if (++last_atexit_chain_slot == atexit_chain_length)
+ {
+ atexit_chain_length += 32;
+ if (atexit_chain)
+ atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
+ * sizeof (func_ptr));
+ else
+ atexit_chain = (func_ptr *) malloc (atexit_chain_length
+ * sizeof (func_ptr));
+ if (! atexit_chain)
+ {
+ atexit_chain_length = 0;
+ last_atexit_chain_slot = -1;
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+ atexit_chain[last_atexit_chain_slot] = func;
+ return (0);
+}
+#endif /* NEED_ATEXIT */
+
/* If we have no known way of registering our own __do_global_dtors
routine so that it will be invoked at program exit time, then we
have to define our own exit routine which will get this to happen. */
extern void __do_global_dtors ();
+extern void __bb_exit_func ();
extern void _cleanup ();
extern void _exit () __attribute__ ((noreturn));
void
-exit (status)
- int status;
+exit (int status)
{
+#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
+#ifdef NEED_ATEXIT
+ if (atexit_chain)
+ {
+ for ( ; last_atexit_chain_slot-- >= 0; )
+ {
+ (*atexit_chain[last_atexit_chain_slot + 1]) ();
+ atexit_chain[last_atexit_chain_slot + 1] = 0;
+ }
+ free (atexit_chain);
+ atexit_chain = 0;
+ }
+#else /* No NEED_ATEXIT */
__do_global_dtors ();
+#endif /* No NEED_ATEXIT */
+#endif
+#ifndef inhibit_libc
+ __bb_exit_func ();
+#endif
#ifdef EXIT_BODY
EXIT_BODY;
#else
#endif /* L_exit */
\f
#ifdef L_eh
+
+#ifdef EH_TABLE_LOOKUP
+
+EH_TABLE_LOOKUP
+
+#else
+
+void
+__default_terminate ()
+{
+ abort ();
+}
+
+void (*__terminate_func)() = __default_terminate;
+
+void
+__terminate ()
+{
+ (*__terminate_func)();
+}
+
+/* Calls to __sjthrow are generated by the compiler when an exception
+ is raised when using the setjmp/longjmp exception handling codegen
+ method. */
+
+extern void longjmp (void *, int);
+
+extern void *__eh_type;
+
+static void *top_elt[2];
+void **__dynamic_handler_chain = top_elt;
+
+/* Routine to get the head of the current thread's dynamic handler chain
+ use for exception handling.
+
+ TODO: make thread safe. */
+
+void ***
+__get_dynamic_handler_chain ()
+{
+ return &__dynamic_handler_chain;
+}
+
+/* This is used to throw an exception when the setjmp/longjmp codegen
+ method is used for exception handling.
+
+ We call __terminate if there are no handlers left (we know this
+ when the dynamic handler chain is top_elt). Otherwise we run the
+ cleanup actions off the dynamic cleanup stack, and pop the top of
+ the dynamic handler chain, and use longjmp to transfer back to the
+ associated handler. */
+
+void
+__sjthrow ()
+{
+ void ***dhc = __get_dynamic_handler_chain ();
+ void *jmpbuf;
+ void (*func)(void *, int);
+ void *arg;
+ void ***cleanup;
+
+ /* The cleanup chain is one word into the buffer. Get the cleanup
+ chain. */
+ cleanup = (void***)&(*dhc)[1];
+
+ /* If there are any cleanups in the chain, run them now. */
+ if (cleanup[0])
+ {
+ double store[200];
+ void **buf = (void**)store;
+ buf[1] = 0;
+ buf[0] = (*dhc);
+
+ /* try { */
+#ifdef DONT_USE_BUILTIN_SETJMP
+ if (! setjmp (&buf[2]))
+#else
+ if (! __builtin_setjmp (&buf[2]))
+#endif
+ {
+ *dhc = buf;
+ while (cleanup[0])
+ {
+ func = (void(*)(void*, int))cleanup[0][1];
+ arg = (void*)cleanup[0][2];
+
+ /* Update this before running the cleanup. */
+ cleanup[0] = (void **)cleanup[0][0];
+
+ (*func)(arg, 2);
+ }
+ *dhc = buf[0];
+ }
+ /* catch (...) */
+ else
+ {
+ __terminate ();
+ }
+ }
+
+ /* We must call terminate if we try and rethrow an exception, when
+ there is no exception currently active and when there are no
+ handlers left. */
+ if (! __eh_type || (*dhc) == top_elt)
+ __terminate ();
+
+ /* Find the jmpbuf associated with the top element of the dynamic
+ handler chain. The jumpbuf starts two words into the buffer. */
+ jmpbuf = &(*dhc)[2];
+
+ /* Then we pop the top element off the dynamic handler chain. */
+ *dhc = (void**)(*dhc)[0];
+
+ /* And then we jump to the handler. */
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+ longjmp (jmpbuf, 1);
+#else
+ __builtin_longjmp (jmpbuf, 1);
+#endif
+}
+
+/* Run cleanups on the dynamic cleanup stack for the current dynamic
+ handler, then pop the handler off the dynamic handler stack, and
+ then throw. This is used to skip the first handler, and transfer
+ control to the next handler in the dynamic handler stack. */
+
+void
+__sjpopnthrow ()
+{
+ void ***dhc = __get_dynamic_handler_chain ();
+ void *jmpbuf;
+ void (*func)(void *, int);
+ void *arg;
+ void ***cleanup;
+
+ /* The cleanup chain is one word into the buffer. Get the cleanup
+ chain. */
+ cleanup = (void***)&(*dhc)[1];
+
+ /* If there are any cleanups in the chain, run them now. */
+ if (cleanup[0])
+ {
+ double store[200];
+ void **buf = (void**)store;
+ buf[1] = 0;
+ buf[0] = (*dhc);
+
+ /* try { */
+#ifdef DONT_USE_BUILTIN_SETJMP
+ if (! setjmp (&buf[2]))
+#else
+ if (! __builtin_setjmp (&buf[2]))
+#endif
+ {
+ *dhc = buf;
+ while (cleanup[0])
+ {
+ func = (void(*)(void*, int))cleanup[0][1];
+ arg = (void*)cleanup[0][2];
+
+ /* Update this before running the cleanup. */
+ cleanup[0] = (void **)cleanup[0][0];
+
+ (*func)(arg, 2);
+ }
+ *dhc = buf[0];
+ }
+ /* catch (...) */
+ else
+ {
+ __terminate ();
+ }
+ }
+
+ /* Then we pop the top element off the dynamic handler chain. */
+ *dhc = (void**)(*dhc)[0];
+
+ __sjthrow ();
+}
+
typedef struct {
void *start;
void *end;
struct exception_table_node *next;
};
-static int except_table_pos = 0;
-static void *except_pc = (void *)0;
-static struct exception_table_node *exception_table_list = 0;
-
-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;
-}
+static struct exception_table_node *exception_table_list;
/* this routine takes a pc, and the address of the exception handler associated
with the closest exception table handler entry associated with that PC,
return 0;
Assuming a correctly sorted table (ascending order) this routine should
- return the tighest match...
+ return the tightest match...
In the advent of a tie, we have to give the last entry, as it represents
- an inner block.
- */
-
+ 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;
+__find_first_exception_table_match (void *pc)
+{
+ register struct exception_table_node *tnp;
+ register exception_table *table;
+ int pos;
+ int best;
+
#if 0
- printf("find_first_exception_table_match(): pc = %x!\n",pc);
+ printf ("find_first_exception_table_match (): pc = %x!\n", pc);
#endif
- except_pc = pc;
+ for (tnp = exception_table_list; tnp != 0; tnp = tnp->next)
+ {
+ if (tnp->start > pc || tnp->end <= pc)
+ continue;
+
+ table = tnp->table;
+ pos = 0;
+ best = 0;
#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;
+ /* We can't do this yet, as we don't know that the table is sorted. */
+ do {
+ ++pos;
+ if (table[pos].start > pc)
+ /* found the first table[pos].start > pc, so the previous
+ entry better be the one we want! */
+ break;
+ } while (table[pos].exception_handler != (void *) -1);
+
+ --pos;
+ if (table[pos].start <= pc && table[pos].end > pc)
+ {
#if 0
- printf("find_first_eh_table_match(): found match: %x\n",table[pos].exception_handler);
+ printf ("find_first_eh_table_match (): found match: %x\n", table[pos].exception_handler);
#endif
- return table[pos].exception_handler;
- }
+ 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;
+ while (table[++pos].exception_handler != (void *) -1) {
+ if (table[pos].start <= pc && table[pos].end > 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");
+ if (best != 0)
+ return table[best].exception_handler;
#endif
- return (void*)0;
-}
+ }
-int
-__throw_type_match (const char *catch_type, const char *throw_type)
-{
#if 0
- printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
- catch_type, throw_type);
+ printf ("find_first_eh_table_match (): else: returning NULL!\n");
#endif
- return strcmp (catch_type, throw_type);
+ return (void *) 0;
}
void
__register_exceptions (exception_table *table)
{
- struct exception_table_node *node = (struct exception_table_node*)
- malloc (sizeof (struct exception_table_node));
+ 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. */
+ is sorted, or if we pass in extra parameters. */
node->start = range->start;
node->end = range->end;
- for (range++ ; range->start != (void*)(-1); range++)
+ for (range++ ; range->start != (void *) (-1); range++)
{
if (range->start < node->start)
node->start = range->start;
node->next = exception_table_list;
exception_table_list = node;
}
+#endif
+
+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;
+}
+
+/* Throw stub routine.
+
+ This is work in progress, but not completed yet. */
+
+void
+__throw ()
+{
+ abort ();
+}
+
+/* This value identifies the place from which an exception is being
+ thrown. */
+
+void *__eh_pc;
+
+/* See expand_builtin_throw for details. */
+
+void **__eh_ffetmnpc () {
+ static void *buf[2] = {
+ &__find_first_exception_table_match,
+ &__eh_pc
+ };
+ return buf;
+}
-#ifdef __i386
+void
+__empty ()
+{
+}
+
+#if #machine(i386)
void
__unwind_function(void *ptr)
{
/* Undo current frame */
asm("movl %ebp,%esp");
asm("popl %ebp");
- asm("# like ret, but stay here");
+ /* like ret, but stay here */
asm("addl $4,%esp");
- /* Now, undo previous frame. */
+ /* 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. */
+ 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("pop %ebx");
+ asm("pop %esi");
+ asm("pop %edi");
asm("movl %ebp,%esp");
asm("popl %ebp");
asm("movl %ecx,0(%esp)");
asm("ret");
}
-#endif
+#elif #machine(rs6000) && !defined _ARCH_PPC
+__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");
+}
+#elif (#machine(rs6000) || #machine(powerpc)) && defined _ARCH_PPC
+__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");
+}
+#elif #machine(vax)
+__unwind_function(void *ptr)
+{
+ __label__ return_again;
+
+ /* Replace our frame's return address with the label below.
+ During execution, we will first return here instead of to
+ caller, then second return takes caller's frame off the stack.
+ Two returns matches two actual calls, so is less likely to
+ confuse debuggers. `16' corresponds to RETURN_ADDRESS_OFFSET. */
+ __asm ("movl %0,16(fp)" : : "p" (&& return_again));
+ return;
+
+ return_again:
+ return;
+}
+#else
+__unwind_function(void *ptr)
+{
+ abort ();
+}
+#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