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

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

Version: ~ [ linux-4.15-rc3 ] ~ [ linux-4.14.5 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.68 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.105 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.47 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.87 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.51 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.96 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.27.62 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/arch/arm/vfp/vfpdouble.c
  3  *
  4  * This code is derived in part from John R. Housers softfloat library, which
  5  * carries the following notice:
  6  *
  7  * ===========================================================================
  8  * This C source file is part of the SoftFloat IEC/IEEE Floating-point
  9  * Arithmetic Package, Release 2.
 10  *
 11  * Written by John R. Hauser.  This work was made possible in part by the
 12  * International Computer Science Institute, located at Suite 600, 1947 Center
 13  * Street, Berkeley, California 94704.  Funding was partially provided by the
 14  * National Science Foundation under grant MIP-9311980.  The original version
 15  * of this code was written as part of a project to build a fixed-point vector
 16  * processor in collaboration with the University of California at Berkeley,
 17  * overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
 18  * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
 19  * arithmetic/softfloat.html'.
 20  *
 21  * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
 22  * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
 23  * TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
 24  * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
 25  * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
 26  *
 27  * Derivative works are acceptable, even for commercial purposes, so long as
 28  * (1) they include prominent notice that the work is derivative, and (2) they
 29  * include prominent notice akin to these three paragraphs for those parts of
 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_qnan = {
 43         .exponent       = 2047,
 44         .sign           = 0,
 45         .significand    = VFP_DOUBLE_SIGNIFICAND_QNAN,
 46 };
 47 
 48 static void vfp_double_dump(const char *str, struct vfp_double *d)
 49 {
 50         pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
 51                  str, d->sign != 0, d->exponent, d->significand);
 52 }
 53 
 54 static void vfp_double_normalise_denormal(struct vfp_double *vd)
 55 {
 56         int bits = 31 - fls(vd->significand >> 32);
 57         if (bits == 31)
 58                 bits = 63 - fls(vd->significand);
 59 
 60         vfp_double_dump("normalise_denormal: in", vd);
 61 
 62         if (bits) {
 63                 vd->exponent -= bits - 1;
 64                 vd->significand <<= bits;
 65         }
 66 
 67         vfp_double_dump("normalise_denormal: out", vd);
 68 }
 69 
 70 u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
 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 case.
 80          */
 81         if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
 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_shiftright64jamming(significand, -exponent);
