OSDN Git Service

* POTFILES.in: Remove dyn-string.[ch].
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index 368b5c6..305d7f0 100644 (file)
@@ -10,6 +10,15 @@ it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
 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
@@ -20,13 +29,6 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* As a special exception, if you link this library with other files,
-   some of which are compiled with GCC, to produce an executable,
-   this library does not by itself cause the resulting executable
-   to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
-
 /* 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.  */
@@ -42,189 +44,7 @@ Boston, MA 02111-1307, USA.  */
 #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)
@@ -264,13 +84,14 @@ __lshrdi3 (DWtype u, word_type b)
   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;
@@ -294,13 +115,14 @@ __ashldi3 (DWtype u, word_type b)
   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;
@@ -329,9 +151,10 @@ __ashrdi3 (DWtype u, word_type b)
     }
   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;
@@ -843,7 +666,7 @@ __ucmpdi2 (DWtype a, DWtype b)
 #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
 DWtype
-__fixunstfdi (TFtype a)
+__fixunstfDI (TFtype a)
 {
   TFtype b;
   UDWtype v;
@@ -871,14 +694,12 @@ __fixunstfdi (TFtype a)
 #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
 
@@ -887,7 +708,7 @@ __fixtfdi (TFtype a)
 #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
 DWtype
-__fixunsxfdi (XFtype a)
+__fixunsxfDI (XFtype a)
 {
   XFtype b;
   UDWtype v;
@@ -915,14 +736,12 @@ __fixunsxfdi (XFtype a)
 #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
 
@@ -931,7 +750,7 @@ __fixxfdi (XFtype a)
 #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
 DWtype
-__fixunsdfdi (DFtype a)
+__fixunsdfDI (DFtype a)
 {
   DFtype b;
   UDWtype v;
@@ -959,14 +778,12 @@ __fixunsdfdi (DFtype a)
 #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
 
@@ -975,7 +792,7 @@ __fixdfdi (DFtype a)
 #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
@@ -994,7 +811,7 @@ __fixunssfdi (SFtype original_a)
   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.  */
@@ -1007,14 +824,12 @@ __fixunssfdi (SFtype original_a)
 #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
 
@@ -1126,11 +941,11 @@ __floatdisf (DWtype u)
   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;
        }
     }
@@ -1157,7 +972,7 @@ __floatdisf (DWtype u)
 #include <limits.h>
 
 UWtype
-__fixunsxfsi (XFtype a)
+__fixunsxfSI (XFtype a)
 {
   if (a >= - (DFtype) LONG_MIN)
     return (Wtype) (a + LONG_MIN) - LONG_MIN;
@@ -1179,7 +994,7 @@ __fixunsxfsi (XFtype a)
 #include <limits.h>
 
 UWtype
-__fixunsdfsi (DFtype a)
+__fixunsdfSI (DFtype a)
 {
   if (a >= - (DFtype) LONG_MIN)
     return (Wtype) (a + LONG_MIN) - LONG_MIN;
@@ -1201,7 +1016,7 @@ __fixunsdfsi (DFtype a)
 #include <limits.h>
 
 UWtype
-__fixunssfsi (SFtype a)
+__fixunssfSI (SFtype a)
 {
   if (a >= - (SFtype) LONG_MIN)
     return (Wtype) (a + LONG_MIN) - LONG_MIN;
@@ -1239,7 +1054,7 @@ __fixunssfsi (SFtype a)
    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)
     {
@@ -1470,7 +1285,7 @@ asm ("___builtin_saveregs:");
   asm ("       .end __builtin_saveregs");
 #else /* not __mips__, etc.  */
 
-void *
+void * __attribute__ ((__noreturn__))
 __builtin_saveregs (void)
 {
   abort ();
@@ -1487,9 +1302,6 @@ __builtin_saveregs (void)
 #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)
@@ -3166,8 +2978,6 @@ atexit (func_ptr func)
 
 /* Shared exception handling support routines.  */
 
-extern void __default_terminate (void) __attribute__ ((__noreturn__));
-
 void
 __default_terminate (void)
 {
@@ -3210,8 +3020,6 @@ __empty (void)
 
 /* Allocate and return a new EH context structure. */
 
-extern void __throw (void);
-
 #if __GTHREADS
 static void *
 new_eh_context (void)
@@ -3380,7 +3188,76 @@ eh_context_specific (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.  */
 
@@ -3410,8 +3287,6 @@ __get_dynamic_handler_chain (void)
    dynamic handler chain, and use longjmp to transfer back to the associated
    handler.  */
 
-extern void __sjthrow (void) __attribute__ ((__noreturn__));
-
 void
 __sjthrow (void)
 {
@@ -3485,8 +3360,6 @@ __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)
 {
@@ -4136,6 +4009,173 @@ label:
 }
 #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
@@ -4153,8 +4193,6 @@ label:
 
 #define MESSAGE "pure virtual method called\n"
 
-extern void __terminate (void) __attribute__ ((__noreturn__));
-
 void
 __pure_virtual (void)
 {