/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
-/* Copyright (C) 1989, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 1999, 2000
+ Free Software Foundation, Inc.
This file is part of GNU CC.
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.)
+
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
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. */
-
/* 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 "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
-#endif
-
-/* Permit the tm.h file to select the endianness to use just for this
- file. This is used when the endianness is determined when the
- compiler is run. */
-
-#ifndef LIBGCC2_WORDS_BIG_ENDIAN
-#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
-#endif
-
-/* In the first part of this file, we are interfacing to calls generated
- by the compiler itself. These calls pass values into these routines
- which have very specific modes (rather than very specific types), and
- these compiler-generated calls also expect any return values to have
- very specific modes (rather than very specific types). Thus, we need
- to avoid using regular C language type names in this part of the file
- because the sizes for those types can be configured to be anything.
- Instead we use the following special type names. */
-
-typedef unsigned int UQItype __attribute__ ((mode (QI)));
-typedef int SItype __attribute__ ((mode (SI)));
-typedef unsigned int USItype __attribute__ ((mode (SI)));
-typedef int DItype __attribute__ ((mode (DI)));
-typedef unsigned int UDItype __attribute__ ((mode (DI)));
-
-typedef float SFtype __attribute__ ((mode (SF)));
-typedef float DFtype __attribute__ ((mode (DF)));
-
-#if LONG_DOUBLE_TYPE_SIZE == 96
-typedef float XFtype __attribute__ ((mode (XF)));
-#endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
-typedef float TFtype __attribute__ ((mode (TF)));
-#endif
-
-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*
- the type names defined above. The following macro definitions insure
- that if we *do* accidentally use some normal C language built-in type name,
- we will get a syntax error. */
-
-#define char bogus_type
-#define short bogus_type
-#define int bogus_type
-#define long bogus_type
-#define unsigned bogus_type
-#define float bogus_type
-#define double bogus_type
-
-#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-
-/* DIstructs are pairs of SItype values in the order determined by
- LIBGCC2_WORDS_BIG_ENDIAN. */
-
-#if LIBGCC2_WORDS_BIG_ENDIAN
- struct DIstruct {SItype high, low;};
-#else
- struct DIstruct {SItype low, high;};
-#endif
-
-/* We need this union to unpack/pack DImode values, since we don't have
- any arithmetic yet. Incoming DImode parameters are stored into the
- `ll' field, and the unpacked result is read from the struct `s'. */
-
-typedef union
-{
- struct DIstruct s;
- DItype ll;
-} DIunion;
-
-#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"
-
-#endif /* udiv or mul */
-
-extern DItype __fixunssfdi (SFtype a);
-extern DItype __fixunsdfdi (DFtype a);
-#if LONG_DOUBLE_TYPE_SIZE == 96
-extern DItype __fixunsxfdi (XFtype a);
-#endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
-extern DItype __fixunstfdi (TFtype a);
-#endif
+#include "libgcc2.h"
\f
#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
#if defined (L_divdi3) || defined (L_moddi3)
static inline
#endif
-DItype
-__negdi2 (DItype u)
+DWtype
+__negdi2 (DWtype u)
{
- DIunion w;
- DIunion uu;
+ DWunion w;
+ DWunion uu;
uu.ll = u;
w.s.low = -uu.s.low;
- w.s.high = -uu.s.high - ((USItype) w.s.low > 0);
+ w.s.high = -uu.s.high - ((UWtype) w.s.low > 0);
return w.ll;
}
/* 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 (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 (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 (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 (DItype u)
+DWtype
+__ffsdi2 (DWtype u)
{
- DIunion uu, w;
+ DWunion uu, w;
uu.ll = u;
w.s.high = 0;
w.s.low = ffs (uu.s.low);
w.s.low = ffs (uu.s.high);
if (w.s.low != 0)
{
- w.s.low += BITS_PER_UNIT * sizeof (SItype);
+ w.s.low += BITS_PER_UNIT * sizeof (Wtype);
return w.ll;
}
return w.ll;
#endif
\f
#ifdef L_muldi3
-DItype
-__muldi3 (DItype u, DItype 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 (USItype *rp, USItype a1, USItype a0, USItype 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 (USItype *rp, USItype a1, USItype a0, USItype 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
defined (L_umoddi3) || defined (L_moddi3))
static inline
#endif
-UDItype
-__udivmoddi4 (UDItype n, UDItype 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 (DItype u, DItype 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 (DItype u, DItype 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 (UDItype u, UDItype v)
+UDWtype
+__umoddi3 (UDWtype u, UDWtype v)
{
- UDItype w;
+ UDWtype w;
(void) __udivmoddi4 (u, v, &w);
#endif
#ifdef L_udivdi3
-UDItype __udivmoddi4 ();
-UDItype
-__udivdi3 (UDItype n, UDItype 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 (DItype a, DItype 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 (DItype a, DItype 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 (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
+#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 (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
+#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 (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
+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 (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 (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 (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 DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
/* Define codes for all the float formats that we know of. Note
that this is copied from real.h. */
#endif
SFtype
-__floatdisf (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 (XFtype a)
+UWtype
+__fixunsxfSI (XFtype a)
{
if (a >= - (DFtype) LONG_MIN)
- return (SItype) (a + LONG_MIN) - LONG_MIN;
- return (SItype) a;
+ return (Wtype) (a + LONG_MIN) - LONG_MIN;
+ return (Wtype) a;
}
#endif
#undef MAX
#include <limits.h>
-USItype
-__fixunsdfsi (DFtype a)
+UWtype
+__fixunsdfSI (DFtype a)
{
if (a >= - (DFtype) LONG_MIN)
- return (SItype) (a + LONG_MIN) - LONG_MIN;
- return (SItype) a;
+ return (Wtype) (a + LONG_MIN) - LONG_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;
+ return (Wtype) (a + LONG_MIN) - LONG_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 (unsigned char *s1, unsigned char *s2, size_t size)
+__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size)
{
while (size > 0)
{
\f\f
#ifdef L__dummy
void
-__dummy () {}
+__dummy (void) {}
#endif
#ifdef L_varargs
#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
asm (" .text");
+#ifdef __mips16
+ asm (" .set nomips16");
+#endif
asm (" .ent __builtin_saveregs");
asm (" .globl __builtin_saveregs");
asm ("__builtin_saveregs:");
asm (" .end __builtin_saveregs");
#else /* not __mips__, etc. */
-void *
-__builtin_saveregs ()
+void * __attribute__ ((__noreturn__))
+__builtin_saveregs (void)
{
abort ();
}
/* This is used by the `assert' macro. */
void
__eprintf (const char *string, const char *expression,
- int line, const char *filename)
+ unsigned int line, const char *filename)
{
fprintf (stderr, string, expression, line, filename);
fflush (stderr);
#include "gbl-ctors.h"
#include "gcov-io.h"
+#include <string.h>
+#ifdef TARGET_HAS_F_SETLKW
+#include <fcntl.h>
+#include <errno.h>
+#endif
static struct bb *bb_head;
+static int num_digits (long value, int base) __attribute__ ((const));
+
/* Return the number of digits needed to print a value */
/* __inline__ */ static int num_digits (long value, int base)
{
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)
+ int firstchar;
+
+ /* Make sure the output file exists -
+ but don't clobber exiting data. */
+ if ((da_file = fopen (ptr->filename, "a")) != 0)
+ fclose (da_file);
+
+ /* Need to re-open in order to be able to write from the start. */
+ da_file = fopen (ptr->filename, "r+b");
+ /* 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, "r+");
+ if (da_file == 0)
{
- long n_counts = 0;
- unsigned char tmp;
- int i;
- int ret = 0;
+ fprintf (stderr, "arc profiling: Can't open output file %s.\n",
+ ptr->filename);
+ continue;
+ }
+
+ /* 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 ();
+
+ while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+ && errno == EINTR);
+ }
+#endif
+ /* If the file is not empty, and the number of counts in it is the
+ same, then merge them in. */
+ firstchar = fgetc (da_file);
+ if (firstchar == EOF)
+ {
+ if (ferror (da_file))
+ {
+ fprintf (stderr, "arc profiling: Can't read output file ");
+ perror (ptr->filename);
+ }
+ }
+ else
+ {
+ long n_counts = 0;
+ if (ungetc (firstchar, da_file) == EOF)
+ rewind (da_file);
if (__read_long (&n_counts, da_file, 8) != 0)
{
fprintf (stderr, "arc profiling: Can't read output file %s.\n",
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)
{
}
}
- 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
+ rewind (da_file);
+
+ /* ??? Should first write a header to the file. Preferably, 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.
for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
{
int i;
- int func_p = (ptr->nwords >= sizeof (struct bb)
+ int func_p = (ptr->nwords >= (long) sizeof (struct bb)
&& ptr->nwords <= 1000
&& ptr->functions);
int line_p = (func_p && ptr->line_nums);
if (cnt_max < ptr->counts[i])
cnt_max = ptr->counts[i];
- if (addr_p && addr_max < ptr->addresses[i])
+ if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
addr_max = ptr->addresses[i];
if (line_p && line_max < ptr->line_nums[i])
if (blocks->zero_word)
return;
-#ifdef ON_EXIT
/* Initialize destructor. */
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;
}
+/* 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;
+
+ __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;
+ }
+}
+
#ifndef MACHINE_STATE_SAVE
#define MACHINE_STATE_SAVE(ID)
#endif
#define MACHINE_STATE_RESTORE(ID)
#endif
-#include <string.h>
-
/* Number of buckets in hashtable of basic block addresses. */
#define BB_BUCKETS 311
#define BBINBUFSIZE 500
-/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
- "BBINBUFSIZE" but want to avoid trouble with preprocessors. */
-
-#define BBINBUFSIZESTR "499"
-
struct bb_edge
{
struct bb_edge *next;
/* Called once per program. */
static void
-__bb_exit_trace_func ()
+__bb_exit_trace_func (void)
{
FILE *file = fopen ("bb.out", "a");
struct bb_func *f;
- struct bb_edge *e;
struct bb *b;
if (!file)
{
for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
{
- if (!ptr->filename || p->filename != (char *) 0 && strcmp (p->filename, ptr->filename))
+ if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
continue;
for (blk = 0; blk < ptr->ncounts; blk++)
{
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",
+ fprintf (file,
+ "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
addr_len, bucket->src_addr,
addr_len, bucket->dst_addr,
cnt_len, bucket->count);
/* Called once per program. */
static void
-__bb_init_prg ()
+__bb_init_prg (void)
{
-
FILE *file;
char buf[BBINBUFSIZE];
const char *p;
const char *pos;
enum bb_func_mode m;
+ int i;
-#ifdef ON_EXIT
/* Initialize destructor. */
- ON_EXIT (__bb_exit_func, 0);
-#endif
+ atexit (__bb_exit_func);
if (!(file = fopen ("bb.in", "r")))
return;
- while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF)
+ while(fgets (buf, BBINBUFSIZE, file) != 0)
{
+ i = strlen (buf);
+ if (buf[i] == '\n')
+ buf[i--] = '\0';
+
p = buf;
if (*p == '-')
{
{
unsigned long l;
f->next = bb_func_head;
- if (pos = strchr (p, ':'))
+ if ((pos = strchr (p, ':')))
{
if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
continue;
bb_hashbuckets = (struct bb_edge **)
malloc (BB_BUCKETS * sizeof (struct bb_edge *));
if (bb_hashbuckets)
- bzero ((char *) bb_hashbuckets, BB_BUCKETS);
+ /* Use a loop here rather than calling bzero to avoid having to
+ conditionalize its existance. */
+ for (i = 0; i < BB_BUCKETS; i++)
+ bb_hashbuckets[i] = 0;
}
if (bb_mode & 12)
bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
}
-#ifdef ON_EXIT
- /* Initialize destructor. */
- ON_EXIT (__bb_exit_trace_func, 0);
-#endif
-
+ /* Initialize destructor. */
+ atexit (__bb_exit_trace_func);
}
/* Called upon entering a basic block. */
void
-__bb_trace_func ()
+__bb_trace_func (void)
{
struct bb_edge *bucket;
/* Called when returning from a function and `__bb_showret__' is set. */
static void
-__bb_trace_func_ret ()
+__bb_trace_func_ret (void)
{
struct bb_edge *bucket;
/* Called when exiting from a function. */
void
-__bb_trace_ret ()
+__bb_trace_ret (void)
{
MACHINE_STATE_SAVE("2")
#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,
#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
void
-__clear_cache (char *beg, char *end)
+__clear_cache (char *beg __attribute__((__unused__)),
+ char *end __attribute__((__unused__)))
{
#ifdef CLEAR_INSN_CACHE
CLEAR_INSN_CACHE (beg, end);
int offset;
void *start_addr
void *end_addr;
- typedef (*function_ptr) ();
+ typedef (*function_ptr) (void);
#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
/* It's cheaper to clear the whole cache.
/* Jump to a trampoline, loading the static chain address. */
-#if defined(WINNT) && ! defined(__CYGWIN32__)
+#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
-long getpagesize()
+long
+getpagesize (void)
{
#ifdef _ALPHA_
return 8192;
#endif
}
-#ifdef i386
+#ifdef __i386__
extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
#endif
return -1;
}
-#endif
+#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
#ifdef TRANSFER_FROM_TRAMPOLINE
TRANSFER_FROM_TRAMPOLINE
#include <machine/machparam.h>
void
-__enable_execute_stack ()
+__enable_execute_stack (void)
{
int fp;
static unsigned lowest = USRSTACK;
#include <sys/m88kbcs.h>
void
-__enable_execute_stack ()
+__enable_execute_stack (void)
{
int save_errno;
static unsigned long lowest = USRSTACK;
#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__
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
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,
#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
+#include "frame.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) && !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
+ {
+ 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 (ASM_OUTPUT_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 = 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[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));
+extern void _cleanup (void);
+extern void _exit (int) __attribute__ ((__noreturn__));
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; )
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
_exit (status);
}
-#else
-int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
-#endif
+#else /* ON_EXIT */
+
+/* Simple; we just need a wrapper for ON_EXIT. */
+int
+atexit (func_ptr func)
+{
+ return ON_EXIT (func);
+}
+
+#endif /* ON_EXIT */
+#endif /* NEED_ATEXIT */
#endif /* L_exit */
\f
#ifdef L_eh
-/* Shared exception handling support routines. */
+#include "gthr.h"
-extern void *__eh_type;
+/* Shared exception handling support routines. */
void
-__default_terminate ()
+__default_terminate (void)
{
abort ();
}
-void (*__terminate_func)() = __default_terminate;
+void (*__terminate_func)(void) __attribute__ ((__noreturn__)) =
+ __default_terminate;
void
-__terminate ()
+__terminate (void)
{
(*__terminate_func)();
}
}
void
-__empty ()
+__empty (void)
{
}
\f
-/* Support routines for setjmp/longjmp exception handling. */
-/* Calls to __sjthrow are generated by the compiler when an exception
- is raised when using the setjmp/longjmp exception handling codegen
- method. */
+/* Include definitions of EH context and table layout */
-extern void longjmp (void *, int);
+#include "eh-common.h"
+#ifndef inhibit_libc
+#include <stdio.h>
+#endif
-static void *top_elt[2];
-void **__dynamic_handler_chain = top_elt;
+/* Allocate and return a new EH context structure. */
-/* Routine to get the head of the current thread's dynamic handler chain
- use for exception handling.
+#if __GTHREADS
+static void *
+new_eh_context (void)
+{
+ struct eh_full_context {
+ struct eh_context c;
+ void *top_elt[2];
+ } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
+
+ if (! ehfc)
+ __terminate ();
- TODO: make thread safe. */
+ memset (ehfc, 0, sizeof *ehfc);
-void ***
-__get_dynamic_handler_chain ()
+ ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
+
+ /* This should optimize out entirely. This should always be true,
+ but just in case it ever isn't, don't allow bogus code to be
+ generated. */
+
+ if ((void*)(&ehfc->c) != (void*)ehfc)
+ __terminate ();
+
+ return &ehfc->c;
+}
+
+static __gthread_key_t eh_context_key;
+
+/* Destructor for struct eh_context. */
+static void
+eh_context_free (void *ptr)
{
- return &__dynamic_handler_chain;
+ __gthread_key_dtor (eh_context_key, ptr);
+ if (ptr)
+ free (ptr);
}
+#endif
-/* This is used to throw an exception when the setjmp/longjmp codegen
- method is used for exception handling.
+/* Pointer to function to return EH context. */
+
+static struct eh_context *eh_context_initialize (void);
+static struct eh_context *eh_context_static (void);
+#if __GTHREADS
+static struct eh_context *eh_context_specific (void);
+#endif
- 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. */
+static struct eh_context *(*get_eh_context) (void) = &eh_context_initialize;
-void
-__sjthrow ()
+/* Routine to get EH context.
+ This one will simply call the function pointer. */
+
+void *
+__get_eh_context (void)
{
- void ***dhc = __get_dynamic_handler_chain ();
- void *jmpbuf;
- void (*func)(void *, int);
- void *arg;
- void ***cleanup;
+ return (void *) (*get_eh_context) ();
+}
- /* The cleanup chain is one word into the buffer. Get the cleanup
- chain. */
- cleanup = (void***)&(*dhc)[1];
+/* Get and set the language specific info pointer. */
- /* If there are any cleanups in the chain, run them now. */
- if (cleanup[0])
- {
- double store[200];
+void **
+__get_eh_info (void)
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ return &eh->info;
+}
+\f
+#ifdef DWARF2_UNWIND_INFO
+static int dwarf_reg_size_table_initialized = 0;
+static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
+
+static void
+init_reg_size_table (void)
+{
+ __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
+ dwarf_reg_size_table_initialized = 1;
+}
+#endif
+
+#if __GTHREADS
+static void
+eh_threads_initialize (void)
+{
+ /* Try to create the key. If it fails, revert to static method,
+ otherwise start using thread specific EH contexts. */
+ if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0)
+ get_eh_context = &eh_context_specific;
+ else
+ get_eh_context = &eh_context_static;
+}
+#endif /* no __GTHREADS */
+
+/* Initialize EH context.
+ This will be called only once, since we change GET_EH_CONTEXT
+ pointer to another routine. */
+
+static struct eh_context *
+eh_context_initialize (void)
+{
+#if __GTHREADS
+
+ static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+ /* Make sure that get_eh_context does not point to us anymore.
+ Some systems have dummy thread routines in their libc that
+ return a success (Solaris 2.6 for example). */
+ if (__gthread_once (&once, eh_threads_initialize) != 0
+ || get_eh_context == &eh_context_initialize)
+ {
+ /* Use static version of EH context. */
+ get_eh_context = &eh_context_static;
+ }
+#ifdef DWARF2_UNWIND_INFO
+ {
+ static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
+ if (__gthread_once (&once_regsizes, init_reg_size_table) != 0
+ || ! dwarf_reg_size_table_initialized)
+ init_reg_size_table ();
+ }
+#endif
+
+#else /* no __GTHREADS */
+
+ /* Use static version of EH context. */
+ get_eh_context = &eh_context_static;
+
+#ifdef DWARF2_UNWIND_INFO
+ init_reg_size_table ();
+#endif
+
+#endif /* no __GTHREADS */
+
+ return (*get_eh_context) ();
+}
+
+/* Return a static EH context. */
+
+static struct eh_context *
+eh_context_static (void)
+{
+ static struct eh_context eh;
+ static int initialized;
+ static void *top_elt[2];
+
+ if (! initialized)
+ {
+ initialized = 1;
+ memset (&eh, 0, sizeof eh);
+ eh.dynamic_handler_chain = top_elt;
+ }
+ return &eh;
+}
+
+#if __GTHREADS
+/* Return a thread specific EH context. */
+
+static struct eh_context *
+eh_context_specific (void)
+{
+ struct eh_context *eh;
+ eh = (struct eh_context *) __gthread_getspecific (eh_context_key);
+ if (! eh)
+ {
+ eh = new_eh_context ();
+ if (__gthread_setspecific (eh_context_key, (void *) eh) != 0)
+ __terminate ();
+ }
+
+ return eh;
+}
+#endif /* __GTHREADS */
+\f
+/* Support routines for alloc/free during exception handling */
+
+/* __eh_alloc and __eh_free attempt allocation using malloc, but fall back to
+ the small arena in the eh_context. This is needed because throwing an
+ out-of-memory exception would fail otherwise. The emergency space is
+ allocated in blocks of size EH_ALLOC_ALIGN, the
+ minimum allocation being two blocks. A bitmask indicates which blocks
+ have been allocated. To indicate the size of an allocation, the bit for
+ the final block is not set. Hence each allocation is a run of 1s followed
+ by a zero. */
+void *
+__eh_alloc (size_t size)
+{
+ void *p;
+
+ if (!size)
+ abort();
+ p = malloc (size);
+ if (p == 0)
+ {
+ struct eh_context *eh = __get_eh_context ();
+ unsigned blocks = (size + EH_ALLOC_ALIGN - 1) / EH_ALLOC_ALIGN;
+ unsigned real_mask = eh->alloc_mask | (eh->alloc_mask << 1);
+ unsigned our_mask;
+ unsigned ix;
+
+ if (blocks > EH_ALLOC_SIZE / EH_ALLOC_ALIGN)
+ __terminate ();
+ blocks += blocks == 1;
+ our_mask = (1 << blocks) - 1;
+
+ for (ix = EH_ALLOC_SIZE / EH_ALLOC_ALIGN - blocks; ix; ix--)
+ if (! ((real_mask >> ix) & our_mask))
+ {
+ /* found some space */
+ p = &eh->alloc_buffer[ix * EH_ALLOC_ALIGN];
+ eh->alloc_mask |= (our_mask >> 1) << ix;
+ return p;
+ }
+ __terminate ();
+ }
+ return p;
+}
+
+/* Free the memory for an cp_eh_info and associated exception, given
+ a pointer to the cp_eh_info. */
+void
+__eh_free (void *p)
+{
+ struct eh_context *eh = __get_eh_context ();
+
+ ptrdiff_t diff = (char *)p - &eh->alloc_buffer[0];
+ if (diff >= 0 && diff < EH_ALLOC_SIZE)
+ {
+ unsigned mask = eh->alloc_mask;
+ unsigned bit = 1 << (diff / EH_ALLOC_ALIGN);
+
+ do
+ {
+ mask ^= bit;
+ bit <<= 1;
+ }
+ while (mask & bit);
+ eh->alloc_mask = mask;
+ }
+ else
+ free (p);
+}
+\f
+/* Support routines for setjmp/longjmp exception handling. */
+
+/* Calls to __sjthrow are generated by the compiler when an exception
+ is raised when using the setjmp/longjmp exception handling codegen
+ method. */
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+extern void longjmp (void *, int);
+#endif
+
+/* Routine to get the head of the current thread's dynamic handler chain
+ use for exception handling. */
+
+void ***
+__get_dynamic_handler_chain (void)
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ return &eh->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. 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)
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void ***dhc = &eh->dynamic_handler_chain;
+ void *jmpbuf;
+ void (*func)(void *, int);
+ void *arg;
+ /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
+ void ***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);
/* 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)
+ if (! eh->info || (*dhc)[0] == 0)
__terminate ();
/* Find the jmpbuf associated with the top element of the dynamic
control to the next handler in the dynamic handler stack. */
void
-__sjpopnthrow ()
+__sjpopnthrow (void)
{
- void ***dhc = __get_dynamic_handler_chain ();
- void *jmpbuf;
+ struct eh_context *eh = (*get_eh_context) ();
+ void ***dhc = &eh->dynamic_handler_chain;
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];
+ /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
+ void ***cleanup = (void***)&(*dhc)[1];
/* If there are any cleanups in the chain, run them now. */
if (cleanup[0])
\f
/* Support code for all exception region-based exception handling. */
+int
+__eh_rtime_match (void *rtime)
+{
+ void *info;
+ __eh_matcher matcher;
+ void *ret;
+
+ info = *(__get_eh_info ());
+ matcher = ((__eh_info *)info)->match_function;
+ if (! matcher)
+ {
+#ifndef inhibit_libc
+ fprintf (stderr, "Internal Compiler Bug: No runtime type matcher.");
+#endif
+ return 0;
+ }
+ ret = (*matcher) (info, rtime, (void *)0);
+ return (ret != NULL);
+}
+
/* This value identifies the place from which an exception is being
thrown. */
-extern void *__eh_pc;
-
#ifdef EH_TABLE_LOOKUP
EH_TABLE_LOOKUP
#else
-typedef struct exception_table {
- void *start;
- void *end;
- void *exception_handler;
-} exception_table;
+#ifdef DWARF2_UNWIND_INFO
+
+/* Return the table version of an exception descriptor */
+
+short
+__get_eh_table_version (exception_descriptor *table)
+{
+ return table->lang.version;
+}
+
+/* Return the originating table language of an exception descriptor */
+
+short
+__get_eh_table_language (exception_descriptor *table)
+{
+ return table->lang.language;
+}
/* This routine takes a PC and a pointer to the exception region TABLE for
its translation unit, and returns the address of the exception handler
an inner block. */
static void *
-find_exception_handler (void *pc, exception_table *table)
+old_find_exception_handler (void *pc, old_exception_table *table)
{
if (table)
{
int pos;
- int best = 0;
+ int best = -1;
/* We can't do a binary search because the table isn't guaranteed
- to be sorted from function to function. */
- for (pos = 0; table[pos].exception_handler != (void *) -1; ++pos)
- {
- if (table[pos].start <= pc && table[pos].end >= pc)
- {
- /* This can apply. Make sure it is at least as small as
- the previous best. */
- if (best == 0 || (table[pos].end <= table[best].end
- && table[pos].start >= table[best].start))
- best = pos;
- }
- /* But it is sorted by starting PC within a function. */
- else if (best && table[pos].start > pc)
- break;
- }
- if (best != 0)
- return table[best].exception_handler;
+ to be sorted from function to function. */
+ for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
+ {
+ if (table[pos].start_region <= pc && table[pos].end_region > pc)
+ {
+ /* This can apply. Make sure it is at least as small as
+ the previous best. */
+ if (best == -1 || (table[pos].end_region <= table[best].end_region
+ && table[pos].start_region >= table[best].start_region))
+ best = pos;
+ }
+ /* But it is sorted by starting PC within a function. */
+ else if (best >= 0 && table[pos].start_region > pc)
+ break;
+ }
+ if (best != -1)
+ return table[best].exception_handler;
}
return (void *) 0;
}
-#endif /* EH_TABLE_LOOKUP */
-\f
-#ifndef DWARF2_UNWIND_INFO
-/* Support code for exception handling using inline unwinders or
- __unwind_function. */
-
-#ifndef EH_TABLE_LOOKUP
-typedef struct exception_table_node {
- exception_table *table;
- void *start;
- void *end;
- struct exception_table_node *next;
-} exception_table_node;
-
-static struct exception_table_node *exception_table_list;
-void *
-__find_first_exception_table_match (void *pc)
+/* find_exception_handler finds the correct handler, if there is one, to
+ handle an exception.
+ returns a pointer to the handler which controlled should be transferred
+ to, or NULL if there is nothing left.
+ Parameters:
+ PC - pc where the exception originates. If this is a rethrow,
+ then this starts out as a pointer to the exception table
+ entry we wish to rethrow out of.
+ TABLE - exception table for the current module.
+ EH_INFO - eh info pointer for this exception.
+ RETHROW - 1 if this is a rethrow. (see incoming value of PC).
+ CLEANUP - returned flag indicating whether this is a cleanup handler.
+*/
+static void *
+find_exception_handler (void *pc, exception_descriptor *table,
+ __eh_info *eh_info, int rethrow, int *cleanup)
{
- register exception_table_node *tnp;
- for (tnp = exception_table_list; tnp != 0; tnp = tnp->next)
+ void *retval = NULL;
+ *cleanup = 1;
+ if (table)
{
- if (tnp->start <= pc && tnp->end >= pc)
- return find_exception_handler (pc, tnp->table);
- }
-
- return (void *) 0;
-}
-
-void
-__register_exceptions (exception_table *table)
-{
- exception_table_node *node;
- exception_table *range = table + 1;
-
- if (range->start == (void *) -1)
- return;
+ int pos = 0;
+ /* The new model assumed the table is sorted inner-most out so the
+ first region we find which matches is the correct one */
- node = (exception_table_node *) malloc (sizeof (exception_table_node));
- node->table = table;
+ exception_table *tab = &(table->table[0]);
- /* 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;
+ /* Subtract 1 from the PC to avoid hitting the next region */
+ if (rethrow)
+ {
+ /* pc is actually the region table entry to rethrow out of */
+ pos = ((exception_table *) pc) - tab;
+ pc = ((exception_table *) pc)->end_region - 1;
+
+ /* The label is always on the LAST handler entry for a region,
+ so we know the next entry is a different region, even if the
+ addresses are the same. Make sure its not end of table tho. */
+ if (tab[pos].start_region != (void *) -1)
+ pos++;
+ }
+ else
+ pc--;
+
+ /* We can't do a binary search because the table is in inner-most
+ to outermost address ranges within functions */
+ for ( ; tab[pos].start_region != (void *) -1; pos++)
+ {
+ if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
+ {
+ if (tab[pos].match_info)
+ {
+ __eh_matcher matcher = eh_info->match_function;
+ /* match info but no matcher is NOT a match */
+ if (matcher)
+ {
+ void *ret = (*matcher)((void *) eh_info,
+ tab[pos].match_info, table);
+ if (ret)
+ {
+ if (retval == NULL)
+ retval = tab[pos].exception_handler;
+ *cleanup = 0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (retval == NULL)
+ retval = tab[pos].exception_handler;
+ }
+ }
+ }
}
-
- node->next = exception_table_list;
- exception_table_list = node;
-}
-#endif /* !EH_TABLE_LOOKUP */
-
-/* Throw stub routine.
-
- This is work in progress, but not completed yet. */
-
-void
-__throw ()
-{
- abort ();
-}
-
-/* See expand_builtin_throw for details. */
-
-void **__eh_pcnthrow () {
- static void *buf[2] = {
- &__eh_pc,
- &__throw
- };
- return buf;
-}
-
-#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;
+ return retval;
}
-#else
-__unwind_function(void *ptr)
-{
- abort ();
-}
-#endif /* powerpc */
+#endif /* DWARF2_UNWIND_INFO */
+#endif /* EH_TABLE_LOOKUP */
\f
-#else /* DWARF2_UNWIND_INFO */
+#ifdef DWARF2_UNWIND_INFO
/* Support code for exception handling using static unwind information. */
#include "frame.h"
typedef int ptr_type __attribute__ ((mode (pointer)));
-/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+#ifdef INCOMING_REGNO
+/* Is the saved value for register REG in frame UDATA stored in a register
+ window in the previous frame? */
+
+/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
+ to use the macro here. One wonders, though, that perhaps TARGET_FLAT
+ compiled functions won't work with the frame-unwind stuff here.
+ Perhaps the entireity of in_reg_window should be conditional on having
+ seen a DW_CFA_GNU_window_save? */
+#define target_flags 0
+
+static int
+in_reg_window (int reg, frame_state *udata)
+{
+ if (udata->saved[reg] == REG_SAVED_REG)
+ return INCOMING_REGNO (reg) == reg;
+ if (udata->saved[reg] != REG_SAVED_OFFSET)
+ return 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+ return udata->reg_or_offset[reg] > 0;
+#else
+ return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#else
+static inline int
+in_reg_window (int reg __attribute__ ((__unused__)),
+ frame_state *udata __attribute__ ((__unused__)))
+{
+ return 0;
+}
+#endif /* INCOMING_REGNO */
+
+/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
frame called by UDATA or 0. */
-static void*
-get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+static word_type *
+get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
{
+ while (udata->saved[reg] == REG_SAVED_REG)
+ {
+ reg = udata->reg_or_offset[reg];
+ if (in_reg_window (reg, udata))
+ {
+ udata = sub_udata;
+ sub_udata = NULL;
+ }
+ }
if (udata->saved[reg] == REG_SAVED_OFFSET)
- return (void *)(ptr_type)
- *(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
- else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
- return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
+ return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
else
abort ();
}
+/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+ frame called by UDATA or 0. */
+
+static inline void *
+get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+{
+ return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
+}
+
/* Overwrite the saved value for register REG in frame UDATA with VAL. */
-static void
+static inline void
put_reg (unsigned reg, void *val, frame_state *udata)
{
- if (udata->saved[reg] == REG_SAVED_OFFSET)
- *(word_type *)(udata->cfa + udata->reg_or_offset[reg])
- = (word_type)(ptr_type) val;
- else
- abort ();
+ *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
}
-/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
- frame called by UDATA or 0. */
+/* Copy the saved value for register REG from frame UDATA to frame
+ TARGET_UDATA. Unlike the previous two functions, this can handle
+ registers that are not one word large. */
+
+static void
+copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
+{
+ word_type *preg = get_reg_addr (reg, udata, NULL);
+ word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
+
+ memcpy (ptreg, preg, dwarf_reg_size_table [reg]);
+}
+
+/* Retrieve the return address for frame UDATA. */
static inline void *
get_return_addr (frame_state *udata, frame_state *sub_udata)
return caller_udata;
}
-#ifdef INCOMING_REGNO
-/* Is the saved value for register REG in frame UDATA stored in a register
- window in the previous frame? */
-
-static int
-in_reg_window (int reg, frame_state *udata)
+/* Hook to call before __terminate if only cleanup handlers remain. */
+void
+__unwinding_cleanup (void)
{
- if (udata->saved[reg] != REG_SAVED_OFFSET)
- return 0;
-
-#ifdef STACK_GROWS_DOWNWARD
- return udata->reg_or_offset[reg] > 0;
-#else
- return udata->reg_or_offset[reg] < 0;
-#endif
}
-#endif /* INCOMING_REGNO */
-/* We first search for an exception handler, and if we don't find
- it, we call __terminate on the current stack frame so that we may
- use the debugger to walk the stack and understand why no handler
- was found.
+/* throw_helper performs some of the common grunt work for a throw. This
+ routine is called by throw and rethrows. This is pretty much split
+ out from the old __throw routine. An addition has been added which allows
+ for a dummy call to a routine __unwinding_cleanup() when there are nothing
+ but cleanups remaining. This allows a debugger to examine the state
+ at which the throw was executed, before any cleanups, rather than
+ at the terminate point after the stack has been unwound.
- If we find one, then we unwind the frames down to the one that
- has the handler and transfer control into the handler. */
+ EH is the current eh_context structure.
+ PC is the address of the call to __throw.
+ MY_UDATA is the unwind information for __throw.
+ OFFSET_P is where we return the SP adjustment offset. */
-void
-__throw ()
+static void *
+throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
+ long *offset_p)
{
- void *pc, *handler, *retaddr;
- frame_state ustruct, ustruct2;
- frame_state *udata = &ustruct;
- frame_state *sub_udata = &ustruct2;
- frame_state my_ustruct, *my_udata = &my_ustruct;
+ frame_state ustruct2, *udata = &ustruct2;
+ frame_state ustruct;
+ frame_state *sub_udata = &ustruct;
+ void *saved_pc = pc;
+ void *handler;
+ void *handler_p = 0;
+ void *pc_p = 0;
+ frame_state saved_ustruct;
+ int new_eh_model;
+ int cleanup = 0;
+ int only_cleanup = 0;
+ int rethrow = 0;
+ int saved_state = 0;
long args_size;
+ __eh_info *eh_info = (__eh_info *)eh->info;
- /* This is required for C++ semantics. We must call terminate if we
- try and rethrow an exception, when there is no exception currently
- active. */
- if (! __eh_type)
- __terminate ();
-
- /* Start at our stack frame. */
-label:
- udata = __frame_state_for (&&label, udata);
- if (! udata)
- __terminate ();
-
- /* We need to get the value from the CFA register. At this point in
- compiling __throw we don't know whether or not we will use the frame
- pointer register for the CFA, so we check our unwind info. */
- if (udata->cfa_reg == __builtin_dwarf_fp_regnum ())
- udata->cfa = __builtin_fp ();
- else
- udata->cfa = __builtin_sp ();
- udata->cfa += udata->cfa_offset;
-
- memcpy (my_udata, udata, sizeof (*udata));
+ /* Do we find a handler based on a re-throw PC? */
+ if (eh->table_index != (void *) 0)
+ rethrow = 1;
- /* Do any necessary initialization to access arbitrary stack frames.
- On the SPARC, this means flushing the register windows. */
- __builtin_unwind_init ();
-
- /* Now reset pc to the right throw point. */
- pc = __eh_pc;
+ memcpy (udata, my_udata, sizeof (*udata));
+ handler = (void *) 0;
for (;;)
{
frame_state *p = udata;
if (! udata)
break;
- handler = find_exception_handler (pc, udata->eh_ptr);
+ if (udata->eh_ptr == NULL)
+ new_eh_model = 0;
+ else
+ new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
+ runtime_id_field == NEW_EH_RUNTIME);
- /* If we found one, we can stop searching. */
+ if (rethrow)
+ {
+ rethrow = 0;
+ handler = find_exception_handler (eh->table_index, udata->eh_ptr,
+ eh_info, 1, &cleanup);
+ eh->table_index = (void *)0;
+ }
+ else
+ if (new_eh_model)
+ handler = find_exception_handler (pc, udata->eh_ptr, eh_info,
+ 0, &cleanup);
+ else
+ handler = old_find_exception_handler (pc, udata->eh_ptr);
+
+ /* If we found one, we can stop searching, if its not a cleanup.
+ for cleanups, we save the state, and keep looking. This allows
+ us to call a debug hook if there are nothing but cleanups left. */
if (handler)
{
- args_size = udata->args_size;
- break;
+ if (cleanup)
+ {
+ if (!saved_state)
+ {
+ saved_ustruct = *udata;
+ handler_p = handler;
+ pc_p = pc;
+ saved_state = 1;
+ only_cleanup = 1;
+ }
+ }
+ else
+ {
+ only_cleanup = 0;
+ break;
+ }
}
- /* Otherwise, we continue searching. */
- pc = get_return_addr (udata, sub_udata);
+ /* Otherwise, we continue searching. We subtract 1 from PC to avoid
+ hitting the beginning of the next region. */
+ pc = get_return_addr (udata, sub_udata) - 1;
+ }
+
+ if (saved_state)
+ {
+ udata = &saved_ustruct;
+ handler = handler_p;
+ pc = pc_p;
+ if (only_cleanup)
+ __unwinding_cleanup ();
}
/* If we haven't found a handler by now, this is an unhandled
exception. */
- if (! handler)
- __terminate ();
+ if (! handler)
+ __terminate();
- if (pc == __eh_pc)
+ eh->handler_label = handler;
+
+ args_size = udata->args_size;
+
+ if (pc == saved_pc)
/* We found a handler in the throw context, no need to unwind. */
udata = my_udata;
else
{
int i;
- void *val;
/* Unwind all the frames between this one and the handler by copying
their saved register values into our register save slots. */
void *handler_pc = pc;
/* Start from the throw context again. */
- pc = __eh_pc;
+ pc = saved_pc;
memcpy (udata, my_udata, sizeof (*udata));
while (pc != handler_pc)
udata = next_stack_level (pc, udata, sub_udata);
sub_udata = p;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
- if (udata->saved[i])
+ for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
+ if (i != udata->retaddr_column && udata->saved[i])
{
-#ifdef INCOMING_REGNO
/* If you modify the saved value of the return address
register on the SPARC, you modify the return address for
your caller's frame. Don't do that here, as it will
&& udata->saved[udata->retaddr_column] == REG_SAVED_REG
&& udata->reg_or_offset[udata->retaddr_column] == i)
continue;
-#endif
- val = get_reg (i, udata, sub_udata);
- put_reg (i, val, my_udata);
+ copy_reg (i, udata, my_udata);
}
- pc = get_return_addr (udata, sub_udata);
+ pc = get_return_addr (udata, sub_udata) - 1;
}
-#ifdef INCOMING_REGNO
/* But we do need to update the saved return address register from
the last frame we unwind, or the handler frame will have the wrong
return address. */
{
i = udata->reg_or_offset[udata->retaddr_column];
if (in_reg_window (i, udata))
- {
- val = get_reg (i, udata, sub_udata);
- put_reg (i, val, my_udata);
- }
+ copy_reg (i, udata, my_udata);
}
-#endif
}
/* udata now refers to the frame called by the handler frame. */
- /* Emit the stub to adjust sp and jump to the handler. */
- retaddr = __builtin_eh_stub ();
-
- /* And then set our return address to point to the stub. */
- if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
- put_return_addr (retaddr, my_udata);
- else
- __builtin_set_return_addr_reg (retaddr);
-
- /* Set up the registers we use to communicate with the stub.
- We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
- __builtin_set_eh_regs (handler,
+ /* We adjust SP by the difference between __throw's CFA and the CFA for
+ the frame called by the handler frame, because those CFAs correspond
+ to the SP values at the two call sites. We need to further adjust by
+ the args_size of the handler frame itself to get the handler frame's
+ SP from before the args were pushed for that call. */
#ifdef STACK_GROWS_DOWNWARD
- udata->cfa - my_udata->cfa
+ *offset_p = udata->cfa - my_udata->cfa + args_size;
#else
- my_udata->cfa - udata->cfa
+ *offset_p = my_udata->cfa - udata->cfa - args_size;
#endif
- + args_size
- );
+
+ return handler;
+}
+
+
+/* We first search for an exception handler, and if we don't find
+ it, we call __terminate on the current stack frame so that we may
+ use the debugger to walk the stack and understand why no handler
+ was found.
+
+ If we find one, then we unwind the frames down to the one that
+ has the handler and transfer control into the handler. */
+
+/*extern void __throw(void) __attribute__ ((__noreturn__));*/
+
+void
+__throw (void)
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void *pc, *handler;
+ long offset;
+
+ /* XXX maybe make my_ustruct static so we don't have to look it up for
+ each throw. */
+ frame_state my_ustruct, *my_udata = &my_ustruct;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ /* Start at our stack frame. */
+label:
+ my_udata = __frame_state_for (&&label, my_udata);
+ if (! my_udata)
+ __terminate ();
+
+ /* We need to get the value from the CFA register. */
+ my_udata->cfa = __builtin_dwarf_cfa ();
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* Now reset pc to the right throw point. */
+ pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+ handler = throw_helper (eh, pc, my_udata, &offset);
+
+ /* Now go! */
+
+ __builtin_eh_return ((void *)eh, offset, handler);
+
+ /* Epilogue: restore the handler frame's register values and return
+ to the stub. */
+}
+
+/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
+
+void
+__rethrow (void *index)
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void *pc, *handler;
+ long offset;
+
+ /* XXX maybe make my_ustruct static so we don't have to look it up for
+ each throw. */
+ frame_state my_ustruct, *my_udata = &my_ustruct;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ /* This is the table index we want to rethrow from. The value of
+ the END_REGION label is used for the PC of the throw, and the
+ search begins with the next table entry. */
+ eh->table_index = index;
+
+ /* Start at our stack frame. */
+label:
+ my_udata = __frame_state_for (&&label, my_udata);
+ if (! my_udata)
+ __terminate ();
+
+ /* We need to get the value from the CFA register. */
+ my_udata->cfa = __builtin_dwarf_cfa ();
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* Now reset pc to the right throw point. */
+ pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+ handler = throw_helper (eh, pc, my_udata, &offset);
+
+ /* Now go! */
+
+ __builtin_eh_return ((void *)eh, offset, handler);
/* Epilogue: restore the handler frame's register values and return
to the stub. */
}
-#endif /* !DWARF2_UNWIND_INFO */
+#endif /* DWARF2_UNWIND_INFO */
+
+#ifdef IA64_UNWIND_INFO
+#include "frame.h"
+
+/* Return handler to which we want to transfer control, NULL if we don't
+ intend to handle this exception here. */
+void *
+__ia64_personality_v1 (void *pc, old_exception_table *table)
+{
+ if (table)
+ {
+ int pos;
+ int best = -1;
+
+ for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
+ {
+ if (table[pos].start_region <= pc && table[pos].end_region > pc)
+ {
+ /* This can apply. Make sure it is at least as small as
+ the previous best. */
+ if (best == -1 || (table[pos].end_region <= table[best].end_region
+ && table[pos].start_region >= table[best].start_region))
+ best = pos;
+ }
+ /* It is sorted by starting PC within a function. */
+ else if (best >= 0 && table[pos].start_region > pc)
+ break;
+ }
+ if (best != -1)
+ return table[best].exception_handler;
+ }
+ return (void *) 0;
+}
+
+static void
+ia64_throw_helper (throw_pc, throw_frame, caller, throw_bsp)
+ void *throw_pc;
+ ia64_frame_state *throw_frame;
+ ia64_frame_state *caller;
+ void *throw_bsp;
+{
+ unwind_info_ptr *info;
+ void *pc, *handler = NULL;
+ void *pc_base;
+ int frame_count;
+ void *bsp;
+
+ __builtin_ia64_flushrs (); /* Make the local register stacks available. */
+
+ /* Start at our stack frame, get our state. */
+ __build_ia64_frame_state (throw_pc, throw_frame, throw_bsp, &pc_base);
+
+ /* Now we have to find the proper frame for pc, and see if there
+ is a handler for it. if not, we keep going back frames until
+ we do find one. Otherwise we call uncaught (). */
+
+ frame_count = 0;
+ memcpy (caller, throw_frame, sizeof (*caller));
+ while (!handler)
+ {
+ void *(*personality) ();
+ void *eh_table;
+
+ frame_count++;
+ /* We only care about the RP right now, so we dont need to keep
+ any other information about a call frame right now. */
+ pc = __get_real_reg_value (&caller->rp) - 1;
+ bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), caller->my_bsp);
+ info = __build_ia64_frame_state (pc, caller, bsp, &pc_base);
+
+ /* If we couldn't find the next frame, we lose. */
+ if (! info)
+ break;
+
+ personality = __get_personality (info);
+ /* TODO Haven't figured out how to actually load the personality address
+ yet, so just always default to the one we expect for now. */
+ if (personality != 0)
+ personality = __ia64_personality_v1;
+ eh_table = __get_except_table (info);
+ /* If there is no personality routine, we'll keep unwinding. */
+ if (personality)
+ /* Pass a segment relative PC address to the personality routine,
+ because the unwind_info section uses segrel relocs. */
+ handler = personality (pc - pc_base, eh_table);
+ }
+
+ if (!handler)
+ __terminate ();
+
+ /* Handler is a segment relative address, so we must adjust it here. */
+ handler += (long) pc_base;
+
+ /* If we found a handler, we need to unwind the stack to that point.
+ We do this by copying saved values from previous frames into the
+ save slot for the throw_frame saved slots. when __throw returns,
+ it'll pickup the correct values. */
+
+ /* Start with where __throw saved things, and copy each saved register
+ of each previous frame until we get to the one before we're
+ throwing back to. */
+ memcpy (caller, throw_frame, sizeof (*caller));
+ for ( ; frame_count > 0; frame_count--)
+ {
+ pc = __get_real_reg_value (&caller->rp) - 1;
+ bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), caller->my_bsp);
+ __build_ia64_frame_state (pc, caller, bsp, &pc_base);
+ /* Any regs that were saved can be put in the throw frame now. */
+ /* We don't want to copy any saved register from the
+ target destination, but we do want to load up it's frame. */
+ if (frame_count > 1)
+ __copy_saved_reg_state (throw_frame, caller);
+ }
+
+ /* Set return address of the throw frame to the handler. */
+ __set_real_reg_value (&throw_frame->rp, handler);
+
+ /* TODO, do we need to do anything to make the values we wrote 'stick'? */
+ /* DO we need to go through the whole loadrs seqeunce? */
+
+}
+
+void
+__throw ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ ia64_frame_state my_frame;
+ ia64_frame_state originator; /* For the context handler is in. */
+ void *bsp, *tmp_bsp;
+ long offset;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ __builtin_unwind_init ();
+label_ia64:
+ /* We have to call another routine to actually process the frame
+ information, which will force all of __throw's local registers into
+ backing store. */
+
+ /* Get the value of ar.bsp while we're here. */
+
+ bsp = __builtin_ia64_bsp ();
+ ia64_throw_helper (&&label_ia64, &my_frame, &originator, bsp);
+
+ /* Now we have to fudge the bsp by the amount in our (__throw)
+ frame marker, since the return is going to adjust it by that much. */
+
+ tmp_bsp = __calc_caller_bsp ((long)__get_real_reg_value (&my_frame.pfs),
+ my_frame.my_bsp);
+ offset = (char *)my_frame.my_bsp - (char *)tmp_bsp;
+ tmp_bsp = (char *)originator.my_bsp + offset;
+
+ /* A throw handler is trated like a non-local goto, which is architeched
+ to set the FP (or PSP) in r7 before branching. gr[0-3] map to
+ r4-r7, so we want gr[3]. */
+ __set_real_reg_value (&my_frame.gr[3], __get_real_reg_value (&originator.psp));
+
+ __builtin_eh_return (tmp_bsp, offset, originator.my_sp);
+
+ /* The return address was already set by throw_helper. */
+}
+
+#endif /* IA64_UNWIND_INFO */
#endif /* L_eh */
\f
#define MESSAGE "pure virtual method called\n"
void
-__pure_virtual ()
+__pure_virtual (void)
{
#ifndef inhibit_libc
write (2, MESSAGE, sizeof (MESSAGE) - 1);
#endif
- _exit (-1);
+ __terminate ();
}
#endif