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