summaryrefslogtreecommitdiff
path: root/libgcc/config/m68k/fpgnulib.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgcc/config/m68k/fpgnulib.c')
-rw-r--r--libgcc/config/m68k/fpgnulib.c595
1 files changed, 595 insertions, 0 deletions
diff --git a/libgcc/config/m68k/fpgnulib.c b/libgcc/config/m68k/fpgnulib.c
new file mode 100644
index 00000000000..fe41edf26aa
--- /dev/null
+++ b/libgcc/config/m68k/fpgnulib.c
@@ -0,0 +1,595 @@
+/* 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.S.
+
+ 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 1022L
+#define HIDDEND (1L << 20L)
+#define EXPDBITS 11
+#define EXPDMASK 0x7FFL
+#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 0xFFFFFL /* mask of upper part */
+
+/* the following deal with IEEE extended-precision numbers */
+#define EXCESSX 16382L
+#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 0x7FFFFFFFL /* 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
+
+int
+__unordsf2(float a, float b)
+{
+ union float_long fl;
+
+ fl.f = a;
+ if (EXP(fl.l) == EXP(~0u) && (MANT(fl.l) & ~HIDDEN) != 0)
+ return 1;
+ fl.f = b;
+ if (EXP(fl.l) == EXP(~0u) && (MANT(fl.l) & ~HIDDEN) != 0)
+ return 1;
+ return 0;
+}
+
+int
+__unorddf2(double a, double b)
+{
+ union double_long dl;
+
+ dl.d = a;
+ if (EXPD(dl) == EXPDMASK
+ && ((dl.l.upper & MANTDMASK) != 0 || dl.l.lower != 0))
+ return 1;
+ dl.d = b;
+ if (EXPD(dl) == EXPDMASK
+ && ((dl.l.upper & MANTDMASK) != 0 || dl.l.lower != 0))
+ return 1;
+ return 0;
+}
+
+/* convert unsigned int to double */
+double
+__floatunsidf (unsigned long a1)
+{
+ long exp = 32 + EXCESSD;
+ union double_long dl;
+
+ if (!a1)
+ {
+ dl.l.upper = dl.l.lower = 0;
+ return dl.d;
+ }
+
+ while (a1 < 0x2000000L)
+ {
+ a1 <<= 4;
+ exp -= 4;
+ }
+
+ while (a1 < 0x80000000L)
+ {
+ a1 <<= 1;
+ exp--;
+ }
+
+ /* pack up and go home */
+ dl.l.upper = exp << 20L;
+ dl.l.upper |= (a1 >> 11L) & ~HIDDEND;
+ dl.l.lower = a1 << 21L;
+
+ return dl.d;
+}
+
+/* convert int to double */
+double
+__floatsidf (long 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 = (long)-(unsigned long)a1;
+ if (a1 < 0)
+ {
+ dl.l.upper = SIGNBIT | ((32 + EXCESSD) << 20L);
+ dl.l.lower = 0;
+ return dl.d;
+ }
+ }
+
+ while (a1 < 0x1000000L)
+ {
+ a1 <<= 4;
+ exp -= 4;
+ }
+
+ while (a1 < 0x40000000L)
+ {
+ 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 unsigned int to float */
+float
+__floatunsisf (unsigned long l)
+{
+ double foo = __floatunsidf (l);
+ return foo;
+}
+
+/* convert int to float */
+float
+__floatsisf (long 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;
+ register long mant;
+
+ fl1.f = a1;
+
+ dl.l.upper = SIGN (fl1.l);
+ if ((fl1.l & ~SIGNBIT) == 0)
+ {
+ dl.l.lower = 0;
+ return dl.d;
+ }
+
+ exp = EXP(fl1.l);
+ mant = MANT (fl1.l) & ~HIDDEN;
+ if (exp == 0)
+ {
+ /* Denormal. */
+ exp = 1;
+ while (!(mant & HIDDEN))
+ {
+ mant <<= 1;
+ exp--;
+ }
+ mant &= ~HIDDEN;
+ }
+ exp = exp - EXCESS + EXCESSD;
+ dl.l.upper |= exp << 20;
+ dl.l.upper |= mant >> 3;
+ dl.l.lower = mant << 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;
+ int sticky;
+ int shift;
+
+ dl1.d = a1;
+
+ if ((dl1.l.upper & ~SIGNBIT) == 0 && !dl1.l.lower)
+ {
+ fl.l = SIGND(dl1);
+ return fl.f;
+ }
+
+ exp = EXPD (dl1) - EXCESSD + EXCESS;
+
+ sticky = dl1.l.lower & ((1 << 22) - 1);
+ mant = MANTD (dl1);
+ /* shift double mantissa 6 bits so we can round */
+ sticky |= mant & ((1 << 6) - 1);
+ mant >>= 6;
+
+ /* Check for underflow and denormals. */
+ if (exp <= 0)
+ {
+ if (exp < -24)
+ {
+ sticky |= mant;
+ mant = 0;
+ }
+ else
+ {
+ sticky |= mant & ((1 << (1 - exp)) - 1);
+ mant >>= 1 - exp;
+ }
+ exp = 0;
+ }
+
+ /* now round */
+ shift = 1;
+ if ((mant & 1) && (sticky || (mant & 2)))
+ {
+ int rounding = exp ? 2 : 1;
+
+ mant += 1;
+
+ /* did the round overflow? */
+ if (mant >= (HIDDEN << rounding))
+ {
+ exp++;
+ shift = rounding;
+ }
+ }
+ /* shift down */
+ mant >>= shift;
+
+ mant &= ~HIDDEN;
+
+ /* pack up and go home */
+ fl.l = PACK (SIGND (dl1), exp, mant);
+ return (fl.f);
+}
+
+/* convert double to int */
+long
+__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) ? 0x80000000L : 0x7fffffffL;
+ }
+
+ if (exp <= -32)
+ return 0;
+
+ /* shift down until exp = 0 */
+ if (exp < 0)
+ l >>= -exp;
+
+ return (SIGND (dl1) ? -l : l);
+}
+
+/* convert float to int */
+long
+__fixsfsi (float a1)
+{
+ double foo = a1;
+ return __fixdfsi (foo);
+}
+
+#else /* EXTFLOAT */
+
+/* We do not need these routines for coldfire, as it has no extended
+ float format. */
+#if !defined (__mcoldfire__)
+
+/* 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 __floatunsidf (unsigned long);
+double __floatsidf (long);
+float __floatsisf (long);
+double __extendsfdf2 (float);
+float __truncdfsf2 (double);
+long __fixdfsi (double);
+long __fixsfsi (float);
+
+int
+__unordxf2(long double a, long double b)
+{
+ union long_double_long ldl;
+
+ ldl.ld = a;
+ if (EXPX(ldl) == EXPXMASK
+ && ((ldl.l.middle & MANTXMASK) != 0 || ldl.l.lower != 0))
+ return 1;
+ ldl.ld = b;
+ if (EXPX(ldl) == EXPXMASK
+ && ((ldl.l.middle & MANTXMASK) != 0 || ldl.l.lower != 0))
+ return 1;
+ return 0;
+}
+
+/* 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);*/
+
+ ldl.l.upper = SIGND (dl);
+ if ((dl.l.upper & ~SIGNBIT) == 0 && !dl.l.lower)
+ {
+ ldl.l.middle = 0;
+ ldl.l.lower = 0;
+ return ldl.ld;
+ }
+
+ 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));*/
+
+ dl.l.upper = SIGNX (ldl);
+ if ((ldl.l.upper & ~SIGNBIT) == 0 && !ldl.l.middle && !ldl.l.lower)
+ {
+ dl.l.lower = 0;
+ return dl.d;
+ }
+
+ exp = EXPX (ldl) - EXCESSX + EXCESSD;
+ /* ??? quick and dirty: keep `exp' sane */
+ if (exp >= EXPDMASK)
+ exp = EXPDMASK - 1;
+ 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 (long l)
+{
+ double foo = __floatsidf (l);
+ return foo;
+}
+
+/* convert an unsigned int to a long double */
+long double
+__floatunsixf (unsigned long l)
+{
+ double foo = __floatunsidf (l);
+ return foo;
+}
+
+/* convert a long double to an int */
+long
+__fixxfsi (long double ld)
+{
+ long 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 /* !__mcoldfire__ */
+#endif /* EXTFLOAT */