update copyrights in config dir.
[official-gcc.git] / gcc / config / m68k / fpgnulib.c
blob0559b628c87a473ad10053b17fad8d6d3b222ae4
1 /* This is a stripped down version of floatlib.c. It supplies only those
2 functions which exist in libgcc, but for which there is not assembly
3 language versions in m68k/lb1sf68.asm.
5 It also includes simplistic support for extended floats (by working in
6 double precision). You must compile this file again with -DEXTFLOAT
7 to get this support. */
9 /*
10 ** gnulib support for software floating point.
11 ** Copyright (C) 1991 by Pipeline Associates, Inc. All rights reserved.
12 ** Permission is granted to do *anything* you want with this file,
13 ** commercial or otherwise, provided this message remains intact. So there!
14 ** I would appreciate receiving any updates/patches/changes that anyone
15 ** makes, and am willing to be the repository for said changes (am I
16 ** making a big mistake?).
18 ** Pat Wood
19 ** Pipeline Associates, Inc.
20 ** pipeline!phw@motown.com or
21 ** sun!pipeline!phw or
22 ** uunet!motown!pipeline!phw
24 ** 05/01/91 -- V1.0 -- first release to gcc mailing lists
25 ** 05/04/91 -- V1.1 -- added float and double prototypes and return values
26 ** -- fixed problems with adding and subtracting zero
27 ** -- fixed rounding in truncdfsf2
28 ** -- fixed SWAP define and tested on 386
32 ** The following are routines that replace the gnulib soft floating point
33 ** routines that are called automatically when -msoft-float is selected.
34 ** The support single and double precision IEEE format, with provisions
35 ** for byte-swapped machines (tested on 386). Some of the double-precision
36 ** routines work at full precision, but most of the hard ones simply punt
37 ** and call the single precision routines, producing a loss of accuracy.
38 ** long long support is not assumed or included.
39 ** Overall accuracy is close to IEEE (actually 68882) for single-precision
40 ** arithmetic. I think there may still be a 1 in 1000 chance of a bit
41 ** being rounded the wrong way during a multiply. I'm not fussy enough to
42 ** bother with it, but if anyone is, knock yourself out.
44 ** Efficiency has only been addressed where it was obvious that something
45 ** would make a big difference. Anyone who wants to do this right for
46 ** best speed should go in and rewrite in assembler.
48 ** I have tested this only on a 68030 workstation and 386/ix integrated
49 ** in with -msoft-float.
52 /* the following deal with IEEE single-precision numbers */
53 #define EXCESS 126L
54 #define SIGNBIT 0x80000000L
55 #define HIDDEN (1L << 23L)
56 #define SIGN(fp) ((fp) & SIGNBIT)
57 #define EXP(fp) (((fp) >> 23L) & 0xFF)
58 #define MANT(fp) (((fp) & 0x7FFFFFL) | HIDDEN)
59 #define PACK(s,e,m) ((s) | ((e) << 23L) | (m))
61 /* the following deal with IEEE double-precision numbers */
62 #define EXCESSD 1022
63 #define HIDDEND (1L << 20L)
64 #define EXPDBITS 11
65 #define EXPDMASK 0x7FF
66 #define EXPD(fp) (((fp.l.upper) >> 20L) & 0x7FFL)
67 #define SIGND(fp) ((fp.l.upper) & SIGNBIT)
68 #define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
69 (fp.l.lower >> 22))
70 #define MANTDMASK 0xFFFFF /* mask of upper part */
72 /* the following deal with IEEE extended-precision numbers */
73 #define EXCESSX 16382
74 #define HIDDENX (1L << 31L)
75 #define EXPXBITS 15
76 #define EXPXMASK 0x7FFF
77 #define EXPX(fp) (((fp.l.upper) >> 16) & EXPXMASK)
78 #define SIGNX(fp) ((fp.l.upper) & SIGNBIT)
79 #define MANTXMASK 0x7FFFFFFF /* mask of upper part */
81 union double_long
83 double d;
84 struct {
85 long upper;
86 unsigned long lower;
87 } l;
90 union float_long {
91 float f;
92 long l;
95 union long_double_long
97 long double ld;
98 struct
100 long upper;
101 unsigned long middle;
102 unsigned long lower;
103 } l;
106 #ifndef EXTFLOAT
108 /* convert int to double */
109 double
110 __floatsidf (int a1)
112 long sign = 0, exp = 31 + EXCESSD;
113 union double_long dl;
115 if (!a1)
117 dl.l.upper = dl.l.lower = 0;
118 return dl.d;
121 if (a1 < 0)
123 sign = SIGNBIT;
124 a1 = -a1;
125 if (a1 < 0)
127 dl.l.upper = SIGNBIT | ((32 + EXCESSD) << 20L);
128 dl.l.lower = 0;
129 return dl.d;
133 while (a1 < 0x1000000)
135 a1 <<= 4;
136 exp -= 4;
139 while (a1 < 0x40000000)
141 a1 <<= 1;
142 exp--;
145 /* pack up and go home */
146 dl.l.upper = sign;
147 dl.l.upper |= exp << 20L;
148 dl.l.upper |= (a1 >> 10L) & ~HIDDEND;
149 dl.l.lower = a1 << 22L;
151 return dl.d;
154 /* convert int to float */
155 float
156 __floatsisf (int l)
158 double foo = __floatsidf (l);
159 return foo;
162 /* convert float to double */
163 double
164 __extendsfdf2 (float a1)
166 register union float_long fl1;
167 register union double_long dl;
168 register long exp;
170 fl1.f = a1;
172 if (!fl1.l)
174 dl.l.upper = dl.l.lower = 0;
175 return dl.d;
178 dl.l.upper = SIGN (fl1.l);
179 exp = EXP (fl1.l) - EXCESS + EXCESSD;
180 dl.l.upper |= exp << 20;
181 dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3;
182 dl.l.lower = MANT (fl1.l) << 29;
184 return dl.d;
187 /* convert double to float */
188 float
189 __truncdfsf2 (double a1)
191 register long exp;
192 register long mant;
193 register union float_long fl;
194 register union double_long dl1;
196 dl1.d = a1;
198 if (!dl1.l.upper && !dl1.l.lower)
199 return 0;
201 exp = EXPD (dl1) - EXCESSD + EXCESS;
203 /* shift double mantissa 6 bits so we can round */
204 mant = MANTD (dl1) >> 6;
206 /* now round and shift down */
207 mant += 1;
208 mant >>= 1;
210 /* did the round overflow? */
211 if (mant & 0xFF000000)
213 mant >>= 1;
214 exp++;
217 mant &= ~HIDDEN;
219 /* pack up and go home */
220 fl.l = PACK (SIGND (dl1), exp, mant);
221 return (fl.f);
224 /* convert double to int */
226 __fixdfsi (double a1)
228 register union double_long dl1;
229 register long exp;
230 register long l;
232 dl1.d = a1;
234 if (!dl1.l.upper && !dl1.l.lower)
235 return 0;
237 exp = EXPD (dl1) - EXCESSD - 31;
238 l = MANTD (dl1);
240 if (exp > 0)
242 /* Return largest integer. */
243 return SIGND (dl1) ? 0x80000000 : 0x7fffffff;
246 if (exp <= -32)
247 return 0;
249 /* shift down until exp = 0 */
250 if (exp < 0)
251 l >>= -exp;
253 return (SIGND (dl1) ? -l : l);
256 /* convert float to int */
258 __fixsfsi (float a1)
260 double foo = a1;
261 return __fixdfsi (foo);
264 #else /* EXTFLOAT */
266 /* Primitive extended precision floating point support.
268 We assume all numbers are normalized, don't do any rounding, etc. */
270 /* Prototypes for the above in case we use them. */
271 double __floatsidf (int);
272 float __floatsisf (int);
273 double __extendsfdf2 (float);
274 float __truncdfsf2 (double);
275 int __fixdfsi (double);
276 int __fixsfsi (float);
278 /* convert double to long double */
279 long double
280 __extenddfxf2 (double d)
282 register union double_long dl;
283 register union long_double_long ldl;
284 register long exp;
286 dl.d = d;
287 /*printf ("dfxf in: %g\n", d);*/
289 if (!dl.l.upper && !dl.l.lower)
290 return 0;
292 ldl.l.upper = SIGND (dl);
293 exp = EXPD (dl) - EXCESSD + EXCESSX;
294 ldl.l.upper |= exp << 16;
295 ldl.l.middle = HIDDENX;
296 /* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */
297 ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20);
298 /* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */
299 ldl.l.middle |= dl.l.lower >> (1 + 20);
300 /* 32 - 21: # bits of dl.l.lower in ldl.l.middle */
301 ldl.l.lower = dl.l.lower << (32 - 21);
303 /*printf ("dfxf out: %s\n", dumpxf (ldl.ld));*/
304 return ldl.ld;
307 /* convert long double to double */
308 double
309 __truncxfdf2 (long double ld)
311 register long exp;
312 register union double_long dl;
313 register union long_double_long ldl;
315 ldl.ld = ld;
316 /*printf ("xfdf in: %s\n", dumpxf (ld));*/
318 if (!ldl.l.upper && !ldl.l.middle && !ldl.l.lower)
319 return 0;
321 exp = EXPX (ldl) - EXCESSX + EXCESSD;
322 /* ??? quick and dirty: keep `exp' sane */
323 if (exp >= EXPDMASK)
324 exp = EXPDMASK - 1;
325 dl.l.upper = SIGNX (ldl);
326 dl.l.upper |= exp << (32 - (EXPDBITS + 1));
327 /* +1-1: add one for sign bit, but take one off for explicit-integer-bit */
328 dl.l.upper |= (ldl.l.middle & MANTXMASK) >> (EXPDBITS + 1 - 1);
329 dl.l.lower = (ldl.l.middle & MANTXMASK) << (32 - (EXPDBITS + 1 - 1));
330 dl.l.lower |= ldl.l.lower >> (EXPDBITS + 1 - 1);
332 /*printf ("xfdf out: %g\n", dl.d);*/
333 return dl.d;
336 /* convert a float to a long double */
337 long double
338 __extendsfxf2 (float f)
340 long double foo = __extenddfxf2 (__extendsfdf2 (f));
341 return foo;
344 /* convert a long double to a float */
345 float
346 __truncxfsf2 (long double ld)
348 float foo = __truncdfsf2 (__truncxfdf2 (ld));
349 return foo;
352 /* convert an int to a long double */
353 long double
354 __floatsixf (int l)
356 double foo = __floatsidf (l);
357 return foo;
360 /* convert a long double to an int */
362 __fixxfsi (long double ld)
364 int foo = __fixdfsi ((double) ld);
365 return foo;
368 /* The remaining provide crude math support by working in double precision. */
370 long double
371 __addxf3 (long double x1, long double x2)
373 return (double) x1 + (double) x2;
376 long double
377 __subxf3 (long double x1, long double x2)
379 return (double) x1 - (double) x2;
382 long double
383 __mulxf3 (long double x1, long double x2)
385 return (double) x1 * (double) x2;
388 long double
389 __divxf3 (long double x1, long double x2)
391 return (double) x1 / (double) x2;
394 long double
395 __negxf2 (long double x1)
397 return - (double) x1;
400 long
401 __cmpxf2 (long double x1, long double x2)
403 return __cmpdf2 ((double) x1, (double) x2);
406 long
407 __eqxf2 (long double x1, long double x2)
409 return __cmpdf2 ((double) x1, (double) x2);
412 long
413 __nexf2 (long double x1, long double x2)
415 return __cmpdf2 ((double) x1, (double) x2);
418 long
419 __ltxf2 (long double x1, long double x2)
421 return __cmpdf2 ((double) x1, (double) x2);
424 long
425 __lexf2 (long double x1, long double x2)
427 return __cmpdf2 ((double) x1, (double) x2);
430 long
431 __gtxf2 (long double x1, long double x2)
433 return __cmpdf2 ((double) x1, (double) x2);
436 long
437 __gexf2 (long double x1, long double x2)
439 return __cmpdf2 ((double) x1, (double) x2);
442 #endif /* EXTFLOAT */