Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * IEEE754 floating point arithmetic
0004  * single precision: MADDF.f (Fused Multiply Add)
0005  * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft])
0006  *
0007  * MIPS floating point support
0008  * Copyright (C) 2015 Imagination Technologies, Ltd.
0009  * Author: Markos Chandras <markos.chandras@imgtec.com>
0010  */
0011 
0012 #include "ieee754sp.h"
0013 
0014 
0015 static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
0016                  union ieee754sp y, enum maddf_flags flags)
0017 {
0018     int re;
0019     int rs;
0020     unsigned int rm;
0021     u64 rm64;
0022     u64 zm64;
0023     int s;
0024 
0025     COMPXSP;
0026     COMPYSP;
0027     COMPZSP;
0028 
0029     EXPLODEXSP;
0030     EXPLODEYSP;
0031     EXPLODEZSP;
0032 
0033     FLUSHXSP;
0034     FLUSHYSP;
0035     FLUSHZSP;
0036 
0037     ieee754_clearcx();
0038 
0039     rs = xs ^ ys;
0040     if (flags & MADDF_NEGATE_PRODUCT)
0041         rs ^= 1;
0042     if (flags & MADDF_NEGATE_ADDITION)
0043         zs ^= 1;
0044 
0045     /*
0046      * Handle the cases when at least one of x, y or z is a NaN.
0047      * Order of precedence is sNaN, qNaN and z, x, y.
0048      */
0049     if (zc == IEEE754_CLASS_SNAN)
0050         return ieee754sp_nanxcpt(z);
0051     if (xc == IEEE754_CLASS_SNAN)
0052         return ieee754sp_nanxcpt(x);
0053     if (yc == IEEE754_CLASS_SNAN)
0054         return ieee754sp_nanxcpt(y);
0055     if (zc == IEEE754_CLASS_QNAN)
0056         return z;
0057     if (xc == IEEE754_CLASS_QNAN)
0058         return x;
0059     if (yc == IEEE754_CLASS_QNAN)
0060         return y;
0061 
0062     if (zc == IEEE754_CLASS_DNORM)
0063         SPDNORMZ;
0064     /* ZERO z cases are handled separately below */
0065 
0066     switch (CLPAIR(xc, yc)) {
0067 
0068 
0069     /*
0070      * Infinity handling
0071      */
0072     case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
0073     case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
0074         ieee754_setcx(IEEE754_INVALID_OPERATION);
0075         return ieee754sp_indef();
0076 
0077     case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
0078     case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
0079     case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
0080     case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
0081     case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
0082         if ((zc == IEEE754_CLASS_INF) && (zs != rs)) {
0083             /*
0084              * Cases of addition of infinities with opposite signs
0085              * or subtraction of infinities with same signs.
0086              */
0087             ieee754_setcx(IEEE754_INVALID_OPERATION);
0088             return ieee754sp_indef();
0089         }
0090         /*
0091          * z is here either not an infinity, or an infinity having the
0092          * same sign as product (x*y). The result must be an infinity,
0093          * and its sign is determined only by the sign of product (x*y).
0094          */
0095         return ieee754sp_inf(rs);
0096 
0097     case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
0098     case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
0099     case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
0100     case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
0101     case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
0102         if (zc == IEEE754_CLASS_INF)
0103             return ieee754sp_inf(zs);
0104         if (zc == IEEE754_CLASS_ZERO) {
0105             /* Handle cases +0 + (-0) and similar ones. */
0106             if (zs == rs)
0107                 /*
0108                  * Cases of addition of zeros of equal signs
0109                  * or subtraction of zeroes of opposite signs.
0110                  * The sign of the resulting zero is in any
0111                  * such case determined only by the sign of z.
0112                  */
0113                 return z;
0114 
0115             return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
0116         }
0117         /* x*y is here 0, and z is not 0, so just return z */
0118         return z;
0119 
0120     case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
0121         SPDNORMX;
0122         fallthrough;
0123     case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
0124         if (zc == IEEE754_CLASS_INF)
0125             return ieee754sp_inf(zs);
0126         SPDNORMY;
0127         break;
0128 
0129     case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
0130         if (zc == IEEE754_CLASS_INF)
0131             return ieee754sp_inf(zs);
0132         SPDNORMX;
0133         break;
0134 
0135     case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
0136         if (zc == IEEE754_CLASS_INF)
0137             return ieee754sp_inf(zs);
0138         /* continue to real computations */
0139     }
0140 
0141     /* Finally get to do some computation */
0142 
0143     /*
0144      * Do the multiplication bit first
0145      *
0146      * rm = xm * ym, re = xe + ye basically
0147      *
0148      * At this point xm and ym should have been normalized.
0149      */
0150 
0151     /* rm = xm * ym, re = xe+ye basically */
0152     assert(xm & SP_HIDDEN_BIT);
0153     assert(ym & SP_HIDDEN_BIT);
0154 
0155     re = xe + ye;
0156 
0157     /* Multiple 24 bit xm and ym to give 48 bit results */
0158     rm64 = (uint64_t)xm * ym;
0159 
0160     /* Shunt to top of word */
0161     rm64 = rm64 << 16;
0162 
0163     /* Put explicit bit at bit 62 if necessary */
0164     if ((int64_t) rm64 < 0) {
0165         rm64 = rm64 >> 1;
0166         re++;
0167     }
0168 
0169     assert(rm64 & (1 << 62));
0170 
0171     if (zc == IEEE754_CLASS_ZERO) {
0172         /*
0173          * Move explicit bit from bit 62 to bit 26 since the
0174          * ieee754sp_format code expects the mantissa to be
0175          * 27 bits wide (24 + 3 rounding bits).
0176          */
0177         rm = XSPSRS64(rm64, (62 - 26));
0178         return ieee754sp_format(rs, re, rm);
0179     }
0180 
0181     /* Move explicit bit from bit 23 to bit 62 */
0182     zm64 = (uint64_t)zm << (62 - 23);
0183     assert(zm64 & (1 << 62));
0184 
0185     /* Make the exponents the same */
0186     if (ze > re) {
0187         /*
0188          * Have to shift r fraction right to align.
0189          */
0190         s = ze - re;
0191         rm64 = XSPSRS64(rm64, s);
0192         re += s;
0193     } else if (re > ze) {
0194         /*
0195          * Have to shift z fraction right to align.
0196          */
0197         s = re - ze;
0198         zm64 = XSPSRS64(zm64, s);
0199         ze += s;
0200     }
0201     assert(ze == re);
0202     assert(ze <= SP_EMAX);
0203 
0204     /* Do the addition */
0205     if (zs == rs) {
0206         /*
0207          * Generate 64 bit result by adding two 63 bit numbers
0208          * leaving result in zm64, zs and ze.
0209          */
0210         zm64 = zm64 + rm64;
0211         if ((int64_t)zm64 < 0) {    /* carry out */
0212             zm64 = XSPSRS1(zm64);
0213             ze++;
0214         }
0215     } else {
0216         if (zm64 >= rm64) {
0217             zm64 = zm64 - rm64;
0218         } else {
0219             zm64 = rm64 - zm64;
0220             zs = rs;
0221         }
0222         if (zm64 == 0)
0223             return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
0224 
0225         /*
0226          * Put explicit bit at bit 62 if necessary.
0227          */
0228         while ((zm64 >> 62) == 0) {
0229             zm64 <<= 1;
0230             ze--;
0231         }
0232     }
0233 
0234     /*
0235      * Move explicit bit from bit 62 to bit 26 since the
0236      * ieee754sp_format code expects the mantissa to be
0237      * 27 bits wide (24 + 3 rounding bits).
0238      */
0239     zm = XSPSRS64(zm64, (62 - 26));
0240 
0241     return ieee754sp_format(zs, ze, zm);
0242 }
0243 
0244 union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
0245                 union ieee754sp y)
0246 {
0247     return _sp_maddf(z, x, y, 0);
0248 }
0249 
0250 union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
0251                 union ieee754sp y)
0252 {
0253     return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
0254 }
0255 
0256 union ieee754sp ieee754sp_madd(union ieee754sp z, union ieee754sp x,
0257                 union ieee754sp y)
0258 {
0259     return _sp_maddf(z, x, y, 0);
0260 }
0261 
0262 union ieee754sp ieee754sp_msub(union ieee754sp z, union ieee754sp x,
0263                 union ieee754sp y)
0264 {
0265     return _sp_maddf(z, x, y, MADDF_NEGATE_ADDITION);
0266 }
0267 
0268 union ieee754sp ieee754sp_nmadd(union ieee754sp z, union ieee754sp x,
0269                 union ieee754sp y)
0270 {
0271     return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT|MADDF_NEGATE_ADDITION);
0272 }
0273 
0274 union ieee754sp ieee754sp_nmsub(union ieee754sp z, union ieee754sp x,
0275                 union ieee754sp y)
0276 {
0277     return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
0278 }