115                 exponent = 0;
116 #ifdef DEBUG
117                 vd->exponent = exponent;
118                 vd->significand = significand;
119                 vfp_double_dump("pack: tiny number", vd);
120 #endif
121                 if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
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_BITS;
133                 if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
134                         incr -= 1;
135         } else if (rmode == FPSCR_ROUND_TOZERO) {
136                 incr = 0;
137         } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
138                 incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
139 
140         pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
141 
142         /*
143          * Is our rounding going to overflow?
144          */
145         if ((significand + incr) < significand) {
146                 exponent += 1;
147                 significand = (significand >> 1) | (significand & 1);
148                 incr >>= 1;
149 #ifdef DEBUG
150                 vd->exponent = exponent;
151                 vd->significand = significand;
152                 vfp_double_dump("pack: overflow", vd);
153 #endif
154         }
155 
156         /*
157          * If any of the low bits (which will be shifted out of the
158          * number) are non-zero, the result is inexact.
159          */
160         if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
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 | FPSCR_IXC;
173                 if (incr == 0) {
174                         vd->exponent = 2045;
175                         vd->significand = 0x7fffffffffffffffULL;
176                 } else {
177                         vd->exponent = 2047;            /* infinity */
178                         vd->significand = 0;
179                 }
180         } else {
181                 if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
182                         exponent = 0;
183                 if (exponent || significand > 0x8000000000000000ULL)
184                         underflow = 0;
185                 if (underflow)
186                         exceptions |= FPSCR_UFC;
187                 vd->exponent = exponent;
188                 vd->significand = significand >> 1;
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)=%016llx exceptions=%08x\n", func,
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 is signalling.
204  * 'n' is always a NaN.  'm' may be a number, NaN or infinity.
205  */
206 static u32
207 vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
208                   struct vfp_double *vdm, u32 fpscr)
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 returns a quiet NaN
221                  */
222                 nan = &vfp_double_default_qnan;
223         else {
224                 /*
225                  * Contemporary mode - select the first signalling
226                  * NAN, or if neither are signalling, the first
227                  * quiet NAN.
228                  */
229                 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
230                         nan = vdn;
231                 else
232                         nan = vdm;
233                 /*
234                  * Make the NaN quiet.
235                  */
236                 nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
237         }
238 
239         *vdd = *nan;
240 
241         /*
242          * If one was a signalling NAN, raise invalid operation.
243          */
244         return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
245 }
246 
247 /*
248  * Extended operations
249  */
250 static u32 vfp_double_fabs(int dd, int unused, int dm, u32 fpscr)
251 {
252         vfp_put_double(vfp_double_packed_abs(vfp_get_double(dm)), dd);
253         return 0;
254 }
255 
256 static u32 vfp_double_fcpy(int dd, int unused, int dm, u32 fpscr)
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, int dm, u32 fpscr)
263 {
264         vfp_put_double(vfp_double_packed_negate(vfp_get_double(dm)), dd);
265         return 0;
266 }
267 
268 static u32 vfp_double_fsqrt(int dd, int unused, int dm, u32 fpscr)
269 {
270         struct vfp_double vdm, vdd;
271         int ret, tm;
272 
273         vfp_double_unpack(&vdm, vfp_get_double(dm));
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_nan(vdp, &vdm, NULL, fpscr);
280                 else if (vdm.sign == 0) {
281  sqrt_copy:
282                         vdp = &vdm;
283                         ret = 0;
284                 } else {
285  sqrt_invalid:
286                         vdp = &vfp_double_default_qnan;
287                         ret = FPSCR_IOC;
288                 }
289                 vfp_put_double(vfp_double_pack(vdp), dd);
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(&vdm);
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) >> 1) + 1023;
318         vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
319 
320         vfp_double_dump("sqrt estimate1", &vdd);
321 
322         vdm.significand >>= 1 + (vdm.exponent & 1);
323         vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
324 
325         vfp_double_dump("sqrt estimate2", &vdd);
326 
327         /*
328          * And now adjust.
329          */
330         if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
331                 if (vdd.significand < 2) {
332                         vdd.significand = ~0ULL;
333                 } else {
334                         u64 termh, terml, remh, reml;
335                         vdm.significand <<= 2;
336                         mul64to128(&termh, &terml, vdd.significand, vdd.significand);
337                         sub128(&remh, &reml, vdm.significand, 0, termh, terml);
338                         while ((s64)remh < 0) {
339                                 vdd.significand -= 1;
340                                 shift64left(&termh, &terml, vdd.significand);
341                                 terml |= 1;
342                                 add128(&remh, &reml, remh, reml, termh, terml);
343                         }
344                         vdd.significand |= (remh | reml) != 0;
345                 }
346         }
347         vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
348 
349         return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fsqrt");
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_qnan, int dm, u32 fpscr)
359 {
360         s64 d, m;
361         u32 ret = 0;
362 
363         m = vfp_get_double(dm);
364         if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
365                 ret |= FPSCR_C | FPSCR_V;
366                 if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
367                         /*
368                          * Signalling NaN, or signalling on quiet NaN
369                          */
370                         ret |= FPSCR_IOC;
371         }
372 
373         d = vfp_get_double(dd);
374         if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
375                 ret |= FPSCR_C | FPSCR_V;
376                 if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
377                         /*
378                          * Signalling NaN, or signalling on quiet NaN
379                          */
380                         ret |= FPSCR_IOC;
381         }
382 
383         if (ret == 0) {
384                 if (d == m || vfp_double_packed_abs(d | m) == 0) {
385                         /*
386                          * equal
387                          */
388                         ret |= FPSCR_Z | FPSCR_C;
389                 } else if (vfp_double_packed_sign(d ^ m)) {
390                         /*
391                          * different signs
392                          */
393                         if (vfp_double_packed_sign(d))
394                                 /*
395                                  * d is negative, so d < m
396                                  */
397                                 ret |= FPSCR_N;
398                         else
399                                 /*
400                                  * d is positive, so d > m
401                                  */
402                                 ret |= FPSCR_C;
403                 } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
404                         /*
405                          * d < m
406                          */
407                         ret |= FPSCR_N;
408                 } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
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, int dm, u32 fpscr)
420 {
421         return vfp_compare(dd, 0, dm, fpscr);
422 }
423 
424 static u32 vfp_double_fcmpe(int dd, int unused, int dm, u32 fpscr)
425 {
426         return vfp_compare(dd, 1, dm, fpscr);
427 }
428 
429 static u32 vfp_double_fcmpz(int dd, int unused, int dm, u32 fpscr)
430 {
431         return vfp_compare(dd, 0, VFP_REG_ZERO, fpscr);
432 }
433 
434 static u32 vfp_double_fcmpez(int dd, int unused, int dm, u32 fpscr)
435 {
436         return vfp_compare(dd, 1, VFP_REG_ZERO, fpscr);
437 }
438 
439 static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr)
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(dm));
447 
448         tm = vfp_double_type(&vdm);
449 
450         /*
451          * If we have a signalling NaN, signal invalid operation.
452          */
453         if (tm == VFP_SNAN)
454                 exceptions = FPSCR_IOC;
455 
456         if (tm & VFP_DENORMAL)
457                 vfp_double_normalise_denormal(&vdm);
458 
459         vsd.sign = vdm.sign;
460         vsd.significand = vfp_hi64to32jamming(vdm.significand);
461 
462         /*
463          * If we have an infinity or a NaN, the exponent must be 255
464          */
465         if (tm & (VFP_INFINITY|VFP_NAN)) {
466                 vsd.exponent = 255;
467                 if (tm == VFP_QNAN)
468                         vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
469                 goto pack_nan;
470         } else if (tm & VFP_ZERO)
471                 vsd.exponent = 0;
472         else
473                 vsd.exponent = vdm.exponent - (1023 - 127);
474 
475         return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fcvts");
476 
477  pack_nan:
478         vfp_put_float(vfp_single_pack(&vsd), sd);
479         return exceptions;
480 }
481 
482 static u32 vfp_double_fuito(int dd, int unused, int dm, u32 fpscr)
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, &vdm, fpscr, 0, "fuito");
492 }
493 
494 static u32 vfp_double_fsito(int dd, int unused, int dm, u32 fpscr)
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, &vdm, fpscr, 0, "fsito");
504 }
505 
506 static u32 vfp_double_ftoui(int sd, int unused, int dm, u32 fpscr)
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(dm));
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.exponent;
530                 u64 rem, incr = 0;
531 
532                 /*
533                  * 2^0 <= m < 2^32-2^8
534                  */
535                 d = (vdm.significand << 1) >> shift;
536                 rem = vdm.significand << (65 - shift);
537 
538                 if (rmode == FPSCR_ROUND_NEAREST) {
539                         incr = 0x8000000000000000ULL;
540                         if ((d & 1) == 0)
541                                 incr -= 1;
542                 } else if (rmode == FPSCR_ROUND_TOZERO) {
543                         incr = 0;
544                 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
545                         incr = ~0ULL;
546                 }
547 
548                 if ((rem + incr) < rem) {
549                         if (d < 0xffffffff)
550                                 d += 1;
551                         else
552                                 exceptions |= FPSCR_IOC;
553                 }
554 
555                 if (d && vdm.sign) {
556                         d = 0;
557                         exceptions |= FPSCR_IOC;
558                 } else if (rem)
559                         exceptions |= FPSCR_IXC;
560         } else {
561                 d = 0;
562                 if (vdm.exponent | vdm.significand) {
563                         exceptions |= FPSCR_IXC;
564                         if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
565                                 d = 1;
566                         else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
567                                 d = 0;
568                                 exceptions |= FPSCR_IOC;
569                         }
570                 }
571         }
572 
573         pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
574 
575         vfp_put_float(d, sd);
576 
577         return exceptions;
578 }
579 
580 static u32 vfp_double_ftouiz(int sd, int unused, int dm, u32 fpscr)
581 {
582         return vfp_double_ftoui(sd, unused, dm, FPSCR_ROUND_TOZERO);
583 }
584 
585 static u32 vfp_double_ftosi(int sd, int unused, int dm, u32 fpscr)
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(dm));
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.exponent;   /* 58 */
612                 u64 rem, incr = 0;
613 
614                 d = (vdm.significand << 1) >> shift;
615                 rem = vdm.significand << (65 - shift);
616 
617                 if (rmode == FPSCR_ROUND_NEAREST) {
618                         incr = 0x8000000000000000ULL;
619                         if ((d & 1) == 0)
620                                 incr -= 1;
621                 } else if (rmode == FPSCR_ROUND_TOZERO) {
622                         incr = 0;
623                 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
624                         incr = ~0ULL;
625                 }
626 
627                 if ((rem + incr) < rem && d < 0xffffffff)
628                         d += 1;
629                 if (d > 0x7fffffff + (vdm.sign != 0)) {
630                         d = 0x7fffffff + (vdm.sign != 0);
631                         exceptions |= FPSCR_IOC;
632                 } else if (rem)
633                         exceptions |= FPSCR_IXC;
634 
635                 if (vdm.sign)
636                         d = -d;
637         } else {
638                 d = 0;
639                 if (vdm.exponent | vdm.significand) {
640                         exceptions |= FPSCR_IXC;
641                         if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
642                                 d = 1;
643                         else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
644                                 d = -1;
645                 }
646         }
647 
648         pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
649 
650         vfp_put_float((s32)d, sd);
651 
652         return exceptions;
653 }
654 
655 static u32 vfp_double_ftosiz(int dd, int unused, int dm, u32 fpscr)
656 {
657         return vfp_double_ftosi(dd, unused, dm, FPSCR_ROUND_TOZERO);
658 }
659 
660 
661 static struct op fops_ext[32] = {
662         [FEXT_TO_IDX(FEXT_FCPY)]        = { vfp_double_fcpy,   0 },
663         [FEXT_TO_IDX(FEXT_FABS)]        = { vfp_double_fabs,   0 },
664         [FEXT_TO_IDX(FEXT_FNEG)]        = { vfp_double_fneg,   0 },
665         [FEXT_TO_IDX(FEXT_FSQRT)]       = { vfp_double_fsqrt,  0 },
666         [FEXT_TO_IDX(FEXT_FCMP)]        = { vfp_double_fcmp,   OP_SCALAR },
667         [FEXT_TO_IDX(FEXT_FCMPE)]       = { vfp_double_fcmpe,  OP_SCALAR },
668         [FEXT_TO_IDX(FEXT_FCMPZ)]       = { vfp_double_fcmpz,  OP_SCALAR },
669         [FEXT_TO_IDX(FEXT_FCMPEZ)]      = { vfp_double_fcmpez, OP_SCALAR },
670         [FEXT_TO_IDX(FEXT_FCVT)]        = { vfp_double_fcvts,  OP_SCALAR|OP_SD },
671         [FEXT_TO_IDX(FEXT_FUITO)]       = { vfp_double_fuito,  OP_SCALAR|OP_SM },
672         [FEXT_TO_IDX(FEXT_FSITO)]       = { vfp_double_fsito,  OP_SCALAR|OP_SM },
673         [FEXT_TO_IDX(FEXT_FTOUI)]       = { vfp_double_ftoui,  OP_SCALAR|OP_SD },
674         [FEXT_TO_IDX(FEXT_FTOUIZ)]      = { vfp_double_ftouiz, OP_SCALAR|OP_SD },
675         [FEXT_TO_IDX(FEXT_FTOSI)]       = { vfp_double_ftosi,  OP_SCALAR|OP_SD },
676         [FEXT_TO_IDX(FEXT_FTOSIZ)]      = { vfp_double_ftosiz, OP_SCALAR|OP_SD },
677 };
678 
679 
680 
681 
682 static u32
683 vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
684                           struct vfp_double *vdm, u32 fpscr)
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 different signs?
696                  */
697                 if (vdn->sign ^ vdm->sign) {
698                         /*
699                          * different signs -> invalid
700                          */
701                         exceptions = FPSCR_IOC;
702                         vdp = &vfp_double_default_qnan;
703                 } else {
704                         /*
705                          * same signs -> valid
706                          */
707                         vdp = vdn;
708                 }
709         } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
710                 /*
711                  * One infinity and one number -> infinity
712                  */
713                 vdp = vdn;
714         } else {
715                 /*
716                  * 'n' is a NaN of some type
717                  */
718                 return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
719         }
720         *vdd = *vdp;
721         return exceptions;
722 }
723 
724 static u32
725 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,
726                struct vfp_double *vdm, u32 fpscr)
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 %s\n", __func__);
734                 vfp_double_dump("VDN", vdn);
735                 vfp_double_dump("VDM", vdm);
736         }
737 
738         /*
739          * Ensure that 'n' is the largest magnitude number.  Note that
740          * if 'n' and 'm' have equal exponents, we do not swap them.
741          * This ensures that NaN propagation works correctly.
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 that 'm' may be a number,
751          * infinity or a NaN here.
752          */
753         if (vdn->exponent == 2047)
754                 return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
755 
756         /*
757          * We have two proper numbers, where 'vdn' is the larger magnitude.
758          *
759          * Copy 'n' to 'd' before doing the arithmetic.
760          */
761         *vdd = *vdn;
762 
763         /*
764          * Align 'm' with the result.
765          */
766         exp_diff = vdn->exponent - vdm->exponent;
767         m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
768 
769         /*
770          * If the signs are different, we are really subtracting.
771          */
772         if (vdn->sign ^ vdm->sign) {
773                 m_sig = vdn->significand - m_sig;
774                 if ((s64)m_sig < 0) {
775                         vdd->sign = vfp_sign_negate(vdd->sign);
776                         m_sig = -m_sig;
777                 } else if (m_sig == 0) {
778                         vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
779                                       FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
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, struct vfp_double *vdn,
791                     struct vfp_double *vdm, u32 fpscr)
792 {
793         vfp_double_dump("VDN", vdn);
794         vfp_double_dump("VDM", vdm);
795 
796         /*
797          * Ensure that 'n' is the largest magnitude number.  Note that
798          * if 'n' and 'm' have equal exponents, we do not swap them.
799          * This ensures that NaN propagation works correctly.
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 <-> N\n");
806         }
807 
808         vdd->sign = vdn->sign ^ vdm->sign;
809 
810         /*
811          * If 'n' is an infinity or NaN, handle it.  'm' may be anything.
812          */
813         if (vdn->exponent == 2047) {
814                 if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
815                         return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
816                 if ((vdm->exponent | vdm->significand) == 0) {
817                         *vdd = vfp_double_default_qnan;
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 always zero.  In this case,
827          * 'n' may be zero or a number, but it doesn't matter which.
828          */
829         if ((vdm->exponent | vdm->significand) == 0) {
830                 vdd->exponent = 0;
831                 vdd->significand = 0;
832                 return 0;
833         }
834 
835         /*
836          * We add 2 to the destination exponent for the same reason
837          * as the addition case - though this time we have +1 from
838          * each input operand.
839          */
840         vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
841         vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
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, int dm, u32 fpscr, u32 negate, char *func)
852 {
853         struct vfp_double vdd, vdp, vdn, vdm;
854         u32 exceptions;
855 
856         vfp_double_unpack(&vdn, vfp_get_double(dn));
857         if (vdn.exponent == 0 && vdn.significand)
858                 vfp_double_normalise_denormal(&vdn);
859 
860         vfp_double_unpack(&vdm, vfp_get_double(dm));
861         if (vdm.exponent == 0 && vdm.significand)
862                 vfp_double_normalise_denormal(&vdm);
863 
864         exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
865         if (negate & NEG_MULTIPLY)
866                 vdp.sign = vfp_sign_negate(vdp.sign);
867 
868         vfp_double_unpack(&vdn, vfp_get_double(dd));
869         if (vdn.exponent == 0 && vdn.significand)
870                 vfp_double_normalise_denormal(&vdn);
871         if (negate & NEG_SUBTRACT)
872                 vdn.sign = vfp_sign_negate(vdn.sign);
873 
874         exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
875 
876         return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, func);
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 dm, u32 fpscr)
887 {
888         return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, 0, "fmac");
889 }
890 
891 /*
892  * sd = sd - (sn * sm)
893  */
894 static u32 vfp_double_fnmac(int dd, int dn, int dm, u32 fpscr)
895 {
896         return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
897 }
898 
899 /*
900  * sd = -sd + (sn * sm)
901  */
902 static u32 vfp_double_fmsc(int dd, int dn, int dm, u32 fpscr)
903 {
904         return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
905 }
906 
907 /*
908  * sd = -sd - (sn * sm)
909  */
910 static u32 vfp_double_fnmsc(int dd, int dn, int dm, u32 fpscr)
911 {
912         return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
913 }
914 
915 /*
916  * sd = sn * sm
917  */
918 static u32 vfp_double_fmul(int dd, int dn, int dm, u32 fpscr)
919 {
920         struct vfp_double vdd, vdn, vdm;
921         u32 exceptions;
922 
923         vfp_double_unpack(&vdn, vfp_get_double(dn));
924         if (vdn.exponent == 0 && vdn.significand)
925                 vfp_double_normalise_denormal(&vdn);
926 
927         vfp_double_unpack(&vdm, vfp_get_double(dm));
928         if (vdm.exponent == 0 && vdm.significand)
929                 vfp_double_normalise_denormal(&vdm);
930 
931         exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
932         return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fmul");
933 }
934 
935 /*
936  * sd = -(sn * sm)
937  */
938 static u32 vfp_double_fnmul(int dd, int dn, int dm, u32 fpscr)
939 {
940         struct vfp_double vdd, vdn, vdm;
941         u32 exceptions;
942 
943         vfp_double_unpack(&vdn, vfp_get_double(dn));
944         if (vdn.exponent == 0 && vdn.significand)
945                 vfp_double_normalise_denormal(&vdn);
946 
947         vfp_double_unpack(&vdm, vfp_get_double(dm));
948         if (vdm.exponent == 0 && vdm.significand)
949                 vfp_double_normalise_denormal(&vdm);
950 
951         exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
952         vdd.sign = vfp_sign_negate(vdd.sign);
953 
954         return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fnmul");
955 }
956 
957 /*
958  * sd = sn + sm
959  */
960 static u32 vfp_double_fadd(int dd, int dn, int dm, u32 fpscr)
961 {
962         struct vfp_double vdd, vdn, vdm;
963         u32 exceptions;
964 
965         vfp_double_unpack(&vdn, vfp_get_double(dn));
966         if (vdn.exponent == 0 && vdn.significand)
967                 vfp_double_normalise_denormal(&vdn);
968 
969         vfp_double_unpack(&vdm, vfp_get_double(dm));
970         if (vdm.exponent == 0 && vdm.significand)
971                 vfp_double_normalise_denormal(&vdm);
972 
973         exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
974 
975         return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fadd");
976 }
977 
978 /*
979  * sd = sn - sm
980  */
981 static u32 vfp_double_fsub(int dd, int dn, int dm, u32 fpscr)
982 {
983         struct vfp_double vdd, vdn, vdm;
984         u32 exceptions;
985 
986         vfp_double_unpack(&vdn, vfp_get_double(dn));
987         if (vdn.exponent == 0 && vdn.significand)
988                 vfp_double_normalise_denormal(&vdn);
989 
990         vfp_double_unpack(&vdm, vfp_get_double(dm));
991         if (vdm.exponent == 0 && vdm.significand)
992                 vfp_double_normalise_denormal(&vdm);
993 
994         /*
995          * Subtraction is like addition, but with a negated operand.
996          */
997         vdm.sign = vfp_sign_negate(vdm.sign);
998 
999         exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1000 
1001         return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fsub");
1002 }
1003 
1004 /*
1005  * sd = sn / sm
1006  */
1007 static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
1008 {
1009         struct vfp_double vdd, vdn, vdm;
1010         u32 exceptions = 0;
1011         int tm, tn;
1012 
1013         vfp_double_unpack(&vdn, vfp_get_double(dn));
1014         vfp_double_unpack(&vdm, vfp_get_double(dm));
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 result is invalid
1035          * If n and m are zero, the result is invalid
1036          */
1037         if (tm & tn & (VFP_INFINITY|VFP_ZERO))
1038                 goto invalid;
1039 
1040         /*
1041          * If n is infinity, the result is infinity
1042          */
1043         if (tn & VFP_INFINITY)
1044                 goto infinity;
1045 
1046         /*
1047          * If m is zero, raise div0 exceptions
1048          */
1049         if (tm & VFP_ZERO)
1050                 goto divzero;
1051 
1052         /*
1053          * If m is infinity, or n is zero, the result is zero
1054          */
1055         if (tm & VFP_INFINITY || tn & VFP_ZERO)
1056                 goto zero;
1057 
1058         if (tn & VFP_DENORMAL)
1059                 vfp_double_normalise_denormal(&vdn);
1060         if (tm & VFP_DENORMAL)
1061                 vfp_double_normalise_denormal(&vdm);
1062 
1063         /*
1064          * Ok, we have two numbers, we can perform division.
1065          */
1066         vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
1067         vdm.significand <<= 1;
1068         if (vdm.significand <= (2 * vdn.significand)) {
1069                 vdn.significand >>= 1;
1070                 vdd.exponent++;
1071         }
1072         vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
1073         if ((vdd.significand & 0x1ff) <= 2) {
1074                 u64 termh, terml, remh, reml;
1075                 mul64to128(&termh, &terml, vdm.significand, vdd.significand);
1076                 sub128(&remh, &reml, vdn.significand, 0, termh, terml);
1077                 while ((s64)remh < 0) {
1078                         vdd.significand -= 1;
1079                         add128(&remh, &reml, remh, reml, 0, vdm.significand);
1080                 }
1081                 vdd.significand |= (reml != 0);
1082         }
1083         return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fdiv");
1084 
1085  vdn_nan:
1086         exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
1087  pack:
1088         vfp_put_double(vfp_double_pack(&vdd), dd);
1089         return exceptions;
1090 
1091  vdm_nan:
1092         exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
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_double_default_qnan), dd);
1109         return FPSCR_IOC;
1110 }
1111 
1112 static struct op fops[16] = {
1113         [FOP_TO_IDX(FOP_FMAC)]  = { vfp_double_fmac,  0 },
1114         [FOP_TO_IDX(FOP_FNMAC)] = { vfp_double_fnmac, 0 },
1115         [FOP_TO_IDX(FOP_FMSC)]  = { vfp_double_fmsc,  0 },
1116         [FOP_TO_IDX(FOP_FNMSC)] = { vfp_double_fnmsc, 0 },
1117         [FOP_TO_IDX(FOP_FMUL)]  = { vfp_double_fmul,  0 },
1118         [FOP_TO_IDX(FOP_FNMUL)] = { vfp_double_fnmul, 0 },
1119         [FOP_TO_IDX(FOP_FADD)]  = { vfp_double_fadd,  0 },
1120         [FOP_TO_IDX(FOP_FSUB)]  = { vfp_double_fsub,  0 },
1121         [FOP_TO_IDX(FOP_FDIV)]  = { vfp_double_fdiv,  0 },
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, vecstride;
1135         struct op *fop;
1136 
1137         vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
1138 
1139         fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1140 
1141         /*
1142          * fcvtds takes an sN register number as destination, not dN.
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 dN operand.
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, vector length is always '1'.
1160          * ARM DDI0100F C5.1.3, C5.3.2.
1161          */
1162         if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
1163                 veclen = 0;
1164         else
1165                 veclen = fpscr & FPSCR_LENGTH_MASK;
1166 
1167         pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1168                  (veclen >> FPSCR_LENGTH_BIT) + 1);
1169 
1170         if (!fop->fn)
1171                 goto invalid;
1172 
1173         for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1174                 u32 except;
1175                 char type;
1176 
1177                 type = fop->flags & OP_SD ? 's' : 'd';
1178                 if (op == FOP_EXT)
1179                         pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
1180                                  vecitr >> FPSCR_LENGTH_BIT,
1181                                  type, dest, dn, dm);
1182                 else
1183                         pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
1184                                  vecitr >> FPSCR_LENGTH_BIT,
1185                                  type, dest, dn, FOP_TO_IDX(op), dm);
1186 
1187                 except = fop->fn(dest, dn, dm, fpscr);
1188                 pr_debug("VFP: itr%d: exceptions=%08x\n",
1189                          vecitr >> FPSCR_LENGTH_BIT, except);
1190 
1191                 exceptions |= except;
1192 
1193                 /*
1194                  * CHECK: It appears to be undefined whether we stop when
1195                  * we encounter an exception.  We continue.
1196                  */
1197                 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
1198                 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
1199                 if (FREG_BANK(dm) != 0)
1200                         dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
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 | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp