X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Flibgcc2.c;h=13da298fd268f3d85d12d68d4c5c43de01711d9b;hb=b0d8e49cb34af0a14e5e21c23a7933d482c5d3ec;hp=29195119e733be0ad9118b865f480fdbbbef77e3;hpb=369e527ef8e45f3da9946149e802d331f6f36f17;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 29195119e73..13da298fd26 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -1,183 +1,266 @@ /* 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. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* As a special exception, if you link this library with other files, - some of which are compiled with GCC, to produce an executable, - this library does not by itself cause the resulting executable - to be covered by the GNU General Public License. - This exception does not however invalidate any other reasons why - the executable file might be covered by the GNU General Public License. */ +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ /* It is incorrect to include config.h here, because this file is being compiled for the target, and hence definitions concerning only the host do not apply. */ #include "tconfig.h" +#include "tsystem.h" + +#include "symcat.h" #include "machmode.h" -#include "defaults.h" -#ifndef L_trampoline -#include -#endif /* Don't use `fancy_abort' here even if config.h says to use it. */ #ifdef abort #undef abort #endif -#if (SUPPORTS_WEAK == 1) && (defined (ASM_OUTPUT_DEF) || defined (ASM_OUTPUT_WEAK_ALIAS)) -#define WEAK_ALIAS +#include "libgcc2.h" + +#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3) +#if defined (L_divdi3) || defined (L_moddi3) +static inline #endif +DWtype +__negdi2 (DWtype u) +{ + DWunion w; + DWunion uu; + + uu.ll = u; -/* Permit the tm.h file to select the endianness to use just for this - file. This is used when the endianness is determined when the - compiler is run. */ + w.s.low = -uu.s.low; + w.s.high = -uu.s.high - ((UWtype) w.s.low > 0); -#ifndef LIBGCC2_WORDS_BIG_ENDIAN -#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN + return w.ll; +} #endif -/* In the first part of this file, we are interfacing to calls generated - by the compiler itself. These calls pass values into these routines - which have very specific modes (rather than very specific types), and - these compiler-generated calls also expect any return values to have - very specific modes (rather than very specific types). Thus, we need - to avoid using regular C language type names in this part of the file - because the sizes for those types can be configured to be anything. - Instead we use the following special type names. */ +#ifdef L_addvsi3 +Wtype +__addvsi3 (Wtype a, Wtype b) +{ + Wtype w; -typedef unsigned int UQItype __attribute__ ((mode (QI))); -typedef int SItype __attribute__ ((mode (SI))); -typedef unsigned int USItype __attribute__ ((mode (SI))); -typedef int DItype __attribute__ ((mode (DI))); -typedef unsigned int UDItype __attribute__ ((mode (DI))); + w = a + b; -typedef float SFtype __attribute__ ((mode (SF))); -typedef float DFtype __attribute__ ((mode (DF))); + if (b >= 0 ? w < a : w > a) + abort (); -#if LONG_DOUBLE_TYPE_SIZE == 96 -typedef float XFtype __attribute__ ((mode (XF))); -#endif -#if LONG_DOUBLE_TYPE_SIZE == 128 -typedef float TFtype __attribute__ ((mode (TF))); + return w; +} #endif + +#ifdef L_addvdi3 +DWtype +__addvdi3 (DWtype a, DWtype b) +{ + DWtype w; -typedef int word_type __attribute__ ((mode (__word__))); + w = a + b; -/* Make sure that we don't accidentally use any normal C language built-in - type names in the first part of this file. Instead we want to use *only* - the type names defined above. The following macro definitions insure - that if we *do* accidentally use some normal C language built-in type name, - we will get a syntax error. */ + if (b >= 0 ? w < a : w > a) + abort (); -#define char bogus_type -#define short bogus_type -#define int bogus_type -#define long bogus_type -#define unsigned bogus_type -#define float bogus_type -#define double bogus_type + return w; +} +#endif + +#ifdef L_subvsi3 +Wtype +__subvsi3 (Wtype a, Wtype b) +{ +#ifdef L_addvsi3 + return __addvsi3 (a, (-b)); +#else + DWtype w; -#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) + w = a - b; -/* DIstructs are pairs of SItype values in the order determined by - LIBGCC2_WORDS_BIG_ENDIAN. */ + if (b >= 0 ? w > a : w < a) + abort (); -#if LIBGCC2_WORDS_BIG_ENDIAN - struct DIstruct {SItype high, low;}; + return w; +#endif +} +#endif + +#ifdef L_subvdi3 +DWtype +__subvdi3 (DWtype a, DWtype b) +{ +#ifdef L_addvdi3 + return (a, (-b)); #else - struct DIstruct {SItype low, high;}; + DWtype w; + + w = a - b; + + if (b >= 0 ? w > a : w < a) + abort (); + + return w; +#endif +} +#endif + +#ifdef L_mulvsi3 +Wtype +__mulvsi3 (Wtype a, Wtype b) +{ + DWtype w; + + w = a * b; + + if (((a >= 0) == (b >= 0)) ? w < 0 : w > 0) + abort (); + + return w; +} #endif + +#ifdef L_negvsi2 +Wtype +__negvsi2 (Wtype a) +{ + Wtype w; -/* We need this union to unpack/pack DImode values, since we don't have - any arithmetic yet. Incoming DImode parameters are stored into the - `ll' field, and the unpacked result is read from the struct `s'. */ + w = -a; -typedef union + if (a >= 0 ? w > 0 : w < 0) + abort (); + + return w; +} +#endif + +#ifdef L_negvdi2 +DWtype +__negvdi2 (DWtype a) { - struct DIstruct s; - DItype ll; -} DIunion; + DWtype w; -#if (defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)\ - || defined (L_divdi3) || defined (L_udivdi3) \ - || defined (L_moddi3) || defined (L_umoddi3)) + w = -a; -#include "longlong.h" + if (a >= 0 ? w > 0 : w < 0) + abort (); + + return w; +} +#endif + +#ifdef L_absvsi2 +Wtype +__absvsi2 (Wtype a) +{ + Wtype w = a; -#endif /* udiv or mul */ + if (a < 0) +#ifdef L_negvsi2 + w = __negvsi2 (a); +#else + w = -a; -extern DItype __fixunssfdi (SFtype a); -extern DItype __fixunsdfdi (DFtype a); -#if LONG_DOUBLE_TYPE_SIZE == 96 -extern DItype __fixunsxfdi (XFtype a); + if (w < 0) + abort (); #endif -#if LONG_DOUBLE_TYPE_SIZE == 128 -extern DItype __fixunstfdi (TFtype a); + + return w; +} #endif -#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3) -#if defined (L_divdi3) || defined (L_moddi3) -static inline +#ifdef L_absvdi2 +DWtype +__absvdi2 (DWtype a) +{ + DWtype w = a; + + if (a < 0) +#ifdef L_negvsi2 + w = __negvsi2 (a); +#else + w = -a; + + if (w < 0) + abort (); #endif -DItype -__negdi2 (DItype u) + + return w; +} +#endif + +#ifdef L_mulvdi3 +DWtype +__mulvdi3 (DWtype u, DWtype v) { - DIunion w; - DIunion uu; + DWtype w; - uu.ll = u; + w = u * v; - w.s.low = -uu.s.low; - w.s.high = -uu.s.high - ((USItype) w.s.low > 0); + if (((u >= 0) == (v >= 0)) ? w < 0 : w > 0) + abort (); - return w.ll; + return w; } #endif + /* 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; @@ -185,29 +268,30 @@ __lshrdi3 (DItype u, word_type b) #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; @@ -215,30 +299,31 @@ __ashldi3 (DItype u, word_type b) #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; @@ -246,38 +331,38 @@ __ashrdi3 (DItype u, word_type b) #endif #ifdef L_ffsdi2 -DItype -__ffsdi2 (DItype u) +DWtype +__ffsdi2 (DWtype u) { - DIunion uu, w; + DWunion uu; + UWtype word, count, add; + uu.ll = u; - w.s.high = 0; - w.s.low = ffs (uu.s.low); - if (w.s.low != 0) - return w.ll; - w.s.low = ffs (uu.s.high); - if (w.s.low != 0) - { - w.s.low += BITS_PER_UNIT * sizeof (SItype); - return w.ll; - } - return w.ll; + if (uu.s.low != 0) + word = uu.s.low, add = 0; + else if (uu.s.high != 0) + word = uu.s.high, add = BITS_PER_UNIT * sizeof (Wtype); + else + return 0; + + count_trailing_zeros (count, word); + return count + add + 1; } #endif #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; } @@ -285,15 +370,15 @@ __muldi3 (DItype u, DItype v) #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); @@ -301,18 +386,18 @@ __udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype 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 */ { @@ -383,9 +468,14 @@ __udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d) } #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 @@ -394,8 +484,8 @@ __udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d) #define L_udivmoddi4 #endif -#ifdef L_udivmoddi4 -static const UQItype __clz_tab[] = +#ifdef L_clz +const UQItype __clz_tab[] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, @@ -406,20 +496,23 @@ static const UQItype __clz_tab[] = 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, }; +#endif + +#ifdef L_udivmoddi4 #if (defined (L_udivdi3) || defined (L_divdi3) || \ defined (L_umoddi3) || defined (L_moddi3)) static inline #endif -UDItype -__udivmoddi4 (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; @@ -478,7 +571,7 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) denominator set. */ d0 = d0 << bm; - n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); n0 = n0 << bm; } @@ -503,7 +596,7 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) 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; @@ -512,7 +605,7 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) { /* Normalize. */ - b = SI_TYPE_SIZE - bm; + b = W_TYPE_SIZE - bm; d0 = d0 << bm; n2 = n1 >> b; @@ -589,10 +682,10 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) } 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; @@ -630,14 +723,12 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp) #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; @@ -649,7 +740,7 @@ __divdi3 (DItype u, DItype 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); @@ -658,13 +749,12 @@ __divdi3 (DItype u, DItype v) #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; @@ -684,11 +774,10 @@ __moddi3 (DItype u, DItype 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); @@ -697,19 +786,18 @@ __umoddi3 (UDItype u, UDItype v) #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 #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; @@ -717,9 +805,9 @@ __cmpdi2 (DItype a, DItype 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; } @@ -727,310 +815,269 @@ __cmpdi2 (DItype a, DItype b) #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 -#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 codes for all the float formats that we know of. Note - that this is copied from real.h. */ - -#define UNKNOWN_FLOAT_FORMAT 0 -#define IEEE_FLOAT_FORMAT 1 -#define VAX_FLOAT_FORMAT 2 -#define IBM_FLOAT_FORMAT 3 - -/* Default to IEEE float if not specified. Nearly all machines use it. */ -#ifndef HOST_FLOAT_FORMAT -#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT -#endif - -#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT -#define DF_SIZE 53 -#define SF_SIZE 24 -#endif - -#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT -#define DF_SIZE 56 -#define SF_SIZE 24 -#endif - -#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT -#define DF_SIZE 56 -#define SF_SIZE 24 -#endif +#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT) +#define DF_SIZE DBL_MANT_DIG +#define SF_SIZE FLT_MANT_DIG SFtype -__floatdisf (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, @@ -1041,23 +1088,24 @@ __floatdisf (DItype u) 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 @@ -1070,12 +1118,12 @@ __floatdisf (DItype u) #undef MAX #include -USItype -__fixunsxfsi (XFtype a) +UWtype +__fixunsxfSI (XFtype a) { - if (a >= - (DFtype) LONG_MIN) - return (SItype) (a + LONG_MIN) - LONG_MIN; - return (SItype) a; + if (a >= - (DFtype) Wtype_MIN) + return (Wtype) (a + Wtype_MIN) - Wtype_MIN; + return (Wtype) a; } #endif @@ -1092,12 +1140,12 @@ __fixunsxfsi (XFtype a) #undef MAX #include -USItype -__fixunsdfsi (DFtype a) +UWtype +__fixunsdfSI (DFtype a) { - if (a >= - (DFtype) LONG_MIN) - return (SItype) (a + LONG_MIN) - LONG_MIN; - return (SItype) a; + if (a >= - (DFtype) Wtype_MIN) + return (Wtype) (a + Wtype_MIN) - Wtype_MIN; + return (Wtype) a; } #endif @@ -1114,12 +1162,12 @@ __fixunsdfsi (DFtype a) #undef MAX #include -USItype -__fixunssfsi (SFtype a) +UWtype +__fixunssfSI (SFtype a) { - if (a >= - (SFtype) LONG_MIN) - return (SItype) (a + LONG_MIN) - LONG_MIN; - return (SItype) a; + if (a >= - (SFtype) Wtype_MIN) + return (Wtype) (a + Wtype_MIN) - Wtype_MIN; + return (Wtype) a; } #endif @@ -1131,6 +1179,12 @@ __fixunssfsi (SFtype a) #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 @@ -1147,7 +1201,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) { @@ -1160,241 +1214,20 @@ __gcc_bcmp (unsigned char *s1, unsigned char *s2, size_t size) } #endif - -#ifdef L__dummy -void -__dummy () {} -#endif - -#ifdef L_varargs -#ifdef __i860__ -#if defined(__svr4__) || defined(__alliant__) - asm (" .text"); - asm (" .align 4"); - -/* The Alliant needs the added underscore. */ - asm (".globl __builtin_saveregs"); -asm ("__builtin_saveregs:"); - asm (".globl ___builtin_saveregs"); -asm ("___builtin_saveregs:"); - - asm (" andnot 0x0f,%sp,%sp"); /* round down to 16-byte boundary */ - asm (" adds -96,%sp,%sp"); /* allocate stack space for reg save - area and also for a new va_list - structure */ - /* Save all argument registers in the arg reg save area. The - arg reg save area must have the following layout (according - to the svr4 ABI): - - struct { - union { - float freg[8]; - double dreg[4]; - } float_regs; - long ireg[12]; - }; - */ - - asm (" fst.q %f8, 0(%sp)"); /* save floating regs (f8-f15) */ - asm (" fst.q %f12,16(%sp)"); - - asm (" st.l %r16,32(%sp)"); /* save integer regs (r16-r27) */ - asm (" st.l %r17,36(%sp)"); - asm (" st.l %r18,40(%sp)"); - asm (" st.l %r19,44(%sp)"); - asm (" st.l %r20,48(%sp)"); - asm (" st.l %r21,52(%sp)"); - asm (" st.l %r22,56(%sp)"); - asm (" st.l %r23,60(%sp)"); - asm (" st.l %r24,64(%sp)"); - asm (" st.l %r25,68(%sp)"); - asm (" st.l %r26,72(%sp)"); - asm (" st.l %r27,76(%sp)"); - - asm (" adds 80,%sp,%r16"); /* compute the address of the new - va_list structure. Put in into - r16 so that it will be returned - to the caller. */ - - /* Initialize all fields of the new va_list structure. This - structure looks like: - - typedef struct { - unsigned long ireg_used; - unsigned long freg_used; - long *reg_base; - long *mem_ptr; - } va_list; - */ - - asm (" st.l %r0, 0(%r16)"); /* nfixed */ - asm (" st.l %r0, 4(%r16)"); /* nfloating */ - asm (" st.l %sp, 8(%r16)"); /* __va_ctl points to __va_struct. */ - asm (" bri %r1"); /* delayed return */ - asm (" st.l %r28,12(%r16)"); /* pointer to overflow args */ - -#else /* not __svr4__ */ -#if defined(__PARAGON__) - /* - * we'll use SVR4-ish varargs but need SVR3.2 assembler syntax, - * and we stand a better chance of hooking into libraries - * compiled by PGI. [andyp@ssd.intel.com] - */ - asm (" .text"); - asm (" .align 4"); - asm (".globl __builtin_saveregs"); -asm ("__builtin_saveregs:"); - asm (".globl ___builtin_saveregs"); -asm ("___builtin_saveregs:"); - - asm (" andnot 0x0f,sp,sp"); /* round down to 16-byte boundary */ - asm (" adds -96,sp,sp"); /* allocate stack space for reg save - area and also for a new va_list - structure */ - /* Save all argument registers in the arg reg save area. The - arg reg save area must have the following layout (according - to the svr4 ABI): - - struct { - union { - float freg[8]; - double dreg[4]; - } float_regs; - long ireg[12]; - }; - */ - - asm (" fst.q f8, 0(sp)"); - asm (" fst.q f12,16(sp)"); - asm (" st.l r16,32(sp)"); - asm (" st.l r17,36(sp)"); - asm (" st.l r18,40(sp)"); - asm (" st.l r19,44(sp)"); - asm (" st.l r20,48(sp)"); - asm (" st.l r21,52(sp)"); - asm (" st.l r22,56(sp)"); - asm (" st.l r23,60(sp)"); - asm (" st.l r24,64(sp)"); - asm (" st.l r25,68(sp)"); - asm (" st.l r26,72(sp)"); - asm (" st.l r27,76(sp)"); - - asm (" adds 80,sp,r16"); /* compute the address of the new - va_list structure. Put in into - r16 so that it will be returned - to the caller. */ - - /* Initialize all fields of the new va_list structure. This - structure looks like: - - typedef struct { - unsigned long ireg_used; - unsigned long freg_used; - long *reg_base; - long *mem_ptr; - } va_list; - */ - - asm (" st.l r0, 0(r16)"); /* nfixed */ - asm (" st.l r0, 4(r16)"); /* nfloating */ - asm (" st.l sp, 8(r16)"); /* __va_ctl points to __va_struct. */ - asm (" bri r1"); /* delayed return */ - asm (" st.l r28,12(r16)"); /* pointer to overflow args */ -#else /* not __PARAGON__ */ - asm (" .text"); - asm (" .align 4"); - - asm (".globl ___builtin_saveregs"); - asm ("___builtin_saveregs:"); - asm (" mov sp,r30"); - asm (" andnot 0x0f,sp,sp"); - asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */ - -/* Fill in the __va_struct. */ - asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */ - asm (" st.l r17, 4(sp)"); /* int fixed[12] */ - asm (" st.l r18, 8(sp)"); - asm (" st.l r19,12(sp)"); - asm (" st.l r20,16(sp)"); - asm (" st.l r21,20(sp)"); - asm (" st.l r22,24(sp)"); - asm (" st.l r23,28(sp)"); - asm (" st.l r24,32(sp)"); - asm (" st.l r25,36(sp)"); - asm (" st.l r26,40(sp)"); - asm (" st.l r27,44(sp)"); - - asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */ - asm (" fst.q f12,64(sp)"); /* int floating[8] */ - -/* Fill in the __va_ctl. */ - asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */ - asm (" st.l r28,84(sp)"); /* pointer to more args */ - asm (" st.l r0, 88(sp)"); /* nfixed */ - asm (" st.l r0, 92(sp)"); /* nfloating */ - - asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */ - asm (" bri r1"); - asm (" mov r30,sp"); - /* recover stack and pass address to start - of data. */ -#endif /* not __PARAGON__ */ -#endif /* not __svr4__ */ -#else /* not __i860__ */ -#ifdef __sparc__ - asm (".global __builtin_saveregs"); - asm ("__builtin_saveregs:"); - asm (".global ___builtin_saveregs"); - asm ("___builtin_saveregs:"); -#ifdef NEED_PROC_COMMAND - asm (".proc 020"); -#endif - asm ("st %i0,[%fp+68]"); - asm ("st %i1,[%fp+72]"); - asm ("st %i2,[%fp+76]"); - asm ("st %i3,[%fp+80]"); - asm ("st %i4,[%fp+84]"); - asm ("retl"); - asm ("st %i5,[%fp+88]"); -#ifdef NEED_TYPE_COMMAND - asm (".type __builtin_saveregs,#function"); - asm (".size __builtin_saveregs,.-__builtin_saveregs"); -#endif -#else /* not __sparc__ */ -#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__) - - asm (" .text"); - asm (" .ent __builtin_saveregs"); - asm (" .globl __builtin_saveregs"); - asm ("__builtin_saveregs:"); - asm (" sw $4,0($30)"); - asm (" sw $5,4($30)"); - asm (" sw $6,8($30)"); - asm (" sw $7,12($30)"); - asm (" j $31"); - asm (" .end __builtin_saveregs"); -#else /* not __mips__, etc. */ - -void * -__builtin_saveregs () -{ - abort (); -} - -#endif /* not __mips__ */ -#endif /* not __sparc__ */ -#endif /* not __i860__ */ -#endif +/* __eprintf used to be used by GCC's private version of . + We no longer provide that header, but this routine remains in libgcc.a + for binary backward compatibility. Note that it is not included in + the shared version of libgcc. */ #ifdef L_eprintf #ifndef inhibit_libc #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ #include -/* 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); @@ -1406,27 +1239,26 @@ __eprintf (const char *string, const char *expression, #ifdef L_bb +struct bb_function_info { + long checksum; + int arc_count; + const char *name; +}; + /* Structure emitted by -a */ struct bb { long zero_word; const char *filename; - long *counts; + gcov_type *counts; long ncounts; struct bb *next; - const unsigned long *addresses; /* Older GCC's did not emit these fields. */ - long nwords; - const char **functions; - const long *line_nums; - const char **filenames; - char *flags; + long sizeof_bb; + struct bb_function_info *function_infos; }; -#ifdef BLOCK_PROFILER_CODE -BLOCK_PROFILER_CODE -#else #ifndef inhibit_libc /* Simple minded basic block profiling output dumper for @@ -1435,256 +1267,189 @@ BLOCK_PROFILER_CODE #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ #include -char *ctime (); #include "gbl-ctors.h" #include "gcov-io.h" +#include +#ifdef TARGET_HAS_F_SETLKW +#include +#include +#endif -static struct bb *bb_head; - -/* Return the number of digits needed to print a value */ -/* __inline__ */ static int num_digits (long value, int base) -{ - int minus = (value < 0 && base != 16); - unsigned long v = (minus) ? -value : value; - int ret = minus; +#include - do - { - v /= base; - ret++; - } - while (v); +static struct bb *bb_head; - return ret; -} +int __global_counters = 0, __gthreads_active = 0; void __bb_exit_func (void) { - FILE *da_file, *file; - long time_value; - int i; + FILE *da_file; + struct bb *ptr; + long n_counters_p = 0; + gcov_type max_counter_p = 0; + gcov_type sum_counters_p = 0; if (bb_head == 0) return; - i = strlen (bb_head->filename) - 3; + /* Calculate overall "statistics". */ - if (!strcmp (bb_head->filename+i, ".da")) + for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) { - /* Must be -fprofile-arcs not -a. - Dump data in a form that gcov expects. */ + int i; - struct bb *ptr; + n_counters_p += ptr->ncounts; - for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) + for (i = 0; i < ptr->ncounts; i++) { - /* If the file exists, and the number of counts in it is the same, - then merge them in. */ - - if ((da_file = fopen (ptr->filename, "r")) != 0) - { - long n_counts = 0; - unsigned char tmp; - int i; - int ret = 0; - - - if (__read_long (&n_counts, da_file, 8) != 0) - { - fprintf (stderr, "arc profiling: Can't read output file %s.\n", - ptr->filename); - continue; - } - - if (n_counts == ptr->ncounts) - { - int i; - - for (i = 0; i < n_counts; i++) - { - long v = 0; - unsigned char tmp; - int j; - int ret = 0; - - if (__read_long (&v, da_file, 8) != 0) - { - fprintf (stderr, "arc profiling: Can't read output file %s.\n", - ptr->filename); - break; - } - ptr->counts[i] += v; - } - } - - if (fclose (da_file) == EOF) - fprintf (stderr, "arc profiling: Error closing output file %s.\n", - ptr->filename); - } - if ((da_file = fopen (ptr->filename, "w")) < 0) - { - fprintf (stderr, "arc profiling: Can't open output file %s.\n", - ptr->filename); - continue; - } - - /* ??? Should first write a header to the file. Perferably, a 4 byte - magic number, 4 bytes containing the time the program was - compiled, 4 bytes containing the last modification time of the - source file, and 4 bytes indicating the compiler options used. - - That way we can easily verify that the proper source/executable/ - data file combination is being used from gcov. */ + sum_counters_p += ptr->counts[i]; - if (__write_long (ptr->ncounts, da_file, 8) != 0) - { - - fprintf (stderr, "arc profiling: Error writing output file %s.\n", - ptr->filename); - } - else - { - int j; - long *count_ptr = ptr->counts; - int ret = 0; - for (j = ptr->ncounts; j > 0; j--) - { - if (__write_long (*count_ptr, da_file, 8) != 0) - { - ret=1; - break; - } - count_ptr++; - } - if (ret) - fprintf (stderr, "arc profiling: Error writing output file %s.\n", - ptr->filename); - } - - if (fclose (da_file) == EOF) - fprintf (stderr, "arc profiling: Error closing output file %s.\n", - ptr->filename); + if (ptr->counts[i] > max_counter_p) + max_counter_p = ptr->counts[i]; } - - return; } - /* Must be basic block profiling. Emit a human readable output file. */ - - file = fopen ("bb.out", "a"); - - if (!file) - perror ("bb.out"); - - else + for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) { - struct bb *ptr; + gcov_type max_counter_o = 0; + gcov_type sum_counters_o = 0; + int i; - /* This is somewhat type incorrect, but it avoids worrying about - exactly where time.h is included from. It should be ok unless - a void * differs from other pointer formats, or if sizeof (long) - is < sizeof (time_t). It would be nice if we could assume the - use of rationale standards here. */ + /* Calculate the per-object statistics. */ - time ((void *) &time_value); - fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value)); + for (i = 0; i < ptr->ncounts; i++) + { + sum_counters_o += ptr->counts[i]; - /* We check the length field explicitly in order to allow compatibility - with older GCC's which did not provide it. */ + if (ptr->counts[i] > max_counter_o) + max_counter_o = ptr->counts[i]; + } - for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) + /* open the file for appending, creating it if necessary. */ + da_file = fopen (ptr->filename, "ab"); + /* Some old systems might not allow the 'b' mode modifier. + Therefore, try to open without it. This can lead to a race + condition so that when you delete and re-create the file, the + file might be opened in text mode, but then, you shouldn't + delete the file in the first place. */ + if (da_file == 0) + da_file = fopen (ptr->filename, "a"); + if (da_file == 0) { - int i; - int func_p = (ptr->nwords >= sizeof (struct bb) - && ptr->nwords <= 1000 - && ptr->functions); - int line_p = (func_p && ptr->line_nums); - int file_p = (func_p && ptr->filenames); - int addr_p = (ptr->addresses != 0); - long ncounts = ptr->ncounts; - long cnt_max = 0; - long line_max = 0; - long addr_max = 0; - int file_len = 0; - int func_len = 0; - int blk_len = num_digits (ncounts, 10); - int cnt_len; - int line_len; - int addr_len; - - fprintf (file, "File %s, %ld basic blocks \n\n", - ptr->filename, ncounts); - - /* Get max values for each field. */ - for (i = 0; i < ncounts; i++) - { - const char *p; - int len; - - if (cnt_max < ptr->counts[i]) - cnt_max = ptr->counts[i]; + fprintf (stderr, "arc profiling: Can't open output file %s.\n", + ptr->filename); + continue; + } - if (addr_p && addr_max < ptr->addresses[i]) - addr_max = ptr->addresses[i]; + /* After a fork, another process might try to read and/or write + the same file simultanously. So if we can, lock the file to + avoid race conditions. */ +#if defined (TARGET_HAS_F_SETLKW) + { + struct flock s_flock; + + s_flock.l_type = F_WRLCK; + s_flock.l_whence = SEEK_SET; + s_flock.l_start = 0; + s_flock.l_len = 1; + s_flock.l_pid = getpid (); + + while (fcntl (fileno (da_file), F_SETLKW, &s_flock) + && errno == EINTR); + } +#endif - if (line_p && line_max < ptr->line_nums[i]) - line_max = ptr->line_nums[i]; + if (__write_long (-123, da_file, 4) != 0) /* magic */ + { + fprintf (stderr, "arc profiling: Error writing output file %s.\n", + ptr->filename); + } + else + { - if (func_p) + struct bb_function_info *fn_info; + gcov_type *count_ptr = ptr->counts; + int i; + int count_functions = 0; + + for (fn_info = ptr->function_infos; fn_info->arc_count != -1; + fn_info++) + count_functions++; + + /* number of functions in this block. */ + __write_long (count_functions, da_file, 4); + + /* length of extra data in bytes. */ + __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4); + + /* overall statistics. */ + /* number of counters. */ + __write_long (n_counters_p, da_file, 4); + /* sum of counters. */ + __write_gcov_type (sum_counters_p, da_file, 8); + /* maximal counter. */ + __write_gcov_type (max_counter_p, da_file, 8); + + /* per-object statistics. */ + /* number of counters. */ + __write_long (ptr->ncounts, da_file, 4); + /* sum of counters. */ + __write_gcov_type (sum_counters_o, da_file, 8); + /* maximal counter. */ + __write_gcov_type (max_counter_o, da_file, 8); + + /* write execution counts for each function. */ + + for (fn_info = ptr->function_infos; fn_info->arc_count != -1; + fn_info++) + { + /* new function. */ + if (__write_gcov_string + (fn_info->name, strlen (fn_info->name), da_file, -1) != 0) { - p = (ptr->functions[i]) ? (ptr->functions[i]) : ""; - len = strlen (p); - if (func_len < len) - func_len = len; + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; } - if (file_p) + if (__write_long (fn_info->checksum, da_file, 4) != 0) { - p = (ptr->filenames[i]) ? (ptr->filenames[i]) : ""; - len = strlen (p); - if (file_len < len) - file_len = len; + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; } - } - - addr_len = num_digits (addr_max, 16); - cnt_len = num_digits (cnt_max, 10); - line_len = num_digits (line_max, 10); - - /* Now print out the basic block information. */ - for (i = 0; i < ncounts; i++) - { - fprintf (file, - " Block #%*d: executed %*ld time(s)", - blk_len, i+1, - cnt_len, ptr->counts[i]); - if (addr_p) - fprintf (file, " address= 0x%.*lx", addr_len, - ptr->addresses[i]); - - if (func_p) - fprintf (file, " function= %-*s", func_len, - (ptr->functions[i]) ? ptr->functions[i] : ""); - - if (line_p) - fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]); + if (__write_long (fn_info->arc_count, da_file, 4) != 0) + { + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; + } - if (file_p) - fprintf (file, " file= %s", - (ptr->filenames[i]) ? ptr->filenames[i] : ""); + for (i = fn_info->arc_count; i > 0; i--, count_ptr++) + { + if (__write_gcov_type (*count_ptr, da_file, 8) != 0) + break; + } - fprintf (file, "\n"); + if (i) /* there was an error */ + { + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; + } } - - fprintf (file, "\n"); - fflush (file); } - fprintf (file, "\n\n"); - fclose (file); + if (fclose (da_file) != 0) + fprintf (stderr, "arc profiling: Error closing output file %s.\n", + ptr->filename); } } @@ -1697,11 +1462,9 @@ __bb_init_func (struct bb *blocks) if (blocks->zero_word) return; -#ifdef ON_EXIT - /* Initialize destructor. */ + /* Initialize destructor and per-thread data. */ if (!bb_head) - ON_EXIT (__bb_exit_func, 0); -#endif + atexit (__bb_exit_func); /* Set up linked list. */ blocks->zero_word = 1; @@ -1709,949 +1472,79 @@ __bb_init_func (struct bb *blocks) bb_head = blocks; } -#ifndef MACHINE_STATE_SAVE -#define MACHINE_STATE_SAVE(ID) -#endif -#ifndef MACHINE_STATE_RESTORE -#define MACHINE_STATE_RESTORE(ID) -#endif - -#include - -/* Number of buckets in hashtable of basic block addresses. */ - -#define BB_BUCKETS 311 - -/* Maximum length of string in file bb.in. */ - -#define BBINBUFSIZE 500 - -/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or - "BBINBUFSIZE" but want to avoid trouble with preprocessors. */ +/* 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; -#define BBINBUFSIZESTR "499" + __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; + } +} -struct bb_edge -{ - struct bb_edge *next; - unsigned long src_addr; - unsigned long dst_addr; - unsigned long count; -}; +#endif /* not inhibit_libc */ +#endif /* L_bb */ + +#ifdef L_clear_cache +/* Clear part of an instruction cache. */ -enum bb_func_mode -{ - TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2 -}; +#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH) -struct bb_func +void +__clear_cache (char *beg __attribute__((__unused__)), + char *end __attribute__((__unused__))) { - struct bb_func *next; - char *funcname; - char *filename; - enum bb_func_mode mode; -}; - -/* This is the connection to the outside world. - The BLOCK_PROFILER macro must set __bb.blocks - and __bb.blockno. */ +#ifdef CLEAR_INSN_CACHE + CLEAR_INSN_CACHE (beg, end); +#else +#ifdef INSN_CACHE_SIZE + static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH]; + static int initialized; + int offset; + void *start_addr + void *end_addr; + typedef (*function_ptr) (void); -struct { - unsigned long blockno; - struct bb *blocks; -} __bb; +#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16 + /* It's cheaper to clear the whole cache. + Put in a series of jump instructions so that calling the beginning + of the cache will clear the whole thing. */ -/* Vars to store addrs of source and destination basic blocks - of a jump. */ + if (! initialized) + { + int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) + & -INSN_CACHE_LINE_WIDTH); + int end_ptr = ptr + INSN_CACHE_SIZE; -static unsigned long bb_src = 0; -static unsigned long bb_dst = 0; + while (ptr < end_ptr) + { + *(INSTRUCTION_TYPE *)ptr + = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH; + ptr += INSN_CACHE_LINE_WIDTH; + } + *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION; -static FILE *bb_tracefile = (FILE *) 0; -static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0; -static struct bb_func *bb_func_head = (struct bb_func *) 0; -static unsigned long bb_callcount = 0; -static int bb_mode = 0; + initialized = 1; + } -static unsigned long *bb_stack = (unsigned long *) 0; -static size_t bb_stacksize = 0; + /* Call the beginning of the sequence. */ + (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1) + & -INSN_CACHE_LINE_WIDTH)) + ()); -static int reported = 0; +#else /* Cache is large. */ -/* Trace modes: -Always : Print execution frequencies of basic blocks - to file bb.out. -bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz] -bb_mode & 2 != 0 : Print jump frequencies to file bb.out. -bb_mode & 4 != 0 : Cut call instructions from basic block flow. -bb_mode & 8 != 0 : Insert return instructions in basic block flow. -*/ - -#ifdef HAVE_POPEN - -/*#include */ -#include -/*#include */ - -/* Commands executed by gopen. */ - -#define GOPENDECOMPRESS "gzip -cd " -#define GOPENCOMPRESS "gzip -c >" - -/* Like fopen but pipes through gzip. mode may only be "r" or "w". - If it does not compile, simply replace gopen by fopen and delete - '.gz' from any first parameter to gopen. */ - -static FILE * -gopen (char *fn, char *mode) -{ - int use_gzip; - char *p; - - if (mode[1]) - return (FILE *) 0; - - if (mode[0] != 'r' && mode[0] != 'w') - return (FILE *) 0; - - p = fn + strlen (fn)-1; - use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z')) - || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z')); - - if (use_gzip) - { - if (mode[0]=='r') - { - FILE *f; - char *s = (char *) malloc (sizeof (char) * strlen (fn) - + sizeof (GOPENDECOMPRESS)); - strcpy (s, GOPENDECOMPRESS); - strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn); - f = popen (s, mode); - free (s); - return f; - } - - else - { - FILE *f; - char *s = (char *) malloc (sizeof (char) * strlen (fn) - + sizeof (GOPENCOMPRESS)); - strcpy (s, GOPENCOMPRESS); - strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn); - if (!(f = popen (s, mode))) - f = fopen (s, mode); - free (s); - return f; - } - } - - else - return fopen (fn, mode); -} - -static int -gclose (FILE *f) -{ - struct stat buf; - - if (f != 0) - { - if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode)) - return pclose (f); - - return fclose (f); - } - return 0; -} - -#endif /* HAVE_POPEN */ - -/* Called once per program. */ - -static void -__bb_exit_trace_func () -{ - FILE *file = fopen ("bb.out", "a"); - struct bb_func *f; - struct bb_edge *e; - struct bb *b; - - if (!file) - perror ("bb.out"); - - if (bb_mode & 1) - { - if (!bb_tracefile) - perror ("bbtrace"); - else -#ifdef HAVE_POPEN - gclose (bb_tracefile); -#else - fclose (bb_tracefile); -#endif /* HAVE_POPEN */ - } - - /* Check functions in `bb.in'. */ - - if (file) - { - long time_value; - const struct bb_func *p; - int printed_something = 0; - struct bb *ptr; - long blk; - - /* This is somewhat type incorrect. */ - time ((void *) &time_value); - - for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next) - { - for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) - { - if (!ptr->filename || p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)) - continue; - for (blk = 0; blk < ptr->ncounts; blk++) - { - if (!strcmp (p->funcname, ptr->functions[blk])) - goto found; - } - } - - if (!printed_something) - { - fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value)); - printed_something = 1; - } - - fprintf (file, "\tFunction %s", p->funcname); - if (p->filename) - fprintf (file, " of file %s", p->filename); - fprintf (file, "\n" ); - -found: ; - } - - if (printed_something) - fprintf (file, "\n"); - - } - - if (bb_mode & 2) - { - if (!bb_hashbuckets) - { - if (!reported) - { - fprintf (stderr, "Profiler: out of memory\n"); - reported = 1; - } - return; - } - - else if (file) - { - long time_value; - int i; - unsigned long addr_max = 0; - unsigned long cnt_max = 0; - int cnt_len; - int addr_len; - - /* This is somewhat type incorrect, but it avoids worrying about - exactly where time.h is included from. It should be ok unless - a void * differs from other pointer formats, or if sizeof (long) - is < sizeof (time_t). It would be nice if we could assume the - use of rationale standards here. */ - - time ((void *) &time_value); - fprintf (file, "Basic block jump tracing"); - - switch (bb_mode & 12) - { - case 0: - fprintf (file, " (with call)"); - break; - - case 4: - /* Print nothing. */ - break; - - case 8: - fprintf (file, " (with call & ret)"); - break; - - case 12: - fprintf (file, " (with ret)"); - break; - } - - fprintf (file, " finished on %s\n", ctime ((void *) &time_value)); - - for (i = 0; i < BB_BUCKETS; i++) - { - struct bb_edge *bucket = bb_hashbuckets[i]; - for ( ; bucket; bucket = bucket->next ) - { - if (addr_max < bucket->src_addr) - addr_max = bucket->src_addr; - if (addr_max < bucket->dst_addr) - addr_max = bucket->dst_addr; - if (cnt_max < bucket->count) - cnt_max = bucket->count; - } - } - addr_len = num_digits (addr_max, 16); - cnt_len = num_digits (cnt_max, 10); - - for ( i = 0; i < BB_BUCKETS; i++) - { - struct bb_edge *bucket = bb_hashbuckets[i]; - for ( ; bucket; bucket = bucket->next ) - { - fprintf (file, "Jump from block 0x%.*lx to " - "block 0x%.*lx executed %*d time(s)\n", - addr_len, bucket->src_addr, - addr_len, bucket->dst_addr, - cnt_len, bucket->count); - } - } - - fprintf (file, "\n"); - - } - } - - if (file) - fclose (file); - - /* Free allocated memory. */ - - f = bb_func_head; - while (f) - { - struct bb_func *old = f; - - f = f->next; - if (old->funcname) free (old->funcname); - if (old->filename) free (old->filename); - free (old); - } - - if (bb_stack) - free (bb_stack); - - if (bb_hashbuckets) - { - int i; - - for (i = 0; i < BB_BUCKETS; i++) - { - struct bb_edge *old, *bucket = bb_hashbuckets[i]; - - while (bucket) - { - old = bucket; - bucket = bucket->next; - free (old); - } - } - free (bb_hashbuckets); - } - - for (b = bb_head; b; b = b->next) - if (b->flags) free (b->flags); -} - -/* Called once per program. */ - -static void -__bb_init_prg () -{ - - FILE *file; - char buf[BBINBUFSIZE]; - const char *p; - const char *pos; - enum bb_func_mode m; - -#ifdef ON_EXIT - /* Initialize destructor. */ - ON_EXIT (__bb_exit_func, 0); -#endif - - if (!(file = fopen ("bb.in", "r"))) - return; - - while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF) - { - p = buf; - if (*p == '-') - { - m = TRACE_OFF; - p++; - } - else - { - m = TRACE_ON; - } - if (!strcmp (p, "__bb_trace__")) - bb_mode |= 1; - else if (!strcmp (p, "__bb_jumps__")) - bb_mode |= 2; - else if (!strcmp (p, "__bb_hidecall__")) - bb_mode |= 4; - else if (!strcmp (p, "__bb_showret__")) - bb_mode |= 8; - else - { - struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func)); - if (f) - { - unsigned long l; - f->next = bb_func_head; - if (pos = strchr (p, ':')) - { - if (!(f->funcname = (char *) malloc (strlen (pos+1)+1))) - continue; - strcpy (f->funcname, pos+1); - l = pos-p; - if ((f->filename = (char *) malloc (l+1))) - { - strncpy (f->filename, p, l); - f->filename[l] = '\0'; - } - else - f->filename = (char *) 0; - } - else - { - if (!(f->funcname = (char *) malloc (strlen (p)+1))) - continue; - strcpy (f->funcname, p); - f->filename = (char *) 0; - } - f->mode = m; - bb_func_head = f; - } - } - } - fclose (file); - -#ifdef HAVE_POPEN - - if (bb_mode & 1) - bb_tracefile = gopen ("bbtrace.gz", "w"); - -#else - - if (bb_mode & 1) - bb_tracefile = fopen ("bbtrace", "w"); - -#endif /* HAVE_POPEN */ - - if (bb_mode & 2) - { - bb_hashbuckets = (struct bb_edge **) - malloc (BB_BUCKETS * sizeof (struct bb_edge *)); - if (bb_hashbuckets) - bzero ((char *) bb_hashbuckets, BB_BUCKETS); - } - - if (bb_mode & 12) - { - bb_stacksize = 10; - bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack)); - } - -#ifdef ON_EXIT - /* Initialize destructor. */ - ON_EXIT (__bb_exit_trace_func, 0); -#endif - -} - -/* Called upon entering a basic block. */ - -void -__bb_trace_func () -{ - struct bb_edge *bucket; - - MACHINE_STATE_SAVE("1") - - if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF))) - goto skip; - - bb_dst = __bb.blocks->addresses[__bb.blockno]; - __bb.blocks->counts[__bb.blockno]++; - - if (bb_tracefile) - { - fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile); - } - - if (bb_hashbuckets) - { - struct bb_edge **startbucket, **oldnext; - - oldnext = startbucket - = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ]; - bucket = *startbucket; - - for (bucket = *startbucket; bucket; - oldnext = &(bucket->next), bucket = *oldnext) - { - if (bucket->src_addr == bb_src - && bucket->dst_addr == bb_dst) - { - bucket->count++; - *oldnext = bucket->next; - bucket->next = *startbucket; - *startbucket = bucket; - goto ret; - } - } - - bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge)); - - if (!bucket) - { - if (!reported) - { - fprintf (stderr, "Profiler: out of memory\n"); - reported = 1; - } - } - - else - { - bucket->src_addr = bb_src; - bucket->dst_addr = bb_dst; - bucket->next = *startbucket; - *startbucket = bucket; - bucket->count = 1; - } - } - -ret: - bb_src = bb_dst; - -skip: - ; - - MACHINE_STATE_RESTORE("1") - -} - -/* Called when returning from a function and `__bb_showret__' is set. */ - -static void -__bb_trace_func_ret () -{ - struct bb_edge *bucket; - - if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF))) - goto skip; - - if (bb_hashbuckets) - { - struct bb_edge **startbucket, **oldnext; - - oldnext = startbucket - = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ]; - bucket = *startbucket; - - for (bucket = *startbucket; bucket; - oldnext = &(bucket->next), bucket = *oldnext) - { - if (bucket->src_addr == bb_dst - && bucket->dst_addr == bb_src) - { - bucket->count++; - *oldnext = bucket->next; - bucket->next = *startbucket; - *startbucket = bucket; - goto ret; - } - } - - bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge)); - - if (!bucket) - { - if (!reported) - { - fprintf (stderr, "Profiler: out of memory\n"); - reported = 1; - } - } - - else - { - bucket->src_addr = bb_dst; - bucket->dst_addr = bb_src; - bucket->next = *startbucket; - *startbucket = bucket; - bucket->count = 1; - } - } - -ret: - bb_dst = bb_src; - -skip: - ; - -} - -/* Called upon entering the first function of a file. */ - -static void -__bb_init_file (struct bb *blocks) -{ - - const struct bb_func *p; - long blk, ncounts = blocks->ncounts; - const char **functions = blocks->functions; - - /* Set up linked list. */ - blocks->zero_word = 1; - blocks->next = bb_head; - bb_head = blocks; - - blocks->flags = 0; - if (!bb_func_head - || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts))) - return; - - for (blk = 0; blk < ncounts; blk++) - blocks->flags[blk] = 0; - - for (blk = 0; blk < ncounts; blk++) - { - for (p = bb_func_head; p; p = p->next) - { - if (!strcmp (p->funcname, functions[blk]) - && (!p->filename || !strcmp (p->filename, blocks->filename))) - { - blocks->flags[blk] |= p->mode; - } - } - } - -} - -/* Called when exiting from a function. */ - -void -__bb_trace_ret () -{ - - MACHINE_STATE_SAVE("2") - - if (bb_callcount) - { - if ((bb_mode & 12) && bb_stacksize > bb_callcount) - { - bb_src = bb_stack[bb_callcount]; - if (bb_mode & 8) - __bb_trace_func_ret (); - } - - bb_callcount -= 1; - } - - MACHINE_STATE_RESTORE("2") - -} - -/* Called when entering a function. */ - -void -__bb_init_trace_func (struct bb *blocks, unsigned long blockno) -{ - static int trace_init = 0; - - MACHINE_STATE_SAVE("3") - - if (!blocks->zero_word) - { - if (!trace_init) - { - trace_init = 1; - __bb_init_prg (); - } - __bb_init_file (blocks); - } - - if (bb_callcount) - { - - bb_callcount += 1; - - if (bb_mode & 12) - { - if (bb_callcount >= bb_stacksize) - { - size_t newsize = bb_callcount + 100; - - bb_stack = (unsigned long *) realloc (bb_stack, newsize); - if (! bb_stack) - { - if (!reported) - { - fprintf (stderr, "Profiler: out of memory\n"); - reported = 1; - } - bb_stacksize = 0; - goto stack_overflow; - } - bb_stacksize = newsize; - } - bb_stack[bb_callcount] = bb_src; - - if (bb_mode & 4) - bb_src = 0; - - } - -stack_overflow:; - - } - - else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON)) - { - bb_callcount = 1; - bb_src = 0; - - if (bb_stack) - bb_stack[bb_callcount] = bb_src; - } - - MACHINE_STATE_RESTORE("3") -} - -#endif /* not inhibit_libc */ -#endif /* not BLOCK_PROFILER_CODE */ -#endif /* L_bb */ - -/* 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 - -#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 */ - -#ifdef L_shtab -unsigned int __shtab[] = { - 0x00000001, 0x00000002, 0x00000004, 0x00000008, - 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, - 0x00001000, 0x00002000, 0x00004000, 0x00008000, - 0x00010000, 0x00020000, 0x00040000, 0x00080000, - 0x00100000, 0x00200000, 0x00400000, 0x00800000, - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000 - }; -#endif - -#ifdef L_clear_cache -/* Clear part of an instruction cache. */ - -#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH) - -void -__clear_cache (char *beg, char *end) -{ -#ifdef CLEAR_INSN_CACHE - CLEAR_INSN_CACHE (beg, end); -#else -#ifdef INSN_CACHE_SIZE - static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH]; - static int initialized; - int offset; - void *start_addr - void *end_addr; - typedef (*function_ptr) (); - -#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16 - /* It's cheaper to clear the whole cache. - Put in a series of jump instructions so that calling the beginning - of the cache will clear the whole thing. */ - - if (! initialized) - { - int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH); - int end_ptr = ptr + INSN_CACHE_SIZE; - - while (ptr < end_ptr) - { - *(INSTRUCTION_TYPE *)ptr - = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH; - ptr += INSN_CACHE_LINE_WIDTH; - } - *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION; - - initialized = 1; - } - - /* Call the beginning of the sequence. */ - (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH)) - ()); - -#else /* Cache is large. */ - - if (! initialized) - { - int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH); + if (! initialized) + { + int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) + & -INSN_CACHE_LINE_WIDTH); while (ptr < (int) array + sizeof array) { @@ -2672,7 +1565,7 @@ __clear_cache (char *beg, char *end) /* Compute the cache alignment of the place to stop clearing. */ #if 0 /* This is not needed for gcc's purposes. */ /* If the block to clear is bigger than a cache plane, - we clear the entire cache, and OFFSET is already correct. */ + we clear the entire cache, and OFFSET is already correct. */ if (end < beg + INSN_CACHE_PLANE_SIZE) #endif offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1) @@ -2718,9 +1611,10 @@ __clear_cache (char *beg, char *end) /* Jump to a trampoline, loading the static chain address. */ -#ifdef WINNT +#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN) -long getpagesize() +long +getpagesize (void) { #ifdef _ALPHA_ return 8192; @@ -2729,28 +1623,38 @@ long getpagesize() #endif } -int mprotect(char *addr, int len, int prot) +#ifdef __i386__ +extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall)); +#endif + +int +mprotect (char *addr, int len, int prot) { int np, op; - if (prot == 7) np = 0x40; - else if (prot == 5) np = 0x20; - else if (prot == 4) np = 0x10; - else if (prot == 3) np = 0x04; - else if (prot == 1) np = 0x02; - else if (prot == 0) np = 0x01; + if (prot == 7) + np = 0x40; + else if (prot == 5) + np = 0x20; + else if (prot == 4) + np = 0x10; + else if (prot == 3) + np = 0x04; + else if (prot == 1) + np = 0x02; + else if (prot == 0) + np = 0x01; if (VirtualProtect (addr, len, np, &op)) return 0; else return -1; - } -#endif +#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */ -#ifdef TRANSFER_FROM_TRAMPOLINE -TRANSFER_FROM_TRAMPOLINE +#ifdef TRANSFER_FROM_TRAMPOLINE +TRANSFER_FROM_TRAMPOLINE #endif #if defined (NeXT) && defined (__MACH__) @@ -2785,7 +1689,7 @@ __enable_execute_stack (char *addr) #else __clear_cache ((int) addr, (int) eaddr); #endif -} +} #endif /* defined (NeXT) && defined (__MACH__) */ @@ -2799,7 +1703,7 @@ __enable_execute_stack (char *addr) #include void -__enable_execute_stack () +__enable_execute_stack (void) { int fp; static unsigned lowest = USRSTACK; @@ -2817,7 +1721,7 @@ __enable_execute_stack () } #endif /* __convex__ */ -#ifdef __DOLPHIN__ +#ifdef __sysV88__ /* Modified from the convex -code above. */ @@ -2826,14 +1730,14 @@ __enable_execute_stack () #include void -__enable_execute_stack () +__enable_execute_stack (void) { int save_errno; static unsigned long lowest = USRSTACK; unsigned long current = (unsigned long) &save_errno & -NBPC; - + /* Ignore errno being set. memctl sets errno to EINVAL whenever the - address is seen as 'negative'. That is the case with the stack. */ + address is seen as 'negative'. That is the case with the stack. */ save_errno=errno; if (lowest > current) @@ -2847,7 +1751,52 @@ __enable_execute_stack () errno=save_errno; } -#endif /* __DOLPHIN__ */ +#endif /* __sysV88__ */ + +#ifdef __sysV68__ + +#include +#include + +/* 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__ @@ -2862,7 +1811,7 @@ __enable_execute_stack () 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, @@ -2901,6 +1850,7 @@ cacheflush (char *beg, int size, int flag) #endif /* sony_news */ #endif /* L_trampoline */ +#ifndef __CYGWIN__ #ifdef L__main #include "gbl-ctors.h" @@ -2919,10 +1869,19 @@ cacheflush (char *beg, int size, int flag) #endif #if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF) + +/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this + code to run constructors. In that case, we need to handle EH here, too. */ + +#ifdef EH_FRAME_SECTION_NAME +#include "unwind-dw2-fde.h" +extern unsigned char __EH_FRAME_BEGIN__[]; +#endif + /* Run all the global destructors on exit from the program. */ void -__do_global_dtors () +__do_global_dtors (void) { #ifdef DO_GLOBAL_DTORS_BODY DO_GLOBAL_DTORS_BODY; @@ -2934,28 +1893,33 @@ __do_global_dtors () (*(p-1)) (); } #endif +#if defined (EH_FRAME_SECTION_NAME) && !defined (HAS_INIT_SECTION) + { + static int completed = 0; + if (! completed) + { + completed = 1; + __deregister_frame_info (__EH_FRAME_BEGIN__); + } + } +#endif } #endif #ifndef HAS_INIT_SECTION /* Run all the global constructors on entry to the program. */ -#ifndef ON_EXIT -#define ON_EXIT(a, b) -#else -/* Make sure the exit routine is pulled in to define the globals as - bss symbols, just in case the linker does not automatically pull - bss definitions from the library. */ - -extern int _exit_dummy_decl; -int *_exit_dummy_ref = &_exit_dummy_decl; -#endif /* ON_EXIT */ - void -__do_global_ctors () +__do_global_ctors (void) { +#ifdef EH_FRAME_SECTION_NAME + { + static struct object object; + __register_frame_info (__EH_FRAME_BEGIN__, &object); + } +#endif DO_GLOBAL_CTORS_BODY; - ON_EXIT (__do_global_dtors, 0); + atexit (__do_global_dtors); } #endif /* no HAS_INIT_SECTION */ @@ -2982,6 +1946,7 @@ SYMBOL__MAIN () #endif /* no HAS_INIT_SECTION or INVOKE__main */ #endif /* L__main */ +#endif /* __CYGWIN__ */ #ifdef L_ctors @@ -2993,10 +1958,15 @@ SYMBOL__MAIN () the right values. */ /* We declare the lists here with two elements each, - so that they are valid empty lists if no other definition is loaded. */ + so that they are valid empty lists if no other definition is loaded. + + If we are using the old "set" extensions to have the gnu linker + collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__ + must be in the bss/common section. + + Long term no port should use those extensions. But many still do. */ #if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY) -#if defined(__NeXT__) || defined(_AIX) -/* After 2.3, try this definition on all systems. */ +#if defined (TARGET_ASM_CONSTRUCTOR) || defined (USE_COLLECT2) func_ptr __CTOR_LIST__[2] = {0, 0}; func_ptr __DTOR_LIST__[2] = {0, 0}; #else @@ -3011,22 +1981,17 @@ func_ptr __DTOR_LIST__[2]; #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 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) { @@ -3048,22 +2013,13 @@ int atexit (func_ptr func) atexit_chain[last_atexit_chain_slot] = func; return (0); } -#endif /* NEED_ATEXIT */ -/* If we have no known way of registering our own __do_global_dtors - routine so that it will be invoked at program exit time, then we - have to define our own exit routine which will get this to happen. */ +extern void _cleanup (void); +extern void _exit (int) __attribute__ ((__noreturn__)); -extern void __do_global_dtors (); -extern void __bb_exit_func (); -extern void _cleanup (); -extern void _exit () __attribute__ ((noreturn)); - -void +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; ) @@ -3074,13 +2030,6 @@ exit (int status) 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 @@ -3089,469 +2038,16 @@ exit (int status) _exit (status); } -#else -int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */ -#endif - -#endif /* L_exit */ - -#ifdef L_eh - -#ifdef EH_TABLE_LOOKUP - -EH_TABLE_LOOKUP - -#else - -void -__default_terminate () -{ - abort (); -} - -void (*__terminate_func)() = __default_terminate; - -void -__terminate () -{ - (*__terminate_func)(); -} - -/* Calls to __sjthrow are generated by the compiler when an exception - is raised when using the setjmp/longjmp exception handling codegen - method. */ - -extern void longjmp (void *, int); - -extern void *__eh_type; - -static void *top_elt[2]; -void **__dynamic_handler_chain = top_elt; - -/* Routine to get the head of the current thread's dynamic handler chain - use for exception handling. - - TODO: make thread safe. */ - -void *** -__get_dynamic_handler_chain () -{ - return &__dynamic_handler_chain; -} - -/* This is used to throw an exception when the setjmp/longjmp codegen - method is used for exception handling. - - We call __terminate if there are no handlers left (we know this - when the dynamic handler chain is top_elt). Otherwise we run the - cleanup actions off the dynamic cleanup stack, and pop the top of - the dynamic handler chain, and use longjmp to transfer back to the - associated handler. */ - -void -__sjthrow () -{ - void ***dhc = __get_dynamic_handler_chain (); - void *jmpbuf; - void (*func)(void *, int); - void *arg; - void ***cleanup; - - /* The cleanup chain is one word into the buffer. Get the cleanup - chain. */ - cleanup = (void***)&(*dhc)[1]; - - /* If there are any cleanups in the chain, run them now. */ - if (cleanup[0]) - { - double store[200]; - void **buf = (void**)store; - buf[1] = 0; - buf[0] = (*dhc); - - /* try { */ -#ifdef DONT_USE_BUILTIN_SETJMP - if (! setjmp (&buf[2])) -#else - if (! __builtin_setjmp (&buf[2])) -#endif - { - *dhc = buf; - while (cleanup[0]) - { - func = (void(*)(void*, int))cleanup[0][1]; - arg = (void*)cleanup[0][2]; - - /* Update this before running the cleanup. */ - cleanup[0] = (void **)cleanup[0][0]; - - (*func)(arg, 2); - } - *dhc = buf[0]; - } - /* catch (...) */ - else - { - __terminate (); - } - } - - /* We must call terminate if we try and rethrow an exception, when - there is no exception currently active and when there are no - handlers left. */ - if (! __eh_type || (*dhc) == top_elt) - __terminate (); - - /* Find the jmpbuf associated with the top element of the dynamic - handler chain. The jumpbuf starts two words into the buffer. */ - jmpbuf = &(*dhc)[2]; - - /* Then we pop the top element off the dynamic handler chain. */ - *dhc = (void**)(*dhc)[0]; - - /* And then we jump to the handler. */ - -#ifdef DONT_USE_BUILTIN_SETJMP - longjmp (jmpbuf, 1); -#else - __builtin_longjmp (jmpbuf, 1); -#endif -} - -/* Run cleanups on the dynamic cleanup stack for the current dynamic - handler, then pop the handler off the dynamic handler stack, and - then throw. This is used to skip the first handler, and transfer - control to the next handler in the dynamic handler stack. */ - -void -__sjpopnthrow () -{ - void ***dhc = __get_dynamic_handler_chain (); - void *jmpbuf; - void (*func)(void *, int); - void *arg; - void ***cleanup; - - /* The cleanup chain is one word into the buffer. Get the cleanup - chain. */ - cleanup = (void***)&(*dhc)[1]; - - /* If there are any cleanups in the chain, run them now. */ - if (cleanup[0]) - { - double store[200]; - void **buf = (void**)store; - buf[1] = 0; - buf[0] = (*dhc); - - /* try { */ -#ifdef DONT_USE_BUILTIN_SETJMP - if (! setjmp (&buf[2])) -#else - if (! __builtin_setjmp (&buf[2])) -#endif - { - *dhc = buf; - while (cleanup[0]) - { - func = (void(*)(void*, int))cleanup[0][1]; - arg = (void*)cleanup[0][2]; - - /* Update this before running the cleanup. */ - cleanup[0] = (void **)cleanup[0][0]; - - (*func)(arg, 2); - } - *dhc = buf[0]; - } - /* catch (...) */ - else - { - __terminate (); - } - } - - /* Then we pop the top element off the dynamic handler chain. */ - *dhc = (void**)(*dhc)[0]; - - __sjthrow (); -} - -typedef struct { - void *start; - void *end; - void *exception_handler; -} exception_table; - -struct exception_table_node { - exception_table *table; - void *start; - void *end; - struct exception_table_node *next; -}; - -static struct exception_table_node *exception_table_list; - -/* this routine takes a pc, and the address of the exception handler associated - with the closest exception table handler entry associated with that PC, - or 0 if there are no table entries the PC fits in. The algorithm works - something like this: - - while(current_entry exists) { - if(current_entry.start < pc ) - current_entry = next_entry; - else { - if(prev_entry.start <= pc && prev_entry.end > pc) { - save pointer to prev_entry; - return prev_entry.exception_handler; - } - else return 0; - } - } - return 0; - - Assuming a correctly sorted table (ascending order) this routine should - return the tightest match... - - In the advent of a tie, we have to give the last entry, as it represents - an inner block. */ - -void * -__find_first_exception_table_match (void *pc) -{ - register struct exception_table_node *tnp; - register exception_table *table; - int pos; - int best; - -#if 0 - printf ("find_first_exception_table_match (): pc = %x!\n", pc); -#endif +#else /* ON_EXIT */ - for (tnp = exception_table_list; tnp != 0; tnp = tnp->next) - { - if (tnp->start > pc || tnp->end <= pc) - continue; - - table = tnp->table; - - pos = 0; - best = 0; -#if 0 - /* We can't do this yet, as we don't know that the table is sorted. */ - do { - ++pos; - if (table[pos].start > pc) - /* found the first table[pos].start > pc, so the previous - entry better be the one we want! */ - break; - } while (table[pos].exception_handler != (void *) -1); - - --pos; - if (table[pos].start <= pc && table[pos].end > pc) - { -#if 0 - printf ("find_first_eh_table_match (): found match: %x\n", table[pos].exception_handler); -#endif - return table[pos].exception_handler; - } -#else - while (table[++pos].exception_handler != (void *) -1) { - if (table[pos].start <= pc && table[pos].end > pc) - { - /* This can apply. Make sure it is better or as good as - the previous best. */ - /* The best one ends first. */ - if (best == 0 || (table[pos].end <= table[best].end - /* The best one starts last. */ - && table[pos].start >= table[best].start)) - best = pos; - } - } - if (best != 0) - return table[best].exception_handler; -#endif - } - -#if 0 - printf ("find_first_eh_table_match (): else: returning NULL!\n"); -#endif - return (void *) 0; -} - -void -__register_exceptions (exception_table *table) -{ - struct exception_table_node *node; - exception_table *range = table + 1; - - if (range->start == (void *) -1) - return; - - node = (struct exception_table_node *) - malloc (sizeof (struct exception_table_node)); - node->table = table; - - /* This look can be optimized away either if the table - is sorted, or if we pass in extra parameters. */ - node->start = range->start; - node->end = range->end; - for (range++ ; range->start != (void *) (-1); range++) - { - if (range->start < node->start) - node->start = range->start; - if (range->end > node->end) - node->end = range->end; - } - - node->next = exception_table_list; - exception_table_list = node; -} -#endif - -void * -__throw_type_match (void *catch_type, void *throw_type, void *obj) -{ -#if 0 - printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n", - catch_type, throw_type); -#endif - if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0) - return obj; - return 0; -} - -/* Throw stub routine. - - This is work in progress, but not completed yet. */ - -void -__throw () -{ - abort (); -} - -/* This value identifies the place from which an exception is being - thrown. */ - -void *__eh_pc; - -/* See expand_builtin_throw for details. */ - -void **__eh_pcnthrow () { - static void *buf[2] = { - &__eh_pc, - &__throw - }; - return buf; -} - -void -__empty () -{ -} - -#if #machine(i386) -void -__unwind_function(void *ptr) -{ - asm("movl 8(%esp),%ecx"); - /* Undo current frame */ - asm("movl %ebp,%esp"); - asm("popl %ebp"); - /* like ret, but stay here */ - asm("addl $4,%esp"); - - /* Now, undo previous frame. */ - /* This is a test routine, as we have to dynamically probe to find out - what to pop for certain, this is just a guess. */ - asm("leal -16(%ebp),%esp"); - asm("pop %ebx"); - asm("pop %esi"); - asm("pop %edi"); - asm("movl %ebp,%esp"); - asm("popl %ebp"); - - asm("movl %ecx,0(%esp)"); - asm("ret"); -} -#elif #machine(rs6000) && !defined _ARCH_PPC -__unwind_function(void *ptr) -{ - asm("mr 31,1"); - asm("l 1,0(1)"); - asm("l 31,-4(1)"); - asm("# br"); - - asm("mr 31,1"); - asm("l 1,0(1)"); - /* use 31 as a scratch register to restore the link register. */ - asm("l 31, 8(1);mtlr 31 # l lr,8(1)"); - asm("l 31,-4(1)"); - asm("# br"); - asm("mtctr 3;bctr # b 3"); -} -#elif (#machine(rs6000) || #machine(powerpc)) && defined _ARCH_PPC -__unwind_function(void *ptr) -{ - asm("mr 31,1"); - asm("lwz 1,0(1)"); - asm("lwz 31,-4(1)"); - asm("# br"); - - asm("mr 31,1"); - asm("lwz 1,0(1)"); - /* use 31 as a scratch register to restore the link register. */ - asm("lwz 31, 8(1);mtlr 31 # l lr,8(1)"); - asm("lwz 31,-4(1)"); - asm("# br"); - asm("mtctr 3;bctr # b 3"); -} -#elif #machine(vax) -__unwind_function(void *ptr) -{ - __label__ return_again; - - /* Replace our frame's return address with the label below. - During execution, we will first return here instead of to - caller, then second return takes caller's frame off the stack. - Two returns matches two actual calls, so is less likely to - confuse debuggers. `16' corresponds to RETURN_ADDRESS_OFFSET. */ - __asm ("movl %0,16(fp)" : : "p" (&& return_again)); - return; - - return_again: - return; -} -#else -__unwind_function(void *ptr) +/* Simple; we just need a wrapper for ON_EXIT. */ +int +atexit (func_ptr func) { - abort (); + return ON_EXIT (func); } -#endif /* powerpc */ -#endif /* L_eh */ - -#ifdef L_pure -#ifndef inhibit_libc -/* This gets us __GNU_LIBRARY__. */ -#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ -#include -#ifdef __GNU_LIBRARY__ - /* Avoid forcing the library's meaning of `write' on the user program - by using the "internal" name (for use within the library) */ -#define write(fd, buf, n) __write((fd), (buf), (n)) -#endif -#endif /* inhibit_libc */ - -#define MESSAGE "pure virtual method called\n" +#endif /* ON_EXIT */ +#endif /* NEED_ATEXIT */ -void -__pure_virtual () -{ -#ifndef inhibit_libc - write (2, MESSAGE, sizeof (MESSAGE) - 1); -#endif - _exit (-1); -} -#endif +#endif /* L_exit */