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

TOMOYO Linux Cross Reference
Linux/arch/arm/vfp/vfpdouble.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ 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.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/arm/vfp/vfpdouble.c (Architecture m68k) and /arch/i386/vfp/vfpdouble.c (Architecture i386)


  1 /*                                                  1 
  2  *  linux/arch/arm/vfp/vfpdouble.c                
  3  *                                                
  4  * This code is derived in part from John R. H    
  5  * carries the following notice:                  
  6  *                                                
  7  * ===========================================    
  8  * This C source file is part of the SoftFloat    
  9  * Arithmetic Package, Release 2.                 
 10  *                                                
 11  * Written by John R. Hauser.  This work was m    
 12  * International Computer Science Institute, l    
 13  * Street, Berkeley, California 94704.  Fundin    
 14  * National Science Foundation under grant MIP    
 15  * of this code was written as part of a proje    
 16  * processor in collaboration with the Univers    
 17  * overseen by Profs. Nelson Morgan and John W    
 18  * is available through the web page `http://H    
 19  * arithmetic/softfloat.html'.                    
 20  *                                                
 21  * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FRE    
 22  * has been made to avoid it, THIS SOFTWARE MA    
 23  * TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF    
 24  * PERSONS AND ORGANIZATIONS WHO CAN AND WILL     
 25  * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS AR    
 26  *                                                
 27  * Derivative works are acceptable, even for c    
 28  * (1) they include prominent notice that the     
 29  * include prominent notice akin to these thre    
 30  * this code that are retained.                   
 31  * ===========================================    
 32  */                                               
 33 #include <linux/kernel.h>                         
 34 #include <linux/bitops.h>                         
 35                                                   
 36 #include <asm/div64.h>                            
 37 #include <asm/vfp.h>                              
 38                                                   
 39 #include "vfpinstr.h"                             
 40 #include "vfp.h"                                  
 41                                                   
 42 static struct vfp_double vfp_double_default_qn    
 43         .exponent       = 2047,                   
 44         .sign           = 0,                      
 45         .significand    = VFP_DOUBLE_SIGNIFICA    
 46 };                                                
 47                                                   
 48 static void vfp_double_dump(const char *str, s    
 49 {                                                 
 50         pr_debug("VFP: %s: sign=%d exponent=%d    
 51                  str, d->sign != 0, d->exponen    
 52 }                                                 
 53                                                   
 54 static void vfp_double_normalise_denormal(stru    
 55 {                                                 
 56         int bits = 31 - fls(vd->significand >>    
 57         if (bits == 31)                           
 58                 bits = 63 - fls(vd->significan    
 59                                                   
 60         vfp_double_dump("normalise_denormal: i    
 61                                                   
 62         if (bits) {                               
 63                 vd->exponent -= bits - 1;         
 64                 vd->significand <<= bits;         
 65         }                                         
 66                                                   
 67         vfp_double_dump("normalise_denormal: o    
 68 }                                                 
 69                                                   
 70 u32 vfp_double_normaliseround(int dd, struct v    
 71 {                                                 
 72         u64 significand, incr;                    
 73         int exponent, shift, underflow;           
 74         u32 rmode;                                
 75                                                   
 76         vfp_double_dump("pack: in", vd);          
 77                                                   
 78         /*                                        
 79          * Infinities and NaNs are a special c    
 80          */                                       
 81         if (vd->exponent == 2047 && (vd->signi    
 82                 goto pack;                        
 83                                                   
 84         /*                                        
 85          * Special-case zero.                     
 86          */                                       
 87         if (vd->significand == 0) {               
 88                 vd->exponent = 0;                 
 89                 goto pack;                        
 90         }                                         
 91                                                   
 92         exponent = vd->exponent;                  
 93         significand = vd->significand;            
 94                                                   
 95         shift = 32 - fls(significand >> 32);      
 96         if (shift == 32)                          
 97                 shift = 64 - fls(significand);    
 98         if (shift) {                              
 99                 exponent -= shift;                
100                 significand <<= shift;            
101         }                                         
102                                                   
103 #ifdef DEBUG                                      
104         vd->exponent = exponent;                  
105         vd->significand = significand;            
106         vfp_double_dump("pack: normalised", vd    
107 #endif                                            
108                                                   
109         /*                                        
110          * Tiny number?                           
111          */                                       
112         underflow = exponent < 0;                 
113         if (underflow) {                          
114                 significand = vfp_shiftright64    
115                 exponent = 0;                     
116 #ifdef DEBUG                                      
117                 vd->exponent = exponent;          
118                 vd->significand = significand;    
119                 vfp_double_dump("pack: tiny nu    
120 #endif                                            
121                 if (!(significand & ((1ULL <<     
122                         underflow = 0;            
123         }                                         
124                                                   
125         /*                                        
126          * Select rounding increment.             
127          */                                       
128         incr = 0;                                 
129         rmode = fpscr & FPSCR_RMODE_MASK;         
130                                                   
131         if (rmode == FPSCR_ROUND_NEAREST) {       
132                 incr = 1ULL << VFP_DOUBLE_LOW_    
133                 if ((significand & (1ULL << (V    
134                         incr -= 1;                
135         } else if (rmode == FPSCR_ROUND_TOZERO    
136                 incr = 0;                         
137         } else if ((rmode == FPSCR_ROUND_PLUSI    
138                 incr = (1ULL << (VFP_DOUBLE_LO    
139                                                   
140         pr_debug("VFP: rounding increment = 0x    
141                                                   
142         /*                                        
143          * Is our rounding going to overflow?     
144          */                                       
145         if ((significand + incr) < significand    
146                 exponent += 1;                    
147                 significand = (significand >>     
148                 incr >>= 1;                       
149 #ifdef DEBUG                                      
150                 vd->exponent = exponent;          
151                 vd->significand = significand;    
152                 vfp_double_dump("pack: overflo    
153 #endif                                            
154         }                                         
155                                                   
156         /*                                        
157          * If any of the low bits (which will     
158          * number) are non-zero, the result is    
159          */                                       
160         if (significand & ((1 << (VFP_DOUBLE_L    
161                 exceptions |= FPSCR_IXC;          
162                                                   
163         /*                                        
164          * Do our rounding.                       
165          */                                       
166         significand += incr;                      
167                                                   
168         /*                                        
169          * Infinity?                              
170          */                                       
171         if (exponent >= 2046) {                   
172                 exceptions |= FPSCR_OFC | FPSC    
173                 if (incr == 0) {                  
174                         vd->exponent = 2045;      
175                         vd->significand = 0x7f    
176                 } else {                          
177                         vd->exponent = 2047;      
178                         vd->significand = 0;      
179                 }                                 
180         } else {                                  
181                 if (significand >> (VFP_DOUBLE    
182                         exponent = 0;             
183                 if (exponent || significand >     
184                         underflow = 0;            
185                 if (underflow)                    
186                         exceptions |= FPSCR_UF    
187                 vd->exponent = exponent;          
188                 vd->significand = significand     
189         }                                         
190                                                   
191  pack:                                            
192         vfp_double_dump("pack: final", vd);       
193         {                                         
194                 s64 d = vfp_double_pack(vd);      
195                 pr_debug("VFP: %s: d(d%d)=%016    
196                          dd, d, exceptions);      
197                 vfp_put_double(d, dd);            
198         }                                         
199         return exceptions;                        
200 }                                                 
201                                                   
202 /*                                                
203  * Propagate the NaN, setting exceptions if it    
204  * 'n' is always a NaN.  'm' may be a number,     
205  */                                               
206 static u32                                        
207 vfp_propagate_nan(struct vfp_double *vdd, stru    
208                   struct vfp_double *vdm, u32     
209 {                                                 
210         struct vfp_double *nan;                   
211         int tn, tm = 0;                           
212                                                   
213         tn = vfp_double_type(vdn);                
214                                                   
215         if (vdm)                                  
216                 tm = vfp_double_type(vdm);        
217                                                   
218         if (fpscr & FPSCR_DEFAULT_NAN)            
219                 /*                                
220                  * Default NaN mode - always r    
221                  */                               
222                 nan = &vfp_double_default_qnan    
223         else {                                    
224                 /*                                
225                  * Contemporary mode - select     
226                  * NAN, or if neither are sign    
227                  * quiet NAN.                     
228                  */                               
229                 if (tn == VFP_SNAN || (tm != V    
230                         nan = vdn;                
231                 else                              
232                         nan = vdm;                
233                 /*                                
234                  * Make the NaN quiet.            
235                  */                               
236                 nan->significand |= VFP_DOUBLE    
237         }                                         
238                                                   
239         *vdd = *nan;                              
240                                                   
241         /*                                        
242          * If one was a signalling NAN, raise     
243          */                                       
244         return tn == VFP_SNAN || tm == VFP_SNA    
245 }                                                 
246                                                   
247 /*                                                
248  * Extended operations                            
249  */                                               
250 static u32 vfp_double_fabs(int dd, int unused,    
251 {                                                 
252         vfp_put_double(vfp_double_packed_abs(v    
253         return 0;                                 
254 }                                                 
255                                                   
256 static u32 vfp_double_fcpy(int dd, int unused,    
257 {                                                 
258         vfp_put_double(vfp_get_double(dm), dd)    
259         return 0;                                 
260 }                                                 
261                                                   
262 static u32 vfp_double_fneg(int dd, int unused,    
263 {                                                 
264         vfp_put_double(vfp_double_packed_negat    
265         return 0;                                 
266 }                                                 
267                                                   
268 static u32 vfp_double_fsqrt(int dd, int unused    
269 {                                                 
270         struct vfp_double vdm, vdd;               
271         int ret, tm;                              
272                                                   
273         vfp_double_unpack(&vdm, vfp_get_double    
274         tm = vfp_double_type(&vdm);               
275         if (tm & (VFP_NAN|VFP_INFINITY)) {        
276                 struct vfp_double *vdp = &vdd;    
277                                                   
278                 if (tm & VFP_NAN)                 
279                         ret = vfp_propagate_na    
280                 else if (vdm.sign == 0) {         
281  sqrt_copy:                                       
282                         vdp = &vdm;               
283                         ret = 0;                  
284                 } else {                          
285  sqrt_invalid:                                    
286                         vdp = &vfp_double_defa    
287                         ret = FPSCR_IOC;          
288                 }                                 
289                 vfp_put_double(vfp_double_pack    
290                 return ret;                       
291         }                                         
292                                                   
293         /*                                        
294          * sqrt(+/- 0) == +/- 0                   
295          */                                       
296         if (tm & VFP_ZERO)                        
297                 goto sqrt_copy;                   
298                                                   
299         /*                                        
300          * Normalise a denormalised number        
301          */                                       
302         if (tm & VFP_DENORMAL)                    
303                 vfp_double_normalise_denormal(    
304                                                   
305         /*                                        
306          * sqrt(<0) = invalid                     
307          */                                       
308         if (vdm.sign)                             
309                 goto sqrt_invalid;                
310                                                   
311         vfp_double_dump("sqrt", &vdm);            
312                                                   
313         /*                                        
314          * Estimate the square root.              
315          */                                       
316         vdd.sign = 0;                             
317         vdd.exponent = ((vdm.exponent - 1023)     
318         vdd.significand = (u64)vfp_estimate_sq    
319                                                   
320         vfp_double_dump("sqrt estimate1", &vdd    
321                                                   
322         vdm.significand >>= 1 + (vdm.exponent     
323         vdd.significand += 2 + vfp_estimate_di    
324                                                   
325         vfp_double_dump("sqrt estimate2", &vdd    
326                                                   
327         /*                                        
328          * And now adjust.                        
329          */                                       
330         if ((vdd.significand & VFP_DOUBLE_LOW_    
331                 if (vdd.significand < 2) {        
332                         vdd.significand = ~0UL    
333                 } else {                          
334                         u64 termh, terml, remh    
335                         vdm.significand <<= 2;    
336                         mul64to128(&termh, &te    
337                         sub128(&remh, &reml, v    
338                         while ((s64)remh < 0)     
339                                 vdd.significan    
340                                 shift64left(&t    
341                                 terml |= 1;       
342                                 add128(&remh,     
343                         }                         
344                         vdd.significand |= (re    
345                 }                                 
346         }                                         
347         vdd.significand = vfp_shiftright64jamm    
348                                                   
349         return vfp_double_normaliseround(dd, &    
350 }                                                 
351                                                   
352 /*                                                
353  * Equal        := ZC                             
354  * Less than    := N                              
355  * Greater than := C                              
356  * Unordered    := CV                             
357  */                                               
358 static u32 vfp_compare(int dd, int signal_on_q    
359 {                                                 
360         s64 d, m;                                 
361         u32 ret = 0;                              
362                                                   
363         m = vfp_get_double(dm);                   
364         if (vfp_double_packed_exponent(m) == 2    
365                 ret |= FPSCR_C | FPSCR_V;         
366                 if (signal_on_qnan || !(vfp_do    
367                         /*                        
368                          * Signalling NaN, or     
369                          */                       
370                         ret |= FPSCR_IOC;         
371         }                                         
372                                                   
373         d = vfp_get_double(dd);                   
374         if (vfp_double_packed_exponent(d) == 2    
375                 ret |= FPSCR_C | FPSCR_V;         
376                 if (signal_on_qnan || !(vfp_do    
377                         /*                        
378                          * Signalling NaN, or     
379                          */                       
380                         ret |= FPSCR_IOC;         
381         }                                         
382                                                   
383         if (ret == 0) {                           
384                 if (d == m || vfp_double_packe    
385                         /*                        
386                          * equal                  
387                          */                       
388                         ret |= FPSCR_Z | FPSCR    
389                 } else if (vfp_double_packed_s    
390                         /*                        
391                          * different signs        
392                          */                       
393                         if (vfp_double_packed_    
394                                 /*                
395                                  * d is negati    
396                                  */               
397                                 ret |= FPSCR_N    
398                         else                      
399                                 /*                
400                                  * d is positi    
401                                  */               
402                                 ret |= FPSCR_C    
403                 } else if ((vfp_double_packed_    
404                         /*                        
405                          * d < m                  
406                          */                       
407                         ret |= FPSCR_N;           
408                 } else if ((vfp_double_packed_    
409                         /*                        
410                          * d > m                  
411                          */                       
412                         ret |= FPSCR_C;           
413                 }                                 
414         }                                         
415                                                   
416         return ret;                               
417 }                                                 
418                                                   
419 static u32 vfp_double_fcmp(int dd, int unused,    
420 {                                                 
421         return vfp_compare(dd, 0, dm, fpscr);     
422 }                                                 
423                                                   
424 static u32 vfp_double_fcmpe(int dd, int unused    
425 {                                                 
426         return vfp_compare(dd, 1, dm, fpscr);     
427 }                                                 
428                                                   
429 static u32 vfp_double_fcmpz(int dd, int unused    
430 {                                                 
431         return vfp_compare(dd, 0, VFP_REG_ZERO    
432 }                                                 
433                                                   
434 static u32 vfp_double_fcmpez(int dd, int unuse    
435 {                                                 
436         return vfp_compare(dd, 1, VFP_REG_ZERO    
437 }                                                 
438                                                   
439 static u32 vfp_double_fcvts(int sd, int unused    
440 {                                                 
441         struct vfp_double vdm;                    
442         struct vfp_single vsd;                    
443         int tm;                                   
444         u32 exceptions = 0;                       
445                                                   
446         vfp_double_unpack(&vdm, vfp_get_double    
447                                                   
448         tm = vfp_double_type(&vdm);               
449                                                   
450         /*                                        
451          * If we have a signalling NaN, signal    
452          */                                       
453         if (tm == VFP_SNAN)                       
454                 exceptions = FPSCR_IOC;           
455                                                   
456         if (tm & VFP_DENORMAL)                    
457                 vfp_double_normalise_denormal(    
458                                                   
459         vsd.sign = vdm.sign;                      
460         vsd.significand = vfp_hi64to32jamming(    
461                                                   
462         /*                                        
463          * If we have an infinity or a NaN, th    
464          */                                       
465         if (tm & (VFP_INFINITY|VFP_NAN)) {        
466                 vsd.exponent = 255;               
467                 if (tm == VFP_QNAN)               
468                         vsd.significand |= VFP    
469                 goto pack_nan;                    
470         } else if (tm & VFP_ZERO)                 
471                 vsd.exponent = 0;                 
472         else                                      
473                 vsd.exponent = vdm.exponent -     
474                                                   
475         return vfp_single_normaliseround(sd, &    
476                                                   
477  pack_nan:                                        
478         vfp_put_float(vfp_single_pack(&vsd), s    
479         return exceptions;                        
480 }                                                 
481                                                   
482 static u32 vfp_double_fuito(int dd, int unused    
483 {                                                 
484         struct vfp_double vdm;                    
485         u32 m = vfp_get_float(dm);                
486                                                   
487         vdm.sign = 0;                             
488         vdm.exponent = 1023 + 63 - 1;             
489         vdm.significand = (u64)m;                 
490                                                   
491         return vfp_double_normaliseround(dd, &    
492 }                                                 
493                                                   
494 static u32 vfp_double_fsito(int dd, int unused    
495 {                                                 
496         struct vfp_double vdm;                    
497         u32 m = vfp_get_float(dm);                
498                                                   
499         vdm.sign = (m & 0x80000000) >> 16;        
500         vdm.exponent = 1023 + 63 - 1;             
501         vdm.significand = vdm.sign ? -m : m;      
502                                                   
503         return vfp_double_normaliseround(dd, &    
504 }                                                 
505                                                   
506 static u32 vfp_double_ftoui(int sd, int unused    
507 {                                                 
508         struct vfp_double vdm;                    
509         u32 d, exceptions = 0;                    
510         int rmode = fpscr & FPSCR_RMODE_MASK;     
511         int tm;                                   
512                                                   
513         vfp_double_unpack(&vdm, vfp_get_double    
514                                                   
515         /*                                        
516          * Do we have a denormalised number?      
517          */                                       
518         tm = vfp_double_type(&vdm);               
519         if (tm & VFP_DENORMAL)                    
520                 exceptions |= FPSCR_IDC;          
521                                                   
522         if (tm & VFP_NAN)                         
523                 vdm.sign = 0;                     
524                                                   
525         if (vdm.exponent >= 1023 + 32) {          
526                 d = vdm.sign ? 0 : 0xffffffff;    
527                 exceptions = FPSCR_IOC;           
528         } else if (vdm.exponent >= 1023 - 1) {    
529                 int shift = 1023 + 63 - vdm.ex    
530                 u64 rem, incr = 0;                
531                                                   
532                 /*                                
533                  * 2^0 <= m < 2^32-2^8            
534                  */                               
535                 d = (vdm.significand << 1) >>     
536                 rem = vdm.significand << (65 -    
537                                                   
538                 if (rmode == FPSCR_ROUND_NEARE    
539                         incr = 0x8000000000000    
540                         if ((d & 1) == 0)         
541                                 incr -= 1;        
542                 } else if (rmode == FPSCR_ROUN    
543                         incr = 0;                 
544                 } else if ((rmode == FPSCR_ROU    
545                         incr = ~0ULL;             
546                 }                                 
547                                                   
548                 if ((rem + incr) < rem) {         
549                         if (d < 0xffffffff)       
550                                 d += 1;           
551                         else                      
552                                 exceptions |=     
553                 }                                 
554                                                   
555                 if (d && vdm.sign) {              
556                         d = 0;                    
557                         exceptions |= FPSCR_IO    
558                 } else if (rem)                   
559                         exceptions |= FPSCR_IX    
560         } else {                                  
561                 d = 0;                            
562                 if (vdm.exponent | vdm.signifi    
563                         exceptions |= FPSCR_IX    
564                         if (rmode == FPSCR_ROU    
565                                 d = 1;            
566                         else if (rmode == FPSC    
567                                 d = 0;            
568                                 exceptions |=     
569                         }                         
570                 }                                 
571         }                                         
572                                                   
573         pr_debug("VFP: ftoui: d(s%d)=%08x exce    
574                                                   
575         vfp_put_float(d, sd);                     
576                                                   
577         return exceptions;                        
578 }                                                 
579                                                   
580 static u32 vfp_double_ftouiz(int sd, int unuse    
581 {                                                 
582         return vfp_double_ftoui(sd, unused, dm    
583 }                                                 
584                                                   
585 static u32 vfp_double_ftosi(int sd, int unused    
586 {                                                 
587         struct vfp_double vdm;                    
588         u32 d, exceptions = 0;                    
589         int rmode = fpscr & FPSCR_RMODE_MASK;     
590         int tm;                                   
591                                                   
592         vfp_double_unpack(&vdm, vfp_get_double    
593         vfp_double_dump("VDM", &vdm);             
594                                                   
595         /*                                        
596          * Do we have denormalised number?        
597          */                                       
598         tm = vfp_double_type(&vdm);               
599         if (tm & VFP_DENORMAL)                    
600                 exceptions |= FPSCR_IDC;          
601                                                   
602         if (tm & VFP_NAN) {                       
603                 d = 0;                            
604                 exceptions |= FPSCR_IOC;          
605         } else if (vdm.exponent >= 1023 + 32)     
606                 d = 0x7fffffff;                   
607                 if (vdm.sign)                     
608                         d = ~d;                   
609                 exceptions |= FPSCR_IOC;          
610         } else if (vdm.exponent >= 1023 - 1) {    
611                 int shift = 1023 + 63 - vdm.ex    
612                 u64 rem, incr = 0;                
613                                                   
614                 d = (vdm.significand << 1) >>     
615                 rem = vdm.significand << (65 -    
616                                                   
617                 if (rmode == FPSCR_ROUND_NEARE    
618                         incr = 0x8000000000000    
619                         if ((d & 1) == 0)         
620                                 incr -= 1;        
621                 } else if (rmode == FPSCR_ROUN    
622                         incr = 0;                 
623                 } else if ((rmode == FPSCR_ROU    
624                         incr = ~0ULL;             
625                 }                                 
626                                                   
627                 if ((rem + incr) < rem && d <     
628                         d += 1;                   
629                 if (d > 0x7fffffff + (vdm.sign    
630                         d = 0x7fffffff + (vdm.    
631                         exceptions |= FPSCR_IO    
632                 } else if (rem)                   
633                         exceptions |= FPSCR_IX    
634                                                   
635                 if (vdm.sign)                     
636                         d = -d;                   
637         } else {                                  
638                 d = 0;                            
639                 if (vdm.exponent | vdm.signifi    
640                         exceptions |= FPSCR_IX    
641                         if (rmode == FPSCR_ROU    
642                                 d = 1;            
643                         else if (rmode == FPSC    
644                                 d = -1;           
645                 }                                 
646         }                                         
647                                                   
648         pr_debug("VFP: ftosi: d(s%d)=%08x exce    
649                                                   
650         vfp_put_float((s32)d, sd);                
651                                                   
652         return exceptions;                        
653 }                                                 
654                                                   
655 static u32 vfp_double_ftosiz(int dd, int unuse    
656 {                                                 
657         return vfp_double_ftosi(dd, unused, dm    
658 }                                                 
659                                                   
660                                                   
661 static struct op fops_ext[32] = {                 
662         [FEXT_TO_IDX(FEXT_FCPY)]        = { vf    
663         [FEXT_TO_IDX(FEXT_FABS)]        = { vf    
664         [FEXT_TO_IDX(FEXT_FNEG)]        = { vf    
665         [FEXT_TO_IDX(FEXT_FSQRT)]       = { vf    
666         [FEXT_TO_IDX(FEXT_FCMP)]        = { vf    
667         [FEXT_TO_IDX(FEXT_FCMPE)]       = { vf    
668         [FEXT_TO_IDX(FEXT_FCMPZ)]       = { vf    
669         [FEXT_TO_IDX(FEXT_FCMPEZ)]      = { vf    
670         [FEXT_TO_IDX(FEXT_FCVT)]        = { vf    
671         [FEXT_TO_IDX(FEXT_FUITO)]       = { vf    
672         [FEXT_TO_IDX(FEXT_FSITO)]       = { vf    
673         [FEXT_TO_IDX(FEXT_FTOUI)]       = { vf    
674         [FEXT_TO_IDX(FEXT_FTOUIZ)]      = { vf    
675         [FEXT_TO_IDX(FEXT_FTOSI)]       = { vf    
676         [FEXT_TO_IDX(FEXT_FTOSIZ)]      = { vf    
677 };                                                
678                                                   
679                                                   
680                                                   
681                                                   
682 static u32                                        
683 vfp_double_fadd_nonnumber(struct vfp_double *v    
684                           struct vfp_double *v    
685 {                                                 
686         struct vfp_double *vdp;                   
687         u32 exceptions = 0;                       
688         int tn, tm;                               
689                                                   
690         tn = vfp_double_type(vdn);                
691         tm = vfp_double_type(vdm);                
692                                                   
693         if (tn & tm & VFP_INFINITY) {             
694                 /*                                
695                  * Two infinities.  Are they d    
696                  */                               
697                 if (vdn->sign ^ vdm->sign) {      
698                         /*                        
699                          * different signs ->     
700                          */                       
701                         exceptions = FPSCR_IOC    
702                         vdp = &vfp_double_defa    
703                 } else {                          
704                         /*                        
705                          * same signs -> valid    
706                          */                       
707                         vdp = vdn;                
708                 }                                 
709         } else if (tn & VFP_INFINITY && tm & V    
710                 /*                                
711                  * One infinity and one number    
712                  */                               
713                 vdp = vdn;                        
714         } else {                                  
715                 /*                                
716                  * 'n' is a NaN of some type      
717                  */                               
718                 return vfp_propagate_nan(vdd,     
719         }                                         
720         *vdd = *vdp;                              
721         return exceptions;                        
722 }                                                 
723                                                   
724 static u32                                        
725 vfp_double_add(struct vfp_double *vdd, struct     
726                struct vfp_double *vdm, u32 fps    
727 {                                                 
728         u32 exp_diff;                             
729         u64 m_sig;                                
730                                                   
731         if (vdn->significand & (1ULL << 63) ||    
732             vdm->significand & (1ULL << 63)) {    
733                 pr_info("VFP: bad FP values in    
734                 vfp_double_dump("VDN", vdn);      
735                 vfp_double_dump("VDM", vdm);      
736         }                                         
737                                                   
738         /*                                        
739          * Ensure that 'n' is the largest magn    
740          * if 'n' and 'm' have equal exponents    
741          * This ensures that NaN propagation w    
742          */                                       
743         if (vdn->exponent < vdm->exponent) {      
744                 struct vfp_double *t = vdn;       
745                 vdn = vdm;                        
746                 vdm = t;                          
747         }                                         
748                                                   
749         /*                                        
750          * Is 'n' an infinity or a NaN?  Note     
751          * infinity or a NaN here.                
752          */                                       
753         if (vdn->exponent == 2047)                
754                 return vfp_double_fadd_nonnumb    
755                                                   
756         /*                                        
757          * We have two proper numbers, where '    
758          *                                        
759          * Copy 'n' to 'd' before doing the ar    
760          */                                       
761         *vdd = *vdn;                              
762                                                   
763         /*                                        
764          * Align 'm' with the result.             
765          */                                       
766         exp_diff = vdn->exponent - vdm->expone    
767         m_sig = vfp_shiftright64jamming(vdm->s    
768                                                   
769         /*                                        
770          * If the signs are different, we are     
771          */                                       
772         if (vdn->sign ^ vdm->sign) {              
773                 m_sig = vdn->significand - m_s    
774                 if ((s64)m_sig < 0) {             
775                         vdd->sign = vfp_sign_n    
776                         m_sig = -m_sig;           
777                 } else if (m_sig == 0) {          
778                         vdd->sign = (fpscr & F    
779                                       FPSCR_RO    
780                 }                                 
781         } else {                                  
782                 m_sig += vdn->significand;        
783         }                                         
784         vdd->significand = m_sig;                 
785                                                   
786         return 0;                                 
787 }                                                 
788                                                   
789 static u32                                        
790 vfp_double_multiply(struct vfp_double *vdd, st    
791                     struct vfp_double *vdm, u3    
792 {                                                 
793         vfp_double_dump("VDN", vdn);              
794         vfp_double_dump("VDM", vdm);              
795                                                   
796         /*                                        
797          * Ensure that 'n' is the largest magn    
798          * if 'n' and 'm' have equal exponents    
799          * This ensures that NaN propagation w    
800          */                                       
801         if (vdn->exponent < vdm->exponent) {      
802                 struct vfp_double *t = vdn;       
803                 vdn = vdm;                        
804                 vdm = t;                          
805                 pr_debug("VFP: swapping M <->     
806         }                                         
807                                                   
808         vdd->sign = vdn->sign ^ vdm->sign;        
809                                                   
810         /*                                        
811          * If 'n' is an infinity or NaN, handl    
812          */                                       
813         if (vdn->exponent == 2047) {              
814                 if (vdn->significand || (vdm->    
815                         return vfp_propagate_n    
816                 if ((vdm->exponent | vdm->sign    
817                         *vdd = vfp_double_defa    
818                         return FPSCR_IOC;         
819                 }                                 
820                 vdd->exponent = vdn->exponent;    
821                 vdd->significand = 0;             
822                 return 0;                         
823         }                                         
824                                                   
825         /*                                        
826          * If 'm' is zero, the result is alway    
827          * 'n' may be zero or a number, but it    
828          */                                       
829         if ((vdm->exponent | vdm->significand)    
830                 vdd->exponent = 0;                
831                 vdd->significand = 0;             
832                 return 0;                         
833         }                                         
834                                                   
835         /*                                        
836          * We add 2 to the destination exponen    
837          * as the addition case - though this     
838          * each input operand.                    
839          */                                       
840         vdd->exponent = vdn->exponent + vdm->e    
841         vdd->significand = vfp_hi64multiply64(    
842                                                   
843         vfp_double_dump("VDD", vdd);              
844         return 0;                                 
845 }                                                 
846                                                   
847 #define NEG_MULTIPLY    (1 << 0)                  
848 #define NEG_SUBTRACT    (1 << 1)                  
849                                                   
850 static u32                                        
851 vfp_double_multiply_accumulate(int dd, int dn,    
852 {                                                 
853         struct vfp_double vdd, vdp, vdn, vdm;     
854         u32 exceptions;                           
855                                                   
856         vfp_double_unpack(&vdn, vfp_get_double    
857         if (vdn.exponent == 0 && vdn.significa    
858                 vfp_double_normalise_denormal(    
859                                                   
860         vfp_double_unpack(&vdm, vfp_get_double    
861         if (vdm.exponent == 0 && vdm.significa    
862                 vfp_double_normalise_denormal(    
863                                                   
864         exceptions = vfp_double_multiply(&vdp,    
865         if (negate & NEG_MULTIPLY)                
866                 vdp.sign = vfp_sign_negate(vdp    
867                                                   
868         vfp_double_unpack(&vdn, vfp_get_double    
869         if (vdn.exponent == 0 && vdn.significa    
870                 vfp_double_normalise_denormal(    
871         if (negate & NEG_SUBTRACT)                
872                 vdn.sign = vfp_sign_negate(vdn    
873                                                   
874         exceptions |= vfp_double_add(&vdd, &vd    
875                                                   
876         return vfp_double_normaliseround(dd, &    
877 }                                                 
878                                                   
879 /*                                                
880  * Standard operations                            
881  */                                               
882                                                   
883 /*                                                
884  * sd = sd + (sn * sm)                            
885  */                                               
886 static u32 vfp_double_fmac(int dd, int dn, int    
887 {                                                 
888         return vfp_double_multiply_accumulate(    
889 }                                                 
890                                                   
891 /*                                                
892  * sd = sd - (sn * sm)                            
893  */                                               
894 static u32 vfp_double_fnmac(int dd, int dn, in    
895 {                                                 
896         return vfp_double_multiply_accumulate(    
897 }                                                 
898                                                   
899 /*                                                
900  * sd = -sd + (sn * sm)                           
901  */                                               
902 static u32 vfp_double_fmsc(int dd, int dn, int    
903 {                                                 
904         return vfp_double_multiply_accumulate(    
905 }                                                 
906                                                   
907 /*                                                
908  * sd = -sd - (sn * sm)                           
909  */                                               
910 static u32 vfp_double_fnmsc(int dd, int dn, in    
911 {                                                 
912         return vfp_double_multiply_accumulate(    
913 }                                                 
914                                                   
915 /*                                                
916  * sd = sn * sm                                   
917  */                                               
918 static u32 vfp_double_fmul(int dd, int dn, int    
919 {                                                 
920         struct vfp_double vdd, vdn, vdm;          
921         u32 exceptions;                           
922                                                   
923         vfp_double_unpack(&vdn, vfp_get_double    
924         if (vdn.exponent == 0 && vdn.significa    
925                 vfp_double_normalise_denormal(    
926                                                   
927         vfp_double_unpack(&vdm, vfp_get_double    
928         if (vdm.exponent == 0 && vdm.significa    
929                 vfp_double_normalise_denormal(    
930                                                   
931         exceptions = vfp_double_multiply(&vdd,    
932         return vfp_double_normaliseround(dd, &    
933 }                                                 
934                                                   
935 /*                                                
936  * sd = -(sn * sm)                                
937  */                                               
938 static u32 vfp_double_fnmul(int dd, int dn, in    
939 {                                                 
940         struct vfp_double vdd, vdn, vdm;          
941         u32 exceptions;                           
942                                                   
943         vfp_double_unpack(&vdn, vfp_get_double    
944         if (vdn.exponent == 0 && vdn.significa    
945                 vfp_double_normalise_denormal(    
946                                                   
947         vfp_double_unpack(&vdm, vfp_get_double    
948         if (vdm.exponent == 0 && vdm.significa    
949                 vfp_double_normalise_denormal(    
950                                                   
951         exceptions = vfp_double_multiply(&vdd,    
952         vdd.sign = vfp_sign_negate(vdd.sign);     
953                                                   
954         return vfp_double_normaliseround(dd, &    
955 }                                                 
956                                                   
957 /*                                                
958  * sd = sn + sm                                   
959  */                                               
960 static u32 vfp_double_fadd(int dd, int dn, int    
961 {                                                 
962         struct vfp_double vdd, vdn, vdm;          
963         u32 exceptions;                           
964                                                   
965         vfp_double_unpack(&vdn, vfp_get_double    
966         if (vdn.exponent == 0 && vdn.significa    
967                 vfp_double_normalise_denormal(    
968                                                   
969         vfp_double_unpack(&vdm, vfp_get_double    
970         if (vdm.exponent == 0 && vdm.significa    
971                 vfp_double_normalise_denormal(    
972                                                   
973         exceptions = vfp_double_add(&vdd, &vdn    
974                                                   
975         return vfp_double_normaliseround(dd, &    
976 }                                                 
977                                                   
978 /*                                                
979  * sd = sn - sm                                   
980  */                                               
981 static u32 vfp_double_fsub(int dd, int dn, int    
982 {                                                 
983         struct vfp_double vdd, vdn, vdm;          
984         u32 exceptions;                           
985                                                   
986         vfp_double_unpack(&vdn, vfp_get_double    
987         if (vdn.exponent == 0 && vdn.significa    
988                 vfp_double_normalise_denormal(    
989                                                   
990         vfp_double_unpack(&vdm, vfp_get_double    
991         if (vdm.exponent == 0 && vdm.significa    
992                 vfp_double_normalise_denormal(    
993                                                   
994         /*                                        
995          * Subtraction is like addition, but w    
996          */                                       
997         vdm.sign = vfp_sign_negate(vdm.sign);     
998                                                   
999         exceptions = vfp_double_add(&vdd, &vdn    
1000                                                  
1001         return vfp_double_normaliseround(dd,     
1002 }                                                
1003                                                  
1004 /*                                               
1005  * sd = sn / sm                                  
1006  */                                              
1007 static u32 vfp_double_fdiv(int dd, int dn, in    
1008 {                                                
1009         struct vfp_double vdd, vdn, vdm;         
1010         u32 exceptions = 0;                      
1011         int tm, tn;                              
1012                                                  
1013         vfp_double_unpack(&vdn, vfp_get_doubl    
1014         vfp_double_unpack(&vdm, vfp_get_doubl    
1015                                                  
1016         vdd.sign = vdn.sign ^ vdm.sign;          
1017                                                  
1018         tn = vfp_double_type(&vdn);              
1019         tm = vfp_double_type(&vdm);              
1020                                                  
1021         /*                                       
1022          * Is n a NAN?                           
1023          */                                      
1024         if (tn & VFP_NAN)                        
1025                 goto vdn_nan;                    
1026                                                  
1027         /*                                       
1028          * Is m a NAN?                           
1029          */                                      
1030         if (tm & VFP_NAN)                        
1031                 goto vdm_nan;                    
1032                                                  
1033         /*                                       
1034          * If n and m are infinity, the resul    
1035          * If n and m are zero, the result is    
1036          */                                      
1037         if (tm & tn & (VFP_INFINITY|VFP_ZERO)    
1038                 goto invalid;                    
1039                                                  
1040         /*                                       
1041          * If n is infinity, the result is in    
1042          */                                      
1043         if (tn & VFP_INFINITY)                   
1044                 goto infinity;                   
1045                                                  
1046         /*                                       
1047          * If m is zero, raise div0 exception    
1048          */                                      
1049         if (tm & VFP_ZERO)                       
1050                 goto divzero;                    
1051                                                  
1052         /*                                       
1053          * If m is infinity, or n is zero, th    
1054          */                                      
1055         if (tm & VFP_INFINITY || tn & VFP_ZER    
1056                 goto zero;                       
1057                                                  
1058         if (tn & VFP_DENORMAL)                   
1059                 vfp_double_normalise_denormal    
1060         if (tm & VFP_DENORMAL)                   
1061                 vfp_double_normalise_denormal    
1062                                                  
1063         /*                                       
1064          * Ok, we have two numbers, we can pe    
1065          */                                      
1066         vdd.exponent = vdn.exponent - vdm.exp    
1067         vdm.significand <<= 1;                   
1068         if (vdm.significand <= (2 * vdn.signi    
1069                 vdn.significand >>= 1;           
1070                 vdd.exponent++;                  
1071         }                                        
1072         vdd.significand = vfp_estimate_div128    
1073         if ((vdd.significand & 0x1ff) <= 2) {    
1074                 u64 termh, terml, remh, reml;    
1075                 mul64to128(&termh, &terml, vd    
1076                 sub128(&remh, &reml, vdn.sign    
1077                 while ((s64)remh < 0) {          
1078                         vdd.significand -= 1;    
1079                         add128(&remh, &reml,     
1080                 }                                
1081                 vdd.significand |= (reml != 0    
1082         }                                        
1083         return vfp_double_normaliseround(dd,     
1084                                                  
1085  vdn_nan:                                        
1086         exceptions = vfp_propagate_nan(&vdd,     
1087  pack:                                           
1088         vfp_put_double(vfp_double_pack(&vdd),    
1089         return exceptions;                       
1090                                                  
1091  vdm_nan:                                        
1092         exceptions = vfp_propagate_nan(&vdd,     
1093         goto pack;                               
1094                                                  
1095  zero:                                           
1096         vdd.exponent = 0;                        
1097         vdd.significand = 0;                     
1098         goto pack;                               
1099                                                  
1100  divzero:                                        
1101         exceptions = FPSCR_DZC;                  
1102  infinity:                                       
1103         vdd.exponent = 2047;                     
1104         vdd.significand = 0;                     
1105         goto pack;                               
1106                                                  
1107  invalid:                                        
1108         vfp_put_double(vfp_double_pack(&vfp_d    
1109         return FPSCR_IOC;                        
1110 }                                                
1111                                                  
1112 static struct op fops[16] = {                    
1113         [FOP_TO_IDX(FOP_FMAC)]  = { vfp_doubl    
1114         [FOP_TO_IDX(FOP_FNMAC)] = { vfp_doubl    
1115         [FOP_TO_IDX(FOP_FMSC)]  = { vfp_doubl    
1116         [FOP_TO_IDX(FOP_FNMSC)] = { vfp_doubl    
1117         [FOP_TO_IDX(FOP_FMUL)]  = { vfp_doubl    
1118         [FOP_TO_IDX(FOP_FNMUL)] = { vfp_doubl    
1119         [FOP_TO_IDX(FOP_FADD)]  = { vfp_doubl    
1120         [FOP_TO_IDX(FOP_FSUB)]  = { vfp_doubl    
1121         [FOP_TO_IDX(FOP_FDIV)]  = { vfp_doubl    
1122 };                                               
1123                                                  
1124 #define FREG_BANK(x)    ((x) & 0x0c)             
1125 #define FREG_IDX(x)     ((x) & 3)                
1126                                                  
1127 u32 vfp_double_cpdo(u32 inst, u32 fpscr)         
1128 {                                                
1129         u32 op = inst & FOP_MASK;                
1130         u32 exceptions = 0;                      
1131         unsigned int dest;                       
1132         unsigned int dn = vfp_get_dn(inst);      
1133         unsigned int dm;                         
1134         unsigned int vecitr, veclen, vecstrid    
1135         struct op *fop;                          
1136                                                  
1137         vecstride = (1 + ((fpscr & FPSCR_STRI    
1138                                                  
1139         fop = (op == FOP_EXT) ? &fops_ext[FEX    
1140                                                  
1141         /*                                       
1142          * fcvtds takes an sN register number    
1143          * It also always operates on scalars    
1144          */                                      
1145         if (fop->flags & OP_SD)                  
1146                 dest = vfp_get_sd(inst);         
1147         else                                     
1148                 dest = vfp_get_dd(inst);         
1149                                                  
1150         /*                                       
1151          * f[us]ito takes a sN operand, not a    
1152          */                                      
1153         if (fop->flags & OP_SM)                  
1154                 dm = vfp_get_sm(inst);           
1155         else                                     
1156                 dm = vfp_get_dm(inst);           
1157                                                  
1158         /*                                       
1159          * If destination bank is zero, vecto    
1160          * ARM DDI0100F C5.1.3, C5.3.2.          
1161          */                                      
1162         if ((fop->flags & OP_SCALAR) || (FREG    
1163                 veclen = 0;                      
1164         else                                     
1165                 veclen = fpscr & FPSCR_LENGTH    
1166                                                  
1167         pr_debug("VFP: vecstride=%u veclen=%u    
1168                  (veclen >> FPSCR_LENGTH_BIT)    
1169                                                  
1170         if (!fop->fn)                            
1171                 goto invalid;                    
1172                                                  
1173         for (vecitr = 0; vecitr <= veclen; ve    
1174                 u32 except;                      
1175                 char type;                       
1176                                                  
1177                 type = fop->flags & OP_SD ? '    
1178                 if (op == FOP_EXT)               
1179                         pr_debug("VFP: itr%d     
1180                                  vecitr >> FP    
1181                                  type, dest,     
1182                 else                             
1183                         pr_debug("VFP: itr%d     
1184                                  vecitr >> FP    
1185                                  type, dest,     
1186                                                  
1187                 except = fop->fn(dest, dn, dm    
1188                 pr_debug("VFP: itr%d: excepti    
1189                          vecitr >> FPSCR_LENG    
1190                                                  
1191                 exceptions |= except;            
1192                                                  
1193                 /*                               
1194                  * CHECK: It appears to be un    
1195                  * we encounter an exception.    
1196                  */                              
1197                 dest = FREG_BANK(dest) + ((FR    
1198                 dn = FREG_BANK(dn) + ((FREG_I    
1199                 if (FREG_BANK(dm) != 0)          
1200                         dm = FREG_BANK(dm) +     
1201         }                                        
1202         return exceptions;                       
1203                                                  
1204  invalid:                                        
1205         return ~0;                               
1206 }                                                
1207                                                  

~ [ 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