~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/parisc/math-emu/sfdiv.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 }
380 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php