/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
-/* Copyright (C) 1989, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the 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, 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,
- 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. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
/* It is incorrect to include config.h here, because this file is being
compiled for the target, and hence definitions concerning only the host
do not apply. */
#include "tconfig.h"
+#include "tsystem.h"
+
+#include "symcat.h"
#include "machmode.h"
-#include "defaults.h"
-#ifndef L_trampoline
-#include <stddef.h>
-#endif
/* Don't use `fancy_abort' here even if config.h says to use it. */
#ifdef abort
#undef abort
#endif
-#if (SUPPORTS_WEAK == 1) && (defined (ASM_OUTPUT_DEF) || defined (ASM_OUTPUT_WEAK_ALIAS))
-#define WEAK_ALIAS
+#include "libgcc2.h"
+\f
+#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
+#if defined (L_divdi3) || defined (L_moddi3)
+static inline
#endif
+DWtype
+__negdi2 (DWtype u)
+{
+ DWunion w;
+ DWunion uu;
+
+ uu.ll = u;
-/* 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. */
+ w.s.low = -uu.s.low;
+ w.s.high = -uu.s.high - ((UWtype) w.s.low > 0);
-#ifndef LIBGCC2_WORDS_BIG_ENDIAN
-#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
+ return w.ll;
+}
#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
- these compiler-generated calls also expect any return values to have
- very specific modes (rather than very specific types). Thus, we need
- to avoid using regular C language type names in this part of the file
- because the sizes for those types can be configured to be anything.
- Instead we use the following special type names. */
+#ifdef L_addvsi3
+Wtype
+__addvsi3 (Wtype a, Wtype b)
+{
+ Wtype w;
-typedef unsigned int UQItype __attribute__ ((mode (QI)));
-typedef int SItype __attribute__ ((mode (SI)));
-typedef unsigned int USItype __attribute__ ((mode (SI)));
-typedef int DItype __attribute__ ((mode (DI)));
-typedef unsigned int UDItype __attribute__ ((mode (DI)));
+ w = a + b;
-typedef float SFtype __attribute__ ((mode (SF)));
-typedef float DFtype __attribute__ ((mode (DF)));
+ if (b >= 0 ? w < a : w > a)
+ abort ();
-#if LONG_DOUBLE_TYPE_SIZE == 96
-typedef float XFtype __attribute__ ((mode (XF)));
-#endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
-typedef float TFtype __attribute__ ((mode (TF)));
+ return w;
+}
#endif
+\f
+#ifdef L_addvdi3
+DWtype
+__addvdi3 (DWtype a, DWtype b)
+{
+ DWtype w;
-typedef int word_type __attribute__ ((mode (__word__)));
+ w = a + b;
-/* Make sure that we don't accidentally use any normal C language built-in
- type names in the first part of this file. Instead we want to use *only*
- the type names defined above. The following macro definitions insure
- that if we *do* accidentally use some normal C language built-in type name,
- we will get a syntax error. */
+ if (b >= 0 ? w < a : w > a)
+ abort ();
-#define char bogus_type
-#define short bogus_type
-#define int bogus_type
-#define long bogus_type
-#define unsigned bogus_type
-#define float bogus_type
-#define double bogus_type
+ return w;
+}
+#endif
+\f
+#ifdef L_subvsi3
+Wtype
+__subvsi3 (Wtype a, Wtype b)
+{
+#ifdef L_addvsi3
+ return __addvsi3 (a, (-b));
+#else
+ DWtype w;
-#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+ w = a - b;
-/* DIstructs are pairs of SItype values in the order determined by
- LIBGCC2_WORDS_BIG_ENDIAN. */
+ if (b >= 0 ? w > a : w < a)
+ abort ();
-#if LIBGCC2_WORDS_BIG_ENDIAN
- struct DIstruct {SItype high, low;};
+ return w;
+#endif
+}
+#endif
+\f
+#ifdef L_subvdi3
+DWtype
+__subvdi3 (DWtype a, DWtype b)
+{
+#ifdef L_addvdi3
+ return (a, (-b));
#else
- struct DIstruct {SItype low, high;};
+ DWtype w;
+
+ w = a - b;
+
+ if (b >= 0 ? w > a : w < a)
+ abort ();
+
+ return w;
+#endif
+}
+#endif
+\f
+#ifdef L_mulvsi3
+Wtype
+__mulvsi3 (Wtype a, Wtype b)
+{
+ DWtype w;
+
+ w = a * b;
+
+ if (((a >= 0) == (b >= 0)) ? w < 0 : w > 0)
+ abort ();
+
+ return w;
+}
#endif
+\f
+#ifdef L_negvsi2
+Wtype
+__negvsi2 (Wtype a)
+{
+ Wtype w;
-/* We need this union to unpack/pack DImode values, since we don't have
- any arithmetic yet. Incoming DImode parameters are stored into the
- `ll' field, and the unpacked result is read from the struct `s'. */
+ w = -a;
-typedef union
+ if (a >= 0 ? w > 0 : w < 0)
+ abort ();
+
+ return w;
+}
+#endif
+\f
+#ifdef L_negvdi2
+DWtype
+__negvdi2 (DWtype a)
{
- struct DIstruct s;
- DItype ll;
-} DIunion;
+ DWtype w;
-#if (defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)\
- || defined (L_divdi3) || defined (L_udivdi3) \
- || defined (L_moddi3) || defined (L_umoddi3))
+ w = -a;
-#include "longlong.h"
+ if (a >= 0 ? w > 0 : w < 0)
+ abort ();
+
+ return w;
+}
+#endif
+\f
+#ifdef L_absvsi2
+Wtype
+__absvsi2 (Wtype a)
+{
+ Wtype w = a;
-#endif /* udiv or mul */
+ if (a < 0)
+#ifdef L_negvsi2
+ w = __negvsi2 (a);
+#else
+ w = -a;
-extern DItype __fixunssfdi (SFtype a);
-extern DItype __fixunsdfdi (DFtype a);
-#if LONG_DOUBLE_TYPE_SIZE == 96
-extern DItype __fixunsxfdi (XFtype a);
+ if (w < 0)
+ abort ();
#endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
-extern DItype __fixunstfdi (TFtype a);
+
+ return w;
+}
#endif
\f
-#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
-#if defined (L_divdi3) || defined (L_moddi3)
-static inline
+#ifdef L_absvdi2
+DWtype
+__absvdi2 (DWtype a)
+{
+ DWtype w = a;
+
+ if (a < 0)
+#ifdef L_negvsi2
+ w = __negvsi2 (a);
+#else
+ w = -a;
+
+ if (w < 0)
+ abort ();
#endif
-DItype
-__negdi2 (u)
- DItype u;
+
+ return w;
+}
+#endif
+\f
+#ifdef L_mulvdi3
+DWtype
+__mulvdi3 (DWtype u, DWtype v)
{
- DIunion w;
- DIunion uu;
+ DWtype w;
- uu.ll = u;
+ w = u * v;
- w.s.low = -uu.s.low;
- w.s.high = -uu.s.high - ((USItype) w.s.low > 0);
+ if (((u >= 0) == (v >= 0)) ? w < 0 : w > 0)
+ abort ();
- return w.ll;
+ return w;
}
#endif
\f
+
+/* 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;
- word_type b;
+DWtype
+__lshrdi3 (DWtype u, word_type b)
{
- DIunion w;
+ DWunion w;
word_type bm;
- DIunion uu;
+ DWunion uu;
if (b == 0)
return u;
uu.ll = u;
- bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+ bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
if (bm <= 0)
{
w.s.high = 0;
- w.s.low = (USItype)uu.s.high >> -bm;
+ w.s.low = (UWtype) uu.s.high >> -bm;
}
else
{
- USItype carries = (USItype)uu.s.high << bm;
- w.s.high = (USItype)uu.s.high >> b;
- w.s.low = ((USItype)uu.s.low >> b) | carries;
+ UWtype carries = (UWtype) uu.s.high << bm;
+
+ w.s.high = (UWtype) uu.s.high >> b;
+ w.s.low = ((UWtype) uu.s.low >> b) | carries;
}
return w.ll;
#endif
#ifdef L_ashldi3
-DItype
-__ashldi3 (u, b)
- DItype u;
- word_type b;
+DWtype
+__ashldi3 (DWtype u, word_type b)
{
- DIunion w;
+ DWunion w;
word_type bm;
- DIunion uu;
+ DWunion uu;
if (b == 0)
return u;
uu.ll = u;
- bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+ bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
if (bm <= 0)
{
w.s.low = 0;
- w.s.high = (USItype)uu.s.low << -bm;
+ w.s.high = (UWtype) 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;
+ UWtype carries = (UWtype) uu.s.low >> bm;
+
+ w.s.low = (UWtype) uu.s.low << b;
+ w.s.high = ((UWtype) uu.s.high << b) | carries;
}
return w.ll;
#endif
#ifdef L_ashrdi3
-DItype
-__ashrdi3 (u, b)
- DItype u;
- word_type b;
+DWtype
+__ashrdi3 (DWtype u, word_type b)
{
- DIunion w;
+ DWunion w;
word_type bm;
- DIunion uu;
+ DWunion uu;
if (b == 0)
return u;
uu.ll = u;
- bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+ bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
if (bm <= 0)
{
/* w.s.high = 1..1 or 0..0 */
- w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
+ w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
w.s.low = uu.s.high >> -bm;
}
else
{
- USItype carries = (USItype)uu.s.high << bm;
+ UWtype carries = (UWtype) uu.s.high << bm;
+
w.s.high = uu.s.high >> b;
- w.s.low = ((USItype)uu.s.low >> b) | carries;
+ w.s.low = ((UWtype) uu.s.low >> b) | carries;
}
return w.ll;
#endif
\f
#ifdef L_ffsdi2
-DItype
-__ffsdi2 (u)
- DItype u;
+DWtype
+__ffsdi2 (DWtype u)
{
- DIunion uu, w;
+ DWunion uu;
+ UWtype word, count, add;
+
uu.ll = u;
- w.s.high = 0;
- w.s.low = ffs (uu.s.low);
- if (w.s.low != 0)
- return w.ll;
- w.s.low = ffs (uu.s.high);
- if (w.s.low != 0)
- {
- w.s.low += BITS_PER_UNIT * sizeof (SItype);
- return w.ll;
- }
- return w.ll;
+ if (uu.s.low != 0)
+ word = uu.s.low, add = 0;
+ else if (uu.s.high != 0)
+ word = uu.s.high, add = BITS_PER_UNIT * sizeof (Wtype);
+ else
+ return 0;
+
+ count_trailing_zeros (count, word);
+ return count + add + 1;
}
#endif
\f
#ifdef L_muldi3
-DItype
-__muldi3 (u, v)
- DItype u, v;
+DWtype
+__muldi3 (DWtype u, DWtype v)
{
- DIunion w;
- DIunion uu, vv;
+ DWunion w;
+ DWunion uu, vv;
uu.ll = u,
vv.ll = v;
w.ll = __umulsidi3 (uu.s.low, vv.s.low);
- w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
- + (USItype) uu.s.high * (USItype) vv.s.low);
+ w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
+ + (UWtype) uu.s.high * (UWtype) vv.s.low);
return w.ll;
}
\f
#ifdef L_udiv_w_sdiv
#if defined (sdiv_qrnnd)
-USItype
-__udiv_w_sdiv (rp, a1, a0, d)
- USItype *rp, a1, a0, d;
+UWtype
+__udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
{
- USItype q, r;
- USItype c0, c1, b1;
+ UWtype q, r;
+ UWtype c0, c1, b1;
- if ((SItype) d >= 0)
+ if ((Wtype) d >= 0)
{
- if (a1 < d - a1 - (a0 >> (SI_TYPE_SIZE - 1)))
+ if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1)))
{
/* dividend, divisor, and quotient are nonnegative */
sdiv_qrnnd (q, r, a1, a0, d);
else
{
/* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
- sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (SI_TYPE_SIZE - 1));
+ sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1));
/* Divide (c1*2^32 + c0) by d */
sdiv_qrnnd (q, r, c1, c0, d);
/* Add 2^31 to quotient */
- q += (USItype) 1 << (SI_TYPE_SIZE - 1);
+ q += (UWtype) 1 << (W_TYPE_SIZE - 1);
}
}
else
{
b1 = d >> 1; /* d/2, between 2^30 and 2^31 - 1 */
c1 = a1 >> 1; /* A/2 */
- c0 = (a1 << (SI_TYPE_SIZE - 1)) + (a0 >> 1);
+ c0 = (a1 << (W_TYPE_SIZE - 1)) + (a0 >> 1);
if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */
{
}
#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;
-{}
+UWtype
+__udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
+ UWtype a1 __attribute__ ((__unused__)),
+ UWtype a0 __attribute__ ((__unused__)),
+ UWtype d __attribute__ ((__unused__)))
+{
+ return 0;
+}
#endif
#endif
\f
#define L_udivmoddi4
#endif
-#ifdef L_udivmoddi4
-static const UQItype __clz_tab[] =
+#ifdef L_clz
+const UQItype __clz_tab[] =
{
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
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,
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,
};
+#endif
+
+#ifdef L_udivmoddi4
#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;
+UDWtype
+__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
{
- DIunion ww;
- DIunion nn, dd;
- DIunion rr;
- USItype d0, d1, n0, n1, n2;
- USItype q0, q1;
- USItype b, bm;
+ DWunion ww;
+ DWunion nn, dd;
+ DWunion rr;
+ UWtype d0, d1, n0, n1, n2;
+ UWtype q0, q1;
+ UWtype b, bm;
nn.ll = n;
dd.ll = d;
denominator set. */
d0 = d0 << bm;
- n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
+ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
n0 = n0 << bm;
}
leading quotient digit q1 = 1).
This special case is necessary, not an optimization.
- (Shifts counts of SI_TYPE_SIZE are undefined.) */
+ (Shifts counts of W_TYPE_SIZE are undefined.) */
n1 -= d0;
q1 = 1;
{
/* Normalize. */
- b = SI_TYPE_SIZE - bm;
+ b = W_TYPE_SIZE - bm;
d0 = d0 << bm;
n2 = n1 >> b;
}
else
{
- USItype m1, m0;
+ UWtype m1, m0;
/* Normalize. */
- b = SI_TYPE_SIZE - bm;
+ b = W_TYPE_SIZE - bm;
d1 = (d1 << bm) | (d0 >> b);
d0 = d0 << bm;
#endif
#ifdef L_divdi3
-UDItype __udivmoddi4 ();
-
-DItype
-__divdi3 (u, v)
- DItype u, v;
+DWtype
+__divdi3 (DWtype u, DWtype v)
{
word_type c = 0;
- DIunion uu, vv;
- DItype w;
+ DWunion uu, vv;
+ DWtype w;
uu.ll = u;
vv.ll = v;
c = ~c,
vv.ll = __negdi2 (vv.ll);
- w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0);
+ w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
if (c)
w = __negdi2 (w);
#endif
#ifdef L_moddi3
-UDItype __udivmoddi4 ();
-DItype
-__moddi3 (u, v)
- DItype u, v;
+DWtype
+__moddi3 (DWtype u, DWtype v)
{
word_type c = 0;
- DIunion uu, vv;
- DItype w;
+ DWunion uu, vv;
+ DWtype w;
uu.ll = u;
vv.ll = v;
#endif
#ifdef L_umoddi3
-UDItype __udivmoddi4 ();
-UDItype
-__umoddi3 (u, v)
- UDItype u, v;
+UDWtype
+__umoddi3 (UDWtype u, UDWtype v)
{
- UDItype w;
+ UDWtype w;
(void) __udivmoddi4 (u, v, &w);
#endif
#ifdef L_udivdi3
-UDItype __udivmoddi4 ();
-UDItype
-__udivdi3 (n, d)
- UDItype n, d;
+UDWtype
+__udivdi3 (UDWtype n, UDWtype d)
{
- return __udivmoddi4 (n, d, (UDItype *) 0);
+ return __udivmoddi4 (n, d, (UDWtype *) 0);
}
#endif
\f
#ifdef L_cmpdi2
word_type
-__cmpdi2 (a, b)
- DItype a, b;
+__cmpdi2 (DWtype a, DWtype b)
{
- DIunion au, bu;
+ DWunion au, bu;
au.ll = a, bu.ll = b;
return 0;
else if (au.s.high > bu.s.high)
return 2;
- if ((USItype) au.s.low < (USItype) bu.s.low)
+ if ((UWtype) au.s.low < (UWtype) bu.s.low)
return 0;
- else if ((USItype) au.s.low > (USItype) bu.s.low)
+ else if ((UWtype) au.s.low > (UWtype) bu.s.low)
return 2;
return 1;
}
#ifdef L_ucmpdi2
word_type
-__ucmpdi2 (a, b)
- DItype a, b;
+__ucmpdi2 (DWtype a, DWtype b)
{
- DIunion au, bu;
+ DWunion au, bu;
au.ll = a, bu.ll = b;
- if ((USItype) au.s.high < (USItype) bu.s.high)
+ if ((UWtype) au.s.high < (UWtype) bu.s.high)
return 0;
- else if ((USItype) au.s.high > (USItype) bu.s.high)
+ else if ((UWtype) au.s.high > (UWtype) bu.s.high)
return 2;
- if ((USItype) au.s.low < (USItype) bu.s.low)
+ if ((UWtype) au.s.low < (UWtype) bu.s.low)
return 0;
- else if ((USItype) au.s.low > (USItype) bu.s.low)
+ else if ((UWtype) au.s.low > (UWtype) bu.s.low)
return 2;
return 1;
}
#endif
\f
-#if defined(L_fixunstfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
-DItype
-__fixunstfdi (a)
- TFtype a;
+DWtype
+__fixunstfDI (TFtype a)
{
TFtype b;
- UDItype v;
+ UDWtype v;
if (a < 0)
return 0;
/* Compute high word of result, as a flonum. */
b = (a / HIGH_WORD_COEFF);
- /* Convert that to fixed (but not to DItype!),
+ /* Convert that to fixed (but not to DWtype!),
and shift it into the high word. */
- v = (USItype) b;
+ v = (UWtype) b;
v <<= WORD_SIZE;
/* Remove high part from the TFtype, leaving the low part as flonum. */
a -= (TFtype)v;
- /* Convert that to fixed (but not to DItype!) and add it in.
+ /* Convert that to fixed (but not to DWtype!) and add it in.
Sometimes A comes out negative. This is significant, since
A has more bits than a long int does. */
if (a < 0)
- v -= (USItype) (- a);
+ v -= (UWtype) (- a);
else
- v += (USItype) a;
+ v += (UWtype) a;
return v;
}
#endif
-#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
-DItype
-__fixtfdi (a)
- TFtype a;
+#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+DWtype
+__fixtfdi (TFtype a)
{
if (a < 0)
- return - __fixunstfdi (-a);
- return __fixunstfdi (a);
+ return - __fixunstfDI (-a);
+ return __fixunstfDI (a);
}
#endif
-#if defined(L_fixunsxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
-DItype
-__fixunsxfdi (a)
- XFtype a;
+DWtype
+__fixunsxfDI (XFtype a)
{
XFtype b;
- UDItype v;
+ UDWtype v;
if (a < 0)
return 0;
/* Compute high word of result, as a flonum. */
b = (a / HIGH_WORD_COEFF);
- /* Convert that to fixed (but not to DItype!),
+ /* Convert that to fixed (but not to DWtype!),
and shift it into the high word. */
- v = (USItype) b;
+ v = (UWtype) b;
v <<= WORD_SIZE;
/* Remove high part from the XFtype, leaving the low part as flonum. */
a -= (XFtype)v;
- /* Convert that to fixed (but not to DItype!) and add it in.
+ /* Convert that to fixed (but not to DWtype!) and add it in.
Sometimes A comes out negative. This is significant, since
A has more bits than a long int does. */
if (a < 0)
- v -= (USItype) (- a);
+ v -= (UWtype) (- a);
else
- v += (USItype) a;
+ v += (UWtype) a;
return v;
}
#endif
-#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
-DItype
-__fixxfdi (a)
- XFtype a;
+#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
+DWtype
+__fixxfdi (XFtype a)
{
if (a < 0)
- return - __fixunsxfdi (-a);
- return __fixunsxfdi (a);
+ return - __fixunsxfDI (-a);
+ return __fixunsxfDI (a);
}
#endif
#ifdef L_fixunsdfdi
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
-DItype
-__fixunsdfdi (a)
- DFtype a;
+DWtype
+__fixunsdfDI (DFtype a)
{
DFtype b;
- UDItype v;
+ UDWtype v;
if (a < 0)
return 0;
/* Compute high word of result, as a flonum. */
b = (a / HIGH_WORD_COEFF);
- /* Convert that to fixed (but not to DItype!),
+ /* Convert that to fixed (but not to DWtype!),
and shift it into the high word. */
- v = (USItype) b;
+ v = (UWtype) b;
v <<= WORD_SIZE;
/* Remove high part from the DFtype, leaving the low part as flonum. */
a -= (DFtype)v;
- /* Convert that to fixed (but not to DItype!) and add it in.
+ /* Convert that to fixed (but not to DWtype!) and add it in.
Sometimes A comes out negative. This is significant, since
A has more bits than a long int does. */
if (a < 0)
- v -= (USItype) (- a);
+ v -= (UWtype) (- a);
else
- v += (USItype) a;
+ v += (UWtype) a;
return v;
}
#endif
#ifdef L_fixdfdi
-DItype
-__fixdfdi (a)
- DFtype a;
+DWtype
+__fixdfdi (DFtype a)
{
if (a < 0)
- return - __fixunsdfdi (-a);
- return __fixunsdfdi (a);
+ return - __fixunsdfDI (-a);
+ return __fixunsdfDI (a);
}
#endif
#ifdef L_fixunssfdi
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
-DItype
-__fixunssfdi (SFtype original_a)
+DWtype
+__fixunssfDI (SFtype original_a)
{
/* Convert the SFtype to a DFtype, because that is surely not going
to lose any bits. Some day someone else can write a faster version
that avoids converting to DFtype, and verify it really works right. */
DFtype a = original_a;
DFtype b;
- UDItype v;
+ UDWtype v;
if (a < 0)
return 0;
/* Compute high word of result, as a flonum. */
b = (a / HIGH_WORD_COEFF);
- /* Convert that to fixed (but not to DItype!),
+ /* Convert that to fixed (but not to DWtype!),
and shift it into the high word. */
- v = (USItype) b;
+ v = (UWtype) b;
v <<= WORD_SIZE;
/* Remove high part from the DFtype, leaving the low part as flonum. */
- a -= (DFtype)v;
- /* Convert that to fixed (but not to DItype!) and add it in.
+ a -= (DFtype) v;
+ /* Convert that to fixed (but not to DWtype!) and add it in.
Sometimes A comes out negative. This is significant, since
A has more bits than a long int does. */
if (a < 0)
- v -= (USItype) (- a);
+ v -= (UWtype) (- a);
else
- v += (USItype) a;
+ v += (UWtype) a;
return v;
}
#endif
#ifdef L_fixsfdi
-DItype
+DWtype
__fixsfdi (SFtype a)
{
if (a < 0)
- return - __fixunssfdi (-a);
- return __fixunssfdi (a);
+ return - __fixunssfDI (-a);
+ return __fixunssfDI (a);
}
#endif
-#if defined(L_floatdixf) && (LONG_DOUBLE_TYPE_SIZE == 96)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
XFtype
-__floatdixf (u)
- DItype u;
+__floatdixf (DWtype u)
{
XFtype d;
- SItype negate = 0;
-
- if (u < 0)
- u = -u, negate = 1;
- d = (USItype) (u >> WORD_SIZE);
+ d = (Wtype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
- d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+ d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
- return (negate ? -d : d);
+ return d;
}
#endif
-#if defined(L_floatditf) && (LONG_DOUBLE_TYPE_SIZE == 128)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
TFtype
-__floatditf (u)
- DItype u;
+__floatditf (DWtype u)
{
TFtype d;
- SItype negate = 0;
- if (u < 0)
- u = -u, negate = 1;
-
- d = (USItype) (u >> WORD_SIZE);
+ d = (Wtype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
- d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+ d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
- return (negate ? -d : d);
+ return d;
}
#endif
#ifdef L_floatdidf
-#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 WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DFtype
-__floatdidf (u)
- DItype u;
+__floatdidf (DWtype u)
{
DFtype d;
- SItype negate = 0;
-
- if (u < 0)
- u = -u, negate = 1;
- d = (USItype) (u >> WORD_SIZE);
+ d = (Wtype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
- d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+ d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
- return (negate ? -d : d);
+ return d;
}
#endif
#ifdef L_floatdisf
-#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 WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
-/* Define 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
+#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
+#define DF_SIZE DBL_MANT_DIG
+#define SF_SIZE FLT_MANT_DIG
SFtype
-__floatdisf (u)
- DItype u;
+__floatdisf (DWtype u)
{
/* 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,
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))
+#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
+ if (! (- ((DWtype) 1 << DF_SIZE) < u
+ && u < ((DWtype) 1 << DF_SIZE)))
{
- if ((USItype) u & (REP_BIT - 1))
+ if ((UDWtype) u & (REP_BIT - 1))
u |= REP_BIT;
}
}
- f = (USItype) (u >> WORD_SIZE);
+ f = (Wtype) (u >> WORD_SIZE);
f *= HIGH_HALFWORD_COEFF;
f *= HIGH_HALFWORD_COEFF;
- f += (USItype) (u & (HIGH_WORD_COEFF - 1));
+ f += (UWtype) (u & (HIGH_WORD_COEFF - 1));
- return (SFtype) (negate ? -f : f);
+ return (SFtype) f;
}
#endif
-#if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
+#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
/* Reenable the normal types, in case limits.h needs them. */
#undef char
#undef short
#undef MAX
#include <limits.h>
-USItype
-__fixunsxfsi (a)
- XFtype a;
+UWtype
+__fixunsxfSI (XFtype a)
{
- if (a >= - (DFtype) LONG_MIN)
- return (SItype) (a + LONG_MIN) - LONG_MIN;
- return (SItype) a;
+ if (a >= - (DFtype) Wtype_MIN)
+ return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
+ return (Wtype) a;
}
#endif
#undef MAX
#include <limits.h>
-USItype
-__fixunsdfsi (a)
- DFtype a;
+UWtype
+__fixunsdfSI (DFtype a)
{
- if (a >= - (DFtype) LONG_MIN)
- return (SItype) (a + LONG_MIN) - LONG_MIN;
- return (SItype) a;
+ if (a >= - (DFtype) Wtype_MIN)
+ return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
+ return (Wtype) a;
}
#endif
#undef MAX
#include <limits.h>
-USItype
-__fixunssfsi (SFtype a)
+UWtype
+__fixunssfSI (SFtype a)
{
- if (a >= - (SFtype) LONG_MIN)
- return (SItype) (a + LONG_MIN) - LONG_MIN;
- return (SItype) a;
+ if (a >= - (SFtype) Wtype_MIN)
+ return (Wtype) (a + Wtype_MIN) - Wtype_MIN;
+ return (Wtype) a;
}
#endif
\f
#define UDItype bogus_type
#define SFtype bogus_type
#define DFtype bogus_type
+#undef Wtype
+#undef UWtype
+#undef HWtype
+#undef UHWtype
+#undef DWtype
+#undef UDWtype
#undef char
#undef short
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 (const unsigned char *s1, const 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 (" .text");
- asm (" .align 4");
-
-/* The Alliant needs the added underscore. */
- 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)"); /* save floating regs (f8-f15) */
- asm (" fst.q %f12,16(%sp)");
-
- asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */
- 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 __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");
-
- asm (".globl ___builtin_saveregs");
- asm ("___builtin_saveregs:");
- asm (" mov sp,r30");
- asm (" andnot 0x0f,sp,sp");
- asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */
-
-/* Fill in the __va_struct. */
- asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */
- asm (" st.l r17, 4(sp)"); /* int fixed[12] */
- asm (" st.l r18, 8(sp)");
- asm (" st.l r19,12(sp)");
- asm (" st.l r20,16(sp)");
- asm (" st.l r21,20(sp)");
- asm (" st.l r22,24(sp)");
- asm (" st.l r23,28(sp)");
- asm (" st.l r24,32(sp)");
- asm (" st.l r25,36(sp)");
- asm (" st.l r26,40(sp)");
- asm (" st.l r27,44(sp)");
-
- asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */
- asm (" fst.q f12,64(sp)"); /* int floating[8] */
-
-/* Fill in the __va_ctl. */
- asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */
- asm (" st.l r28,84(sp)"); /* pointer to more args */
- asm (" st.l r0, 88(sp)"); /* nfixed */
- asm (" st.l r0, 92(sp)"); /* nfloating */
-
- asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */
- asm (" bri r1");
- asm (" mov r30,sp");
- /* recover stack and pass address to start
- of data. */
-#endif /* not __PARAGON__ */
-#endif /* not __svr4__ */
-#else /* not __i860__ */
-#ifdef __sparc__
- asm (".global __builtin_saveregs");
- asm ("__builtin_saveregs:");
- asm (".global ___builtin_saveregs");
- asm ("___builtin_saveregs:");
-#ifdef NEED_PROC_COMMAND
- asm (".proc 020");
-#endif
- asm ("st %i0,[%fp+68]");
- asm ("st %i1,[%fp+72]");
- asm ("st %i2,[%fp+76]");
- asm ("st %i3,[%fp+80]");
- asm ("st %i4,[%fp+84]");
- asm ("retl");
- asm ("st %i5,[%fp+88]");
-#ifdef NEED_TYPE_COMMAND
- asm (".type __builtin_saveregs,#function");
- asm (".size __builtin_saveregs,.-__builtin_saveregs");
-#endif
-#else /* not __sparc__ */
-#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
-
- asm (" .text");
- asm (" .ent __builtin_saveregs");
- asm (" .globl __builtin_saveregs");
- asm ("__builtin_saveregs:");
- asm (" sw $4,0($30)");
- asm (" sw $5,4($30)");
- asm (" sw $6,8($30)");
- asm (" sw $7,12($30)");
- asm (" j $31");
- asm (" .end __builtin_saveregs");
-#else /* not __mips__, etc. */
-
-void *
-__builtin_saveregs ()
-{
- abort ();
-}
-
-#endif /* not __mips__ */
-#endif /* not __sparc__ */
-#endif /* not __i860__ */
-#endif
\f
+/* __eprintf used to be used by GCC's private version of <assert.h>.
+ We no longer provide that header, but this routine remains in libgcc.a
+ for binary backward compatibility. Note that it is not included in
+ the shared version of libgcc. */
#ifdef L_eprintf
#ifndef inhibit_libc
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
#include <stdio.h>
-/* This is used by the `assert' macro. */
+
void
-__eprintf (string, expression, line, filename)
- const char *string;
- const char *expression;
- int line;
- const char *filename;
+__eprintf (const char *string, const char *expression,
+ unsigned int line, const char *filename)
{
fprintf (stderr, string, expression, line, filename);
fflush (stderr);
#ifdef L_bb
+struct bb_function_info {
+ long checksum;
+ int arc_count;
+ const char *name;
+};
+
/* Structure emitted by -a */
struct bb
{
long zero_word;
const char *filename;
- long *counts;
+ gcov_type *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;
- char *flags;
+ long sizeof_bb;
+ struct bb_function_info *function_infos;
};
-#ifdef BLOCK_PROFILER_CODE
-BLOCK_PROFILER_CODE
-#else
#ifndef inhibit_libc
/* Simple minded basic block profiling output dumper for
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
#include <stdio.h>
-char *ctime ();
#include "gbl-ctors.h"
+#include "gcov-io.h"
+#include <string.h>
+#ifdef TARGET_HAS_F_SETLKW
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#include <gthr.h>
static struct bb *bb_head;
-/* Return the number of digits needed to print a value */
-/* __inline__ */ static int num_digits (long value, int base)
+int __global_counters = 0, __gthreads_active = 0;
+
+void
+__bb_exit_func (void)
{
- int minus = (value < 0 && base != 16);
- unsigned long v = (minus) ? -value : value;
- int ret = minus;
+ FILE *da_file;
+ struct bb *ptr;
+ long n_counters_p = 0;
+ gcov_type max_counter_p = 0;
+ gcov_type sum_counters_p = 0;
- do
+ if (bb_head == 0)
+ return;
+
+ /* Calculate overall "statistics". */
+
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
{
- v /= base;
- ret++;
- }
- while (v);
+ int i;
- return ret;
-}
+ n_counters_p += ptr->ncounts;
-void
-__bb_exit_func (void)
-{
- FILE *file = fopen ("bb.out", "a");
- long time_value;
+ for (i = 0; i < ptr->ncounts; i++)
+ {
+ sum_counters_p += ptr->counts[i];
- if (!file)
- perror ("bb.out");
+ if (ptr->counts[i] > max_counter_p)
+ max_counter_p = ptr->counts[i];
+ }
+ }
- else
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
{
- struct bb *ptr;
+ gcov_type max_counter_o = 0;
+ gcov_type sum_counters_o = 0;
+ int i;
- /* 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. */
+ /* Calculate the per-object statistics. */
- time ((void *) &time_value);
- fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
+ for (i = 0; i < ptr->ncounts; i++)
+ {
+ sum_counters_o += ptr->counts[i];
- /* We check the length field explicitly in order to allow compatibility
- with older GCC's which did not provide it. */
+ if (ptr->counts[i] > max_counter_o)
+ max_counter_o = ptr->counts[i];
+ }
- for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ /* open the file for appending, creating it if necessary. */
+ da_file = fopen (ptr->filename, "ab");
+ /* Some old systems might not allow the 'b' mode modifier.
+ Therefore, try to open without it. This can lead to a race
+ condition so that when you delete and re-create the file, the
+ file might be opened in text mode, but then, you shouldn't
+ delete the file in the first place. */
+ if (da_file == 0)
+ da_file = fopen (ptr->filename, "a");
+ if (da_file == 0)
{
- 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;
+ fprintf (stderr, "arc profiling: Can't open output file %s.\n",
+ ptr->filename);
+ continue;
+ }
- if (cnt_max < ptr->counts[i])
- cnt_max = ptr->counts[i];
+ /* After a fork, another process might try to read and/or write
+ the same file simultanously. So if we can, lock the file to
+ avoid race conditions. */
+#if defined (TARGET_HAS_F_SETLKW)
+ {
+ struct flock s_flock;
+
+ s_flock.l_type = F_WRLCK;
+ s_flock.l_whence = SEEK_SET;
+ s_flock.l_start = 0;
+ s_flock.l_len = 1;
+ s_flock.l_pid = getpid ();
- if (addr_max < ptr->addresses[i])
- addr_max = ptr->addresses[i];
+ while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+ && errno == EINTR);
+ }
+#endif
- if (line_p && line_max < ptr->line_nums[i])
- line_max = ptr->line_nums[i];
+ if (__write_long (-123, da_file, 4) != 0) /* magic */
+ {
+ fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ }
+ else
+ {
- if (func_p)
+ struct bb_function_info *fn_info;
+ gcov_type *count_ptr = ptr->counts;
+ int i;
+ int count_functions = 0;
+
+ for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
+ fn_info++)
+ count_functions++;
+
+ /* number of functions in this block. */
+ __write_long (count_functions, da_file, 4);
+
+ /* length of extra data in bytes. */
+ __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4);
+
+ /* overall statistics. */
+ /* number of counters. */
+ __write_long (n_counters_p, da_file, 4);
+ /* sum of counters. */
+ __write_gcov_type (sum_counters_p, da_file, 8);
+ /* maximal counter. */
+ __write_gcov_type (max_counter_p, da_file, 8);
+
+ /* per-object statistics. */
+ /* number of counters. */
+ __write_long (ptr->ncounts, da_file, 4);
+ /* sum of counters. */
+ __write_gcov_type (sum_counters_o, da_file, 8);
+ /* maximal counter. */
+ __write_gcov_type (max_counter_o, da_file, 8);
+
+ /* write execution counts for each function. */
+
+ for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
+ fn_info++)
+ {
+ /* new function. */
+ if (__write_gcov_string
+ (fn_info->name, strlen (fn_info->name), da_file, -1) != 0)
{
- p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
- len = strlen (p);
- if (func_len < len)
- func_len = len;
+ fprintf (stderr,
+ "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ break;
}
- if (file_p)
+ if (__write_long (fn_info->checksum, da_file, 4) != 0)
{
- p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
- len = strlen (p);
- if (file_len < len)
- file_len = len;
+ fprintf (stderr,
+ "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ break;
}
- }
-
- 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 (__write_long (fn_info->arc_count, da_file, 4) != 0)
+ {
+ fprintf (stderr,
+ "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ break;
+ }
- if (file_p)
- fprintf (file, " file= %s",
- (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
+ for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
+ {
+ if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
+ break;
+ }
- fprintf (file, "\n");
+ if (i) /* there was an error */
+ {
+ fprintf (stderr,
+ "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ break;
+ }
}
-
- fprintf (file, "\n");
- fflush (file);
}
- fprintf (file, "\n\n");
- fclose (file);
+ if (fclose (da_file) != 0)
+ fprintf (stderr, "arc profiling: Error closing output file %s.\n",
+ ptr->filename);
}
}
if (blocks->zero_word)
return;
-#ifdef ON_EXIT
- /* Initialize destructor. */
+ /* Initialize destructor and per-thread data. */
if (!bb_head)
- ON_EXIT (__bb_exit_func, 0);
-#endif
+ atexit (__bb_exit_func);
/* Set up linked list. */
blocks->zero_word = 1;
bb_head = blocks;
}
-#ifndef MACHINE_STATE_SAVE
-#define MACHINE_STATE_SAVE(ID)
-#endif
-#ifndef MACHINE_STATE_RESTORE
-#define MACHINE_STATE_RESTORE(ID)
-#endif
-
-#include <string.h>
-
-/* Number of buckets in hashtable of basic block addresses. */
-
-#define BB_BUCKETS 311
-
-/* Maximum length of string in file bb.in. */
-
-#define BBINBUFSIZE 500
+/* Called before fork or exec - write out profile information gathered so
+ far and reset it to zero. This avoids duplication or loss of the
+ profile information gathered so far. */
+void
+__bb_fork_func (void)
+{
+ struct bb *ptr;
-/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
- "BBINBUFSIZE" but want to avoid trouble with preprocessors. */
+ __bb_exit_func ();
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ {
+ long i;
+ for (i = ptr->ncounts - 1; i >= 0; i--)
+ ptr->counts[i] = 0;
+ }
+}
-#define BBINBUFSIZESTR "499"
+#endif /* not inhibit_libc */
+#endif /* L_bb */
+\f
+#ifdef L_clear_cache
+/* Clear part of an instruction cache. */
-struct bb_edge
-{
- struct bb_edge *next;
- unsigned long src_addr;
- unsigned long dst_addr;
- unsigned long count;
-};
+#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
-enum bb_func_mode
+void
+__clear_cache (char *beg __attribute__((__unused__)),
+ char *end __attribute__((__unused__)))
{
- TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
-};
+#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;
+ int offset;
+ void *start_addr
+ void *end_addr;
+ typedef (*function_ptr) (void);
-struct bb_func
-{
- struct bb_func *next;
- char *funcname;
- char *filename;
- enum bb_func_mode mode;
-};
+#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
+ /* It's cheaper to clear the whole cache.
+ Put in a series of jump instructions so that calling the beginning
+ of the cache will clear the whole thing. */
-/* This is the connection to the outside world.
- The BLOCK_PROFILER macro must set __bb.blocks
- and __bb.blockno. */
+ if (! initialized)
+ {
+ int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
+ & -INSN_CACHE_LINE_WIDTH);
+ int end_ptr = ptr + INSN_CACHE_SIZE;
-struct {
- unsigned long blockno;
- struct bb *blocks;
-} __bb;
+ while (ptr < end_ptr)
+ {
+ *(INSTRUCTION_TYPE *)ptr
+ = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
+ ptr += INSN_CACHE_LINE_WIDTH;
+ }
+ *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
-/* Vars to store addrs of source and destination basic blocks
- of a jump. */
+ initialized = 1;
+ }
-static unsigned long bb_src = 0;
-static unsigned long bb_dst = 0;
+ /* Call the beginning of the sequence. */
+ (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
+ & -INSN_CACHE_LINE_WIDTH))
+ ());
-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;
+#else /* Cache is large. */
-static unsigned long *bb_stack = (unsigned long *) 0;
-static size_t bb_stacksize = 0;
+ if (! initialized)
+ {
+ int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
+ & -INSN_CACHE_LINE_WIDTH);
-static int reported = 0;
+ while (ptr < (int) array + sizeof array)
+ {
+ *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
+ ptr += INSN_CACHE_LINE_WIDTH;
+ }
-/* 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.
-*/
+ initialized = 1;
+ }
-#ifdef HAVE_POPEN
+ /* Find the location in array that occupies the same cache line as BEG. */
-/*#include <sys/types.h>*/
-#include <sys/stat.h>
-/*#include <malloc.h>*/
+ offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
+ start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
+ & -INSN_CACHE_PLANE_SIZE)
+ + offset);
-/* Commands executed by gopen. */
+ /* Compute the cache alignment of the place to stop clearing. */
+#if 0 /* This is not needed for gcc's purposes. */
+ /* If the block to clear is bigger than a cache plane,
+ we clear the entire cache, and OFFSET is already correct. */
+ if (end < beg + INSN_CACHE_PLANE_SIZE)
+#endif
+ offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
+ & -INSN_CACHE_LINE_WIDTH)
+ & (INSN_CACHE_PLANE_SIZE - 1));
-#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 (fn, mode)
- char *fn;
- char *mode;
-{
- int use_gzip;
- char *p;
-
- if (mode[1])
- return (FILE *) 0;
-
- if (mode[0] != 'r' && mode[0] != 'w')
- return (FILE *) 0;
-
- 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 (f)
- FILE *f;
-{
- struct stat buf;
-
- if (f != NULL)
- {
- if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
- return pclose (f);
-
- return fclose (f);
- }
- return 0;
-}
-
-#endif /* HAVE_POPEN */
-
-/* Called once per program. */
-
-static void
-__bb_exit_trace_func ()
-{
- 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 (blocks)
- 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 (blocks, blockno)
- 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 (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;
- int offset;
- void *start_addr
- void *end_addr;
- typedef (*function_ptr) ();
-
-#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
- /* It's cheaper to clear the whole cache.
- Put in a series of jump instructions so that calling the beginning
- of the cache will clear the whole thing. */
-
- if (! initialized)
- {
- int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH);
- int end_ptr = ptr + INSN_CACHE_SIZE;
-
- while (ptr < end_ptr)
- {
- *(INSTRUCTION_TYPE *)ptr
- = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
- ptr += INSN_CACHE_LINE_WIDTH;
- }
- *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
-
- initialized = 1;
- }
-
- /* Call the beginning of the sequence. */
- (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH))
- ());
-
-#else /* Cache is large. */
-
- if (! initialized)
- {
- int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH);
-
- while (ptr < (int) array + sizeof array)
- {
- *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
- ptr += INSN_CACHE_LINE_WIDTH;
- }
-
- initialized = 1;
- }
-
- /* Find the location in array that occupies the same cache line as BEG. */
-
- offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
- start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
- & -INSN_CACHE_PLANE_SIZE)
- + offset);
-
- /* Compute the cache alignment of the place to stop clearing. */
-#if 0 /* This is not needed for gcc's purposes. */
- /* If the block to clear is bigger than a cache plane,
- we clear the entire cache, and OFFSET is already correct. */
- if (end < beg + INSN_CACHE_PLANE_SIZE)
-#endif
- offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH)
- & (INSN_CACHE_PLANE_SIZE - 1));
-
-#if INSN_CACHE_DEPTH > 1
- end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
- if (end_addr <= start_addr)
- end_addr += INSN_CACHE_PLANE_SIZE;
+#if INSN_CACHE_DEPTH > 1
+ end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
+ if (end_addr <= start_addr)
+ end_addr += INSN_CACHE_PLANE_SIZE;
for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
{
/* Jump to a trampoline, loading the static chain address. */
-#ifdef WINNT
+#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
-long getpagesize()
+long
+getpagesize (void)
{
#ifdef _ALPHA_
return 8192;
#endif
}
-int mprotect(addr, len, prot)
- char *addr;
- int len, prot;
+#ifdef __i386__
+extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
+#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 (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
+#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
-#ifdef TRANSFER_FROM_TRAMPOLINE
-TRANSFER_FROM_TRAMPOLINE
+#ifdef TRANSFER_FROM_TRAMPOLINE
+TRANSFER_FROM_TRAMPOLINE
#endif
#if defined (NeXT) && defined (__MACH__)
#endif
void
-__enable_execute_stack (addr)
- char *addr;
+__enable_execute_stack (char *addr)
{
kern_return_t r;
char *eaddr = addr + TRAMPOLINE_SIZE;
#else
__clear_cache ((int) addr, (int) eaddr);
#endif
-}
+}
#endif /* defined (NeXT) && defined (__MACH__) */
#include <machine/machparam.h>
void
-__enable_execute_stack ()
+__enable_execute_stack (void)
{
int fp;
static unsigned lowest = USRSTACK;
}
#endif /* __convex__ */
-#ifdef __DOLPHIN__
+#ifdef __sysV88__
/* Modified from the convex -code above. */
#include <sys/m88kbcs.h>
void
-__enable_execute_stack ()
+__enable_execute_stack (void)
{
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. */
+ address is seen as 'negative'. That is the case with the stack. */
save_errno=errno;
if (lowest > current)
errno=save_errno;
}
-#endif /* __DOLPHIN__ */
+#endif /* __sysV88__ */
+
+#ifdef __sysV68__
+
+#include <sys/signal.h>
+#include <errno.h>
+
+/* Motorola forgot to put memctl.o in the libp version of libc881.a,
+ so define it here, because we need it in __clear_insn_cache below */
+/* On older versions of this OS, no memctl or MCT_TEXT are defined;
+ hence we enable this stuff only if MCT_TEXT is #define'd. */
+
+#ifdef MCT_TEXT
+asm("\n\
+ global memctl\n\
+memctl:\n\
+ movq &75,%d0\n\
+ trap &0\n\
+ bcc.b noerror\n\
+ jmp cerror%\n\
+noerror:\n\
+ movq &0,%d0\n\
+ rts");
+#endif
+
+/* Clear instruction cache so we can call trampolines on stack.
+ This is called from FINALIZE_TRAMPOLINE in mot3300.h. */
+
+void
+__clear_insn_cache (void)
+{
+#ifdef MCT_TEXT
+ int save_errno;
+
+ /* Preserve errno, because users would be surprised to have
+ errno changing without explicitly calling any system-call. */
+ save_errno = errno;
+
+ /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
+ No need to use an address derived from _start or %sp, as 0 works also. */
+ memctl(0, 4096, MCT_TEXT);
+ errno = save_errno;
+#endif
+}
+
+#endif /* __sysV68__ */
#ifdef __pyr__
mremap promises to clear the i-cache. */
void
-__enable_execute_stack ()
+__enable_execute_stack (void)
{
int fp;
if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
defined in config/mips/mips.h. */
void
-cacheflush (beg,size,flag)
- char *beg;
- int size;
- int flag;
+cacheflush (char *beg, int size, int flag)
{
if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
{
#endif /* sony_news */
#endif /* L_trampoline */
\f
+#ifndef __CYGWIN__
#ifdef L__main
#include "gbl-ctors.h"
#endif
#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
+
+/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
+ code to run constructors. In that case, we need to handle EH here, too. */
+
+#ifdef EH_FRAME_SECTION_NAME
+#include "unwind-dw2-fde.h"
+extern unsigned char __EH_FRAME_BEGIN__[];
+#endif
+
/* Run all the global destructors on exit from the program. */
void
-__do_global_dtors ()
+__do_global_dtors (void)
{
#ifdef DO_GLOBAL_DTORS_BODY
DO_GLOBAL_DTORS_BODY;
(*(p-1)) ();
}
#endif
+#if defined (EH_FRAME_SECTION_NAME) && !defined (HAS_INIT_SECTION)
+ {
+ static int completed = 0;
+ if (! completed)
+ {
+ completed = 1;
+ __deregister_frame_info (__EH_FRAME_BEGIN__);
+ }
+ }
+#endif
}
#endif
#ifndef HAS_INIT_SECTION
/* Run all the global constructors on entry to the program. */
-#ifndef ON_EXIT
-#define ON_EXIT(a, b)
-#else
-/* Make sure the exit routine is pulled in to define the globals as
- bss symbols, just in case the linker does not automatically pull
- bss definitions from the library. */
-
-extern int _exit_dummy_decl;
-int *_exit_dummy_ref = &_exit_dummy_decl;
-#endif /* ON_EXIT */
-
void
-__do_global_ctors ()
+__do_global_ctors (void)
{
+#ifdef EH_FRAME_SECTION_NAME
+ {
+ static struct object object;
+ __register_frame_info (__EH_FRAME_BEGIN__, &object);
+ }
+#endif
DO_GLOBAL_CTORS_BODY;
- ON_EXIT (__do_global_dtors, 0);
+ atexit (__do_global_dtors);
}
#endif /* no HAS_INIT_SECTION */
#endif /* no HAS_INIT_SECTION or INVOKE__main */
#endif /* L__main */
+#endif /* __CYGWIN__ */
\f
#ifdef L_ctors
the right values. */
/* We declare the lists here with two elements each,
- so that they are valid empty lists if no other definition is loaded. */
+ so that they are valid empty lists if no other definition is loaded.
+
+ If we are using the old "set" extensions to have the gnu linker
+ collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__
+ must be in the bss/common section.
+
+ Long term no port should use those extensions. But many still do. */
#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
-#if defined(__NeXT__) || defined(_AIX)
-/* After 2.3, try this definition on all systems. */
+#if defined (TARGET_ASM_CONSTRUCTOR) || defined (USE_COLLECT2)
func_ptr __CTOR_LIST__[2] = {0, 0};
func_ptr __DTOR_LIST__[2] = {0, 0};
#else
#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 = NULL;
+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)
+int
+atexit (func_ptr func)
{
if (++last_atexit_chain_slot == atexit_chain_length)
{
atexit_chain_length += 32;
if (atexit_chain)
- atexit_chain = realloc (atexit_chain,
- atexit_chain_length * sizeof (func_ptr));
+ atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
+ * sizeof (func_ptr));
else
- atexit_chain = malloc (atexit_chain_length * sizeof (func_ptr));
+ atexit_chain = (func_ptr *) malloc (atexit_chain_length
+ * sizeof (func_ptr));
if (! atexit_chain)
{
atexit_chain_length = 0;
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 _cleanup (void);
+extern void _exit (int) __attribute__ ((__noreturn__));
-extern void __do_global_dtors ();
-extern void _cleanup ();
-extern void _exit () __attribute__ ((noreturn));
-
-void
-exit (status)
- int status;
+void
+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] = NULL;
+ atexit_chain[last_atexit_chain_slot + 1] = 0;
}
free (atexit_chain);
- atexit_chain = NULL;
+ atexit_chain = 0;
}
-#else /* No NEED_ATEXIT */
- __do_global_dtors ();
-#endif /* No NEED_ATEXIT */
-#endif
#ifdef EXIT_BODY
EXIT_BODY;
#else
_exit (status);
}
-#else
-int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
-#endif
-
-#endif /* L_exit */
-\f
-#ifdef L_eh
-
-#ifdef EH_TABLE_LOOKUP
-
-EH_TABLE_LOOKUP
-
-#else
-
-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 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
-
-#if 0
- /* 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);
-#endif
- return table[pos].exception_handler;
- }
-#else
- 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");
-#endif
- return (void *) 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;
-}
-#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.
+#else /* ON_EXIT */
- 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;
-
-void
-__empty ()
-{
-}
-
-#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 %ebx");
- asm("pop %esi");
- asm("pop %edi");
- asm("movl %ebp,%esp");
- asm("popl %ebp");
-
- asm("movl %ecx,0(%esp)");
- asm("ret");
-}
-#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)
+/* Simple; we just need a wrapper for ON_EXIT. */
+int
+atexit (func_ptr func)
{
- abort ();
+ return ON_EXIT (func);
}
-#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"
+#endif /* ON_EXIT */
+#endif /* NEED_ATEXIT */
-void
-__pure_virtual ()
-{
-#ifndef inhibit_libc
- write (2, MESSAGE, sizeof (MESSAGE) - 1);
-#endif
- _exit (-1);
-}
-#endif
+#endif /* L_exit */