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. */
#undef abort
#endif
-/* In a cross-compilation situation, default to inhibiting compilation
- of routines that use libc. */
-
-#if defined(CROSS_COMPILE) && !defined(inhibit_libc)
-#define inhibit_libc
-#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
-
-#ifndef LIBGCC2_LONG_DOUBLE_TYPE_SIZE
-#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE LONG_DOUBLE_TYPE_SIZE
-#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 int QItype __attribute__ ((mode (QI)));
-typedef unsigned int UQItype __attribute__ ((mode (QI)));
-typedef int HItype __attribute__ ((mode (HI)));
-typedef unsigned int UHItype __attribute__ ((mode (HI)));
-#if UNITS_PER_WORD > 1
-/* These typedefs are usually forbidden on dsp's with UNITS_PER_WORD 1 */
-typedef int SItype __attribute__ ((mode (SI)));
-typedef unsigned int USItype __attribute__ ((mode (SI)));
-#if UNITS_PER_WORD > 2
-/* These typedefs are usually forbidden on archs with UNITS_PER_WORD 2 */
-typedef int DItype __attribute__ ((mode (DI)));
-typedef unsigned int UDItype __attribute__ ((mode (DI)));
-#endif
-#endif
-
-#if BITS_PER_UNIT == 8
-
-typedef float SFtype __attribute__ ((mode (SF)));
-typedef float DFtype __attribute__ ((mode (DF)));
-
-#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
-typedef float XFtype __attribute__ ((mode (XF)));
-#endif
-#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
-typedef float TFtype __attribute__ ((mode (TF)));
-#endif
-
-#else /* BITS_PER_UNIT != 8 */
-
-/* On dsp's there are usually qf/hf/tqf modes used instead of the above.
- For now we don't support them in libgcc2.c. */
-
-#undef L_fixdfdi
-#undef L_fixsfdi
-#undef L_fixtfdi
-#undef L_fixunsdfdi
-#undef L_fixunsdfsi
-#undef L_fixunssfdi
-#undef L_fixunssfsi
-#undef L_fixunstfdi
-#undef L_fixunsxfdi
-#undef L_fixunsxfsi
-#undef L_fixxfdi
-#undef L_floatdidf
-#undef L_floatdisf
-#undef L_floatditf
-#undef L_floatdixf
-
-#endif /* BITS_PER_UNIT != 8 */
-
-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
-
-#if UNITS_PER_WORD > 2
-#define W_TYPE_SIZE (4 * BITS_PER_UNIT)
-#define Wtype SItype
-#define UWtype USItype
-#define HWtype SItype
-#define UHWtype USItype
-#define DWtype DItype
-#define UDWtype UDItype
-#define __NW(a,b) __ ## a ## si ## b
-#define __NDW(a,b) __ ## a ## di ## b
-#elif UNITS_PER_WORD > 1
-#define W_TYPE_SIZE (2 * BITS_PER_UNIT)
-#define Wtype HItype
-#define UWtype UHItype
-#define HWtype HItype
-#define UHWtype UHItype
-#define DWtype SItype
-#define UDWtype USItype
-#define __NW(a,b) __ ## a ## hi ## b
-#define __NDW(a,b) __ ## a ## si ## b
-#else
-#define W_TYPE_SIZE BITS_PER_UNIT
-#define Wtype QItype
-#define UWtype UQItype
-#define HWtype QItype
-#define UHWtype UQItype
-#define DWtype HItype
-#define UDWtype UHItype
-#define __NW(a,b) __ ## a ## qi ## b
-#define __NDW(a,b) __ ## a ## hi ## b
-#endif
-
-#define __muldi3 __NDW(mul,3)
-#define __divdi3 __NDW(div,3)
-#define __udivdi3 __NDW(udiv,3)
-#define __moddi3 __NDW(mod,3)
-#define __umoddi3 __NDW(umod,3)
-#define __negdi2 __NDW(neg,2)
-#define __lshrdi3 __NDW(lshr,3)
-#define __ashldi3 __NDW(ashl,3)
-#define __ashrdi3 __NDW(ashr,3)
-#define __ffsdi2 __NDW(ffs,2)
-#define __cmpdi2 __NDW(cmp,2)
-#define __ucmpdi2 __NDW(ucmp,2)
-#define __udivmoddi4 __NDW(udivmod,4)
-#define __fixunstfdi __NDW(fixunstf,)
-#define __fixtfdi __NDW(fixtf,)
-#define __fixunsxfdi __NDW(fixunsxf,)
-#define __fixxfdi __NDW(fixxf,)
-#define __fixunsdfdi __NDW(fixunsdf,)
-#define __fixdfdi __NDW(fixdf,)
-#define __fixunssfdi __NDW(fixunssf,)
-#define __fixsfdi __NDW(fixsf,)
-#define __floatdixf __NDW(float,xf)
-#define __floatditf __NDW(float,tf)
-#define __floatdidf __NDW(float,df)
-#define __floatdisf __NDW(float,sf)
-#define __fixunsxfsi __NW(fixunsxf,)
-#define __fixunstfsi __NW(fixunstf,)
-#define __fixunsdfsi __NW(fixunsdf,)
-#define __fixunssfsi __NW(fixunssf,)
-
-/* DWstructs are pairs of Wtype values in the order determined by
- LIBGCC2_WORDS_BIG_ENDIAN. */
-
-#if LIBGCC2_WORDS_BIG_ENDIAN
- struct DWstruct {Wtype high, low;};
-#else
- struct DWstruct {Wtype 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 DWstruct s;
- DWtype ll;
-} DWunion;
-
-#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 */
-
+#include "libgcc2.h"
\f
#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
#if defined (L_divdi3) || defined (L_moddi3)
if (bm <= 0)
{
w.s.high = 0;
- w.s.low = (UWtype)uu.s.high >> -bm;
+ w.s.low = (UWtype) uu.s.high >> -bm;
}
else
{
- UWtype carries = (UWtype)uu.s.high << bm;
- w.s.high = (UWtype)uu.s.high >> b;
- w.s.low = ((UWtype)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;
if (bm <= 0)
{
w.s.low = 0;
- w.s.high = (UWtype)uu.s.low << -bm;
+ w.s.high = (UWtype) uu.s.low << -bm;
}
else
{
- UWtype carries = (UWtype)uu.s.low >> bm;
- w.s.low = (UWtype)uu.s.low << b;
- w.s.high = ((UWtype)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;
}
else
{
- UWtype carries = (UWtype)uu.s.high << bm;
+ UWtype carries = (UWtype) uu.s.high << bm;
+
w.s.high = uu.s.high >> b;
- w.s.low = ((UWtype)uu.s.low >> b) | carries;
+ w.s.low = ((UWtype) uu.s.low >> b) | carries;
}
return w.ll;
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
-__fixunstfdi (TFtype a)
+__fixunstfDI (TFtype a)
{
TFtype b;
UDWtype v;
#endif
#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
-extern DWtype __fixunstfdi (TFtype a);
-
DWtype
__fixtfdi (TFtype a)
{
if (a < 0)
- return - __fixunstfdi (-a);
- return __fixunstfdi (a);
+ return - __fixunstfDI (-a);
+ return __fixunstfDI (a);
}
#endif
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
-__fixunsxfdi (XFtype a)
+__fixunsxfDI (XFtype a)
{
XFtype b;
UDWtype v;
#endif
#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
-extern DWtype __fixunsxfdi (XFtype a);
-
DWtype
__fixxfdi (XFtype a)
{
if (a < 0)
- return - __fixunsxfdi (-a);
- return __fixunsxfdi (a);
+ return - __fixunsxfDI (-a);
+ return __fixunsxfDI (a);
}
#endif
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
-__fixunsdfdi (DFtype a)
+__fixunsdfDI (DFtype a)
{
DFtype b;
UDWtype v;
#endif
#ifdef L_fixdfdi
-extern DWtype __fixunsdfdi (DFtype a);
-
DWtype
__fixdfdi (DFtype a)
{
if (a < 0)
- return - __fixunsdfdi (-a);
- return __fixunsdfdi (a);
+ return - __fixunsdfDI (-a);
+ return __fixunsdfDI (a);
}
#endif
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
DWtype
-__fixunssfdi (SFtype original_a)
+__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
v = (UWtype) b;
v <<= WORD_SIZE;
/* Remove high part from the DFtype, leaving the low part as flonum. */
- a -= (DFtype)v;
+ 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. */
#endif
#ifdef L_fixsfdi
-extern DWtype __fixunssfdi (SFtype a);
-
DWtype
__fixsfdi (SFtype a)
{
if (a < 0)
- return - __fixunssfdi (-a);
- return __fixunssfdi (a);
+ return - __fixunssfDI (-a);
+ return __fixunssfDI (a);
}
#endif
if (DF_SIZE < DI_SIZE
&& DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
{
-#define REP_BIT ((UWtype) 1 << (DI_SIZE - DF_SIZE))
+#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
if (! (- ((DWtype) 1 << DF_SIZE) < u
&& u < ((DWtype) 1 << DF_SIZE)))
{
- if ((UWtype) u & (REP_BIT - 1))
+ if ((UDWtype) u & (REP_BIT - 1))
u |= REP_BIT;
}
}
#include <limits.h>
UWtype
-__fixunsxfsi (XFtype a)
+__fixunsxfSI (XFtype a)
{
if (a >= - (DFtype) LONG_MIN)
return (Wtype) (a + LONG_MIN) - LONG_MIN;
#include <limits.h>
UWtype
-__fixunsdfsi (DFtype a)
+__fixunsdfSI (DFtype a)
{
if (a >= - (DFtype) LONG_MIN)
return (Wtype) (a + LONG_MIN) - LONG_MIN;
#include <limits.h>
UWtype
-__fixunssfsi (SFtype a)
+__fixunssfSI (SFtype a)
{
if (a >= - (SFtype) LONG_MIN)
return (Wtype) (a + LONG_MIN) - LONG_MIN;
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)
{
asm (" .end __builtin_saveregs");
#else /* not __mips__, etc. */
-void *
+void * __attribute__ ((__noreturn__))
__builtin_saveregs (void)
{
abort ();
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
#include <stdio.h>
/* This is used by the `assert' macro. */
-extern void __eprintf (const char *, const char *, unsigned int, const char *)
- __attribute__ ((__noreturn__));
-
void
__eprintf (const char *string, const char *expression,
unsigned int line, const char *filename)
/* Shared exception handling support routines. */
-extern void __default_terminate (void) __attribute__ ((__noreturn__));
-
void
__default_terminate (void)
{
/* Allocate and return a new EH context structure. */
-extern void __throw (void);
-
#if __GTHREADS
static void *
new_eh_context (void)
return eh;
}
-#endif __GTHREADS
+#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. */
dynamic handler chain, and use longjmp to transfer back to the associated
handler. */
-extern void __sjthrow (void) __attribute__ ((__noreturn__));
-
void
__sjthrow (void)
{
then throw. This is used to skip the first handler, and transfer
control to the next handler in the dynamic handler stack. */
-extern void __sjpopnthrow (void) __attribute__ ((__noreturn__));
-
void
__sjpopnthrow (void)
{
}
#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
#ifdef L_pure
#define MESSAGE "pure virtual method called\n"
-extern void __terminate (void) __attribute__ ((__noreturn__));
-
void
__pure_virtual (void)
{