Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / parisc / math-emu / fcnvfx.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Linux/PA-RISC Project (http://www.parisc-linux.org/)
4  *
5  * Floating-point emulation code
6  *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
7  */
8 /*
9  * BEGIN_DESC
10  *
11  *  File:
12  *      @(#)    pa/spmath/fcnvfx.c              $Revision: 1.1 $
13  *
14  *  Purpose:
15  *      Single Floating-point to Single Fixed-point
16  *      Single Floating-point to Double Fixed-point 
17  *      Double Floating-point to Single Fixed-point 
18  *      Double Floating-point to Double Fixed-point 
19  *
20  *  External Interfaces:
21  *      dbl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
22  *      dbl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
23  *      sgl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
24  *      sgl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
25  *
26  *  Internal Interfaces:
27  *
28  *  Theory:
29  *      <<please update with a overview of the operation of this file>>
30  *
31  * END_DESC
32 */
33
34
35 #include "float.h"
36 #include "sgl_float.h"
37 #include "dbl_float.h"
38 #include "cnv_float.h"
39
40 /*
41  *  Single Floating-point to Single Fixed-point 
42  */
43 /*ARGSUSED*/
44 int
45 sgl_to_sgl_fcnvfx(
46                     sgl_floating_point *srcptr,
47                     sgl_floating_point *nullptr,
48                     int *dstptr,
49                     sgl_floating_point *status)
50 {
51         register unsigned int src, temp;
52         register int src_exponent, result;
53         register boolean inexact = FALSE;
54
55         src = *srcptr;
56         src_exponent = Sgl_exponent(src) - SGL_BIAS;
57
58         /* 
59          * Test for overflow
60          */
61         if (src_exponent > SGL_FX_MAX_EXP) {
62                 /* check for MININT */
63                 if ((src_exponent > SGL_FX_MAX_EXP + 1) || 
64                 Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
65                         if (Sgl_iszero_sign(src)) result = 0x7fffffff;
66                         else result = 0x80000000; 
67
68                         if (Is_invalidtrap_enabled()) {
69                             return(INVALIDEXCEPTION);
70                         }
71                         Set_invalidflag();
72                         *dstptr = result;
73                         return(NOEXCEPTION);
74                 }
75         }
76         /*
77          * Generate result
78          */
79         if (src_exponent >= 0) {
80                 temp = src;
81                 Sgl_clear_signexponent_set_hidden(temp);
82                 Int_from_sgl_mantissa(temp,src_exponent);
83                 if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
84                 else result = Sgl_all(temp);
85
86                 /* check for inexact */
87                 if (Sgl_isinexact_to_fix(src,src_exponent)) {
88                         inexact = TRUE;
89                         /*  round result  */
90                         switch (Rounding_mode()) {
91                         case ROUNDPLUS:
92                              if (Sgl_iszero_sign(src)) result++;
93                              break;
94                         case ROUNDMINUS:
95                              if (Sgl_isone_sign(src)) result--;
96                              break;
97                         case ROUNDNEAREST:
98                              if (Sgl_isone_roundbit(src,src_exponent)) {
99                                 if (Sgl_isone_stickybit(src,src_exponent) 
100                                 || (Sgl_isone_lowmantissa(temp)))
101                                    if (Sgl_iszero_sign(src)) result++;
102                                    else result--;
103                              }
104                         } 
105                 }
106         }
107         else {
108                 result = 0;
109
110                 /* check for inexact */
111                 if (Sgl_isnotzero_exponentmantissa(src)) {
112                         inexact = TRUE;
113                         /*  round result  */
114                         switch (Rounding_mode()) {
115                         case ROUNDPLUS:
116                              if (Sgl_iszero_sign(src)) result++;
117                              break;
118                         case ROUNDMINUS:
119                              if (Sgl_isone_sign(src)) result--;
120                              break;
121                         case ROUNDNEAREST:
122                              if (src_exponent == -1)
123                                 if (Sgl_isnotzero_mantissa(src))
124                                    if (Sgl_iszero_sign(src)) result++;
125                                    else result--;
126                         } 
127                 }
128         }
129         *dstptr = result;
130         if (inexact) {
131                 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
132                 else Set_inexactflag();
133         }
134         return(NOEXCEPTION);
135 }
136
137 /*
138  *  Single Floating-point to Double Fixed-point 
139  */
140 /*ARGSUSED*/
141 int
142 sgl_to_dbl_fcnvfx(
143                 sgl_floating_point *srcptr,
144                 unsigned int *nullptr,
145                 dbl_integer *dstptr,
146                 unsigned int *status)
147 {
148         register int src_exponent, resultp1;
149         register unsigned int src, temp, resultp2;
150         register boolean inexact = FALSE;
151
152         src = *srcptr;
153         src_exponent = Sgl_exponent(src) - SGL_BIAS;
154
155         /* 
156          * Test for overflow
157          */
158         if (src_exponent > DBL_FX_MAX_EXP) {
159                 /* check for MININT */
160                 if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
161                 Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
162                         if (Sgl_iszero_sign(src)) {
163                               resultp1 = 0x7fffffff;
164                               resultp2 = 0xffffffff;
165                         }
166                         else {
167                             resultp1 = 0x80000000; 
168                             resultp2 = 0;
169                         }
170                         if (Is_invalidtrap_enabled()) {
171                             return(INVALIDEXCEPTION);
172                         }
173                         Set_invalidflag();
174                         Dint_copytoptr(resultp1,resultp2,dstptr);
175                         return(NOEXCEPTION);
176                 }
177                 Dint_set_minint(resultp1,resultp2);
178                 Dint_copytoptr(resultp1,resultp2,dstptr);
179                 return(NOEXCEPTION);
180         }
181         /*
182          * Generate result
183          */
184         if (src_exponent >= 0) {
185                 temp = src;
186                 Sgl_clear_signexponent_set_hidden(temp);
187                 Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
188                 if (Sgl_isone_sign(src)) {
189                         Dint_setone_sign(resultp1,resultp2);
190                 }
191
192                 /* check for inexact */
193                 if (Sgl_isinexact_to_fix(src,src_exponent)) {
194                         inexact = TRUE;
195                         /*  round result  */
196                         switch (Rounding_mode()) {
197                         case ROUNDPLUS:
198                              if (Sgl_iszero_sign(src)) {
199                                 Dint_increment(resultp1,resultp2);
200                              }
201                              break;
202                         case ROUNDMINUS:
203                              if (Sgl_isone_sign(src)) {
204                                 Dint_decrement(resultp1,resultp2);
205                              }
206                              break;
207                         case ROUNDNEAREST:
208                              if (Sgl_isone_roundbit(src,src_exponent))
209                                 if (Sgl_isone_stickybit(src,src_exponent) || 
210                                 (Dint_isone_lowp2(resultp2)))
211                                    if (Sgl_iszero_sign(src)) {
212                                       Dint_increment(resultp1,resultp2);
213                                    }
214                                    else {
215                                       Dint_decrement(resultp1,resultp2);
216                                    }
217                         }
218                 }
219         }
220         else {
221                 Dint_setzero(resultp1,resultp2);
222
223                 /* check for inexact */
224                 if (Sgl_isnotzero_exponentmantissa(src)) {
225                         inexact = TRUE;
226                         /*  round result  */
227                         switch (Rounding_mode()) {
228                         case ROUNDPLUS:
229                              if (Sgl_iszero_sign(src)) {
230                                 Dint_increment(resultp1,resultp2);
231                              }
232                              break;
233                         case ROUNDMINUS:
234                              if (Sgl_isone_sign(src)) {
235                                 Dint_decrement(resultp1,resultp2);
236                              }
237                              break;
238                         case ROUNDNEAREST:
239                              if (src_exponent == -1)
240                                 if (Sgl_isnotzero_mantissa(src))
241                                    if (Sgl_iszero_sign(src)) {
242                                       Dint_increment(resultp1,resultp2);
243                                    }
244                                    else {
245                                       Dint_decrement(resultp1,resultp2);
246                                    }
247                         }
248                 }
249         }
250         Dint_copytoptr(resultp1,resultp2,dstptr);
251         if (inexact) {
252                 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
253                 else Set_inexactflag();
254         }
255         return(NOEXCEPTION);
256 }
257
258 /*
259  *  Double Floating-point to Single Fixed-point 
260  */
261 /*ARGSUSED*/
262 int
263 dbl_to_sgl_fcnvfx(
264                     dbl_floating_point *srcptr,
265                     unsigned int *nullptr,
266                     int *dstptr,
267                     unsigned int *status)
268 {
269         register unsigned int srcp1,srcp2, tempp1,tempp2;
270         register int src_exponent, result;
271         register boolean inexact = FALSE;
272
273         Dbl_copyfromptr(srcptr,srcp1,srcp2);
274         src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
275
276         /* 
277          * Test for overflow
278          */
279         if (src_exponent > SGL_FX_MAX_EXP) {
280                 /* check for MININT */
281                 if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
282                         if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
283                         else result = 0x80000000; 
284
285                         if (Is_invalidtrap_enabled()) {
286                             return(INVALIDEXCEPTION);
287                         }
288                         Set_invalidflag();
289                         *dstptr = result;
290                         return(NOEXCEPTION);
291                 }
292         }
293         /*
294          * Generate result
295          */
296         if (src_exponent >= 0) {
297                 tempp1 = srcp1;
298                 tempp2 = srcp2;
299                 Dbl_clear_signexponent_set_hidden(tempp1);
300                 Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
301                 if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
302                         result = -Dbl_allp1(tempp1);
303                 else result = Dbl_allp1(tempp1);
304
305                 /* check for inexact */
306                 if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
307                         inexact = TRUE;
308                         /*  round result  */
309                         switch (Rounding_mode()) {
310                         case ROUNDPLUS:
311                              if (Dbl_iszero_sign(srcp1)) result++;
312                              break;
313                         case ROUNDMINUS:
314                              if (Dbl_isone_sign(srcp1)) result--;
315                              break;
316                         case ROUNDNEAREST:
317                              if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
318                                 if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
319                                 (Dbl_isone_lowmantissap1(tempp1)))
320                                    if (Dbl_iszero_sign(srcp1)) result++;
321                                    else result--;
322                         } 
323                         /* check for overflow */
324                         if ((Dbl_iszero_sign(srcp1) && result < 0) ||
325                             (Dbl_isone_sign(srcp1) && result > 0)) {
326                                 
327                           if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
328                           else result = 0x80000000; 
329
330                           if (Is_invalidtrap_enabled()) {
331                             return(INVALIDEXCEPTION);
332                           }
333                           Set_invalidflag();
334                           *dstptr = result;
335                           return(NOEXCEPTION);
336                         }
337                 }
338         }
339         else {
340                 result = 0;
341
342                 /* check for inexact */
343                 if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
344                         inexact = TRUE;
345                         /*  round result  */
346                         switch (Rounding_mode()) {
347                         case ROUNDPLUS:
348                              if (Dbl_iszero_sign(srcp1)) result++;
349                              break;
350                         case ROUNDMINUS:
351                              if (Dbl_isone_sign(srcp1)) result--;
352                              break;
353                         case ROUNDNEAREST:
354                              if (src_exponent == -1)
355                                 if (Dbl_isnotzero_mantissa(srcp1,srcp2))
356                                    if (Dbl_iszero_sign(srcp1)) result++;
357                                    else result--;
358                         }
359                 }
360         }
361         *dstptr = result;
362         if (inexact) {
363                 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
364                 else Set_inexactflag();
365         }
366         return(NOEXCEPTION);
367 }
368
369 /*
370  *  Double Floating-point to Double Fixed-point 
371  */
372 /*ARGSUSED*/
373 int
374 dbl_to_dbl_fcnvfx(
375                     dbl_floating_point *srcptr,
376                     unsigned int *nullptr,
377                     dbl_integer *dstptr,
378                     unsigned int *status)
379 {
380         register int src_exponent, resultp1;
381         register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
382         register boolean inexact = FALSE;
383
384         Dbl_copyfromptr(srcptr,srcp1,srcp2);
385         src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
386
387         /* 
388          * Test for overflow
389          */
390         if (src_exponent > DBL_FX_MAX_EXP) {
391                 /* check for MININT */
392                 if ((src_exponent > DBL_FX_MAX_EXP + 1) || 
393                 Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
394                         if (Dbl_iszero_sign(srcp1)) {
395                               resultp1 = 0x7fffffff;
396                               resultp2 = 0xffffffff;
397                         }
398                         else {
399                             resultp1 = 0x80000000; 
400                             resultp2 = 0;
401                         }
402                         if (Is_invalidtrap_enabled()) {
403                             return(INVALIDEXCEPTION);
404                         }
405                         Set_invalidflag();
406                         Dint_copytoptr(resultp1,resultp2,dstptr);
407                         return(NOEXCEPTION);
408                 }
409         }
410  
411         /*
412          * Generate result
413          */
414         if (src_exponent >= 0) {
415                 tempp1 = srcp1;
416                 tempp2 = srcp2;
417                 Dbl_clear_signexponent_set_hidden(tempp1);
418                 Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,resultp1,
419                 resultp2);
420                 if (Dbl_isone_sign(srcp1)) {
421                         Dint_setone_sign(resultp1,resultp2);
422                 }
423
424                 /* check for inexact */
425                 if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
426                         inexact = TRUE;
427                         /*  round result  */
428                         switch (Rounding_mode()) {
429                         case ROUNDPLUS:
430                              if (Dbl_iszero_sign(srcp1)) {
431                                 Dint_increment(resultp1,resultp2);
432                              }
433                              break;
434                         case ROUNDMINUS:
435                              if (Dbl_isone_sign(srcp1)) {
436                                 Dint_decrement(resultp1,resultp2);
437                              }
438                              break;
439                         case ROUNDNEAREST:
440                              if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
441                                 if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
442                                 (Dint_isone_lowp2(resultp2)))
443                                    if (Dbl_iszero_sign(srcp1)) {
444                                       Dint_increment(resultp1,resultp2);
445                                    }
446                                    else {
447                                       Dint_decrement(resultp1,resultp2);
448                                    }
449                         } 
450                 }
451         }
452         else {
453                 Dint_setzero(resultp1,resultp2);
454
455                 /* check for inexact */
456                 if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
457                         inexact = TRUE;
458                         /*  round result  */
459                         switch (Rounding_mode()) {
460                         case ROUNDPLUS:
461                              if (Dbl_iszero_sign(srcp1)) {
462                                 Dint_increment(resultp1,resultp2);
463                              }
464                              break;
465                         case ROUNDMINUS:
466                              if (Dbl_isone_sign(srcp1)) {
467                                 Dint_decrement(resultp1,resultp2);
468                              }
469                              break;
470                         case ROUNDNEAREST:
471                              if (src_exponent == -1)
472                                 if (Dbl_isnotzero_mantissa(srcp1,srcp2))
473                                    if (Dbl_iszero_sign(srcp1)) {
474                                       Dint_increment(resultp1,resultp2);
475                                    }
476                                    else {
477                                       Dint_decrement(resultp1,resultp2);
478                                    }
479                         }
480                 }
481         }
482         Dint_copytoptr(resultp1,resultp2,dstptr);
483         if (inexact) {
484                 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
485                 else Set_inexactflag();
486         }
487         return(NOEXCEPTION);
488 }