home *** CD-ROM | disk | FTP | other *** search
- /* This is a stripped down version of floatlib.c. It supplies only those
- functions which exist in libgcc, but for which there is not assembly
- language versions in m68k/lb1sf68.asm.
-
- It also includes simplistic support for extended floats (by working in
- double precision). You must compile this file again with -DEXTFLOAT
- to get this support. */
-
- /*
- ** gnulib support for software floating point.
- ** Copyright (C) 1991 by Pipeline Associates, Inc. All rights reserved.
- ** Permission is granted to do *anything* you want with this file,
- ** commercial or otherwise, provided this message remains intact. So there!
- ** I would appreciate receiving any updates/patches/changes that anyone
- ** makes, and am willing to be the repository for said changes (am I
- ** making a big mistake?).
- **
- ** Pat Wood
- ** Pipeline Associates, Inc.
- ** pipeline!phw@motown.com or
- ** sun!pipeline!phw or
- ** uunet!motown!pipeline!phw
- **
- ** 05/01/91 -- V1.0 -- first release to gcc mailing lists
- ** 05/04/91 -- V1.1 -- added float and double prototypes and return values
- ** -- fixed problems with adding and subtracting zero
- ** -- fixed rounding in truncdfsf2
- ** -- fixed SWAP define and tested on 386
- */
-
- /*
- ** The following are routines that replace the gnulib soft floating point
- ** routines that are called automatically when -msoft-float is selected.
- ** The support single and double precision IEEE format, with provisions
- ** for byte-swapped machines (tested on 386). Some of the double-precision
- ** routines work at full precision, but most of the hard ones simply punt
- ** and call the single precision routines, producing a loss of accuracy.
- ** long long support is not assumed or included.
- ** Overall accuracy is close to IEEE (actually 68882) for single-precision
- ** arithmetic. I think there may still be a 1 in 1000 chance of a bit
- ** being rounded the wrong way during a multiply. I'm not fussy enough to
- ** bother with it, but if anyone is, knock yourself out.
- **
- ** Efficiency has only been addressed where it was obvious that something
- ** would make a big difference. Anyone who wants to do this right for
- ** best speed should go in and rewrite in assembler.
- **
- ** I have tested this only on a 68030 workstation and 386/ix integrated
- ** in with -msoft-float.
- */
-
- /* the following deal with IEEE single-precision numbers */
- #define EXCESS 126L
- #define SIGNBIT 0x80000000L
- #define HIDDEN (1L << 23L)
- #define SIGN(fp) ((fp) & SIGNBIT)
- #define EXP(fp) (((fp) >> 23L) & 0xFF)
- #define MANT(fp) (((fp) & 0x7FFFFFL) | HIDDEN)
- #define PACK(s,e,m) ((s) | ((e) << 23L) | (m))
-
- /* the following deal with IEEE double-precision numbers */
- #define EXCESSD 1022
- #define HIDDEND (1L << 20L)
- #define EXPDBITS 11
- #define EXPDMASK 0x7FF
- #define EXPD(fp) (((fp.l.upper) >> 20L) & 0x7FFL)
- #define SIGND(fp) ((fp.l.upper) & SIGNBIT)
- #define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
- (fp.l.lower >> 22))
- #define MANTDMASK 0xFFFFF /* mask of upper part */
-
- /* the following deal with IEEE extended-precision numbers */
- #define EXCESSX 16382
- #define HIDDENX (1L << 31L)
- #define EXPXBITS 15
- #define EXPXMASK 0x7FFF
- #define EXPX(fp) (((fp.l.upper) >> 16) & EXPXMASK)
- #define SIGNX(fp) ((fp.l.upper) & SIGNBIT)
- #define MANTXMASK 0x7FFFFFFF /* mask of upper part */
-
- union double_long
- {
- double d;
- struct {
- long upper;
- unsigned long lower;
- } l;
- };
-
- union float_long {
- float f;
- long l;
- };
-
- union long_double_long
- {
- long double ld;
- struct
- {
- long upper;
- unsigned long middle;
- unsigned long lower;
- } l;
- };
-
- #ifndef EXTFLOAT
-
- /* convert int to double */
- double
- __floatsidf (int a1)
- {
- long sign = 0, exp = 31 + EXCESSD;
- union double_long dl;
-
- if (!a1)
- {
- dl.l.upper = dl.l.lower = 0;
- return dl.d;
- }
-
- if (a1 < 0)
- {
- sign = SIGNBIT;
- a1 = -a1;
- if (a1 < 0)
- {
- dl.l.upper = SIGNBIT | ((32 + EXCESSD) << 20L);
- dl.l.lower = 0;
- return dl.d;
- }
- }
-
- while (a1 < 0x1000000)
- {
- a1 <<= 4;
- exp -= 4;
- }
-
- while (a1 < 0x40000000)
- {
- a1 <<= 1;
- exp--;
- }
-
- /* pack up and go home */
- dl.l.upper = sign;
- dl.l.upper |= exp << 20L;
- dl.l.upper |= (a1 >> 10L) & ~HIDDEND;
- dl.l.lower = a1 << 22L;
-
- return dl.d;
- }
-
- /* convert int to float */
- float
- __floatsisf (int l)
- {
- double foo = __floatsidf (l);
- return foo;
- }
-
- /* convert float to double */
- double
- __extendsfdf2 (float a1)
- {
- register union float_long fl1;
- register union double_long dl;
- register long exp;
-
- fl1.f = a1;
-
- if (!fl1.l)
- {
- dl.l.upper = dl.l.lower = 0;
- return dl.d;
- }
-
- dl.l.upper = SIGN (fl1.l);
- exp = EXP (fl1.l) - EXCESS + EXCESSD;
- dl.l.upper |= exp << 20;
- dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3;
- dl.l.lower = MANT (fl1.l) << 29;
-
- return dl.d;
- }
-
- /* convert double to float */
- float
- __truncdfsf2 (double a1)
- {
- register long exp;
- register long mant;
- register union float_long fl;
- register union double_long dl1;
-
- dl1.d = a1;
-
- if (!dl1.l.upper && !dl1.l.lower)
- return 0;
-
- exp = EXPD (dl1) - EXCESSD + EXCESS;
-
- /* shift double mantissa 6 bits so we can round */
- mant = MANTD (dl1) >> 6;
-
- /* now round and shift down */
- mant += 1;
- mant >>= 1;
-
- /* did the round overflow? */
- if (mant & 0xFF000000)
- {
- mant >>= 1;
- exp++;
- }
-
- mant &= ~HIDDEN;
-
- /* pack up and go home */
- fl.l = PACK (SIGND (dl1), exp, mant);
- return (fl.f);
- }
-
- /* convert double to int */
- int
- __fixdfsi (double a1)
- {
- register union double_long dl1;
- register long exp;
- register long l;
-
- dl1.d = a1;
-
- if (!dl1.l.upper && !dl1.l.lower)
- return 0;
-
- exp = EXPD (dl1) - EXCESSD - 31;
- l = MANTD (dl1);
-
- if (exp > 0)
- {
- /* Return largest integer. */
- return SIGND (dl1) ? 0x80000000 : 0x7fffffff;
- }
-
- if (exp <= -32)
- return 0;
-
- /* shift down until exp = 0 */
- if (exp < 0)
- l >>= -exp;
-
- return (SIGND (dl1) ? -l : l);
- }
-
- /* convert float to int */
- int
- __fixsfsi (float a1)
- {
- double foo = a1;
- return __fixdfsi (foo);
- }
-
- #else /* EXTFLOAT */
-
- /* Primitive extended precision floating point support.
-
- We assume all numbers are normalized, don't do any rounding, etc. */
-
- /* Prototypes for the above in case we use them. */
- double __floatsidf (int);
- float __floatsisf (int);
- double __extendsfdf2 (float);
- float __truncdfsf2 (double);
- int __fixdfsi (double);
- int __fixsfsi (float);
-
- /* convert double to long double */
- long double
- __extenddfxf2 (double d)
- {
- register union double_long dl;
- register union long_double_long ldl;
- register long exp;
-
- dl.d = d;
- /*printf ("dfxf in: %g\n", d);*/
-
- if (!dl.l.upper && !dl.l.lower)
- return 0;
-
- ldl.l.upper = SIGND (dl);
- exp = EXPD (dl) - EXCESSD + EXCESSX;
- ldl.l.upper |= exp << 16;
- ldl.l.middle = HIDDENX;
- /* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */
- ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20);
- /* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */
- ldl.l.middle |= dl.l.lower >> (1 + 20);
- /* 32 - 21: # bits of dl.l.lower in ldl.l.middle */
- ldl.l.lower = dl.l.lower << (32 - 21);
-
- /*printf ("dfxf out: %s\n", dumpxf (ldl.ld));*/
- return ldl.ld;
- }
-
- /* convert long double to double */
- double
- __truncxfdf2 (long double ld)
- {
- register long exp;
- register union double_long dl;
- register union long_double_long ldl;
-
- ldl.ld = ld;
- /*printf ("xfdf in: %s\n", dumpxf (ld));*/
-
- if (!ldl.l.upper && !ldl.l.middle && !ldl.l.lower)
- return 0;
-
- exp = EXPX (ldl) - EXCESSX + EXCESSD;
- /* ??? quick and dirty: keep `exp' sane */
- if (exp >= EXPDMASK)
- exp = EXPDMASK - 1;
- dl.l.upper = SIGNX (ldl);
- dl.l.upper |= exp << (32 - (EXPDBITS + 1));
- /* +1-1: add one for sign bit, but take one off for explicit-integer-bit */
- dl.l.upper |= (ldl.l.middle & MANTXMASK) >> (EXPDBITS + 1 - 1);
- dl.l.lower = (ldl.l.middle & MANTXMASK) << (32 - (EXPDBITS + 1 - 1));
- dl.l.lower |= ldl.l.lower >> (EXPDBITS + 1 - 1);
-
- /*printf ("xfdf out: %g\n", dl.d);*/
- return dl.d;
- }
-
- /* convert a float to a long double */
- long double
- __extendsfxf2 (float f)
- {
- long double foo = __extenddfxf2 (__extendsfdf2 (f));
- return foo;
- }
-
- /* convert a long double to a float */
- float
- __truncxfsf2 (long double ld)
- {
- float foo = __truncdfsf2 (__truncxfdf2 (ld));
- return foo;
- }
-
- /* convert an int to a long double */
- long double
- __floatsixf (int l)
- {
- double foo = __floatsidf (l);
- return foo;
- }
-
- /* convert a long double to an int */
- int
- __fixxfsi (long double ld)
- {
- int foo = __fixdfsi ((double) ld);
- return foo;
- }
-
- /* The remaining provide crude math support by working in double precision. */
-
- long double
- __addxf3 (long double x1, long double x2)
- {
- return (double) x1 + (double) x2;
- }
-
- long double
- __subxf3 (long double x1, long double x2)
- {
- return (double) x1 - (double) x2;
- }
-
- long double
- __mulxf3 (long double x1, long double x2)
- {
- return (double) x1 * (double) x2;
- }
-
- long double
- __divxf3 (long double x1, long double x2)
- {
- return (double) x1 / (double) x2;
- }
-
- long double
- __negxf2 (long double x1)
- {
- return - (double) x1;
- }
-
- long
- __cmpxf2 (long double x1, long double x2)
- {
- return __cmpdf2 ((double) x1, (double) x2);
- }
-
- long
- __eqxf2 (long double x1, long double x2)
- {
- return __cmpdf2 ((double) x1, (double) x2);
- }
-
- long
- __nexf2 (long double x1, long double x2)
- {
- return __cmpdf2 ((double) x1, (double) x2);
- }
-
- long
- __ltxf2 (long double x1, long double x2)
- {
- return __cmpdf2 ((double) x1, (double) x2);
- }
-
- long
- __lexf2 (long double x1, long double x2)
- {
- return __cmpdf2 ((double) x1, (double) x2);
- }
-
- long
- __gtxf2 (long double x1, long double x2)
- {
- return __cmpdf2 ((double) x1, (double) x2);
- }
-
- long
- __gexf2 (long double x1, long double x2)
- {
- return __cmpdf2 ((double) x1, (double) x2);
- }
-
- #endif /* EXTFLOAT */
-