1992-01-28 04:44:05 +01:00
|
|
|
|
/* More subroutines needed by GCC output code on some machines. */
|
|
|
|
|
/* Compile this one with gcc. */
|
|
|
|
|
/* Copyright (C) 1989, 1992 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.
|
|
|
|
|
|
|
|
|
|
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
|
|
|
|
|
|
/* As a special exception, if you link this library with files
|
|
|
|
|
compiled with GCC to produce an executable, this does not cause
|
|
|
|
|
the resulting executable to be covered by the GNU General Public License.
|
|
|
|
|
This exception does not however invalidate any other reasons why
|
|
|
|
|
the executable file might be covered by the GNU General Public License. */
|
|
|
|
|
|
|
|
|
|
/* It is incorrect to include config.h here, because this file is being
|
|
|
|
|
compiled for the target, and hence definitions concerning only the host
|
|
|
|
|
do not apply. */
|
|
|
|
|
|
|
|
|
|
#include "tm.h"
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#ifndef L_trampoline
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#include "gstddef.h"
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#endif
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
/* Don't use `fancy_abort' here even if config.h says to use it. */
|
|
|
|
|
#ifdef abort
|
|
|
|
|
#undef abort
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* In the first part of this file, we are interfacing to calls generated
|
|
|
|
|
by the compiler itself. These calls pass values into these routines
|
|
|
|
|
which have very specific modes (rather than very specific types), and
|
|
|
|
|
these compiler-generated calls also expect any return values to have
|
|
|
|
|
very specific modes (rather than very specific types). Thus, we need
|
|
|
|
|
to avoid using regular C language type names in this part of the file
|
|
|
|
|
because the sizes for those types can be configured to be anything.
|
|
|
|
|
Instead we use the following special type names. */
|
|
|
|
|
|
|
|
|
|
typedef unsigned int UQItype __attribute__ ((mode (QI)));
|
|
|
|
|
typedef int SItype __attribute__ ((mode (SI)));
|
|
|
|
|
typedef unsigned int USItype __attribute__ ((mode (SI)));
|
|
|
|
|
typedef int DItype __attribute__ ((mode (DI)));
|
|
|
|
|
typedef unsigned int UDItype __attribute__ ((mode (DI)));
|
|
|
|
|
typedef float SFtype __attribute__ ((mode (SF)));
|
|
|
|
|
typedef float DFtype __attribute__ ((mode (DF)));
|
1992-07-07 23:40:53 +02:00
|
|
|
|
#if 0
|
1992-07-07 21:46:10 +02:00
|
|
|
|
typedef float XFtype __attribute__ ((mode (XF)));
|
1992-07-07 23:40:53 +02:00
|
|
|
|
#endif
|
|
|
|
|
#if LONG_DOUBLE_TYPE_SIZE == 128
|
1992-07-07 21:46:10 +02:00
|
|
|
|
typedef float TFtype __attribute__ ((mode (TF)));
|
1992-07-07 23:40:53 +02:00
|
|
|
|
#endif
|
1992-07-07 21:46:10 +02:00
|
|
|
|
|
|
|
|
|
/* Make sure that we don't accidentaly 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* accidently use soem normal C language built-in type name,
|
|
|
|
|
we will get a syntax error. */
|
|
|
|
|
|
|
|
|
|
#define char bogus_type
|
|
|
|
|
#define short bogus_type
|
|
|
|
|
#define int bogus_type
|
|
|
|
|
#define long bogus_type
|
|
|
|
|
#define unsigned bogus_type
|
|
|
|
|
#define float bogus_type
|
|
|
|
|
#define double bogus_type
|
|
|
|
|
|
|
|
|
|
#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
|
|
|
|
|
|
|
|
|
|
/* DIstructs are pairs of SItype values in the order determined by
|
1992-01-28 04:44:05 +01:00
|
|
|
|
WORDS_BIG_ENDIAN. */
|
|
|
|
|
|
|
|
|
|
#if WORDS_BIG_ENDIAN
|
1992-07-07 21:46:10 +02:00
|
|
|
|
struct DIstruct {SItype high, low;};
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#else
|
1992-07-07 21:46:10 +02:00
|
|
|
|
struct DIstruct {SItype low, high;};
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* 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'. */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
typedef union
|
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
struct DIstruct s;
|
|
|
|
|
DItype ll;
|
|
|
|
|
} DIunion;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
1992-07-10 00:30:59 +02:00
|
|
|
|
#if defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
#include "longlong.h"
|
|
|
|
|
|
|
|
|
|
#endif /* udiv or mul */
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
extern DItype __fixunssfdi (SFtype a);
|
|
|
|
|
extern DItype __fixunsdfdi (DFtype a);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
|
|
|
|
|
#if defined (L_divdi3) || defined (L_moddi3)
|
|
|
|
|
static inline
|
|
|
|
|
#endif
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__negdi2 (u)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion w;
|
|
|
|
|
DIunion uu;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
uu.ll = u;
|
|
|
|
|
|
|
|
|
|
w.s.low = -uu.s.low;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w.s.high = -uu.s.high - ((USItype) w.s.low > 0);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
return w.ll;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_lshldi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__lshldi3 (u, b)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u;
|
|
|
|
|
SItype b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion w;
|
|
|
|
|
SItype bm;
|
|
|
|
|
DIunion uu;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (b == 0)
|
|
|
|
|
return u;
|
|
|
|
|
|
|
|
|
|
uu.ll = u;
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
if (bm <= 0)
|
|
|
|
|
{
|
|
|
|
|
w.s.low = 0;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w.s.high = (USItype)uu.s.low << -bm;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
USItype carries = (USItype)uu.s.low >> bm;
|
|
|
|
|
w.s.low = (USItype)uu.s.low << b;
|
|
|
|
|
w.s.high = ((USItype)uu.s.high << b) | carries;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return w.ll;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_lshrdi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__lshrdi3 (u, b)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u;
|
|
|
|
|
SItype b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion w;
|
|
|
|
|
SItype bm;
|
|
|
|
|
DIunion uu;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (b == 0)
|
|
|
|
|
return u;
|
|
|
|
|
|
|
|
|
|
uu.ll = u;
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
if (bm <= 0)
|
|
|
|
|
{
|
|
|
|
|
w.s.high = 0;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w.s.low = (USItype)uu.s.high >> -bm;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
USItype carries = (USItype)uu.s.high << bm;
|
|
|
|
|
w.s.high = (USItype)uu.s.high >> b;
|
|
|
|
|
w.s.low = ((USItype)uu.s.low >> b) | carries;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return w.ll;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_ashldi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__ashldi3 (u, b)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u;
|
|
|
|
|
SItype b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion w;
|
|
|
|
|
SItype bm;
|
|
|
|
|
DIunion uu;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (b == 0)
|
|
|
|
|
return u;
|
|
|
|
|
|
|
|
|
|
uu.ll = u;
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
if (bm <= 0)
|
|
|
|
|
{
|
|
|
|
|
w.s.low = 0;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w.s.high = (USItype)uu.s.low << -bm;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
USItype carries = (USItype)uu.s.low >> bm;
|
|
|
|
|
w.s.low = (USItype)uu.s.low << b;
|
|
|
|
|
w.s.high = ((USItype)uu.s.high << b) | carries;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return w.ll;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_ashrdi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__ashrdi3 (u, b)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u;
|
|
|
|
|
SItype b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion w;
|
|
|
|
|
SItype bm;
|
|
|
|
|
DIunion uu;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (b == 0)
|
|
|
|
|
return u;
|
|
|
|
|
|
|
|
|
|
uu.ll = u;
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
if (bm <= 0)
|
|
|
|
|
{
|
|
|
|
|
/* w.s.high = 1..1 or 0..0 */
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
w.s.low = uu.s.high >> -bm;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
USItype carries = (USItype)uu.s.high << bm;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
w.s.high = uu.s.high >> b;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w.s.low = ((USItype)uu.s.low >> b) | carries;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return w.ll;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_muldi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__muldi3 (u, v)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u, v;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion w;
|
|
|
|
|
DIunion uu, vv;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
uu.ll = u,
|
|
|
|
|
vv.ll = v;
|
|
|
|
|
|
|
|
|
|
w.ll = __umulsidi3 (uu.s.low, vv.s.low);
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
|
|
|
|
|
+ (USItype) uu.s.high * (USItype) vv.s.low);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
return w.ll;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-07-10 00:30:59 +02:00
|
|
|
|
#ifdef L_udiv_w_sdiv
|
1992-07-07 21:58:52 +02:00
|
|
|
|
USItype
|
1992-07-10 00:30:59 +02:00
|
|
|
|
__udiv_w_sdiv (rp, a1, a0, d)
|
1992-07-07 21:58:52 +02:00
|
|
|
|
USItype *rp, a1, a0, d;
|
|
|
|
|
{
|
|
|
|
|
USItype q, r;
|
|
|
|
|
USItype c0, c1, b1;
|
|
|
|
|
|
|
|
|
|
if ((SItype) d >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (a1 < d - a1 - (a0 >> 31))
|
|
|
|
|
{
|
|
|
|
|
/* dividend, divisor, and quotient are nonnegative */
|
|
|
|
|
sdiv_qrnnd (q, r, a1, a0, d);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
|
|
|
|
|
sub_ddmmss (c1, c0, a1, a0, d >> 1, d << 31);
|
|
|
|
|
/* Divide (c1*2^32 + c0) by d */
|
|
|
|
|
sdiv_qrnnd (q, r, c1, c0, d);
|
|
|
|
|
/* Add 2^31 to quotient */
|
|
|
|
|
q += 1 << 31;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
b1 = d >> 1; /* d/2, between 2^30 and 2^31 - 1 */
|
|
|
|
|
c1 = a1 >> 1; /* A/2 */
|
|
|
|
|
c0 = (a1 << 31) + (a0 >> 1);
|
|
|
|
|
|
|
|
|
|
if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */
|
|
|
|
|
{
|
|
|
|
|
sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
|
|
|
|
|
|
|
|
|
|
r = 2*r + (a0 & 1); /* Remainder from A/(2*b1) */
|
|
|
|
|
if ((d & 1) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (r >= q)
|
|
|
|
|
r = r - q;
|
|
|
|
|
else if (q - r <= d)
|
|
|
|
|
{
|
|
|
|
|
r = r - q + d;
|
|
|
|
|
q--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
r = r - q + 2*d;
|
|
|
|
|
q -= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (c1 < b1) /* So 2^31 <= (A/2)/b1 < 2^32 */
|
|
|
|
|
{
|
|
|
|
|
c1 = (b1 - 1) - c1;
|
|
|
|
|
c0 = ~c0; /* logical NOT */
|
|
|
|
|
|
|
|
|
|
sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
|
|
|
|
|
|
|
|
|
|
q = ~q; /* (A/2)/b1 */
|
|
|
|
|
r = (b1 - 1) - r;
|
|
|
|
|
|
|
|
|
|
r = 2*r + (a0 & 1); /* A/(2*b1) */
|
|
|
|
|
|
|
|
|
|
if ((d & 1) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (r >= q)
|
|
|
|
|
r = r - q;
|
|
|
|
|
else if (q - r <= d)
|
|
|
|
|
{
|
|
|
|
|
r = r - q + d;
|
|
|
|
|
q--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
r = r - q + 2*d;
|
|
|
|
|
q -= 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else /* Implies c1 = b1 */
|
|
|
|
|
{ /* Hence a1 = d - 1 = 2*b1 - 1 */
|
|
|
|
|
if (a0 >= -d)
|
|
|
|
|
{
|
|
|
|
|
q = -1;
|
|
|
|
|
r = a0 + d;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
q = -2;
|
|
|
|
|
r = a0 + 2*d;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*rp = r;
|
|
|
|
|
return q;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#ifdef L_udivmoddi4
|
1992-07-07 21:46:10 +02:00
|
|
|
|
static const UQItype __clz_tab[] =
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
|
|
|
|
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,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
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,
|
|
|
|
|
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,
|
|
|
|
|
};
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__udivmoddi4 (n, d, rp)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype n, d;
|
|
|
|
|
UDItype *rp;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion ww;
|
|
|
|
|
DIunion nn, dd;
|
|
|
|
|
DIunion rr;
|
|
|
|
|
USItype d0, d1, n0, n1, n2;
|
|
|
|
|
USItype q0, q1;
|
|
|
|
|
USItype b, bm;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
nn.ll = n;
|
|
|
|
|
dd.ll = d;
|
|
|
|
|
|
|
|
|
|
d0 = dd.s.low;
|
|
|
|
|
d1 = dd.s.high;
|
|
|
|
|
n0 = nn.s.low;
|
|
|
|
|
n1 = nn.s.high;
|
|
|
|
|
|
|
|
|
|
#if !UDIV_NEEDS_NORMALIZATION
|
|
|
|
|
if (d1 == 0)
|
|
|
|
|
{
|
|
|
|
|
if (d0 > n1)
|
|
|
|
|
{
|
|
|
|
|
/* 0q = nn / 0D */
|
|
|
|
|
|
|
|
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
|
|
|
q1 = 0;
|
|
|
|
|
|
|
|
|
|
/* Remainder in n0. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* qq = NN / 0d */
|
|
|
|
|
|
|
|
|
|
if (d0 == 0)
|
|
|
|
|
d0 = 1 / d0; /* Divide intentionally by zero. */
|
|
|
|
|
|
|
|
|
|
udiv_qrnnd (q1, n1, 0, n1, d0);
|
|
|
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
|
|
|
|
|
|
|
|
/* Remainder in n0. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rp != 0)
|
|
|
|
|
{
|
|
|
|
|
rr.s.low = n0;
|
|
|
|
|
rr.s.high = 0;
|
|
|
|
|
*rp = rr.ll;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else /* UDIV_NEEDS_NORMALIZATION */
|
|
|
|
|
|
|
|
|
|
if (d1 == 0)
|
|
|
|
|
{
|
|
|
|
|
if (d0 > n1)
|
|
|
|
|
{
|
|
|
|
|
/* 0q = nn / 0D */
|
|
|
|
|
|
|
|
|
|
count_leading_zeros (bm, d0);
|
|
|
|
|
|
|
|
|
|
if (bm != 0)
|
|
|
|
|
{
|
|
|
|
|
/* Normalize, i.e. make the most significant bit of the
|
|
|
|
|
denominator set. */
|
|
|
|
|
|
|
|
|
|
d0 = d0 << bm;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
|
1992-01-28 04:44:05 +01:00
|
|
|
|
n0 = n0 << bm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
|
|
|
q1 = 0;
|
|
|
|
|
|
|
|
|
|
/* Remainder in n0 >> bm. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* qq = NN / 0d */
|
|
|
|
|
|
|
|
|
|
if (d0 == 0)
|
|
|
|
|
d0 = 1 / d0; /* Divide intentionally by zero. */
|
|
|
|
|
|
|
|
|
|
count_leading_zeros (bm, d0);
|
|
|
|
|
|
|
|
|
|
if (bm == 0)
|
|
|
|
|
{
|
|
|
|
|
/* From (n1 >= d0) /\ (the most significant bit of d0 is set),
|
|
|
|
|
conclude (the most significant bit of n1 is set) /\ (the
|
|
|
|
|
leading quotient digit q1 = 1).
|
|
|
|
|
|
|
|
|
|
This special case is necessary, not an optimization.
|
1992-07-07 21:46:10 +02:00
|
|
|
|
(Shifts counts of SI_TYPE_SIZE are undefined.) */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
n1 -= d0;
|
|
|
|
|
q1 = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Normalize. */
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
b = SI_TYPE_SIZE - bm;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
d0 = d0 << bm;
|
|
|
|
|
n2 = n1 >> b;
|
|
|
|
|
n1 = (n1 << bm) | (n0 >> b);
|
|
|
|
|
n0 = n0 << bm;
|
|
|
|
|
|
|
|
|
|
udiv_qrnnd (q1, n1, n2, n1, d0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* n1 != d0... */
|
|
|
|
|
|
|
|
|
|
udiv_qrnnd (q0, n0, n1, n0, d0);
|
|
|
|
|
|
|
|
|
|
/* Remainder in n0 >> bm. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rp != 0)
|
|
|
|
|
{
|
|
|
|
|
rr.s.low = n0 >> bm;
|
|
|
|
|
rr.s.high = 0;
|
|
|
|
|
*rp = rr.ll;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* UDIV_NEEDS_NORMALIZATION */
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (d1 > n1)
|
|
|
|
|
{
|
|
|
|
|
/* 00 = nn / DD */
|
|
|
|
|
|
|
|
|
|
q0 = 0;
|
|
|
|
|
q1 = 0;
|
|
|
|
|
|
|
|
|
|
/* Remainder in n1n0. */
|
|
|
|
|
if (rp != 0)
|
|
|
|
|
{
|
|
|
|
|
rr.s.low = n0;
|
|
|
|
|
rr.s.high = n1;
|
|
|
|
|
*rp = rr.ll;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* 0q = NN / dd */
|
|
|
|
|
|
|
|
|
|
count_leading_zeros (bm, d1);
|
|
|
|
|
if (bm == 0)
|
|
|
|
|
{
|
|
|
|
|
/* From (n1 >= d1) /\ (the most significant bit of d1 is set),
|
|
|
|
|
conclude (the most significant bit of n1 is set) /\ (the
|
|
|
|
|
quotient digit q0 = 0 or 1).
|
|
|
|
|
|
|
|
|
|
This special case is necessary, not an optimization. */
|
|
|
|
|
|
|
|
|
|
/* The condition on the next line takes advantage of that
|
|
|
|
|
n1 >= d1 (true due to program flow). */
|
|
|
|
|
if (n1 > d1 || n0 >= d0)
|
|
|
|
|
{
|
|
|
|
|
q0 = 1;
|
|
|
|
|
sub_ddmmss (n1, n0, n1, n0, d1, d0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
q0 = 0;
|
|
|
|
|
|
|
|
|
|
q1 = 0;
|
|
|
|
|
|
|
|
|
|
if (rp != 0)
|
|
|
|
|
{
|
|
|
|
|
rr.s.low = n0;
|
|
|
|
|
rr.s.high = n1;
|
|
|
|
|
*rp = rr.ll;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
USItype m1, m0;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
/* Normalize. */
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
b = SI_TYPE_SIZE - bm;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
d1 = (d1 << bm) | (d0 >> b);
|
|
|
|
|
d0 = d0 << bm;
|
|
|
|
|
n2 = n1 >> b;
|
|
|
|
|
n1 = (n1 << bm) | (n0 >> b);
|
|
|
|
|
n0 = n0 << bm;
|
|
|
|
|
|
|
|
|
|
udiv_qrnnd (q0, n1, n2, n1, d1);
|
|
|
|
|
umul_ppmm (m1, m0, q0, d0);
|
|
|
|
|
|
|
|
|
|
if (m1 > n1 || (m1 == n1 && m0 > n0))
|
|
|
|
|
{
|
|
|
|
|
q0--;
|
|
|
|
|
sub_ddmmss (m1, m0, m1, m0, d1, d0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q1 = 0;
|
|
|
|
|
|
|
|
|
|
/* Remainder in (n1n0 - m1m0) >> bm. */
|
|
|
|
|
if (rp != 0)
|
|
|
|
|
{
|
|
|
|
|
sub_ddmmss (n1, n0, n1, n0, m1, m0);
|
|
|
|
|
rr.s.low = (n1 << b) | (n0 >> bm);
|
|
|
|
|
rr.s.high = n1 >> bm;
|
|
|
|
|
*rp = rr.ll;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ww.s.low = q0;
|
|
|
|
|
ww.s.high = q1;
|
|
|
|
|
return ww.ll;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_divdi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype __udivmoddi4 ();
|
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__divdi3 (u, v)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u, v;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
SItype c = 0;
|
|
|
|
|
DIunion uu, vv;
|
|
|
|
|
DItype w;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
uu.ll = u;
|
|
|
|
|
vv.ll = v;
|
|
|
|
|
|
|
|
|
|
if (uu.s.high < 0)
|
|
|
|
|
c = ~c,
|
|
|
|
|
uu.ll = __negdi2 (uu.ll);
|
|
|
|
|
if (vv.s.high < 0)
|
|
|
|
|
c = ~c,
|
|
|
|
|
vv.ll = __negdi2 (vv.ll);
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
if (c)
|
|
|
|
|
w = __negdi2 (w);
|
|
|
|
|
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_moddi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype __udivmoddi4 ();
|
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__moddi3 (u, v)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u, v;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
SItype c = 0;
|
|
|
|
|
DIunion uu, vv;
|
|
|
|
|
DItype w;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
uu.ll = u;
|
|
|
|
|
vv.ll = v;
|
|
|
|
|
|
|
|
|
|
if (uu.s.high < 0)
|
|
|
|
|
c = ~c,
|
|
|
|
|
uu.ll = __negdi2 (uu.ll);
|
|
|
|
|
if (vv.s.high < 0)
|
|
|
|
|
vv.ll = __negdi2 (vv.ll);
|
|
|
|
|
|
|
|
|
|
(void) __udivmoddi4 (uu.ll, vv.ll, &w);
|
|
|
|
|
if (c)
|
|
|
|
|
w = __negdi2 (w);
|
|
|
|
|
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_umoddi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype __udivmoddi4 ();
|
|
|
|
|
UDItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__umoddi3 (u, v)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype u, v;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype w;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
(void) __udivmoddi4 (u, v, &w);
|
|
|
|
|
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_udivdi3
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype __udivmoddi4 ();
|
|
|
|
|
UDItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__udivdi3 (n, d)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
UDItype n, d;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
return __udivmoddi4 (n, d, (UDItype *) 0);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_cmpdi2
|
|
|
|
|
SItype
|
|
|
|
|
__cmpdi2 (a, b)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype a, b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion au, bu;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
au.ll = a, bu.ll = b;
|
|
|
|
|
|
|
|
|
|
if (au.s.high < bu.s.high)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (au.s.high > bu.s.high)
|
|
|
|
|
return 2;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
if ((USItype) au.s.low < (USItype) bu.s.low)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return 0;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
else if ((USItype) au.s.low > (USItype) bu.s.low)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return 2;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_ucmpdi2
|
|
|
|
|
SItype
|
|
|
|
|
__ucmpdi2 (a, b)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype a, b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DIunion au, bu;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
au.ll = a, bu.ll = b;
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
if ((USItype) au.s.high < (USItype) bu.s.high)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return 0;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
else if ((USItype) au.s.high > (USItype) bu.s.high)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return 2;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
if ((USItype) au.s.low < (USItype) bu.s.low)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return 0;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
else if ((USItype) au.s.low > (USItype) bu.s.low)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return 2;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
#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)
|
|
|
|
|
|
|
|
|
|
DItype
|
|
|
|
|
__fixunstfdi (a)
|
|
|
|
|
TFtype a;
|
|
|
|
|
{
|
|
|
|
|
TFtype b;
|
|
|
|
|
UDItype 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!),
|
|
|
|
|
and shift it into the high word. */
|
|
|
|
|
v = (USItype) 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.
|
|
|
|
|
Sometimes A comes out negative. This is significant, since
|
|
|
|
|
A has more bits than a long int does. */
|
|
|
|
|
if (a < 0)
|
|
|
|
|
v -= (USItype) (- a);
|
|
|
|
|
else
|
|
|
|
|
v += (USItype) a;
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
|
|
|
|
|
DItype
|
|
|
|
|
__fixtfdi (a)
|
|
|
|
|
TFtype a;
|
|
|
|
|
{
|
|
|
|
|
if (a < 0)
|
|
|
|
|
return - __fixunstfdi (-a);
|
|
|
|
|
return __fixunstfdi (a);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#ifdef L_fixunsdfdi
|
1992-07-07 21:46:10 +02:00
|
|
|
|
#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
|
|
|
|
|
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__fixunsdfdi (a)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DFtype a;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DFtype b;
|
|
|
|
|
UDItype v;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (a < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Compute high word of result, as a flonum. */
|
|
|
|
|
b = (a / HIGH_WORD_COEFF);
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* Convert that to fixed (but not to DItype!),
|
1992-01-28 04:44:05 +01:00
|
|
|
|
and shift it into the high word. */
|
1992-07-07 21:46:10 +02:00
|
|
|
|
v = (USItype) b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
v <<= WORD_SIZE;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* 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.
|
1992-01-28 04:44:05 +01:00
|
|
|
|
Sometimes A comes out negative. This is significant, since
|
|
|
|
|
A has more bits than a long int does. */
|
|
|
|
|
if (a < 0)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
v -= (USItype) (- a);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
else
|
1992-07-07 21:46:10 +02:00
|
|
|
|
v += (USItype) a;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_fixdfdi
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__fixdfdi (a)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DFtype a;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
|
|
|
|
if (a < 0)
|
|
|
|
|
return - __fixunsdfdi (-a);
|
|
|
|
|
return __fixunsdfdi (a);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_fixunssfdi
|
1992-07-07 21:46:10 +02:00
|
|
|
|
#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
|
|
|
|
|
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
|
|
|
|
__fixunssfdi (SFtype original_a)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* Convert the SFtype to a DFtype, because that is surely not going
|
1992-01-28 04:44:05 +01:00
|
|
|
|
to lose any bits. Some day someone else can write a faster version
|
1992-07-07 21:46:10 +02:00
|
|
|
|
that avoids converting to DFtype, and verify it really works right. */
|
|
|
|
|
DFtype a = original_a;
|
|
|
|
|
DFtype b;
|
|
|
|
|
UDItype v;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (a < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Compute high word of result, as a flonum. */
|
|
|
|
|
b = (a / HIGH_WORD_COEFF);
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* Convert that to fixed (but not to DItype!),
|
1992-01-28 04:44:05 +01:00
|
|
|
|
and shift it into the high word. */
|
1992-07-07 21:46:10 +02:00
|
|
|
|
v = (USItype) b;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
v <<= WORD_SIZE;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* 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.
|
1992-01-28 04:44:05 +01:00
|
|
|
|
Sometimes A comes out negative. This is significant, since
|
|
|
|
|
A has more bits than a long int does. */
|
|
|
|
|
if (a < 0)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
v -= (USItype) (- a);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
else
|
1992-07-07 21:46:10 +02:00
|
|
|
|
v += (USItype) a;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_fixsfdi
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype
|
|
|
|
|
__fixsfdi (SFtype a)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
|
|
|
|
if (a < 0)
|
|
|
|
|
return - __fixunssfdi (-a);
|
|
|
|
|
return __fixunssfdi (a);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
#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)
|
|
|
|
|
|
|
|
|
|
TFtype
|
|
|
|
|
__floatditf (u)
|
|
|
|
|
DItype u;
|
|
|
|
|
{
|
|
|
|
|
TFtype d;
|
|
|
|
|
SItype negate = 0;
|
|
|
|
|
|
|
|
|
|
if (u < 0)
|
|
|
|
|
u = -u, negate = 1;
|
|
|
|
|
|
|
|
|
|
d = (USItype) (u >> WORD_SIZE);
|
|
|
|
|
d *= HIGH_HALFWORD_COEFF;
|
|
|
|
|
d *= HIGH_HALFWORD_COEFF;
|
|
|
|
|
d += (USItype) (u & (HIGH_WORD_COEFF - 1));
|
|
|
|
|
|
|
|
|
|
return (negate ? -d : d);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#ifdef L_floatdidf
|
1992-07-07 21:46:10 +02:00
|
|
|
|
#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)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DFtype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__floatdidf (u)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DFtype d;
|
|
|
|
|
SItype negate = 0;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (u < 0)
|
|
|
|
|
u = -u, negate = 1;
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
d = (USItype) (u >> WORD_SIZE);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
d *= HIGH_HALFWORD_COEFF;
|
|
|
|
|
d *= HIGH_HALFWORD_COEFF;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
d += (USItype) (u & (HIGH_WORD_COEFF - 1));
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
return (negate ? -d : d);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_floatdisf
|
1992-07-07 21:46:10 +02:00
|
|
|
|
#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)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
SFtype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__floatdisf (u)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DItype u;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
SFtype f;
|
|
|
|
|
SItype negate = 0;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
if (u < 0)
|
|
|
|
|
u = -u, negate = 1;
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
f = (USItype) (u >> WORD_SIZE);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
f *= HIGH_HALFWORD_COEFF;
|
|
|
|
|
f *= HIGH_HALFWORD_COEFF;
|
1992-07-07 21:46:10 +02:00
|
|
|
|
f += (USItype) (u & (HIGH_WORD_COEFF - 1));
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
return (negate ? -f : f);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_fixunsdfsi
|
|
|
|
|
#include "limits.h"
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
USItype
|
1992-01-28 04:44:05 +01:00
|
|
|
|
__fixunsdfsi (a)
|
1992-07-07 21:46:10 +02:00
|
|
|
|
DFtype a;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
if (a >= - (DFtype) LONG_MIN)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return (SItype) (a + LONG_MIN) - LONG_MIN;
|
|
|
|
|
return (SItype) a;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_fixunssfsi
|
|
|
|
|
#include "limits.h"
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
USItype
|
|
|
|
|
__fixunssfsi (SFtype a)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
1992-07-07 21:46:10 +02:00
|
|
|
|
if (a >= - (SFtype) LONG_MIN)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
return (SItype) (a + LONG_MIN) - LONG_MIN;
|
|
|
|
|
return (SItype) a;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-07-07 21:46:10 +02:00
|
|
|
|
/* 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 char
|
|
|
|
|
#undef short
|
|
|
|
|
#undef int
|
|
|
|
|
#undef long
|
|
|
|
|
#undef unsigned
|
|
|
|
|
#undef float
|
|
|
|
|
#undef double
|
|
|
|
|
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#ifdef L_varargs
|
|
|
|
|
#ifdef __i860__
|
1992-07-05 01:21:06 +02:00
|
|
|
|
#if defined(__svr4__) || defined(__alliant__)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
asm (" .text");
|
|
|
|
|
asm (" .align 4");
|
|
|
|
|
|
1992-06-26 04:43:09 +02:00
|
|
|
|
/* The Alliant needs the added underscore. */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
asm (".globl __builtin_saveregs");
|
|
|
|
|
asm ("__builtin_saveregs:");
|
1992-06-26 04:43:09 +02:00
|
|
|
|
asm (".globl ___builtin_saveregs");
|
|
|
|
|
asm ("___builtin_saveregs:");
|
|
|
|
|
|
|
|
|
|
asm (" andnot 0x0f,%sp,%sp"); /* round down to 16-byte boundary */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
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 */
|
|
|
|
|
|
1992-07-05 01:21:06 +02:00
|
|
|
|
#else /* not __SVR4__ */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
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. */
|
1992-07-05 01:21:06 +02:00
|
|
|
|
#endif /* not __SVR4__ */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#else /* not __i860__ */
|
|
|
|
|
#ifdef __sparc__
|
1992-03-19 21:41:45 +01:00
|
|
|
|
asm (".global __builtin_saveregs");
|
|
|
|
|
asm ("__builtin_saveregs:");
|
1992-01-28 04:44:05 +01:00
|
|
|
|
asm (".global ___builtin_saveregs");
|
|
|
|
|
asm ("___builtin_saveregs:");
|
1992-03-29 05:21:13 +02:00
|
|
|
|
#ifdef NEED_PROC_COMMAND
|
|
|
|
|
asm (".proc 020");
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#endif
|
1992-01-28 04:44:05 +01:00
|
|
|
|
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]");
|
1992-03-29 05:21:13 +02:00
|
|
|
|
#ifdef NEED_TYPE_COMMAND
|
|
|
|
|
asm (".type __builtin_saveregs,#function");
|
|
|
|
|
asm (".size __builtin_saveregs,.-__builtin_saveregs");
|
|
|
|
|
#endif
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#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. */
|
|
|
|
|
__builtin_saveregs ()
|
|
|
|
|
{
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
#endif /* not __mips__ */
|
|
|
|
|
#endif /* not __sparc__ */
|
|
|
|
|
#endif /* not __i860__ */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_eprintf
|
|
|
|
|
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
/* This is used by the `assert' macro. */
|
|
|
|
|
void
|
|
|
|
|
__eprintf (string, expression, line, filename)
|
1992-03-29 05:21:13 +02:00
|
|
|
|
const char *string;
|
|
|
|
|
const char *expression;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
int line;
|
1992-03-29 05:21:13 +02:00
|
|
|
|
const char *filename;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, string, expression, line, filename);
|
|
|
|
|
fflush (stderr);
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_bb
|
|
|
|
|
/* Avoid warning from ranlib about empty object file. */
|
|
|
|
|
void
|
|
|
|
|
__bb_avoid_warning ()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
#if defined (__sun__) && defined (__mc68000__)
|
|
|
|
|
struct bb
|
|
|
|
|
{
|
|
|
|
|
int initialized;
|
|
|
|
|
char *filename;
|
|
|
|
|
int *counts;
|
|
|
|
|
int ncounts;
|
|
|
|
|
int zero_word;
|
|
|
|
|
int *addresses;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern int ___tcov_init;
|
|
|
|
|
|
|
|
|
|
__bb_init_func (blocks)
|
|
|
|
|
struct bb *blocks;
|
|
|
|
|
{
|
|
|
|
|
if (! ___tcov_init)
|
|
|
|
|
___tcov_init_func ();
|
|
|
|
|
|
|
|
|
|
___bb_link (blocks->filename, blocks->counts, blocks->ncounts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* frills for C++ */
|
|
|
|
|
|
|
|
|
|
#ifdef L_builtin_new
|
|
|
|
|
typedef void (*vfp)(void);
|
|
|
|
|
|
|
|
|
|
extern vfp __new_handler;
|
1992-05-05 03:46:51 +02:00
|
|
|
|
extern void *malloc ();
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
__builtin_new (sz)
|
1992-05-05 03:46:51 +02:00
|
|
|
|
size_t sz;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
{
|
|
|
|
|
void *p;
|
|
|
|
|
|
1992-03-29 05:21:13 +02:00
|
|
|
|
p = malloc (sz);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
if (p == 0)
|
|
|
|
|
(*__new_handler) ();
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1992-06-30 02:35:54 +02:00
|
|
|
|
#ifdef L_caps_New
|
1992-01-28 04:44:05 +01:00
|
|
|
|
typedef void (*vfp)(void);
|
|
|
|
|
|
1992-05-05 03:46:51 +02:00
|
|
|
|
extern void *__builtin_new (size_t);
|
|
|
|
|
static void default_new_handler (void);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
vfp __new_handler = default_new_handler;
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
__builtin_vec_new (p, maxindex, size, ctor)
|
|
|
|
|
void *p;
|
1992-05-05 03:46:51 +02:00
|
|
|
|
size_t maxindex;
|
|
|
|
|
size_t size;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
void (*ctor)(void *);
|
|
|
|
|
{
|
1992-05-05 03:46:51 +02:00
|
|
|
|
size_t i;
|
|
|
|
|
size_t nelts = maxindex + 1;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
void *rval;
|
|
|
|
|
|
|
|
|
|
if (p == 0)
|
1992-03-29 05:21:13 +02:00
|
|
|
|
p = __builtin_new (nelts * size);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
rval = p;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < nelts; i++)
|
|
|
|
|
{
|
|
|
|
|
(*ctor) (p);
|
|
|
|
|
p += size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vfp
|
|
|
|
|
__set_new_handler (handler)
|
|
|
|
|
vfp handler;
|
|
|
|
|
{
|
|
|
|
|
vfp prev_handler;
|
|
|
|
|
|
|
|
|
|
prev_handler = __new_handler;
|
|
|
|
|
if (handler == 0) handler = default_new_handler;
|
|
|
|
|
__new_handler = handler;
|
|
|
|
|
return prev_handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vfp
|
|
|
|
|
set_new_handler (handler)
|
|
|
|
|
vfp handler;
|
|
|
|
|
{
|
|
|
|
|
return __set_new_handler (handler);
|
|
|
|
|
}
|
|
|
|
|
|
1992-03-29 05:21:13 +02:00
|
|
|
|
#define MESSAGE "Virtual memory exceeded in `new'\n"
|
|
|
|
|
|
1992-01-28 04:44:05 +01:00
|
|
|
|
static void
|
|
|
|
|
default_new_handler ()
|
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
1992-03-29 05:21:13 +02:00
|
|
|
|
write (2, MESSAGE, sizeof (MESSAGE));
|
1992-01-28 04:44:05 +01:00
|
|
|
|
/* don't call exit () because that may call global destructors which
|
|
|
|
|
may cause a loop. */
|
|
|
|
|
_exit (-1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_builtin_del
|
|
|
|
|
typedef void (*vfp)(void);
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
__builtin_delete (ptr)
|
|
|
|
|
void *ptr;
|
|
|
|
|
{
|
|
|
|
|
if (ptr)
|
|
|
|
|
free (ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
__builtin_vec_delete (ptr, maxindex, size, dtor, auto_delete_vec, auto_delete)
|
|
|
|
|
void *ptr;
|
1992-05-05 03:46:51 +02:00
|
|
|
|
size_t maxindex;
|
|
|
|
|
size_t size;
|
|
|
|
|
void (*dtor)(void *, int);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
int auto_delete;
|
|
|
|
|
{
|
1992-05-05 03:46:51 +02:00
|
|
|
|
size_t i;
|
|
|
|
|
size_t nelts = maxindex + 1;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
void *p = ptr;
|
|
|
|
|
|
|
|
|
|
ptr += nelts * size;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < nelts; i++)
|
|
|
|
|
{
|
|
|
|
|
ptr -= size;
|
|
|
|
|
(*dtor) (ptr, auto_delete);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto_delete_vec)
|
|
|
|
|
__builtin_delete (p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#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 (beg, end)
|
|
|
|
|
char *beg, *end;
|
|
|
|
|
{
|
|
|
|
|
#ifdef INSN_CACHE_SIZE
|
|
|
|
|
static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
|
|
|
|
|
static int initialized = 0;
|
|
|
|
|
int offset;
|
1992-05-05 03:46:51 +02:00
|
|
|
|
void *start_addr
|
|
|
|
|
void *end_addr;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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 /* L_clear_cache */
|
|
|
|
|
|
|
|
|
|
#ifdef L_trampoline
|
|
|
|
|
|
|
|
|
|
/* Jump to a trampoline, loading the static chain address. */
|
|
|
|
|
|
|
|
|
|
#ifdef TRANSFER_FROM_TRAMPOLINE
|
|
|
|
|
TRANSFER_FROM_TRAMPOLINE
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef __convex__
|
|
|
|
|
|
|
|
|
|
/* Make stack executable so we can call trampolines on stack.
|
|
|
|
|
This is called from INITIALIZE_TRAMPOLINE in convex.h. */
|
|
|
|
|
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#include <sys/vmparam.h>
|
|
|
|
|
#include <machine/machparam.h>
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
__enable_execute_stack ()
|
|
|
|
|
{
|
|
|
|
|
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__ */
|
1992-03-19 21:41:45 +01:00
|
|
|
|
|
|
|
|
|
#ifdef __pyr__
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
|
#include <sys/vmmac.h>
|
|
|
|
|
|
|
|
|
|
/* Modified from the convex -code above.
|
|
|
|
|
mremap promises to clear the i-cache. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
__enable_execute_stack ()
|
|
|
|
|
{
|
|
|
|
|
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__ */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#endif /* L_trampoline */
|
|
|
|
|
|
|
|
|
|
#ifdef L__main
|
|
|
|
|
|
|
|
|
|
#include "gbl-ctors.h"
|
|
|
|
|
|
|
|
|
|
/* Run all the global destructors on exit from the program. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
__do_global_dtors ()
|
|
|
|
|
{
|
1992-02-12 18:47:31 +01:00
|
|
|
|
#ifdef DO_GLOBAL_DTORS_BODY
|
|
|
|
|
DO_GLOBAL_DTORS_BODY;
|
|
|
|
|
#else
|
1992-05-05 03:46:51 +02:00
|
|
|
|
unsigned nptrs = (unsigned) __DTOR_LIST__[0];
|
|
|
|
|
unsigned i;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
/* Some systems place the number of pointers
|
|
|
|
|
in the first word of the table.
|
|
|
|
|
On other systems, that word is -1.
|
|
|
|
|
In all cases, the table is null-terminated. */
|
|
|
|
|
|
|
|
|
|
/* If the length is not recorded, count up to the null. */
|
|
|
|
|
if (nptrs == -1)
|
|
|
|
|
for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++);
|
|
|
|
|
|
|
|
|
|
/* GNU LD format. */
|
|
|
|
|
for (i = nptrs; i >= 1; i--)
|
|
|
|
|
__DTOR_LIST__[i] ();
|
1992-02-12 18:47:31 +01:00
|
|
|
|
#endif
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef INIT_SECTION_ASM_OP
|
|
|
|
|
/* Run all the global constructors on entry to the program. */
|
|
|
|
|
|
1992-03-07 05:39:10 +01:00
|
|
|
|
#ifndef ON_EXIT
|
1992-01-28 04:44:05 +01:00
|
|
|
|
#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_BODY;
|
1992-03-07 05:39:10 +01:00
|
|
|
|
ON_EXIT (__do_global_dtors, 0);
|
1992-01-28 04:44:05 +01:00
|
|
|
|
}
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#endif /* no INIT_SECTION_ASM_OP */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
/* Subroutine called automatically by `main'.
|
|
|
|
|
Compiling a global function named `main'
|
|
|
|
|
produces an automatic call to this function at the beginning.
|
|
|
|
|
|
|
|
|
|
For many systems, this routine calls __do_global_ctors.
|
|
|
|
|
For systems which support a .init section we use the .init section
|
|
|
|
|
to run __do_global_ctors, so we need not do anything here. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
__main ()
|
|
|
|
|
{
|
|
|
|
|
/* Support recursive calls to `main': run initializers just once. */
|
1992-05-05 03:46:51 +02:00
|
|
|
|
static int initialized = 0;
|
1992-01-28 04:44:05 +01:00
|
|
|
|
if (! initialized)
|
|
|
|
|
{
|
|
|
|
|
initialized = 1;
|
|
|
|
|
__do_global_ctors ();
|
|
|
|
|
}
|
|
|
|
|
}
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#endif /* no INIT_SECTION_ASM_OP or INVOKE__main */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
#endif /* L__main */
|
|
|
|
|
|
|
|
|
|
#ifdef L_exit
|
|
|
|
|
|
|
|
|
|
#include "gbl-ctors.h"
|
|
|
|
|
|
|
|
|
|
/* Provide default definitions for the lists of constructors and
|
|
|
|
|
destructors, so that we don't get linker errors. These symbols are
|
|
|
|
|
intentionally bss symbols, so that gld and/or collect will provide
|
|
|
|
|
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. */
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
|
1992-01-28 04:44:05 +01:00
|
|
|
|
func_ptr __CTOR_LIST__[2];
|
|
|
|
|
func_ptr __DTOR_LIST__[2];
|
1992-03-19 21:41:45 +01:00
|
|
|
|
#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
|
1992-01-28 04:44:05 +01:00
|
|
|
|
|
|
|
|
|
#ifndef ON_EXIT
|
|
|
|
|
|
|
|
|
|
/* If we have no known way of registering our own __do_global_dtors
|
|
|
|
|
routine so that it will be invoked at program exit time, then we
|
|
|
|
|
have to define our own exit routine which will get this to happen. */
|
|
|
|
|
|
|
|
|
|
extern void __do_global_dtors ();
|
|
|
|
|
extern void _cleanup ();
|
|
|
|
|
extern void _exit ();
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
exit (status)
|
|
|
|
|
int status;
|
|
|
|
|
{
|
|
|
|
|
__do_global_dtors ();
|
|
|
|
|
#ifdef EXIT_BODY
|
|
|
|
|
EXIT_BODY;
|
|
|
|
|
#else
|
|
|
|
|
_cleanup ();
|
|
|
|
|
#endif
|
|
|
|
|
_exit (status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif /* L_exit */
|
|
|
|
|
|
|
|
|
|
/* In a.out systems, we need to have these dummy constructor and destructor
|
|
|
|
|
lists in the library.
|
|
|
|
|
|
|
|
|
|
When using `collect', the first link will resolve __CTOR_LIST__
|
|
|
|
|
and __DTOR_LIST__ to these symbols. We will then run "nm" on the
|
|
|
|
|
result, build the correct __CTOR_LIST__ and __DTOR_LIST__, and relink.
|
|
|
|
|
Since we don't do the second link if no constructors existed, these
|
|
|
|
|
dummies must be fully functional empty lists.
|
|
|
|
|
|
|
|
|
|
When using `gnu ld', these symbols will be used if there are no
|
|
|
|
|
constructors. If there are constructors, the N_SETV symbol defined
|
|
|
|
|
by the linker from the N_SETT's in input files will define __CTOR_LIST__
|
|
|
|
|
and __DTOR_LIST__ rather than its being allocated as common storage
|
|
|
|
|
by the definitions below.
|
|
|
|
|
|
|
|
|
|
When using a linker that supports constructor and destructor segments,
|
|
|
|
|
these definitions will not be used, since crtbegin.o and crtend.o
|
|
|
|
|
(from crtstuff.c) will have already defined __CTOR_LIST__ and
|
|
|
|
|
__DTOR_LIST__. The crt*.o files are passed directly to the linker
|
|
|
|
|
on its command line, by gcc. */
|
|
|
|
|
|
|
|
|
|
/* The list needs two elements: one is ignored (the old count); the
|
|
|
|
|
second is the terminating zero. Since both values are zero, this
|
|
|
|
|
declaration is not initialized, and it becomes `common'. */
|
|
|
|
|
|
|
|
|
|
#ifdef L_ctor_list
|
|
|
|
|
#include "gbl-ctors.h"
|
|
|
|
|
func_ptr __CTOR_LIST__[2];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef L_dtor_list
|
|
|
|
|
#include "gbl-ctors.h"
|
|
|
|
|
func_ptr __DTOR_LIST__[2];
|
|
|
|
|
#endif
|