X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Flibgcc2.c;h=a303d0bce25fdadf99744b5d0c4d414f8e805eb6;hb=41b60827878f5f840120c95c52846ce0fe072c3f;hp=0c42ac6e2db2563254dd778f3cdc2232958b6c47;hpb=63f236087f033781e482c61b8d159595cb371d4f;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 0c42ac6e2db..a303d0bce25 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -1,14 +1,14 @@ /* More subroutines needed by GCC output code on some machines. */ /* Compile this one with gcc. */ /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. -This file is part of GNU CC. +This file is part of GCC. -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. +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 @@ -19,46 +19,40 @@ 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 -GNU General Public License for more details. +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. */ - -/* 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. */ +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. */ #include "tconfig.h" #include "tsystem.h" +#include "coretypes.h" +#include "tm.h" -#include "machmode.h" - -/* Don't use `fancy_abort' here even if config.h says to use it. */ -#ifdef abort -#undef abort +#ifdef HAVE_GAS_HIDDEN +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) +#else +#define ATTRIBUTE_HIDDEN #endif #include "libgcc2.h" -#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3) -#if defined (L_divdi3) || defined (L_moddi3) -static inline +#ifdef DECLARE_LIBRARY_RENAMES + DECLARE_LIBRARY_RENAMES #endif + +#if defined (L_negdi2) DWtype __negdi2 (DWtype u) { - DWunion w; - DWunion uu; - - uu.ll = u; - - w.s.low = -uu.s.low; - w.s.high = -uu.s.high - ((UWtype) w.s.low > 0); + const DWunion uu = {.ll = u}; + const DWunion w = { {.low = -uu.s.low, + .high = -uu.s.high - ((UWtype) -uu.s.low > 0) } }; return w.ll; } @@ -66,26 +60,34 @@ __negdi2 (DWtype u) #ifdef L_addvsi3 Wtype -__addvsi3 (Wtype a, Wtype b) +__addvSI3 (Wtype a, Wtype b) { - Wtype w; + const Wtype w = a + b; + + if (b >= 0 ? w < a : w > a) + abort (); - w = a + b; + return w; +} +#ifdef COMPAT_SIMODE_TRAPPING_ARITHMETIC +SItype +__addvsi3 (SItype a, SItype b) +{ + const SItype w = a + b; if (b >= 0 ? w < a : w > a) abort (); return w; -} +} +#endif /* COMPAT_SIMODE_TRAPPING_ARITHMETIC */ #endif #ifdef L_addvdi3 DWtype -__addvdi3 (DWtype a, DWtype b) +__addvDI3 (DWtype a, DWtype b) { - DWtype w; - - w = a + b; + const DWtype w = a + b; if (b >= 0 ? w < a : w > a) abort (); @@ -96,159 +98,304 @@ __addvdi3 (DWtype a, DWtype b) #ifdef L_subvsi3 Wtype -__subvsi3 (Wtype a, Wtype b) +__subvSI3 (Wtype a, Wtype b) { -#ifdef L_addvsi3 - return __addvsi3 (a, (-b)); -#else - DWtype w; + const Wtype w = a - b; + + if (b >= 0 ? w > a : w < a) + abort (); - w = a - b; + return w; +} +#ifdef COMPAT_SIMODE_TRAPPING_ARITHMETIC +SItype +__subvsi3 (SItype a, SItype b) +{ + const SItype w = a - b; if (b >= 0 ? w > a : w < a) abort (); return w; -#endif } +#endif /* COMPAT_SIMODE_TRAPPING_ARITHMETIC */ #endif #ifdef L_subvdi3 DWtype -__subvdi3 (DWtype a, DWtype b) +__subvDI3 (DWtype a, DWtype b) { -#ifdef L_addvdi3 - return (a, (-b)); -#else - DWtype w; - - w = a - b; + const DWtype w = a - b; if (b >= 0 ? w > a : w < a) abort (); return w; -#endif } #endif #ifdef L_mulvsi3 Wtype -__mulvsi3 (Wtype a, Wtype b) +__mulvSI3 (Wtype a, Wtype b) { - DWtype w; + const DWtype w = (DWtype) a * (DWtype) b; - w = a * b; + if ((Wtype) (w >> W_TYPE_SIZE) != (Wtype) w >> (W_TYPE_SIZE - 1)) + abort (); + + return w; +} +#ifdef COMPAT_SIMODE_TRAPPING_ARITHMETIC +#undef WORD_SIZE +#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT) +SItype +__mulvsi3 (SItype a, SItype b) +{ + const DItype w = (DItype) a * (DItype) b; - if (((a >= 0) == (b >= 0)) ? w < 0 : w > 0) + if ((SItype) (w >> WORD_SIZE) != (SItype) w >> (WORD_SIZE-1)) abort (); return w; } +#endif /* COMPAT_SIMODE_TRAPPING_ARITHMETIC */ #endif #ifdef L_negvsi2 Wtype -__negvsi2 (Wtype a) +__negvSI2 (Wtype a) { - Wtype w; + const Wtype w = -a; + + if (a >= 0 ? w > 0 : w < 0) + abort (); - w = -a; + return w; +} +#ifdef COMPAT_SIMODE_TRAPPING_ARITHMETIC +SItype +__negvsi2 (SItype a) +{ + const SItype w = -a; if (a >= 0 ? w > 0 : w < 0) abort (); return w; } +#endif /* COMPAT_SIMODE_TRAPPING_ARITHMETIC */ #endif #ifdef L_negvdi2 DWtype -__negvdi2 (DWtype a) +__negvDI2 (DWtype a) { - DWtype w; - - w = -a; + const DWtype w = -a; if (a >= 0 ? w > 0 : w < 0) abort (); - return w; + return w; } #endif #ifdef L_absvsi2 Wtype -__absvsi2 (Wtype a) +__absvSI2 (Wtype a) +{ + Wtype w = a; + + if (a < 0) +#ifdef L_negvsi2 + w = __negvSI2 (a); +#else + w = -a; + + if (w < 0) + abort (); +#endif + + return w; +} +#ifdef COMPAT_SIMODE_TRAPPING_ARITHMETIC +SItype +__absvsi2 (SItype a) { - Wtype w = a; + SItype w = a; - if (a < 0) + if (a < 0) #ifdef L_negvsi2 - w = __negvsi2 (a); + w = __negvsi2 (a); #else - w = -a; + w = -a; - if (w < 0) - abort (); + if (w < 0) + abort (); #endif return w; } +#endif /* COMPAT_SIMODE_TRAPPING_ARITHMETIC */ #endif #ifdef L_absvdi2 DWtype -__absvdi2 (DWtype a) +__absvDI2 (DWtype a) { - DWtype w = a; + DWtype w = a; - if (a < 0) -#ifdef L_negvsi2 - w = __negvsi2 (a); + if (a < 0) +#ifdef L_negvdi2 + w = __negvDI2 (a); #else - w = -a; + w = -a; - if (w < 0) - abort (); + if (w < 0) + abort (); #endif - return w; + return w; } #endif #ifdef L_mulvdi3 DWtype -__mulvdi3 (DWtype u, DWtype v) +__mulvDI3 (DWtype u, DWtype v) { - DWtype w; + /* The unchecked multiplication needs 3 Wtype x Wtype multiplications, + but the checked multiplication needs only two. */ + const DWunion uu = {.ll = u}; + const DWunion vv = {.ll = v}; - w = u * v; + if (__builtin_expect (uu.s.high == uu.s.low >> (W_TYPE_SIZE - 1), 1)) + { + /* u fits in a single Wtype. */ + if (__builtin_expect (vv.s.high == vv.s.low >> (W_TYPE_SIZE - 1), 1)) + { + /* v fits in a single Wtype as well. */ + /* A single multiplication. No overflow risk. */ + return (DWtype) uu.s.low * (DWtype) vv.s.low; + } + else + { + /* Two multiplications. */ + DWunion w0 = {.ll = (UDWtype) (UWtype) uu.s.low + * (UDWtype) (UWtype) vv.s.low}; + DWunion w1 = {.ll = (UDWtype) (UWtype) uu.s.low + * (UDWtype) (UWtype) vv.s.high}; + + if (vv.s.high < 0) + w1.s.high -= uu.s.low; + if (uu.s.low < 0) + w1.ll -= vv.ll; + w1.ll += (UWtype) w0.s.high; + if (__builtin_expect (w1.s.high == w1.s.low >> (W_TYPE_SIZE - 1), 1)) + { + w0.s.high = w1.s.low; + return w0.ll; + } + } + } + else + { + if (__builtin_expect (vv.s.high == vv.s.low >> (W_TYPE_SIZE - 1), 1)) + { + /* v fits into a single Wtype. */ + /* Two multiplications. */ + DWunion w0 = {.ll = (UDWtype) (UWtype) uu.s.low + * (UDWtype) (UWtype) vv.s.low}; + DWunion w1 = {.ll = (UDWtype) (UWtype) uu.s.high + * (UDWtype) (UWtype) vv.s.low}; + + if (uu.s.high < 0) + w1.s.high -= vv.s.low; + if (vv.s.low < 0) + w1.ll -= uu.ll; + w1.ll += (UWtype) w0.s.high; + if (__builtin_expect (w1.s.high == w1.s.low >> (W_TYPE_SIZE - 1), 1)) + { + w0.s.high = w1.s.low; + return w0.ll; + } + } + else + { + /* A few sign checks and a single multiplication. */ + if (uu.s.high >= 0) + { + if (vv.s.high >= 0) + { + if (uu.s.high == 0 && vv.s.high == 0) + { + const DWtype w = (UDWtype) (UWtype) uu.s.low + * (UDWtype) (UWtype) vv.s.low; + if (__builtin_expect (w >= 0, 1)) + return w; + } + } + else + { + if (uu.s.high == 0 && vv.s.high == (Wtype) -1) + { + DWunion ww = {.ll = (UDWtype) (UWtype) uu.s.low + * (UDWtype) (UWtype) vv.s.low}; - if (((u >= 0) == (v >= 0)) ? w < 0 : w > 0) - abort (); + ww.s.high -= uu.s.low; + if (__builtin_expect (ww.s.high < 0, 1)) + return ww.ll; + } + } + } + else + { + if (vv.s.high >= 0) + { + if (uu.s.high == (Wtype) -1 && vv.s.high == 0) + { + DWunion ww = {.ll = (UDWtype) (UWtype) uu.s.low + * (UDWtype) (UWtype) vv.s.low}; - return w; + ww.s.high -= vv.s.low; + if (__builtin_expect (ww.s.high < 0, 1)) + return ww.ll; + } + } + else + { + if (uu.s.high == (Wtype) -1 && vv.s.high == (Wtype) - 1) + { + DWunion ww = {.ll = (UDWtype) (UWtype) uu.s.low + * (UDWtype) (UWtype) vv.s.low}; + + ww.s.high -= uu.s.low; + ww.s.high -= vv.s.low; + if (__builtin_expect (ww.s.high >= 0, 1)) + return ww.ll; + } + } + } + } + } + + /* Overflow. */ + abort (); } #endif -/* Unless shift functions are defined whith full ANSI prototypes, +/* Unless shift functions are defined with full ANSI prototypes, parameter b will be promoted to int if word_type is smaller than an int. */ #ifdef L_lshrdi3 DWtype __lshrdi3 (DWtype u, word_type b) { - DWunion w; - word_type bm; - DWunion uu; - if (b == 0) return u; - uu.ll = u; + const DWunion uu = {.ll = u}; + const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b; + DWunion w; - bm = (sizeof (Wtype) * BITS_PER_UNIT) - b; if (bm <= 0) { w.s.high = 0; @@ -256,7 +403,7 @@ __lshrdi3 (DWtype u, word_type b) } else { - UWtype carries = (UWtype) uu.s.high << bm; + const UWtype carries = (UWtype) uu.s.high << bm; w.s.high = (UWtype) uu.s.high >> b; w.s.low = ((UWtype) uu.s.low >> b) | carries; @@ -270,16 +417,13 @@ __lshrdi3 (DWtype u, word_type b) DWtype __ashldi3 (DWtype u, word_type b) { - DWunion w; - word_type bm; - DWunion uu; - if (b == 0) return u; - uu.ll = u; + const DWunion uu = {.ll = u}; + const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b; + DWunion w; - bm = (sizeof (Wtype) * BITS_PER_UNIT) - b; if (bm <= 0) { w.s.low = 0; @@ -287,7 +431,7 @@ __ashldi3 (DWtype u, word_type b) } else { - UWtype carries = (UWtype) uu.s.low >> bm; + const UWtype carries = (UWtype) uu.s.low >> bm; w.s.low = (UWtype) uu.s.low << b; w.s.high = ((UWtype) uu.s.high << b) | carries; @@ -301,16 +445,13 @@ __ashldi3 (DWtype u, word_type b) DWtype __ashrdi3 (DWtype u, word_type b) { - DWunion w; - word_type bm; - DWunion uu; - if (b == 0) return u; - uu.ll = u; + const DWunion uu = {.ll = u}; + const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b; + DWunion w; - bm = (sizeof (Wtype) * BITS_PER_UNIT) - b; if (bm <= 0) { /* w.s.high = 1..1 or 0..0 */ @@ -319,7 +460,7 @@ __ashrdi3 (DWtype u, word_type b) } else { - UWtype carries = (UWtype) uu.s.high << bm; + const UWtype carries = (UWtype) uu.s.high << bm; w.s.high = uu.s.high >> b; w.s.low = ((UWtype) uu.s.low >> b) | carries; @@ -329,14 +470,29 @@ __ashrdi3 (DWtype u, word_type b) } #endif +#ifdef L_ffssi2 +#undef int +int +__ffsSI2 (UWtype u) +{ + UWtype count; + + if (u == 0) + return 0; + + count_trailing_zeros (count, u); + return count + 1; +} +#endif + #ifdef L_ffsdi2 -DWtype -__ffsdi2 (DWtype u) +#undef int +int +__ffsDI2 (DWtype u) { - DWunion uu; + const DWunion uu = {.ll = u}; UWtype word, count, add; - uu.ll = u; if (uu.s.low != 0) word = uu.s.low, add = 0; else if (uu.s.high != 0) @@ -353,13 +509,10 @@ __ffsdi2 (DWtype u) DWtype __muldi3 (DWtype u, DWtype v) { - DWunion w; - DWunion uu, vv; + const DWunion uu = {.ll = u}; + const DWunion vv = {.ll = v}; + DWunion w = {.ll = __umulsidi3 (uu.s.low, vv.s.low)}; - uu.ll = u, - vv.ll = v; - - w.ll = __umulsidi3 (uu.s.low, vv.s.low); w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high + (UWtype) uu.s.high * (UWtype) vv.s.low); @@ -367,8 +520,19 @@ __muldi3 (DWtype u, DWtype v) } #endif +#if (defined (L_udivdi3) || defined (L_divdi3) || \ + defined (L_umoddi3) || defined (L_moddi3)) +#if defined (sdiv_qrnnd) +#define L_udiv_w_sdiv +#endif +#endif + #ifdef L_udiv_w_sdiv #if defined (sdiv_qrnnd) +#if (defined (L_udivdi3) || defined (L_divdi3) || \ + defined (L_umoddi3) || defined (L_moddi3)) +static inline __attribute__ ((__always_inline__)) +#endif UWtype __udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d) { @@ -379,16 +543,16 @@ __udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d) { if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1))) { - /* dividend, divisor, and quotient are nonnegative */ + /* Dividend, divisor, and quotient are nonnegative. */ sdiv_qrnnd (q, r, a1, a0, d); } else { - /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */ + /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d. */ sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1)); - /* Divide (c1*2^32 + c0) by d */ + /* Divide (c1*2^32 + c0) by d. */ sdiv_qrnnd (q, r, c1, c0, d); - /* Add 2^31 to quotient */ + /* Add 2^31 to quotient. */ q += (UWtype) 1 << (W_TYPE_SIZE - 1); } } @@ -496,26 +660,179 @@ 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, }; #endif + +#ifdef L_clzsi2 +#undef int +int +__clzSI2 (UWtype x) +{ + Wtype ret; + + count_leading_zeros (ret, x); + + return ret; +} +#endif + +#ifdef L_clzdi2 +#undef int +int +__clzDI2 (UDWtype x) +{ + const DWunion uu = {.ll = x}; + UWtype word; + Wtype ret, add; + + if (uu.s.high) + word = uu.s.high, add = 0; + else + word = uu.s.low, add = W_TYPE_SIZE; + + count_leading_zeros (ret, word); + return ret + add; +} +#endif + +#ifdef L_ctzsi2 +#undef int +int +__ctzSI2 (UWtype x) +{ + Wtype ret; + + count_trailing_zeros (ret, x); + + return ret; +} +#endif + +#ifdef L_ctzdi2 +#undef int +int +__ctzDI2 (UDWtype x) +{ + const DWunion uu = {.ll = x}; + UWtype word; + Wtype ret, add; + + if (uu.s.low) + word = uu.s.low, add = 0; + else + word = uu.s.high, add = W_TYPE_SIZE; + + count_trailing_zeros (ret, word); + return ret + add; +} +#endif + +#if (defined (L_popcountsi2) || defined (L_popcountdi2) \ + || defined (L_popcount_tab)) +extern const UQItype __popcount_tab[] ATTRIBUTE_HIDDEN; +#endif + +#ifdef L_popcount_tab +const UQItype __popcount_tab[] = +{ + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, +}; +#endif + +#ifdef L_popcountsi2 +#undef int +int +__popcountSI2 (UWtype x) +{ + UWtype i, ret = 0; + + for (i = 0; i < W_TYPE_SIZE; i += 8) + ret += __popcount_tab[(x >> i) & 0xff]; + + return ret; +} +#endif + +#ifdef L_popcountdi2 +#undef int +int +__popcountDI2 (UDWtype x) +{ + UWtype i, ret = 0; + + for (i = 0; i < 2*W_TYPE_SIZE; i += 8) + ret += __popcount_tab[(x >> i) & 0xff]; + + return ret; +} +#endif + +#ifdef L_paritysi2 +#undef int +int +__paritySI2 (UWtype x) +{ +#if W_TYPE_SIZE > 64 +# error "fill out the table" +#endif +#if W_TYPE_SIZE > 32 + x ^= x >> 32; +#endif +#if W_TYPE_SIZE > 16 + x ^= x >> 16; +#endif + x ^= x >> 8; + x ^= x >> 4; + x &= 0xf; + return (0x6996 >> x) & 1; +} +#endif + +#ifdef L_paritydi2 +#undef int +int +__parityDI2 (UDWtype x) +{ + const DWunion uu = {.ll = x}; + UWtype nx = uu.s.low ^ uu.s.high; + +#if W_TYPE_SIZE > 64 +# error "fill out the table" +#endif +#if W_TYPE_SIZE > 32 + nx ^= nx >> 32; +#endif +#if W_TYPE_SIZE > 16 + nx ^= nx >> 16; +#endif + nx ^= nx >> 8; + nx ^= nx >> 4; + nx &= 0xf; + return (0x6996 >> nx) & 1; +} +#endif #ifdef L_udivmoddi4 #if (defined (L_udivdi3) || defined (L_divdi3) || \ defined (L_umoddi3) || defined (L_moddi3)) -static inline +static inline __attribute__ ((__always_inline__)) #endif UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) { - DWunion ww; - DWunion nn, dd; + const DWunion nn = {.ll = n}; + const DWunion dd = {.ll = d}; DWunion rr; UWtype d0, d1, n0, n1, n2; UWtype q0, q1; UWtype b, bm; - nn.ll = n; - dd.ll = d; - d0 = dd.s.low; d1 = dd.s.high; n0 = nn.s.low; @@ -715,8 +1032,7 @@ __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) } } - ww.s.low = q0; - ww.s.high = q1; + const DWunion ww = {{.low = q0, .high = q1}}; return ww.ll; } #endif @@ -726,22 +1042,20 @@ DWtype __divdi3 (DWtype u, DWtype v) { word_type c = 0; - DWunion uu, vv; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; DWtype w; - uu.ll = u; - vv.ll = v; - if (uu.s.high < 0) c = ~c, - uu.ll = __negdi2 (uu.ll); + uu.ll = -uu.ll; if (vv.s.high < 0) c = ~c, - vv.ll = __negdi2 (vv.ll); + vv.ll = -vv.ll; w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); if (c) - w = __negdi2 (w); + w = -w; return w; } @@ -752,21 +1066,19 @@ DWtype __moddi3 (DWtype u, DWtype v) { word_type c = 0; - DWunion uu, vv; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; DWtype w; - uu.ll = u; - vv.ll = v; - if (uu.s.high < 0) c = ~c, - uu.ll = __negdi2 (uu.ll); + uu.ll = -uu.ll; if (vv.s.high < 0) - vv.ll = __negdi2 (vv.ll); + vv.ll = -vv.ll; - (void) __udivmoddi4 (uu.ll, vv.ll, &w); + (void) __udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&w); if (c) - w = __negdi2 (w); + w = -w; return w; } @@ -796,9 +1108,8 @@ __udivdi3 (UDWtype n, UDWtype d) word_type __cmpdi2 (DWtype a, DWtype b) { - DWunion au, bu; - - au.ll = a, bu.ll = b; + const DWunion au = {.ll = a}; + const DWunion bu = {.ll = b}; if (au.s.high < bu.s.high) return 0; @@ -816,9 +1127,8 @@ __cmpdi2 (DWtype a, DWtype b) word_type __ucmpdi2 (DWtype a, DWtype b) { - DWunion au, bu; - - au.ll = a, bu.ll = b; + const DWunion au = {.ll = a}; + const DWunion bu = {.ll = b}; if ((UWtype) au.s.high < (UWtype) bu.s.high) return 0; @@ -832,25 +1142,19 @@ __ucmpdi2 (DWtype a, DWtype b) } #endif -#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) - +#if defined(L_fixunstfdi) && LIBGCC2_HAS_TF_MODE DWtype __fixunstfDI (TFtype a) { - TFtype b; - UDWtype v; - if (a < 0) return 0; /* Compute high word of result, as a flonum. */ - b = (a / HIGH_WORD_COEFF); + const TFtype b = (a / Wtype_MAXp1_F); /* Convert that to fixed (but not to DWtype!), and shift it into the high word. */ - v = (UWtype) b; - v <<= WORD_SIZE; + UDWtype v = (UWtype) b; + v <<= W_TYPE_SIZE; /* Remove high part from the TFtype, leaving the low part as flonum. */ a -= (TFtype)v; /* Convert that to fixed (but not to DWtype!) and add it in. @@ -864,7 +1168,7 @@ __fixunstfDI (TFtype a) } #endif -#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128) +#if defined(L_fixtfdi) && LIBGCC2_HAS_TF_MODE DWtype __fixtfdi (TFtype a) { @@ -874,25 +1178,19 @@ __fixtfdi (TFtype a) } #endif -#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) - +#if defined(L_fixunsxfdi) && LIBGCC2_HAS_XF_MODE DWtype __fixunsxfDI (XFtype a) { - XFtype b; - UDWtype v; - if (a < 0) return 0; /* Compute high word of result, as a flonum. */ - b = (a / HIGH_WORD_COEFF); + const XFtype b = (a / Wtype_MAXp1_F); /* Convert that to fixed (but not to DWtype!), and shift it into the high word. */ - v = (UWtype) b; - v <<= WORD_SIZE; + UDWtype v = (UWtype) b; + v <<= W_TYPE_SIZE; /* Remove high part from the XFtype, leaving the low part as flonum. */ a -= (XFtype)v; /* Convert that to fixed (but not to DWtype!) and add it in. @@ -906,7 +1204,7 @@ __fixunsxfDI (XFtype a) } #endif -#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96) +#if defined(L_fixxfdi) && LIBGCC2_HAS_XF_MODE DWtype __fixxfdi (XFtype a) { @@ -916,39 +1214,26 @@ __fixxfdi (XFtype a) } #endif -#ifdef L_fixunsdfdi -#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) -#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) - +#if defined(L_fixunsdfdi) && LIBGCC2_HAS_DF_MODE DWtype __fixunsdfDI (DFtype a) { - DFtype b; - UDWtype v; + /* Get high part of result. The division here will just moves the radix + point and will not cause any rounding. Then the conversion to integral + type chops result as desired. */ + const UWtype hi = a / Wtype_MAXp1_F; - if (a < 0) - return 0; + /* Get low part of result. Convert `hi' to floating type and scale it back, + then subtract this from the number being converted. This leaves the low + part. Convert that to integral type. */ + const UWtype lo = a - (DFtype) hi * Wtype_MAXp1_F; - /* Compute high word of result, as a flonum. */ - b = (a / HIGH_WORD_COEFF); - /* Convert that to fixed (but not to DWtype!), - and shift it into the high word. */ - 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 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 -= (UWtype) (- a); - else - v += (UWtype) a; - return v; + /* Assemble result from the two parts. */ + return ((UDWtype) hi << W_TYPE_SIZE) | lo; } #endif -#ifdef L_fixdfdi +#if defined(L_fixdfdi) && LIBGCC2_HAS_DF_MODE DWtype __fixdfdi (DFtype a) { @@ -958,43 +1243,71 @@ __fixdfdi (DFtype a) } #endif -#ifdef L_fixunssfdi -#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) -#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) - +#if defined(L_fixunssfdi) && LIBGCC2_HAS_SF_MODE DWtype -__fixunssfDI (SFtype original_a) +__fixunssfDI (SFtype a) { +#if LIBGCC2_HAS_DF_MODE /* 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; - UDWtype v; - - if (a < 0) + const DFtype dfa = a; + + /* Get high part of result. The division here will just moves the radix + point and will not cause any rounding. Then the conversion to integral + type chops result as desired. */ + const UWtype hi = dfa / Wtype_MAXp1_F; + + /* Get low part of result. Convert `hi' to floating type and scale it back, + then subtract this from the number being converted. This leaves the low + part. Convert that to integral type. */ + const UWtype lo = dfa - (DFtype) hi * Wtype_MAXp1_F; + + /* Assemble result from the two parts. */ + return ((UDWtype) hi << W_TYPE_SIZE) | lo; +#elif FLT_MANT_DIG < W_TYPE_SIZE + if (a < 1) return 0; + if (a < Wtype_MAXp1_F) + return (UWtype)a; + if (a < Wtype_MAXp1_F * Wtype_MAXp1_F) + { + /* Since we know that there are fewer significant bits in the SFmode + quantity than in a word, we know that we can convert out all the + significant bits in one step, and thus avoid losing bits. */ - /* Compute high word of result, as a flonum. */ - b = (a / HIGH_WORD_COEFF); - /* Convert that to fixed (but not to DWtype!), - and shift it into the high word. */ - 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 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 -= (UWtype) (- a); - else - v += (UWtype) a; - return v; + /* ??? This following loop essentially performs frexpf. If we could + use the real libm function, or poke at the actual bits of the fp + format, it would be significantly faster. */ + + UWtype shift = 0, counter; + SFtype msb; + + a /= Wtype_MAXp1_F; + for (counter = W_TYPE_SIZE / 2; counter != 0; counter >>= 1) + { + SFtype counterf = (UWtype)1 << counter; + if (a >= counterf) + { + shift |= counter; + a /= counterf; + } + } + + /* Rescale into the range of one word, extract the bits of that + one word, and shift the result into position. */ + a *= Wtype_MAXp1_F; + counter = a; + return (DWtype)counter << shift; + } + return -1; +#else +# error +#endif } #endif -#ifdef L_fixsfdi +#if defined(L_fixsfdi) && LIBGCC2_HAS_SF_MODE DWtype __fixsfdi (SFtype a) { @@ -1004,132 +1317,128 @@ __fixsfdi (SFtype a) } #endif -#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) - +#if defined(L_floatdixf) && LIBGCC2_HAS_XF_MODE XFtype __floatdixf (DWtype u) { - XFtype d; - - d = (Wtype) (u >> WORD_SIZE); - d *= HIGH_HALFWORD_COEFF; - d *= HIGH_HALFWORD_COEFF; - d += (UWtype) (u & (HIGH_WORD_COEFF - 1)); - + XFtype d = (Wtype) (u >> W_TYPE_SIZE); + d *= Wtype_MAXp1_F; + d += (UWtype)u; return d; } #endif -#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) - +#if defined(L_floatditf) && LIBGCC2_HAS_TF_MODE TFtype __floatditf (DWtype u) { - TFtype d; - - d = (Wtype) (u >> WORD_SIZE); - d *= HIGH_HALFWORD_COEFF; - d *= HIGH_HALFWORD_COEFF; - d += (UWtype) (u & (HIGH_WORD_COEFF - 1)); - + TFtype d = (Wtype) (u >> W_TYPE_SIZE); + d *= Wtype_MAXp1_F; + d += (UWtype)u; return d; } #endif -#ifdef L_floatdidf -#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) - +#if defined(L_floatdidf) && LIBGCC2_HAS_DF_MODE DFtype __floatdidf (DWtype u) { - DFtype d; - - d = (Wtype) (u >> WORD_SIZE); - d *= HIGH_HALFWORD_COEFF; - d *= HIGH_HALFWORD_COEFF; - d += (UWtype) (u & (HIGH_WORD_COEFF - 1)); - + DFtype d = (Wtype) (u >> W_TYPE_SIZE); + d *= Wtype_MAXp1_F; + d += (UWtype)u; return d; } #endif -#ifdef L_floatdisf -#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) -#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2)) -#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) -#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT) - -/* Define codes for all the float formats that we know of. Note - that this is copied from real.h. */ - -#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 +#if defined(L_floatdisf) && LIBGCC2_HAS_SF_MODE +#define DI_SIZE (W_TYPE_SIZE * 2) +#define SF_SIZE FLT_MANT_DIG SFtype __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; +#if SF_SIZE >= W_TYPE_SIZE + /* When the word size is small, we never get any rounding error. */ + SFtype f = (Wtype) (u >> W_TYPE_SIZE); + f *= Wtype_MAXp1_F; + f += (UWtype)u; + return f; +#elif LIBGCC2_HAS_DF_MODE + +#if LIBGCC2_DOUBLE_TYPE_SIZE == 64 +#define DF_SIZE DBL_MANT_DIG +#elif LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 64 +#define DF_SIZE LDBL_MANT_DIG +#else +# error +#endif + +#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE)) /* Protect against double-rounding error. - Represent any low-order bits, that might be truncated in DFmode, - by a bit that won't be lost. The bit can go in anywhere below the - rounding position of the SFmode. A fixed mask and bit position - handles all usual configurations. It doesn't handle the case - of 128-bit DImode, however. */ + Represent any low-order bits, that might be truncated by a bit that + won't be lost. The bit can go in anywhere below the rounding position + of the SFmode. A fixed mask and bit position handles all usual + configurations. It doesn't handle the case of 128-bit DImode, however. */ if (DF_SIZE < DI_SIZE && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE)) { -#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE)) if (! (- ((DWtype) 1 << DF_SIZE) < u && u < ((DWtype) 1 << DF_SIZE))) { if ((UDWtype) u & (REP_BIT - 1)) - u |= REP_BIT; + { + u &= ~ (REP_BIT - 1); + u |= REP_BIT; + } } } - f = (Wtype) (u >> WORD_SIZE); - f *= HIGH_HALFWORD_COEFF; - f *= HIGH_HALFWORD_COEFF; - f += (UWtype) (u & (HIGH_WORD_COEFF - 1)); + /* Do the calculation in DFmode so that we don't lose any of the + precision of the high word while multiplying it. */ + DFtype f = (Wtype) (u >> W_TYPE_SIZE); + f *= Wtype_MAXp1_F; + f += (UWtype)u; return (SFtype) f; +#else + /* Finally, the word size is larger than the number of bits in SFmode, + and we've got no DFmode. The only way to avoid double rounding is + to special case the extraction. */ + + /* If there are no high bits set, fall back to one conversion. */ + if ((Wtype)u == u) + return (SFtype)(Wtype)u; + + /* Otherwise, find the power of two. */ + Wtype hi = u >> W_TYPE_SIZE; + if (hi < 0) + hi = -hi; + + UWtype count, shift; + count_leading_zeros (count, hi); + + /* No leading bits means u == minimum. */ + if (count == 0) + return -(Wtype_MAXp1_F * Wtype_MAXp1_F / 2); + + shift = W_TYPE_SIZE - count; + + /* Shift down the most significant bits. */ + hi = u >> shift; + + /* If we lost any nonzero bits, set the lsb to ensure correct rounding. */ + if (u & ((1 << shift) - 1)) + hi |= 1; + + /* Convert the one word of data, and rescale. */ + SFtype f = hi; + f *= (UWtype)1 << shift; + return f; +#endif } #endif -#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96 +#if defined(L_fixunsxfsi) && LIBGCC2_HAS_XF_MODE /* Reenable the normal types, in case limits.h needs them. */ #undef char #undef short @@ -1151,7 +1460,7 @@ __fixunsxfSI (XFtype a) } #endif -#ifdef L_fixunsdfsi +#if defined(L_fixunsdfsi) && LIBGCC2_HAS_DF_MODE /* Reenable the normal types, in case limits.h needs them. */ #undef char #undef short @@ -1173,7 +1482,7 @@ __fixunsdfSI (DFtype a) } #endif -#ifdef L_fixunssfsi +#if defined(L_fixunssfsi) && LIBGCC2_HAS_SF_MODE /* Reenable the normal types, in case limits.h needs them. */ #undef char #undef short @@ -1195,1286 +1504,346 @@ __fixunssfSI (SFtype a) } #endif -/* From here on down, the routines use normal data types. */ - -#define SItype bogus_type -#define USItype bogus_type -#define DItype bogus_type -#define UDItype bogus_type -#define SFtype bogus_type -#define DFtype bogus_type -#undef Wtype -#undef UWtype -#undef HWtype -#undef UHWtype -#undef DWtype -#undef UDWtype +/* Integer power helper used from __builtin_powi for non-constant + exponents. */ + +#if (defined(L_powisf2) && LIBGCC2_HAS_SF_MODE) \ + || (defined(L_powidf2) && LIBGCC2_HAS_DF_MODE) \ + || (defined(L_powixf2) && LIBGCC2_HAS_XF_MODE) \ + || (defined(L_powitf2) && LIBGCC2_HAS_TF_MODE) +# if defined(L_powisf2) +# define TYPE SFtype +# define NAME __powisf2 +# elif defined(L_powidf2) +# define TYPE DFtype +# define NAME __powidf2 +# elif defined(L_powixf2) +# define TYPE XFtype +# define NAME __powixf2 +# elif defined(L_powitf2) +# define TYPE TFtype +# define NAME __powitf2 +# endif -#undef char -#undef short #undef int -#undef long #undef unsigned -#undef float -#undef double - -#ifdef L__gcc_bcmp - -/* Like bcmp except the sign is meaningful. - Result is negative if S1 is less than S2, - positive if S1 is greater, 0 if S1 and S2 are equal. */ - -int -__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size) +TYPE +NAME (TYPE x, int m) { - while (size > 0) + unsigned int n = m < 0 ? -m : m; + TYPE y = n % 2 ? x : 1; + while (n >>= 1) { - unsigned char c1 = *s1++, c2 = *s2++; - if (c1 != c2) - return c1 - c2; - size--; + x = x * x; + if (n % 2) + y = y * x; } - return 0; + return m < 0 ? 1/y : y; } #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 - -void -__eprintf (const char *string, const char *expression, - unsigned int line, const char *filename) -{ - fprintf (stderr, string, expression, line, filename); - fflush (stderr); - abort (); -} - -#endif -#endif - -#ifdef L_bb - -#if LONG_TYPE_SIZE == GCOV_TYPE_SIZE -typedef long gcov_type; -#else -typedef long long gcov_type; -#endif - - -/* Structure emitted by -a */ -struct bb -{ - long zero_word; - const char *filename; - 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; -}; - -#ifdef BLOCK_PROFILER_CODE -BLOCK_PROFILER_CODE -#else -#ifndef inhibit_libc - -/* Simple minded basic block profiling output dumper for - systems that don't provide tcov support. At present, - it requires atexit and stdio. */ - -#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ -#include -char *ctime PARAMS ((const time_t *)); - -#include "gbl-ctors.h" -#include "gcov-io.h" -#include -#ifdef TARGET_HAS_F_SETLKW -#include -#include -#endif - -static struct bb *bb_head; - -static int num_digits (long value, int base) __attribute__ ((const)); - -/* Return the number of digits needed to print a value */ -/* __inline__ */ static int num_digits (long value, int base) -{ - int minus = (value < 0 && base != 16); - unsigned long v = (minus) ? -value : value; - int ret = minus; - - do - { - v /= base; - ret++; - } - while (v); - - return ret; -} - -void -__bb_exit_func (void) -{ - FILE *da_file, *file; - long time_value; - int i; - - if (bb_head == 0) - return; - - i = strlen (bb_head->filename) - 3; - - if (!strcmp (bb_head->filename+i, ".da")) - { - /* Must be -fprofile-arcs not -a. - Dump data in a form that gcov expects. */ - - struct bb *ptr; - - for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) - { - int firstchar; - - /* Make sure the output file exists - - but don't clobber exiting data. */ - if ((da_file = fopen (ptr->filename, "a")) != 0) - fclose (da_file); - - /* Need to re-open in order to be able to write from the start. */ - da_file = fopen (ptr->filename, "r+b"); - /* Some old systems might not allow the 'b' mode modifier. - Therefore, try to open without it. This can lead to a race - condition so that when you delete and re-create the file, the - file might be opened in text mode, but then, you shouldn't - delete the file in the first place. */ - if (da_file == 0) - da_file = fopen (ptr->filename, "r+"); - if (da_file == 0) - { - fprintf (stderr, "arc profiling: Can't open output file %s.\n", - ptr->filename); - continue; - } - - /* After a fork, another process might try to read and/or write - the same file simultanously. So if we can, lock the file to - avoid race conditions. */ -#if defined (TARGET_HAS_F_SETLKW) - { - struct flock s_flock; - - s_flock.l_type = F_WRLCK; - s_flock.l_whence = SEEK_SET; - s_flock.l_start = 0; - s_flock.l_len = 1; - s_flock.l_pid = getpid (); - - while (fcntl (fileno (da_file), F_SETLKW, &s_flock) - && errno == EINTR); - } -#endif - - /* If the file is not empty, and the number of counts in it is the - same, then merge them in. */ - firstchar = fgetc (da_file); - if (firstchar == EOF) - { - if (ferror (da_file)) - { - fprintf (stderr, "arc profiling: Can't read output file "); - perror (ptr->filename); - } - } - else - { - long n_counts = 0; - - if (ungetc (firstchar, da_file) == EOF) - rewind (da_file); - if (__read_long (&n_counts, da_file, 8) != 0) - { - fprintf (stderr, "arc profiling: Can't read output file %s.\n", - ptr->filename); - continue; - } - - if (n_counts == ptr->ncounts) - { - int i; - - for (i = 0; i < n_counts; i++) - { - gcov_type v = 0; - - if (__read_gcov_type (&v, da_file, 8) != 0) - { - fprintf (stderr, "arc profiling: Can't read output file %s.\n", - ptr->filename); - break; - } - ptr->counts[i] += v; - } - } +#if ((defined(L_mulsc3) || defined(L_divsc3)) && LIBGCC2_HAS_SF_MODE) \ + || ((defined(L_muldc3) || defined(L_divdc3)) && LIBGCC2_HAS_DF_MODE) \ + || ((defined(L_mulxc3) || defined(L_divxc3)) && LIBGCC2_HAS_XF_MODE) \ + || ((defined(L_multc3) || defined(L_divtc3)) && LIBGCC2_HAS_TF_MODE) - } - - rewind (da_file); - - /* ??? Should first write a header to the file. Preferably, a 4 byte - magic number, 4 bytes containing the time the program was - compiled, 4 bytes containing the last modification time of the - source file, and 4 bytes indicating the compiler options used. - - That way we can easily verify that the proper source/executable/ - data file combination is being used from gcov. */ - - if (__write_gcov_type (ptr->ncounts, da_file, 8) != 0) - { - - fprintf (stderr, "arc profiling: Error writing output file %s.\n", - ptr->filename); - } - else - { - int j; - gcov_type *count_ptr = ptr->counts; - int ret = 0; - for (j = ptr->ncounts; j > 0; j--) - { - if (__write_gcov_type (*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); - } - - return; - } - - /* Must be basic block profiling. Emit a human readable output file. */ - - file = fopen ("bb.out", "a"); - - if (!file) - perror ("bb.out"); - - else - { - struct bb *ptr; - - /* 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 profiling finished on %s\n", ctime ((void *) &time_value)); - - /* We check the length field explicitly in order to allow compatibility - with older GCC's which did not provide it. */ - - for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) - { - int i; - int func_p = (ptr->nwords >= (long) 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]; - - if (addr_p && (unsigned long) addr_max < ptr->addresses[i]) - addr_max = ptr->addresses[i]; - - if (line_p && line_max < ptr->line_nums[i]) - line_max = ptr->line_nums[i]; - - if (func_p) - { - p = (ptr->functions[i]) ? (ptr->functions[i]) : ""; - len = strlen (p); - if (func_len < len) - func_len = len; - } - - if (file_p) - { - p = (ptr->filenames[i]) ? (ptr->filenames[i]) : ""; - len = strlen (p); - if (file_len < len) - file_len = len; - } - } - - 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 (file_p) - fprintf (file, " file= %s", - (ptr->filenames[i]) ? ptr->filenames[i] : ""); - - fprintf (file, "\n"); - } - - fprintf (file, "\n"); - fflush (file); - } - - fprintf (file, "\n\n"); - fclose (file); - } -} - -void -__bb_init_func (struct bb *blocks) -{ - /* User is supposed to check whether the first word is non-0, - but just in case.... */ - - if (blocks->zero_word) - return; - - /* Initialize destructor. */ - if (!bb_head) - atexit (__bb_exit_func); - - /* Set up linked list. */ - blocks->zero_word = 1; - blocks->next = bb_head; - bb_head = blocks; -} - -/* Called before fork or exec - write out profile information gathered so - far and reset it to zero. This avoids duplication or loss of the - profile information gathered so far. */ -void -__bb_fork_func (void) -{ - struct bb *ptr; - - __bb_exit_func (); - for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) - { - long i; - for (i = ptr->ncounts - 1; i >= 0; i--) - ptr->counts[i] = 0; - } -} - -#ifndef MACHINE_STATE_SAVE -#define MACHINE_STATE_SAVE(ID) -#endif -#ifndef MACHINE_STATE_RESTORE -#define MACHINE_STATE_RESTORE(ID) -#endif - -/* Number of buckets in hashtable of basic block addresses. */ - -#define BB_BUCKETS 311 - -/* Maximum length of string in file bb.in. */ - -#define BBINBUFSIZE 500 - -struct bb_edge -{ - struct bb_edge *next; - unsigned long src_addr; - unsigned long dst_addr; - unsigned long count; -}; - -enum bb_func_mode -{ - TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2 -}; - -struct bb_func -{ - 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. */ - -struct { - unsigned long blockno; - struct bb *blocks; -} __bb; - -/* Vars to store addrs of source and destination basic blocks - of a jump. */ - -static unsigned long bb_src = 0; -static unsigned long bb_dst = 0; - -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; - -static unsigned long *bb_stack = (unsigned long *) 0; -static size_t bb_stacksize = 0; - -static int reported = 0; - -/* 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 (void) -{ - FILE *file = fopen ("bb.out", "a"); - struct bb_func *f; - 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 %*lu 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 (void) -{ - FILE *file; - char buf[BBINBUFSIZE]; - const char *p; - const char *pos; - enum bb_func_mode m; - int i; - - /* Initialize destructor. */ - atexit (__bb_exit_func); - - if (!(file = fopen ("bb.in", "r"))) - return; - - while(fgets (buf, BBINBUFSIZE, file) != 0) - { - i = strlen (buf); - if (buf[i] == '\n') - buf[i--] = '\0'; - - 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) - /* Use a loop here rather than calling bzero to avoid having to - conditionalize its existance. */ - for (i = 0; i < BB_BUCKETS; i++) - bb_hashbuckets[i] = 0; - } - - if (bb_mode & 12) - { - bb_stacksize = 10; - bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack)); - } - - /* Initialize destructor. */ - atexit (__bb_exit_trace_func); -} - -/* Called upon entering a basic block. */ - -void -__bb_trace_func (void) -{ - 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") +#undef float +#undef double +#undef long -} +#if defined(L_mulsc3) || defined(L_divsc3) +# define MTYPE SFtype +# define CTYPE SCtype +# define MODE sc +# define CEXT f +# define NOTRUNC __FLT_EVAL_METHOD__ == 0 +#elif defined(L_muldc3) || defined(L_divdc3) +# define MTYPE DFtype +# define CTYPE DCtype +# define MODE dc +# if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 64 +# define CEXT l +# define NOTRUNC 1 +# else +# define CEXT +# define NOTRUNC __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1 +# endif +#elif defined(L_mulxc3) || defined(L_divxc3) +# define MTYPE XFtype +# define CTYPE XCtype +# define MODE xc +# define CEXT l +# define NOTRUNC 1 +#elif defined(L_multc3) || defined(L_divtc3) +# define MTYPE TFtype +# define CTYPE TCtype +# define MODE tc +# define CEXT l +# define NOTRUNC 1 +#else +# error +#endif -/* Called when returning from a function and `__bb_showret__' is set. */ +#define CONCAT3(A,B,C) _CONCAT3(A,B,C) +#define _CONCAT3(A,B,C) A##B##C -static void -__bb_trace_func_ret (void) -{ - struct bb_edge *bucket; +#define CONCAT2(A,B) _CONCAT2(A,B) +#define _CONCAT2(A,B) A##B - if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF))) - goto skip; +/* All of these would be present in a full C99 implementation of + and . Our problem is that only a few systems have such full + implementations. Further, libgcc_s.so isn't currently linked against + libm.so, and even for systems that do provide full C99, the extra overhead + of all programs using libgcc having to link against libm. So avoid it. */ - 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; - } - } +#define isnan(x) __builtin_expect ((x) != (x), 0) +#define isfinite(x) __builtin_expect (!isnan((x) - (x)), 1) +#define isinf(x) __builtin_expect (!isnan(x) & !isfinite(x), 0) - else - { - bucket->src_addr = bb_dst; - bucket->dst_addr = bb_src; - bucket->next = *startbucket; - *startbucket = bucket; - bucket->count = 1; - } - } +#define INFINITY CONCAT2(__builtin_inf, CEXT) () +#define I 1i -ret: - bb_dst = bb_src; +/* Helpers to make the following code slightly less gross. */ +#define COPYSIGN CONCAT2(__builtin_copysign, CEXT) +#define FABS CONCAT2(__builtin_fabs, CEXT) -skip: - ; +/* Verify that MTYPE matches up with CEXT. */ +extern void *compile_type_assert[sizeof(INFINITY) == sizeof(MTYPE) ? 1 : -1]; -} +/* Ensure that we've lost any extra precision. */ +#if NOTRUNC +# define TRUNC(x) +#else +# define TRUNC(x) __asm__ ("" : "=m"(x) : "m"(x)) +#endif -/* Called upon entering the first function of a file. */ +#if defined(L_mulsc3) || defined(L_muldc3) \ + || defined(L_mulxc3) || defined(L_multc3) -static void -__bb_init_file (struct bb *blocks) +CTYPE +CONCAT3(__mul,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d) { + MTYPE ac, bd, ad, bc, x, y; - const struct bb_func *p; - long blk, ncounts = blocks->ncounts; - const char **functions = blocks->functions; + ac = a * c; + bd = b * d; + ad = a * d; + bc = b * c; - /* Set up linked list. */ - blocks->zero_word = 1; - blocks->next = bb_head; - bb_head = blocks; + TRUNC (ac); + TRUNC (bd); + TRUNC (ad); + TRUNC (bc); - blocks->flags = 0; - if (!bb_func_head - || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts))) - return; + x = ac - bd; + y = ad + bc; - for (blk = 0; blk < ncounts; blk++) - blocks->flags[blk] = 0; - - for (blk = 0; blk < ncounts; blk++) + if (isnan (x) && isnan (y)) { - 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; - } - } + /* Recover infinities that computed as NaN + iNaN. */ + _Bool recalc = 0; + if (isinf (a) || isinf (b)) + { + /* z is infinite. "Box" the infinity and change NaNs in + the other factor to 0. */ + a = COPYSIGN (isinf (a) ? 1 : 0, a); + b = COPYSIGN (isinf (b) ? 1 : 0, b); + if (isnan (c)) c = COPYSIGN (0, c); + if (isnan (d)) d = COPYSIGN (0, d); + recalc = 1; + } + if (isinf (c) || isinf (d)) + { + /* w is infinite. "Box" the infinity and change NaNs in + the other factor to 0. */ + c = COPYSIGN (isinf (c) ? 1 : 0, c); + d = COPYSIGN (isinf (d) ? 1 : 0, d); + if (isnan (a)) a = COPYSIGN (0, a); + if (isnan (b)) b = COPYSIGN (0, b); + recalc = 1; + } + if (!recalc + && (isinf (ac) || isinf (bd) + || isinf (ad) || isinf (bc))) + { + /* Recover infinities from overflow by changing NaNs to 0. */ + if (isnan (a)) a = COPYSIGN (0, a); + if (isnan (b)) b = COPYSIGN (0, b); + if (isnan (c)) c = COPYSIGN (0, c); + if (isnan (d)) d = COPYSIGN (0, d); + recalc = 1; + } + if (recalc) + { + x = INFINITY * (a * c - b * d); + y = INFINITY * (a * d + b * c); + } } + return x + I * y; } +#endif /* complex multiply */ -/* Called when exiting from a function. */ +#if defined(L_divsc3) || defined(L_divdc3) \ + || defined(L_divxc3) || defined(L_divtc3) -void -__bb_trace_ret (void) +CTYPE +CONCAT3(__div,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d) { + MTYPE denom, ratio, x, y; - MACHINE_STATE_SAVE("2") - - if (bb_callcount) + /* ??? We can get better behavior from logarithmic scaling instead of + the division. But that would mean starting to link libgcc against + libm. We could implement something akin to ldexp/frexp as gcc builtins + fairly easily... */ + if (FABS (c) < FABS (d)) { - 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; + ratio = c / d; + denom = (c * ratio) + d; + x = ((a * ratio) + b) / denom; + y = ((b * ratio) - a) / denom; } - - 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); + else + { + ratio = d / c; + denom = (d * ratio) + c; + x = ((b * ratio) + a) / denom; + y = (b - (a * ratio)) / denom; } - if (bb_callcount) + /* Recover infinities and zeros that computed as NaN+iNaN; the only cases + are nonzero/zero, infinite/finite, and finite/infinite. */ + if (isnan (x) && isnan (y)) { + if (denom == 0.0 && (!isnan (a) || !isnan (b))) + { + x = COPYSIGN (INFINITY, c) * a; + y = COPYSIGN (INFINITY, c) * b; + } + else if ((isinf (a) || isinf (b)) && isfinite (c) && isfinite (d)) + { + a = COPYSIGN (isinf (a) ? 1 : 0, a); + b = COPYSIGN (isinf (b) ? 1 : 0, b); + x = INFINITY * (a * c + b * d); + y = INFINITY * (b * c - a * d); + } + else if ((isinf (c) || isinf (d)) && isfinite (a) && isfinite (b)) + { + c = COPYSIGN (isinf (c) ? 1 : 0, c); + d = COPYSIGN (isinf (d) ? 1 : 0, d); + x = 0.0 * (a * c + b * d); + y = 0.0 * (b * c - a * d); + } + } - bb_callcount += 1; - - if (bb_mode & 12) - { - if (bb_callcount >= bb_stacksize) - { - size_t newsize = bb_callcount + 100; + return x + I * y; +} +#endif /* complex divide */ - 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; +#endif /* all complex float routines */ + +/* From here on down, the routines use normal data types. */ - if (bb_mode & 4) - bb_src = 0; +#define SItype bogus_type +#define USItype bogus_type +#define DItype bogus_type +#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 +#undef int +#undef long +#undef unsigned +#undef float +#undef double + +#ifdef L__gcc_bcmp -stack_overflow:; +/* Like bcmp except the sign is meaningful. + Result is negative if S1 is less than S2, + positive if S1 is greater, 0 if S1 and S2 are equal. */ +int +__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size) +{ + while (size > 0) + { + const unsigned char c1 = *s1++, c2 = *s2++; + if (c1 != c2) + return c1 - c2; + size--; } + return 0; +} - else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON)) - { - bb_callcount = 1; - bb_src = 0; +#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 - if (bb_stack) - bb_stack[bb_callcount] = bb_src; - } +#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ +#include - MACHINE_STATE_RESTORE("3") +void +__eprintf (const char *string, const char *expression, + unsigned int line, const char *filename) +{ + fprintf (stderr, string, expression, line, filename); + fflush (stderr); + abort (); } -#endif /* not inhibit_libc */ -#endif /* not BLOCK_PROFILER_CODE */ -#endif /* L_bb */ +#endif +#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 __attribute__((__unused__)), char *end __attribute__((__unused__))) { -#ifdef CLEAR_INSN_CACHE +#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); - -#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16 - /* It's cheaper to clear the whole cache. - Put in a series of jump instructions so that calling the beginning - of the cache will clear the whole thing. */ - - if (! initialized) - { - int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH); - int end_ptr = ptr + INSN_CACHE_SIZE; - - while (ptr < end_ptr) - { - *(INSTRUCTION_TYPE *)ptr - = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH; - ptr += INSN_CACHE_LINE_WIDTH; - } - *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION; - - initialized = 1; - } - - /* Call the beginning of the sequence. */ - (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH)) - ()); - -#else /* Cache is large. */ - - if (! initialized) - { - int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH); - - while (ptr < (int) array + sizeof array) - { - *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION; - ptr += INSN_CACHE_LINE_WIDTH; - } - - initialized = 1; - } - - /* Find the location in array that occupies the same cache line as BEG. */ - - offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1); - start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1) - & -INSN_CACHE_PLANE_SIZE) - + offset); - - /* Compute the cache alignment of the place to stop clearing. */ -#if 0 /* This is not needed for gcc's purposes. */ - /* If the block to clear is bigger than a cache plane, - we clear the entire cache, and OFFSET is already correct. */ - if (end < beg + INSN_CACHE_PLANE_SIZE) -#endif - offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1) - & -INSN_CACHE_LINE_WIDTH) - & (INSN_CACHE_PLANE_SIZE - 1)); - -#if INSN_CACHE_DEPTH > 1 - end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset; - if (end_addr <= start_addr) - end_addr += INSN_CACHE_PLANE_SIZE; - - for (plane = 0; plane < INSN_CACHE_DEPTH; plane++) - { - int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE; - int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE; - - while (addr != stop) - { - /* Call the return instruction at ADDR. */ - ((function_ptr) addr) (); - - addr += INSN_CACHE_LINE_WIDTH; - } - } -#else /* just one plane */ - do - { - /* Call the return instruction at START_ADDR. */ - ((function_ptr) start_addr) (); - - start_addr += INSN_CACHE_LINE_WIDTH; - } - while ((start_addr % INSN_CACHE_SIZE) != offset); -#endif /* just one plane */ -#endif /* Cache is large */ -#endif /* Cache exists */ #endif /* CLEAR_INSN_CACHE */ } #endif /* L_clear_cache */ +#ifdef L_enable_execute_stack +/* Attempt to turn on execute permission for the stack. */ + +#ifdef ENABLE_EXECUTE_STACK + ENABLE_EXECUTE_STACK +#else +void +__enable_execute_stack (void *addr __attribute__((__unused__))) +{} +#endif /* ENABLE_EXECUTE_STACK */ + +#endif /* L_enable_execute_stack */ + #ifdef L_trampoline /* Jump to a trampoline, loading the static chain address. */ #if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN) -long +int getpagesize (void) { #ifdef _ALPHA_ @@ -2514,207 +1883,16 @@ mprotect (char *addr, int len, int prot) #endif /* WINNT && ! __CYGWIN__ && ! _UWIN */ -#ifdef TRANSFER_FROM_TRAMPOLINE -TRANSFER_FROM_TRAMPOLINE -#endif - -#if defined (NeXT) && defined (__MACH__) - -/* Make stack executable so we can call trampolines on stack. - This is called from INITIALIZE_TRAMPOLINE in next.h. */ -#ifdef NeXTStep21 - #include -#else - #include -#endif - -void -__enable_execute_stack (char *addr) -{ - kern_return_t r; - char *eaddr = addr + TRAMPOLINE_SIZE; - vm_address_t a = (vm_address_t) addr; - - /* turn on execute access on stack */ - r = vm_protect (task_self (), a, TRAMPOLINE_SIZE, FALSE, VM_PROT_ALL); - if (r != KERN_SUCCESS) - { - mach_error("vm_protect VM_PROT_ALL", r); - exit(1); - } - - /* We inline the i-cache invalidation for speed */ - -#ifdef CLEAR_INSN_CACHE - CLEAR_INSN_CACHE (addr, eaddr); -#else - __clear_cache ((int) addr, (int) eaddr); -#endif -} - -#endif /* defined (NeXT) && defined (__MACH__) */ - -#ifdef __convex__ - -/* Make stack executable so we can call trampolines on stack. - This is called from INITIALIZE_TRAMPOLINE in convex.h. */ - -#include -#include -#include - -void -__enable_execute_stack (void) -{ - int fp; - static unsigned lowest = USRSTACK; - unsigned current = (unsigned) &fp & -NBPG; - - if (lowest > current) - { - unsigned len = lowest - current; - mremap (current, &len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE); - lowest = current; - } - - /* Clear instruction cache in case an old trampoline is in it. */ - asm ("pich"); -} -#endif /* __convex__ */ - -#ifdef __sysV88__ - -/* Modified from the convex -code above. */ - -#include -#include -#include - -void -__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. */ - - save_errno=errno; - if (lowest > current) - { - unsigned len=lowest-current; - memctl(current,len,MCT_TEXT); - lowest = current; - } - else - memctl(current,NBPC,MCT_TEXT); - errno=save_errno; -} - -#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; +#ifdef TRANSFER_FROM_TRAMPOLINE +TRANSFER_FROM_TRAMPOLINE #endif -} - -#endif /* __sysV68__ */ - -#ifdef __pyr__ - -#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ -#include -#include -#include -#include -#include - -/* Modified from the convex -code above. - mremap promises to clear the i-cache. */ - -void -__enable_execute_stack (void) -{ - int fp; - if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ, - PROT_READ|PROT_WRITE|PROT_EXEC)) - { - perror ("mprotect in __enable_execute_stack"); - fflush (stderr); - abort (); - } -} -#endif /* __pyr__ */ - -#if defined (sony_news) && defined (SYSTYPE_BSD) - -#include -#include -#include -#include -#include - -/* cacheflush function for NEWS-OS 4.2. - This function is called from trampoline-initialize code - defined in config/mips/mips.h. */ - -void -cacheflush (char *beg, int size, int flag) -{ - if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE)) - { - perror ("cache_flush"); - fflush (stderr); - abort (); - } -} - -#endif /* sony_news */ #endif /* L_trampoline */ #ifndef __CYGWIN__ #ifdef L__main #include "gbl-ctors.h" + /* Some systems use __main in a way incompatible with its use in gcc, in these cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to give the same symbol without quotes for an alternative entry point. You @@ -2724,7 +1902,7 @@ cacheflush (char *beg, int size, int flag) #define SYMBOL__MAIN __main #endif -#ifdef INIT_SECTION_ASM_OP +#if defined (INIT_SECTION_ASM_OP) || defined (INIT_ARRAY_SECTION_ASM_OP) #undef HAS_INIT_SECTION #define HAS_INIT_SECTION #endif @@ -2734,7 +1912,7 @@ cacheflush (char *beg, int size, int flag) /* 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 +#ifdef EH_FRAME_SECTION_NAME #include "unwind-dw2-fde.h" extern unsigned char __EH_FRAME_BEGIN__[]; #endif @@ -2754,7 +1932,7 @@ __do_global_dtors (void) (*(p-1)) (); } #endif -#if defined (EH_FRAME_SECTION) && !defined (HAS_INIT_SECTION) +#if defined (EH_FRAME_SECTION_NAME) && !defined (HAS_INIT_SECTION) { static int completed = 0; if (! completed) @@ -2773,7 +1951,7 @@ __do_global_dtors (void) void __do_global_ctors (void) { -#ifdef EH_FRAME_SECTION +#ifdef EH_FRAME_SECTION_NAME { static struct object object; __register_frame_info (__EH_FRAME_BEGIN__, &object); @@ -2793,8 +1971,9 @@ __do_global_ctors (void) For systems which support a .init section we use the .init section to run __do_global_ctors, so we need not do anything here. */ +extern void SYMBOL__MAIN (void); void -SYMBOL__MAIN () +SYMBOL__MAIN (void) { /* Support recursive calls to `main': run initializers just once. */ static int initialized; @@ -2827,7 +2006,7 @@ SYMBOL__MAIN () 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 (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2) +#if defined (TARGET_ASM_CONSTRUCTOR) || defined (USE_COLLECT2) func_ptr __CTOR_LIST__[2] = {0, 0}; func_ptr __DTOR_LIST__[2] = {0, 0}; #else @@ -2836,79 +2015,3 @@ func_ptr __DTOR_LIST__[2]; #endif #endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */ #endif /* L_ctors */ - -#ifdef L_exit - -#include "gbl-ctors.h" - -#ifdef NEED_ATEXIT - -#ifndef ON_EXIT - -# 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) -{ - if (++last_atexit_chain_slot == atexit_chain_length) - { - atexit_chain_length += 32; - if (atexit_chain) - atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length - * sizeof (func_ptr)); - else - atexit_chain = (func_ptr *) malloc (atexit_chain_length - * sizeof (func_ptr)); - if (! atexit_chain) - { - atexit_chain_length = 0; - last_atexit_chain_slot = -1; - errno = ENOMEM; - return (-1); - } - } - atexit_chain[last_atexit_chain_slot] = func; - return (0); -} - -extern void _cleanup (void); -extern void _exit (int) __attribute__ ((__noreturn__)); - -void -exit (int status) -{ - if (atexit_chain) - { - for ( ; last_atexit_chain_slot-- >= 0; ) - { - (*atexit_chain[last_atexit_chain_slot + 1]) (); - atexit_chain[last_atexit_chain_slot + 1] = 0; - } - free (atexit_chain); - atexit_chain = 0; - } -#ifdef EXIT_BODY - EXIT_BODY; -#else - _cleanup (); -#endif - _exit (status); -} - -#else /* ON_EXIT */ - -/* Simple; we just need a wrapper for ON_EXIT. */ -int -atexit (func_ptr func) -{ - return ON_EXIT (func); -} - -#endif /* ON_EXIT */ -#endif /* NEED_ATEXIT */ - -#endif /* L_exit */