GNU Linux-libre 5.19-rc6-gnu
[releases.git] / arch / parisc / math-emu / sfdiv.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/sfdiv.c               $Revision: 1.1 $
13  *
14  *  Purpose:
15  *      Single Precision Floating-point Divide
16  *
17  *  External Interfaces:
18  *      sgl_fdiv(srcptr1,srcptr2,dstptr,status)
19  *
20  *  Internal Interfaces:
21  *
22  *  Theory:
23  *      <<please update with a overview of the operation of this file>>
24  *
25  * END_DESC
26 */
27
28
29 #include "float.h"
30 #include "sgl_float.h"
31
32 /*
33  *  Single Precision Floating-point Divide
34  */
35
36 int
37 sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
38           sgl_floating_point * dstptr, unsigned int *status)
39 {
40         register unsigned int opnd1, opnd2, opnd3, result;
41         register int dest_exponent, count;
42         register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
43         boolean is_tiny;
44
45         opnd1 = *srcptr1;
46         opnd2 = *srcptr2;
47         /* 
48          * set sign bit of result 
49          */
50         if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);  
51         else Sgl_setzero(result);
52         /*
53          * check first operand for NaN's or infinity
54          */
55         if (Sgl_isinfinity_exponent(opnd1)) {
56                 if (Sgl_iszero_mantissa(opnd1)) {
57                         if (Sgl_isnotnan(opnd2)) {
58                                 if (Sgl_isinfinity(opnd2)) {
59                                         /* 
60                                          * invalid since both operands 
61                                          * are infinity 
62                                          */
63                                         if (Is_invalidtrap_enabled()) 
64                                                 return(INVALIDEXCEPTION);
65                                         Set_invalidflag();
66                                         Sgl_makequietnan(result);
67                                         *dstptr = result;
68                                         return(NOEXCEPTION);
69                                 }
70                                 /*
71                                  * return infinity
72                                  */
73                                 Sgl_setinfinity_exponentmantissa(result);
74                                 *dstptr = result;
75                                 return(NOEXCEPTION);
76                         }
77                 }
78                 else {
79                         /*
80                          * is NaN; signaling or quiet?
81                          */
82                         if (Sgl_isone_signaling(opnd1)) {
83                                 /* trap if INVALIDTRAP enabled */
84                                 if (Is_invalidtrap_enabled()) 
85                                         return(INVALIDEXCEPTION);
86                                 /* make NaN quiet */
87                                 Set_invalidflag();
88                                 Sgl_set_quiet(opnd1);
89                         }
90                         /* 
91                          * is second operand a signaling NaN? 
92                          */
93                         else if (Sgl_is_signalingnan(opnd2)) {
94                                 /* trap if INVALIDTRAP enabled */
95                                 if (Is_invalidtrap_enabled())
96                                         return(INVALIDEXCEPTION);
97                                 /* make NaN quiet */
98                                 Set_invalidflag();
99                                 Sgl_set_quiet(opnd2);
100                                 *dstptr = opnd2;
101                                 return(NOEXCEPTION);
102                         }
103                         /*
104                          * return quiet NaN
105                          */
106                         *dstptr = opnd1;
107                         return(NOEXCEPTION);
108                 }
109         }
110         /*
111          * check second operand for NaN's or infinity
112          */
113         if (Sgl_isinfinity_exponent(opnd2)) {
114                 if (Sgl_iszero_mantissa(opnd2)) {
115                         /*
116                          * return zero
117                          */
118                         Sgl_setzero_exponentmantissa(result);
119                         *dstptr = result;
120                         return(NOEXCEPTION);
121                 }
122                 /*
123                  * is NaN; signaling or quiet?
124                  */
125                 if (Sgl_isone_signaling(opnd2)) {
126                         /* trap if INVALIDTRAP enabled */
127                         if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
128                         /* make NaN quiet */
129                         Set_invalidflag();
130                         Sgl_set_quiet(opnd2);
131                 }
132                 /*
133                  * return quiet NaN
134                  */
135                 *dstptr = opnd2;
136                 return(NOEXCEPTION);
137         }
138         /*
139          * check for division by zero
140          */
141         if (Sgl_iszero_exponentmantissa(opnd2)) {
142                 if (Sgl_iszero_exponentmantissa(opnd1)) {
143                         /* invalid since both operands are zero */
144                         if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
145                         Set_invalidflag();
146                         Sgl_makequietnan(result);
147                         *dstptr = result;
148                         return(NOEXCEPTION);
149                 }
150                 if (Is_divisionbyzerotrap_enabled())
151                         return(DIVISIONBYZEROEXCEPTION);
152                 Set_divisionbyzeroflag();
153                 Sgl_setinfinity_exponentmantissa(result);
154                 *dstptr = result;
155                 return(NOEXCEPTION);
156         }
157         /*
158          * Generate exponent 
159          */
160         dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
161
162         /*
163          * Generate mantissa
164          */
165         if (Sgl_isnotzero_exponent(opnd1)) {
166                 /* set hidden bit */
167                 Sgl_clear_signexponent_set_hidden(opnd1);
168         }
169         else {
170                 /* check for zero */
171                 if (Sgl_iszero_mantissa(opnd1)) {
172                         Sgl_setzero_exponentmantissa(result);
173                         *dstptr = result;
174                         return(NOEXCEPTION);
175                 }
176                 /* is denormalized; want to normalize */
177                 Sgl_clear_signexponent(opnd1);
178                 Sgl_leftshiftby1(opnd1);
179                 Sgl_normalize(opnd1,dest_exponent);
180         }
181         /* opnd2 needs to have hidden bit set with msb in hidden bit */
182         if (Sgl_isnotzero_exponent(opnd2)) {
183                 Sgl_clear_signexponent_set_hidden(opnd2);
184         }
185         else {
186                 /* is denormalized; want to normalize */
187                 Sgl_clear_signexponent(opnd2);
188                 Sgl_leftshiftby1(opnd2);
189                 while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
190                         Sgl_leftshiftby8(opnd2);
191                         dest_exponent += 8;
192                 }
193                 if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
194                         Sgl_leftshiftby4(opnd2);
195                         dest_exponent += 4;
196                 }
197                 while(Sgl_iszero_hidden(opnd2)) {
198                         Sgl_leftshiftby1(opnd2);
199                         dest_exponent += 1;
200                 }
201         }
202
203         /* Divide the source mantissas */
204
205         /*
206          * A non_restoring divide algorithm is used.
207          */
208         Sgl_subtract(opnd1,opnd2,opnd1);
209         Sgl_setzero(opnd3);
210         for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
211                 Sgl_leftshiftby1(opnd1);
212                 Sgl_leftshiftby1(opnd3);
213                 if (Sgl_iszero_sign(opnd1)) {
214                         Sgl_setone_lowmantissa(opnd3);
215                         Sgl_subtract(opnd1,opnd2,opnd1);
216                 }
217                 else Sgl_addition(opnd1,opnd2,opnd1);
218         }
219         if (count <= SGL_P) {
220                 Sgl_leftshiftby1(opnd3);
221                 Sgl_setone_lowmantissa(opnd3);
222                 Sgl_leftshift(opnd3,SGL_P-count);
223                 if (Sgl_iszero_hidden(opnd3)) {
224                         Sgl_leftshiftby1(opnd3);
225                         dest_exponent--;
226                 }
227         }
228         else {
229                 if (Sgl_iszero_hidden(opnd3)) {
230                         /* need to get one more bit of result */
231                         Sgl_leftshiftby1(opnd1);
232                         Sgl_leftshiftby1(opnd3);
233                         if (Sgl_iszero_sign(opnd1)) {
234                                 Sgl_setone_lowmantissa(opnd3);
235                                 Sgl_subtract(opnd1,opnd2,opnd1);
236                         }
237                         else Sgl_addition(opnd1,opnd2,opnd1);
238                         dest_exponent--;
239                 }
240                 if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
241                 stickybit = Sgl_all(opnd1);
242         }
243         inexact = guardbit | stickybit;
244
245         /* 
246          * round result 
247          */
248         if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
249                 Sgl_clear_signexponent(opnd3);
250                 switch (Rounding_mode()) {
251                         case ROUNDPLUS: 
252                                 if (Sgl_iszero_sign(result)) 
253                                         Sgl_increment_mantissa(opnd3);
254                                 break;
255                         case ROUNDMINUS: 
256                                 if (Sgl_isone_sign(result)) 
257                                         Sgl_increment_mantissa(opnd3);
258                                 break;
259                         case ROUNDNEAREST:
260                                 if (guardbit) {
261                                 if (stickybit || Sgl_isone_lowmantissa(opnd3))
262                                     Sgl_increment_mantissa(opnd3);
263                                 }
264                 }
265                 if (Sgl_isone_hidden(opnd3)) dest_exponent++;
266         }
267         Sgl_set_mantissa(result,opnd3);
268
269         /* 
270          * Test for overflow
271          */
272         if (dest_exponent >= SGL_INFINITY_EXPONENT) {
273                 /* trap if OVERFLOWTRAP enabled */
274                 if (Is_overflowtrap_enabled()) {
275                         /*
276                          * Adjust bias of result
277                          */
278                         Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
279                         *dstptr = result;
280                         if (inexact) 
281                             if (Is_inexacttrap_enabled())
282                                 return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
283                             else Set_inexactflag();
284                         return(OVERFLOWEXCEPTION);
285                 }
286                 Set_overflowflag();
287                 /* set result to infinity or largest number */
288                 Sgl_setoverflow(result);
289                 inexact = TRUE;
290         }
291         /* 
292          * Test for underflow
293          */
294         else if (dest_exponent <= 0) {
295                 /* trap if UNDERFLOWTRAP enabled */
296                 if (Is_underflowtrap_enabled()) {
297                         /*
298                          * Adjust bias of result
299                          */
300                         Sgl_setwrapped_exponent(result,dest_exponent,unfl);
301                         *dstptr = result;
302                         if (inexact) 
303                             if (Is_inexacttrap_enabled())
304                                 return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
305                             else Set_inexactflag();
306                         return(UNDERFLOWEXCEPTION);
307                 }
308
309                 /* Determine if should set underflow flag */
310                 is_tiny = TRUE;
311                 if (dest_exponent == 0 && inexact) {
312                         switch (Rounding_mode()) {
313                         case ROUNDPLUS: 
314                                 if (Sgl_iszero_sign(result)) {
315                                         Sgl_increment(opnd3);
316                                         if (Sgl_isone_hiddenoverflow(opnd3))
317                                             is_tiny = FALSE;
318                                         Sgl_decrement(opnd3);
319                                 }
320                                 break;
321                         case ROUNDMINUS: 
322                                 if (Sgl_isone_sign(result)) {
323                                         Sgl_increment(opnd3);
324                                         if (Sgl_isone_hiddenoverflow(opnd3))
325                                             is_tiny = FALSE;
326                                         Sgl_decrement(opnd3);
327                                 }
328                                 break;
329                         case ROUNDNEAREST:
330                                 if (guardbit && (stickybit || 
331                                     Sgl_isone_lowmantissa(opnd3))) {
332                                         Sgl_increment(opnd3);
333                                         if (Sgl_isone_hiddenoverflow(opnd3))
334                                             is_tiny = FALSE;
335                                         Sgl_decrement(opnd3);
336                                 }
337                                 break;
338                         }
339                 }
340
341                 /*
342                  * denormalize result or set to signed zero
343                  */
344                 stickybit = inexact;
345                 Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
346
347                 /* return rounded number */ 
348                 if (inexact) {
349                         switch (Rounding_mode()) {
350                         case ROUNDPLUS:
351                                 if (Sgl_iszero_sign(result)) {
352                                         Sgl_increment(opnd3);
353                                 }
354                                 break;
355                         case ROUNDMINUS: 
356                                 if (Sgl_isone_sign(result))  {
357                                         Sgl_increment(opnd3);
358                                 }
359                                 break;
360                         case ROUNDNEAREST:
361                                 if (guardbit && (stickybit || 
362                                     Sgl_isone_lowmantissa(opnd3))) {
363                                         Sgl_increment(opnd3);
364                                 }
365                                 break;
366                         }
367                         if (is_tiny) Set_underflowflag();
368                 }
369                 Sgl_set_exponentmantissa(result,opnd3);
370         }
371         else Sgl_set_exponent(result,dest_exponent);
372         *dstptr = result;
373         /* check for inexact */
374         if (inexact) {
375                 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
376                 else  Set_inexactflag();
377         }
378         return(NOEXCEPTION);
379 }