math-emu: Add support for reporting exact invalid exception
[linux-3.10.git] / include / math-emu / op-common.h
1 /* Software floating-point emulation. Common operations.
2    Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Richard Henderson (rth@cygnus.com),
5                   Jakub Jelinek (jj@ultra.linux.cz),
6                   David S. Miller (davem@redhat.com) and
7                   Peter Maydell (pmaydell@chiark.greenend.org.uk).
8
9    The GNU C Library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Library General Public License as
11    published by the Free Software Foundation; either version 2 of the
12    License, or (at your option) any later version.
13
14    The GNU C Library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18
19    You should have received a copy of the GNU Library General Public
20    License along with the GNU C Library; see the file COPYING.LIB.  If
21    not, write to the Free Software Foundation, Inc.,
22    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23
24 #ifndef __MATH_EMU_OP_COMMON_H__
25 #define __MATH_EMU_OP_COMMON_H__
26
27 #define _FP_DECL(wc, X)                 \
28   _FP_I_TYPE X##_c=0, X##_s=0, X##_e=0; \
29   _FP_FRAC_DECL_##wc(X)
30
31 /*
32  * Finish truely unpacking a native fp value by classifying the kind
33  * of fp value and normalizing both the exponent and the fraction.
34  */
35
36 #define _FP_UNPACK_CANONICAL(fs, wc, X)                                 \
37 do {                                                                    \
38   switch (X##_e)                                                        \
39   {                                                                     \
40   default:                                                              \
41     _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_IMPLBIT_##fs;                      \
42     _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);                                 \
43     X##_e -= _FP_EXPBIAS_##fs;                                          \
44     X##_c = FP_CLS_NORMAL;                                              \
45     break;                                                              \
46                                                                         \
47   case 0:                                                               \
48     if (_FP_FRAC_ZEROP_##wc(X))                                         \
49       X##_c = FP_CLS_ZERO;                                              \
50     else                                                                \
51       {                                                                 \
52         /* a denormalized number */                                     \
53         _FP_I_TYPE _shift;                                              \
54         _FP_FRAC_CLZ_##wc(_shift, X);                                   \
55         _shift -= _FP_FRACXBITS_##fs;                                   \
56         _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));                    \
57         X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;                         \
58         X##_c = FP_CLS_NORMAL;                                          \
59         FP_SET_EXCEPTION(FP_EX_DENORM);                                 \
60         if (FP_DENORM_ZERO)                                             \
61           {                                                             \
62             FP_SET_EXCEPTION(FP_EX_INEXACT);                            \
63             X##_c = FP_CLS_ZERO;                                        \
64           }                                                             \
65       }                                                                 \
66     break;                                                              \
67                                                                         \
68   case _FP_EXPMAX_##fs:                                                 \
69     if (_FP_FRAC_ZEROP_##wc(X))                                         \
70       X##_c = FP_CLS_INF;                                               \
71     else                                                                \
72       {                                                                 \
73         X##_c = FP_CLS_NAN;                                             \
74         /* Check for signaling NaN */                                   \
75         if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))            \
76           FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_SNAN);         \
77       }                                                                 \
78     break;                                                              \
79   }                                                                     \
80 } while (0)
81
82 /*
83  * Before packing the bits back into the native fp result, take care
84  * of such mundane things as rounding and overflow.  Also, for some
85  * kinds of fp values, the original parts may not have been fully
86  * extracted -- but that is ok, we can regenerate them now.
87  */
88
89 #define _FP_PACK_CANONICAL(fs, wc, X)                           \
90 do {                                                            \
91   switch (X##_c)                                                \
92   {                                                             \
93   case FP_CLS_NORMAL:                                           \
94     X##_e += _FP_EXPBIAS_##fs;                                  \
95     if (X##_e > 0)                                              \
96       {                                                         \
97         _FP_ROUND(wc, X);                                       \
98         if (_FP_FRAC_OVERP_##wc(fs, X))                         \
99           {                                                     \
100             _FP_FRAC_CLEAR_OVERP_##wc(fs, X);                   \
101             X##_e++;                                            \
102           }                                                     \
103         _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                     \
104         if (X##_e >= _FP_EXPMAX_##fs)                           \
105           {                                                     \
106             /* overflow */                                      \
107             switch (FP_ROUNDMODE)                               \
108               {                                                 \
109               case FP_RND_NEAREST:                              \
110                 X##_c = FP_CLS_INF;                             \
111                 break;                                          \
112               case FP_RND_PINF:                                 \
113                 if (!X##_s) X##_c = FP_CLS_INF;                 \
114                 break;                                          \
115               case FP_RND_MINF:                                 \
116                 if (X##_s) X##_c = FP_CLS_INF;                  \
117                 break;                                          \
118               }                                                 \
119             if (X##_c == FP_CLS_INF)                            \
120               {                                                 \
121                 /* Overflow to infinity */                      \
122                 X##_e = _FP_EXPMAX_##fs;                        \
123                 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
124               }                                                 \
125             else                                                \
126               {                                                 \
127                 /* Overflow to maximum normal */                \
128                 X##_e = _FP_EXPMAX_##fs - 1;                    \
129                 _FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc);         \
130               }                                                 \
131             FP_SET_EXCEPTION(FP_EX_OVERFLOW);                   \
132             FP_SET_EXCEPTION(FP_EX_INEXACT);                    \
133           }                                                     \
134       }                                                         \
135     else                                                        \
136       {                                                         \
137         /* we've got a denormalized number */                   \
138         X##_e = -X##_e + 1;                                     \
139         if (X##_e <= _FP_WFRACBITS_##fs)                        \
140           {                                                     \
141             _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs);    \
142             _FP_ROUND(wc, X);                                   \
143             if (_FP_FRAC_HIGH_##fs(X)                           \
144                 & (_FP_OVERFLOW_##fs >> 1))                     \
145               {                                                 \
146                 X##_e = 1;                                      \
147                 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
148                 FP_SET_EXCEPTION(FP_EX_INEXACT);                \
149               }                                                 \
150             else                                                \
151               {                                                 \
152                 X##_e = 0;                                      \
153                 _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);             \
154               }                                                 \
155             if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) ||          \
156                 (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))     \
157                 FP_SET_EXCEPTION(FP_EX_UNDERFLOW);              \
158           }                                                     \
159         else                                                    \
160           {                                                     \
161             /* underflow to zero */                             \
162             X##_e = 0;                                          \
163             if (!_FP_FRAC_ZEROP_##wc(X))                        \
164               {                                                 \
165                 _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);         \
166                 _FP_ROUND(wc, X);                               \
167                 _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS);        \
168               }                                                 \
169             FP_SET_EXCEPTION(FP_EX_UNDERFLOW);                  \
170           }                                                     \
171       }                                                         \
172     break;                                                      \
173                                                                 \
174   case FP_CLS_ZERO:                                             \
175     X##_e = 0;                                                  \
176     _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
177     break;                                                      \
178                                                                 \
179   case FP_CLS_INF:                                              \
180     X##_e = _FP_EXPMAX_##fs;                                    \
181     _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
182     break;                                                      \
183                                                                 \
184   case FP_CLS_NAN:                                              \
185     X##_e = _FP_EXPMAX_##fs;                                    \
186     if (!_FP_KEEPNANFRACP)                                      \
187       {                                                         \
188         _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);                 \
189         X##_s = _FP_NANSIGN_##fs;                               \
190       }                                                         \
191     else                                                        \
192       _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;            \
193     break;                                                      \
194   }                                                             \
195 } while (0)
196
197 /* This one accepts raw argument and not cooked,  returns
198  * 1 if X is a signaling NaN.
199  */
200 #define _FP_ISSIGNAN(fs, wc, X)                                 \
201 ({                                                              \
202   int __ret = 0;                                                \
203   if (X##_e == _FP_EXPMAX_##fs)                                 \
204     {                                                           \
205       if (!_FP_FRAC_ZEROP_##wc(X)                               \
206           && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))   \
207         __ret = 1;                                              \
208     }                                                           \
209   __ret;                                                        \
210 })
211
212
213
214
215
216 /*
217  * Main addition routine.  The input values should be cooked.
218  */
219
220 #define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP)                                \
221 do {                                                                         \
222   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                                     \
223   {                                                                          \
224   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):                         \
225     {                                                                        \
226       /* shift the smaller number so that its exponent matches the larger */ \
227       _FP_I_TYPE diff = X##_e - Y##_e;                                       \
228                                                                              \
229       if (diff < 0)                                                          \
230         {                                                                    \
231           diff = -diff;                                                      \
232           if (diff <= _FP_WFRACBITS_##fs)                                    \
233             _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);                  \
234           else if (!_FP_FRAC_ZEROP_##wc(X))                                  \
235             _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                          \
236           R##_e = Y##_e;                                                     \
237         }                                                                    \
238       else                                                                   \
239         {                                                                    \
240           if (diff > 0)                                                      \
241             {                                                                \
242               if (diff <= _FP_WFRACBITS_##fs)                                \
243                 _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);              \
244               else if (!_FP_FRAC_ZEROP_##wc(Y))                              \
245                 _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);                      \
246             }                                                                \
247           R##_e = X##_e;                                                     \
248         }                                                                    \
249                                                                              \
250       R##_c = FP_CLS_NORMAL;                                                 \
251                                                                              \
252       if (X##_s == Y##_s)                                                    \
253         {                                                                    \
254           R##_s = X##_s;                                                     \
255           _FP_FRAC_ADD_##wc(R, X, Y);                                        \
256           if (_FP_FRAC_OVERP_##wc(fs, R))                                    \
257             {                                                                \
258               _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);                   \
259               R##_e++;                                                       \
260             }                                                                \
261         }                                                                    \
262       else                                                                   \
263         {                                                                    \
264           R##_s = X##_s;                                                     \
265           _FP_FRAC_SUB_##wc(R, X, Y);                                        \
266           if (_FP_FRAC_ZEROP_##wc(R))                                        \
267             {                                                                \
268               /* return an exact zero */                                     \
269               if (FP_ROUNDMODE == FP_RND_MINF)                               \
270                 R##_s |= Y##_s;                                              \
271               else                                                           \
272                 R##_s &= Y##_s;                                              \
273               R##_c = FP_CLS_ZERO;                                           \
274             }                                                                \
275           else                                                               \
276             {                                                                \
277               if (_FP_FRAC_NEGP_##wc(R))                                     \
278                 {                                                            \
279                   _FP_FRAC_SUB_##wc(R, Y, X);                                \
280                   R##_s = Y##_s;                                             \
281                 }                                                            \
282                                                                              \
283               /* renormalize after subtraction */                            \
284               _FP_FRAC_CLZ_##wc(diff, R);                                    \
285               diff -= _FP_WFRACXBITS_##fs;                                   \
286               if (diff)                                                      \
287                 {                                                            \
288                   R##_e -= diff;                                             \
289                   _FP_FRAC_SLL_##wc(R, diff);                                \
290                 }                                                            \
291             }                                                                \
292         }                                                                    \
293       break;                                                                 \
294     }                                                                        \
295                                                                              \
296   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):                               \
297     _FP_CHOOSENAN(fs, wc, R, X, Y, OP);                                      \
298     break;                                                                   \
299                                                                              \
300   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):                           \
301     R##_e = X##_e;                                                           \
302   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):                            \
303   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):                               \
304   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                              \
305     _FP_FRAC_COPY_##wc(R, X);                                                \
306     R##_s = X##_s;                                                           \
307     R##_c = X##_c;                                                           \
308     break;                                                                   \
309                                                                              \
310   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):                           \
311     R##_e = Y##_e;                                                           \
312   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):                            \
313   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):                               \
314   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                              \
315     _FP_FRAC_COPY_##wc(R, Y);                                                \
316     R##_s = Y##_s;                                                           \
317     R##_c = Y##_c;                                                           \
318     break;                                                                   \
319                                                                              \
320   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):                               \
321     if (X##_s != Y##_s)                                                      \
322       {                                                                      \
323         /* +INF + -INF => NAN */                                             \
324         _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                              \
325         R##_s = _FP_NANSIGN_##fs;                                            \
326         R##_c = FP_CLS_NAN;                                                  \
327         FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ISI);                 \
328         break;                                                               \
329       }                                                                      \
330     /* FALLTHRU */                                                           \
331                                                                              \
332   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):                            \
333   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                              \
334     R##_s = X##_s;                                                           \
335     R##_c = FP_CLS_INF;                                                      \
336     break;                                                                   \
337                                                                              \
338   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):                            \
339   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                              \
340     R##_s = Y##_s;                                                           \
341     R##_c = FP_CLS_INF;                                                      \
342     break;                                                                   \
343                                                                              \
344   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):                             \
345     /* make sure the sign is correct */                                      \
346     if (FP_ROUNDMODE == FP_RND_MINF)                                         \
347       R##_s = X##_s | Y##_s;                                                 \
348     else                                                                     \
349       R##_s = X##_s & Y##_s;                                                 \
350     R##_c = FP_CLS_ZERO;                                                     \
351     break;                                                                   \
352                                                                              \
353   default:                                                                   \
354     abort();                                                                 \
355   }                                                                          \
356 } while (0)
357
358 #define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+')
359 #define _FP_SUB(fs, wc, R, X, Y)                                             \
360   do {                                                                       \
361     if (Y##_c != FP_CLS_NAN) Y##_s ^= 1;                                     \
362     _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-');                                  \
363   } while (0)
364
365
366 /*
367  * Main negation routine.  FIXME -- when we care about setting exception
368  * bits reliably, this will not do.  We should examine all of the fp classes.
369  */
370
371 #define _FP_NEG(fs, wc, R, X)           \
372   do {                                  \
373     _FP_FRAC_COPY_##wc(R, X);           \
374     R##_c = X##_c;                      \
375     R##_e = X##_e;                      \
376     R##_s = 1 ^ X##_s;                  \
377   } while (0)
378
379
380 /*
381  * Main multiplication routine.  The input values should be cooked.
382  */
383
384 #define _FP_MUL(fs, wc, R, X, Y)                        \
385 do {                                                    \
386   R##_s = X##_s ^ Y##_s;                                \
387   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
388   {                                                     \
389   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
390     R##_c = FP_CLS_NORMAL;                              \
391     R##_e = X##_e + Y##_e + 1;                          \
392                                                         \
393     _FP_MUL_MEAT_##fs(R,X,Y);                           \
394                                                         \
395     if (_FP_FRAC_OVERP_##wc(fs, R))                     \
396       _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);      \
397     else                                                \
398       R##_e--;                                          \
399     break;                                              \
400                                                         \
401   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
402     _FP_CHOOSENAN(fs, wc, R, X, Y, '*');                \
403     break;                                              \
404                                                         \
405   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
406   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
407   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
408     R##_s = X##_s;                                      \
409                                                         \
410   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
411   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
412   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
413   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
414     _FP_FRAC_COPY_##wc(R, X);                           \
415     R##_c = X##_c;                                      \
416     break;                                              \
417                                                         \
418   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
419   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
420   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
421     R##_s = Y##_s;                                      \
422                                                         \
423   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
424   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
425     _FP_FRAC_COPY_##wc(R, Y);                           \
426     R##_c = Y##_c;                                      \
427     break;                                              \
428                                                         \
429   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
430   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
431     R##_s = _FP_NANSIGN_##fs;                           \
432     R##_c = FP_CLS_NAN;                                 \
433     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
434     FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IMZ);\
435     break;                                              \
436                                                         \
437   default:                                              \
438     abort();                                            \
439   }                                                     \
440 } while (0)
441
442
443 /*
444  * Main division routine.  The input values should be cooked.
445  */
446
447 #define _FP_DIV(fs, wc, R, X, Y)                        \
448 do {                                                    \
449   R##_s = X##_s ^ Y##_s;                                \
450   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
451   {                                                     \
452   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
453     R##_c = FP_CLS_NORMAL;                              \
454     R##_e = X##_e - Y##_e;                              \
455                                                         \
456     _FP_DIV_MEAT_##fs(R,X,Y);                           \
457     break;                                              \
458                                                         \
459   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
460     _FP_CHOOSENAN(fs, wc, R, X, Y, '/');                \
461     break;                                              \
462                                                         \
463   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
464   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
465   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
466     R##_s = X##_s;                                      \
467     _FP_FRAC_COPY_##wc(R, X);                           \
468     R##_c = X##_c;                                      \
469     break;                                              \
470                                                         \
471   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
472   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
473   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
474     R##_s = Y##_s;                                      \
475     _FP_FRAC_COPY_##wc(R, Y);                           \
476     R##_c = Y##_c;                                      \
477     break;                                              \
478                                                         \
479   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
480   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
481   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
482     R##_c = FP_CLS_ZERO;                                \
483     break;                                              \
484                                                         \
485   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
486     FP_SET_EXCEPTION(FP_EX_DIVZERO);                    \
487   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
488   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
489     R##_c = FP_CLS_INF;                                 \
490     break;                                              \
491                                                         \
492   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
493     R##_s = _FP_NANSIGN_##fs;                           \
494     R##_c = FP_CLS_NAN;                                 \
495     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
496     FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IDI);\
497   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
498     R##_s = _FP_NANSIGN_##fs;                           \
499     R##_c = FP_CLS_NAN;                                 \
500     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
501     FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ZDZ);\
502     break;                                              \
503                                                         \
504   default:                                              \
505     abort();                                            \
506   }                                                     \
507 } while (0)
508
509
510 /*
511  * Main differential comparison routine.  The inputs should be raw not
512  * cooked.  The return is -1,0,1 for normal values, 2 otherwise.
513  */
514
515 #define _FP_CMP(fs, wc, ret, X, Y, un)                                  \
516   do {                                                                  \
517     /* NANs are unordered */                                            \
518     if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))           \
519         || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))       \
520       {                                                                 \
521         ret = un;                                                       \
522       }                                                                 \
523     else                                                                \
524       {                                                                 \
525         int __is_zero_x;                                                \
526         int __is_zero_y;                                                \
527                                                                         \
528         __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0;       \
529         __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0;       \
530                                                                         \
531         if (__is_zero_x && __is_zero_y)                                 \
532                 ret = 0;                                                \
533         else if (__is_zero_x)                                           \
534                 ret = Y##_s ? 1 : -1;                                   \
535         else if (__is_zero_y)                                           \
536                 ret = X##_s ? -1 : 1;                                   \
537         else if (X##_s != Y##_s)                                        \
538           ret = X##_s ? -1 : 1;                                         \
539         else if (X##_e > Y##_e)                                         \
540           ret = X##_s ? -1 : 1;                                         \
541         else if (X##_e < Y##_e)                                         \
542           ret = X##_s ? 1 : -1;                                         \
543         else if (_FP_FRAC_GT_##wc(X, Y))                                \
544           ret = X##_s ? -1 : 1;                                         \
545         else if (_FP_FRAC_GT_##wc(Y, X))                                \
546           ret = X##_s ? 1 : -1;                                         \
547         else                                                            \
548           ret = 0;                                                      \
549       }                                                                 \
550   } while (0)
551
552
553 /* Simplification for strict equality.  */
554
555 #define _FP_CMP_EQ(fs, wc, ret, X, Y)                                     \
556   do {                                                                    \
557     /* NANs are unordered */                                              \
558     if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))             \
559         || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))         \
560       {                                                                   \
561         ret = 1;                                                          \
562       }                                                                   \
563     else                                                                  \
564       {                                                                   \
565         ret = !(X##_e == Y##_e                                            \
566                 && _FP_FRAC_EQ_##wc(X, Y)                                 \
567                 && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
568       }                                                                   \
569   } while (0)
570
571 /*
572  * Main square root routine.  The input value should be cooked.
573  */
574
575 #define _FP_SQRT(fs, wc, R, X)                                          \
576 do {                                                                    \
577     _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S);                       \
578     _FP_W_TYPE q;                                                       \
579     switch (X##_c)                                                      \
580     {                                                                   \
581     case FP_CLS_NAN:                                                    \
582         _FP_FRAC_COPY_##wc(R, X);                                       \
583         R##_s = X##_s;                                                  \
584         R##_c = FP_CLS_NAN;                                             \
585         break;                                                          \
586     case FP_CLS_INF:                                                    \
587         if (X##_s)                                                      \
588           {                                                             \
589             R##_s = _FP_NANSIGN_##fs;                                   \
590             R##_c = FP_CLS_NAN; /* NAN */                               \
591             _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
592             FP_SET_EXCEPTION(FP_EX_INVALID);                            \
593           }                                                             \
594         else                                                            \
595           {                                                             \
596             R##_s = 0;                                                  \
597             R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */                 \
598           }                                                             \
599         break;                                                          \
600     case FP_CLS_ZERO:                                                   \
601         R##_s = X##_s;                                                  \
602         R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */                      \
603         break;                                                          \
604     case FP_CLS_NORMAL:                                                 \
605         R##_s = 0;                                                      \
606         if (X##_s)                                                      \
607           {                                                             \
608             R##_c = FP_CLS_NAN; /* sNAN */                              \
609             R##_s = _FP_NANSIGN_##fs;                                   \
610             _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
611             FP_SET_EXCEPTION(FP_EX_INVALID);                            \
612             break;                                                      \
613           }                                                             \
614         R##_c = FP_CLS_NORMAL;                                          \
615         if (X##_e & 1)                                                  \
616           _FP_FRAC_SLL_##wc(X, 1);                                      \
617         R##_e = X##_e >> 1;                                             \
618         _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);                        \
619         _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);                        \
620         q = _FP_OVERFLOW_##fs >> 1;                                     \
621         _FP_SQRT_MEAT_##wc(R, S, T, X, q);                              \
622     }                                                                   \
623   } while (0)
624
625 /*
626  * Convert from FP to integer
627  */
628
629 /* RSIGNED can have following values:
630  * 0:  the number is required to be 0..(2^rsize)-1, if not, NV is set plus
631  *     the result is either 0 or (2^rsize)-1 depending on the sign in such case.
632  * 1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
633  *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
634  *     on the sign in such case.
635  * 2:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
636  *     set plus the result is truncated to fit into destination.
637  * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
638  *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
639  *     on the sign in such case.
640  */
641 #define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)                                \
642   do {                                                                          \
643     switch (X##_c)                                                              \
644       {                                                                         \
645       case FP_CLS_NORMAL:                                                       \
646         if (X##_e < 0)                                                          \
647           {                                                                     \
648             FP_SET_EXCEPTION(FP_EX_INEXACT);                                    \
649           case FP_CLS_ZERO:                                                     \
650             r = 0;                                                              \
651           }                                                                     \
652         else if (X##_e >= rsize - (rsigned > 0 || X##_s)                        \
653                  || (!rsigned && X##_s))                                        \
654           {     /* overflow */                                                  \
655           case FP_CLS_NAN:                                                      \
656           case FP_CLS_INF:                                                      \
657             if (rsigned == 2)                                                   \
658               {                                                                 \
659                 if (X##_c != FP_CLS_NORMAL                                      \
660                     || X##_e >= rsize - 1 + _FP_WFRACBITS_##fs)                 \
661                   r = 0;                                                        \
662                 else                                                            \
663                   {                                                             \
664                     _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));     \
665                     _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
666                   }                                                             \
667               }                                                                 \
668             else if (rsigned)                                                   \
669               {                                                                 \
670                 r = 1;                                                          \
671                 r <<= rsize - 1;                                                \
672                 r -= 1 - X##_s;                                                 \
673               }                                                                 \
674             else                                                                \
675               {                                                                 \
676                 r = 0;                                                          \
677                 if (X##_s)                                                      \
678                   r = ~r;                                                       \
679               }                                                                 \
680             FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
681           }                                                                     \
682         else                                                                    \
683           {                                                                     \
684             if (_FP_W_TYPE_SIZE*wc < rsize)                                     \
685               {                                                                 \
686                 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
687                 r <<= X##_e - _FP_WFRACBITS_##fs;                               \
688               }                                                                 \
689             else                                                                \
690               {                                                                 \
691                 if (X##_e >= _FP_WFRACBITS_##fs)                                \
692                   _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));       \
693                 else if (X##_e < _FP_WFRACBITS_##fs - 1)                        \
694                   {                                                             \
695                     _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2),      \
696                                       _FP_WFRACBITS_##fs);                      \
697                     if (_FP_FRAC_LOW_##wc(X) & 1)                               \
698                       FP_SET_EXCEPTION(FP_EX_INEXACT);                          \
699                     _FP_FRAC_SRL_##wc(X, 1);                                    \
700                   }                                                             \
701                 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
702               }                                                                 \
703             if (rsigned && X##_s)                                               \
704               r = -r;                                                           \
705           }                                                                     \
706         break;                                                                  \
707       }                                                                         \
708   } while (0)
709
710 #define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned)                          \
711   do {                                                                          \
712     r = 0;                                                                      \
713     switch (X##_c)                                                              \
714       {                                                                         \
715       case FP_CLS_NORMAL:                                                       \
716         if (X##_e >= _FP_FRACBITS_##fs - 1)                                     \
717           {                                                                     \
718             if (X##_e < rsize - 1 + _FP_WFRACBITS_##fs)                         \
719               {                                                                 \
720                 if (X##_e >= _FP_WFRACBITS_##fs - 1)                            \
721                   {                                                             \
722                     _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
723                     r <<= X##_e - _FP_WFRACBITS_##fs + 1;                       \
724                   }                                                             \
725                 else                                                            \
726                   {                                                             \
727                     _FP_FRAC_SRL_##wc(X, _FP_WORKBITS - X##_e                   \
728                                       + _FP_FRACBITS_##fs - 1);                 \
729                     _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
730                   }                                                             \
731               }                                                                 \
732           }                                                                     \
733         else                                                                    \
734           {                                                                     \
735             if (X##_e <= -_FP_WORKBITS - 1)                                     \
736               _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                           \
737             else                                                                \
738               _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e,               \
739                                 _FP_WFRACBITS_##fs);                            \
740             _FP_ROUND(wc, X);                                                   \
741             _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                                 \
742             _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                                \
743           }                                                                     \
744         if (rsigned && X##_s)                                                   \
745           r = -r;                                                               \
746         if (X##_e >= rsize - (rsigned > 0 || X##_s)                             \
747             || (!rsigned && X##_s))                                             \
748           {     /* overflow */                                                  \
749           case FP_CLS_NAN:                                                      \
750           case FP_CLS_INF:                                                      \
751             if (!rsigned)                                                       \
752               {                                                                 \
753                 r = 0;                                                          \
754                 if (X##_s)                                                      \
755                   r = ~r;                                                       \
756               }                                                                 \
757             else if (rsigned != 2)                                              \
758               {                                                                 \
759                 r = 1;                                                          \
760                 r <<= rsize - 1;                                                \
761                 r -= 1 - X##_s;                                                 \
762               }                                                                 \
763             FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
764           }                                                                     \
765         break;                                                                  \
766       case FP_CLS_ZERO:                                                         \
767         break;                                                                  \
768       }                                                                         \
769   } while (0)
770
771 #define _FP_FROM_INT(fs, wc, X, r, rsize, rtype)                        \
772   do {                                                                  \
773     if (r)                                                              \
774       {                                                                 \
775         unsigned rtype ur_;                                             \
776         X##_c = FP_CLS_NORMAL;                                          \
777                                                                         \
778         if ((X##_s = (r < 0)))                                          \
779           ur_ = (unsigned rtype) -r;                                    \
780         else                                                            \
781           ur_ = (unsigned rtype) r;                                     \
782         if (rsize <= _FP_W_TYPE_SIZE)                                   \
783           __FP_CLZ(X##_e, ur_);                                         \
784         else                                                            \
785           __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE),       \
786                      (_FP_W_TYPE)ur_);                                  \
787         if (rsize < _FP_W_TYPE_SIZE)                                    \
788                 X##_e -= (_FP_W_TYPE_SIZE - rsize);                     \
789         X##_e = rsize - X##_e - 1;                                      \
790                                                                         \
791         if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)    \
792           __FP_FRAC_SRS_1(ur_, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);\
793         _FP_FRAC_DISASSEMBLE_##wc(X, ur_, rsize);                       \
794         if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0)                       \
795           _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));       \
796       }                                                                 \
797     else                                                                \
798       {                                                                 \
799         X##_c = FP_CLS_ZERO, X##_s = 0;                                 \
800       }                                                                 \
801   } while (0)
802
803
804 #define FP_CONV(dfs,sfs,dwc,swc,D,S)                    \
805   do {                                                  \
806     _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S);        \
807     D##_e = S##_e;                                      \
808     D##_c = S##_c;                                      \
809     D##_s = S##_s;                                      \
810   } while (0)
811
812 /*
813  * Helper primitives.
814  */
815
816 /* Count leading zeros in a word.  */
817
818 #ifndef __FP_CLZ
819 #if _FP_W_TYPE_SIZE < 64
820 /* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
821 #define __FP_CLZ(r, x)                          \
822   do {                                          \
823     _FP_W_TYPE _t = (x);                        \
824     r = _FP_W_TYPE_SIZE - 1;                    \
825     if (_t > 0xffff) r -= 16;                   \
826     if (_t > 0xffff) _t >>= 16;                 \
827     if (_t > 0xff) r -= 8;                      \
828     if (_t > 0xff) _t >>= 8;                    \
829     if (_t & 0xf0) r -= 4;                      \
830     if (_t & 0xf0) _t >>= 4;                    \
831     if (_t & 0xc) r -= 2;                       \
832     if (_t & 0xc) _t >>= 2;                     \
833     if (_t & 0x2) r -= 1;                       \
834   } while (0)
835 #else /* not _FP_W_TYPE_SIZE < 64 */
836 #define __FP_CLZ(r, x)                          \
837   do {                                          \
838     _FP_W_TYPE _t = (x);                        \
839     r = _FP_W_TYPE_SIZE - 1;                    \
840     if (_t > 0xffffffff) r -= 32;               \
841     if (_t > 0xffffffff) _t >>= 32;             \
842     if (_t > 0xffff) r -= 16;                   \
843     if (_t > 0xffff) _t >>= 16;                 \
844     if (_t > 0xff) r -= 8;                      \
845     if (_t > 0xff) _t >>= 8;                    \
846     if (_t & 0xf0) r -= 4;                      \
847     if (_t & 0xf0) _t >>= 4;                    \
848     if (_t & 0xc) r -= 2;                       \
849     if (_t & 0xc) _t >>= 2;                     \
850     if (_t & 0x2) r -= 1;                       \
851   } while (0)
852 #endif /* not _FP_W_TYPE_SIZE < 64 */
853 #endif /* ndef __FP_CLZ */
854
855 #define _FP_DIV_HELP_imm(q, r, n, d)            \
856   do {                                          \
857     q = n / d, r = n % d;                       \
858   } while (0)
859
860 #endif /* __MATH_EMU_OP_COMMON_H__ */