source: trunk/third/gcc/floatlib.c @ 8834

Revision 8834, 11.1 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r8833, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2** libgcc support for software floating point.
3** Copyright (C) 1991 by Pipeline Associates, Inc.  All rights reserved.
4** Permission is granted to do *anything* you want with this file,
5** commercial or otherwise, provided this message remains intact.  So there!
6** I would appreciate receiving any updates/patches/changes that anyone
7** makes, and am willing to be the repository for said changes (am I
8** making a big mistake?).
9
10Warning! Only single-precision is actually implemented.  This file
11won't really be much use until double-precision is supported.
12
13However, once that is done, this file might eventually become a
14replacement for libgcc1.c.  It might also make possible
15cross-compilation for an IEEE target machine from a non-IEEE
16host such as a VAX.
17
18If you'd like to work on completing this, please talk to rms@gnu.ai.mit.edu.
19
20
21**
22** Pat Wood
23** Pipeline Associates, Inc.
24** pipeline!phw@motown.com or
25** sun!pipeline!phw or
26** uunet!motown!pipeline!phw
27**
28** 05/01/91 -- V1.0 -- first release to gcc mailing lists
29** 05/04/91 -- V1.1 -- added float and double prototypes and return values
30**                  -- fixed problems with adding and subtracting zero
31**                  -- fixed rounding in truncdfsf2
32**                  -- fixed SWAP define and tested on 386
33*/
34
35/*
36** The following are routines that replace the libgcc soft floating point
37** routines that are called automatically when -msoft-float is selected.
38** The support single and double precision IEEE format, with provisions
39** for byte-swapped machines (tested on 386).  Some of the double-precision
40** routines work at full precision, but most of the hard ones simply punt
41** and call the single precision routines, producing a loss of accuracy.
42** long long support is not assumed or included.
43** Overall accuracy is close to IEEE (actually 68882) for single-precision
44** arithmetic.  I think there may still be a 1 in 1000 chance of a bit
45** being rounded the wrong way during a multiply.  I'm not fussy enough to
46** bother with it, but if anyone is, knock yourself out.
47**
48** Efficiency has only been addressed where it was obvious that something
49** would make a big difference.  Anyone who wants to do this right for
50** best speed should go in and rewrite in assembler.
51**
52** I have tested this only on a 68030 workstation and 386/ix integrated
53** in with -msoft-float.
54*/
55
56/* the following deal with IEEE single-precision numbers */
57#define EXCESS          126
58#define SIGNBIT         0x80000000
59#define HIDDEN          (1 << 23)
60#define SIGN(fp)        ((fp) & SIGNBIT)
61#define EXP(fp)         (((fp) >> 23) & 0xFF)
62#define MANT(fp)        (((fp) & 0x7FFFFF) | HIDDEN)
63#define PACK(s,e,m)     ((s) | ((e) << 23) | (m))
64
65/* the following deal with IEEE double-precision numbers */
66#define EXCESSD         1022
67#define HIDDEND         (1 << 20)
68#define EXPD(fp)        (((fp.l.upper) >> 20) & 0x7FF)
69#define SIGND(fp)       ((fp.l.upper) & SIGNBIT)
70#define MANTD(fp)       (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
71                                (fp.l.lower >> 22))
72
73/* define SWAP for 386/960 reverse-byte-order brain-damaged CPUs */
74union double_long
75  {
76    double d;
77#ifdef SWAP
78    struct {
79      unsigned long lower;
80      long upper;
81    } l;
82#else
83    struct {
84      long upper;
85      unsigned long lower;
86    } l;
87#endif
88  };
89
90union float_long
91  {
92    float f;
93    long l;
94  };
95
96/* add two floats */
97float
98__addsf3 (float a1, float a2)
99{
100  register long mant1, mant2;
101  register union float_long fl1, fl2;
102  register int exp1, exp2;
103  int sign = 0;
104
105  fl1.f = a1;
106  fl2.f = a2;
107
108  /* check for zero args */
109  if (!fl1.l)
110    return (fl2.f);
111  if (!fl2.l)
112    return (fl1.f);
113
114  exp1 = EXP (fl1.l);
115  exp2 = EXP (fl2.l);
116
117  if (exp1 > exp2 + 25)
118    return (fl1.l);
119  if (exp2 > exp1 + 25)
120    return (fl2.l);
121
122  /* do everything in excess precision so's we can round later */
123  mant1 = MANT (fl1.l) << 6;
124  mant2 = MANT (fl2.l) << 6;
125
126  if (SIGN (fl1.l))
127    mant1 = -mant1;
128  if (SIGN (fl2.l))
129    mant2 = -mant2;
130
131  if (exp1 > exp2)
132    {
133      mant2 >>= exp1 - exp2;
134    }
135  else
136    {
137      mant1 >>= exp2 - exp1;
138      exp1 = exp2;
139    }
140  mant1 += mant2;
141
142  if (mant1 < 0)
143    {
144      mant1 = -mant1;
145      sign = SIGNBIT;
146    }
147  else if (!mant1)
148    return (0);
149
150  /* normalize up */
151  while (!(mant1 & 0xE0000000))
152    {
153      mant1 <<= 1;
154      exp1--;
155    }
156
157  /* normalize down? */
158  if (mant1 & (1 << 30))
159    {
160      mant1 >>= 1;
161      exp1++;
162    }
163
164  /* round to even */
165  mant1 += (mant1 & 0x40) ? 0x20 : 0x1F;
166
167  /* normalize down? */
168  if (mant1 & (1 << 30))
169    {
170      mant1 >>= 1;
171      exp1++;
172    }
173
174  /* lose extra precision */
175  mant1 >>= 6;
176
177  /* turn off hidden bit */
178  mant1 &= ~HIDDEN;
179
180  /* pack up and go home */
181  fl1.l = PACK (sign, exp1, mant1);
182  return (fl1.f);
183}
184
185/* subtract two floats */
186float
187__subsf3 (float a1, float a2)
188{
189  register union float_long fl1, fl2;
190
191  fl1.f = a1;
192  fl2.f = a2;
193
194  /* check for zero args */
195  if (!fl2.l)
196    return (fl1.f);
197  if (!fl1.l)
198    return (-fl2.f);
199
200  /* twiddle sign bit and add */
201  fl2.l ^= SIGNBIT;
202  return __addsf3 (a1, fl2.f);
203}
204
205/* compare two floats */
206long
207__cmpsf2 (float a1, float a2)
208{
209  register union float_long fl1, fl2;
210
211  fl1.f = a1;
212  fl2.f = a2;
213
214  if (SIGN (fl1.l) && SIGN (fl2.l))
215    {
216      fl1.l ^= SIGNBIT;
217      fl2.l ^= SIGNBIT;
218    }
219  if (fl1.l < fl2.l)
220    return (-1);
221  if (fl1.l > fl2.l)
222    return (1);
223  return (0);
224}
225
226/* multiply two floats */
227float
228__mulsf3 (float a1, float a2)
229{
230  register union float_long fl1, fl2;
231  register unsigned long result;
232  register int exp;
233  int sign;
234
235  fl1.f = a1;
236  fl2.f = a2;
237
238  if (!fl1.l || !fl2.l)
239    return (0);
240
241  /* compute sign and exponent */
242  sign = SIGN (fl1.l) ^ SIGN (fl2.l);
243  exp = EXP (fl1.l) - EXCESS;
244  exp += EXP (fl2.l);
245
246  fl1.l = MANT (fl1.l);
247  fl2.l = MANT (fl2.l);
248
249  /* the multiply is done as one 16x16 multiply and two 16x8 multiples */
250  result = (fl1.l >> 8) * (fl2.l >> 8);
251  result += ((fl1.l & 0xFF) * (fl2.l >> 8)) >> 8;
252  result += ((fl2.l & 0xFF) * (fl1.l >> 8)) >> 8;
253
254  if (result & 0x80000000)
255    {
256      /* round */
257      result += 0x80;
258      result >>= 8;
259    }
260  else
261    {
262      /* round */
263      result += 0x40;
264      result >>= 7;
265      exp--;
266    }
267
268  result &= ~HIDDEN;
269
270  /* pack up and go home */
271  fl1.l = PACK (sign, exp, result);
272  return (fl1.f);
273}
274
275/* divide two floats */
276float
277__divsf3 (float a1, float a2)
278{
279  register union float_long fl1, fl2;
280  register int result;
281  register int mask;
282  register int exp, sign;
283
284  fl1.f = a1;
285  fl2.f = a2;
286
287  /* subtract exponents */
288  exp = EXP (fl1.l) - EXP (fl2.l) + EXCESS;
289
290  /* compute sign */
291  sign = SIGN (fl1.l) ^ SIGN (fl2.l);
292
293  /* divide by zero??? */
294  if (!fl2.l)
295    /* return NaN or -NaN */
296    return (sign ? 0xFFFFFFFF : 0x7FFFFFFF);
297
298  /* numerator zero??? */
299  if (!fl1.l)
300    return (0);
301
302  /* now get mantissas */
303  fl1.l = MANT (fl1.l);
304  fl2.l = MANT (fl2.l);
305
306  /* this assures we have 25 bits of precision in the end */
307  if (fl1.l < fl2.l)
308    {
309      fl1.l <<= 1;
310      exp--;
311    }
312
313  /* now we perform repeated subtraction of fl2.l from fl1.l */
314  mask = 0x1000000;
315  result = 0;
316  while (mask)
317    {
318      if (fl1.l >= fl2.l)
319        {
320          result |= mask;
321          fl1.l -= fl2.l;
322        }
323      fl1.l <<= 1;
324      mask >>= 1;
325    }
326
327  /* round */
328  result += 1;
329
330  /* normalize down */
331  exp++;
332  result >>= 1;
333
334  result &= ~HIDDEN;
335
336  /* pack up and go home */
337  fl1.l = PACK (sign, exp, result);
338  return (fl1.f);
339}
340
341/* convert int to double */
342double
343__floatsidf (register long a1)
344{
345  register int sign = 0, exp = 31 + EXCESSD;
346  union double_long dl;
347
348  if (!a1)
349    {
350      dl.l.upper = dl.l.lower = 0;
351      return (dl.d);
352    }
353
354  if (a1 < 0)
355    {
356      sign = SIGNBIT;
357      a1 = -a1;
358    }
359
360  while (a1 < 0x1000000)
361    {
362      a1 <<= 4;
363      exp -= 4;
364    }
365
366  while (a1 < 0x40000000)
367    {
368      a1 <<= 1;
369      exp--;
370    }
371
372  /* pack up and go home */
373  dl.l.upper = sign;
374  dl.l.upper |= exp << 20;
375  dl.l.upper |= (a1 >> 10) & ~HIDDEND;
376  dl.l.lower = a1 << 22;
377
378  return (dl.d);
379}
380
381/* negate a float */
382float
383__negsf2 (float a1)
384{
385  register union float_long fl1;
386
387  fl1.f = a1;
388  if (!fl1.l)
389    return (0);
390
391  fl1.l ^= SIGNBIT;
392  return (fl1.f);
393}
394
395/* negate a double */
396double
397__negdf2 (double a1)
398{
399  register union double_long dl1;
400
401  dl1.d = a1;
402
403  if (!dl1.l.upper && !dl1.l.lower)
404      return (dl1.d);
405
406  dl1.l.upper ^= SIGNBIT;
407  return (dl1.d);
408}
409
410/* convert float to double */
411double
412__extendsfdf2 (float a1)
413{
414  register union float_long fl1;
415  register union double_long dl;
416  register int exp;
417
418  fl1.f = a1;
419
420  if (!fl1.l)
421    {
422      dl.l.upper = dl.l.lower = 0;
423      return (dl.d);
424    }
425
426  dl.l.upper = SIGN (fl1.l);
427  exp = EXP (fl1.l) - EXCESS + EXCESSD;
428  dl.l.upper |= exp << 20;
429  dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3;
430  dl.l.lower = MANT (fl1.l) << 29;
431
432  return (dl.d);
433}
434
435/* convert double to float */
436float
437__truncdfsf2 (double a1)
438{
439  register int exp;
440  register long mant;
441  register union float_long fl;
442  register union double_long dl1;
443
444  dl1.d = a1;
445
446  if (!dl1.l.upper && !dl1.l.lower)
447    return (0);
448
449  exp = EXPD (dl1) - EXCESSD + EXCESS;
450
451  /* shift double mantissa 6 bits so we can round */
452  mant = MANTD (dl1) >> 6;
453
454  /* now round and shift down */
455  mant += 1;
456  mant >>= 1;
457
458  /* did the round overflow? */
459  if (mant & 0xFF000000)
460    {
461      mant >>= 1;
462      exp++;
463    }
464
465  mant &= ~HIDDEN;
466
467  /* pack up and go home */
468  fl.l = PACK (SIGND (dl1), exp, mant);
469  return (fl.f);
470}
471
472/* compare two doubles */
473long
474__cmpdf2 (double a1, double a2)
475{
476  register union double_long dl1, dl2;
477
478  dl1.d = a1;
479  dl2.d = a2;
480
481  if (SIGND (dl1) && SIGND (dl2))
482    {
483      dl1.l.upper ^= SIGNBIT;
484      dl2.l.upper ^= SIGNBIT;
485    }
486  if (dl1.l.upper < dl2.l.upper)
487    return (-1);
488  if (dl1.l.upper > dl2.l.upper)
489    return (1);
490  if (dl1.l.lower < dl2.l.lower)
491    return (-1);
492  if (dl1.l.lower > dl2.l.lower)
493    return (1);
494  return (0);
495}
496
497/* convert double to int */
498long
499__fixdfsi (double a1)
500{
501  register union double_long dl1;
502  register int exp;
503  register long l;
504
505  dl1.d = a1;
506
507  if (!dl1.l.upper && !dl1.l.lower)
508    return (0);
509
510  exp = EXPD (dl1) - EXCESSD - 31;
511  l = MANTD (dl1);
512
513  if (exp > 0)
514    return (0x7FFFFFFF | SIGND (dl1)); /* largest integer */
515
516  /* shift down until exp = 0 or l = 0 */
517  if (exp < 0 && exp > -32 && l)
518    l >>= -exp;
519  else
520    return (0);
521
522  return (SIGND (dl1) ? -l : l);
523}
524
525/* convert double to unsigned int */
526unsigned
527long __fixunsdfsi (double a1)
528{
529  register union double_long dl1;
530  register int exp;
531  register unsigned long l;
532
533  dl1.d = a1;
534
535  if (!dl1.l.upper && !dl1.l.lower)
536    return (0);
537
538  exp = EXPD (dl1) - EXCESSD - 32;
539  l = (((((dl1.l.upper) & 0xFFFFF) | HIDDEND) << 11) | (dl1.l.lower >> 21));
540
541  if (exp > 0)
542    return (0xFFFFFFFF);        /* largest integer */
543
544  /* shift down until exp = 0 or l = 0 */
545  if (exp < 0 && exp > -32 && l)
546    l >>= -exp;
547  else
548    return (0);
549
550  return (l);
551}
552
553/* For now, the hard double-precision routines simply
554   punt and do it in single */
555/* addtwo doubles */
556double
557__adddf3 (double a1, double a2)
558{
559  return ((float) a1 + (float) a2);
560}
561
562/* subtract two doubles */
563double
564__subdf3 (double a1, double a2)
565{
566  return ((float) a1 - (float) a2);
567}
568
569/* multiply two doubles */
570double
571__muldf3 (double a1, double a2)
572{
573  return ((float) a1 * (float) a2);
574}
575
576/* divide two doubles */
577double
578__divdf3 (double a1, double a2)
579{
580  return ((float) a1 / (float) a2);
581}
Note: See TracBrowser for help on using the repository browser.