1 // SPDX-License-Identifier: GPL-2.0-only 2 /* IEEE754 floating point arithmetic 3 * double precision: common utilities 4 */ 5 /* 6 * MIPS floating point support 7 * Copyright (C) 1994-2000 Algorithmics Ltd. 8 */ 9 10 #include <linux/compiler.h> 11 12 #include "ieee754dp.h" 13 14 int ieee754dp_class(union ieee754dp x) 15 { 16 COMPXDP; 17 EXPLODEXDP; 18 return xc; 19 } 20 21 static inline int ieee754dp_isnan(union ieee754dp x) 22 { 23 return ieee754_class_nan(ieee754dp_class(x)); 24 } 25 26 static inline int ieee754dp_issnan(union ieee754dp x) 27 { 28 int qbit; 29 30 assert(ieee754dp_isnan(x)); 31 qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1); 32 return ieee754_csr.nan2008 ^ qbit; 33 } 34 35 36 /* 37 * Raise the Invalid Operation IEEE 754 exception 38 * and convert the signaling NaN supplied to a quiet NaN. 39 */ 40 union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) 41 { 42 assert(ieee754dp_issnan(r)); 43 44 ieee754_setcx(IEEE754_INVALID_OPERATION); 45 if (ieee754_csr.nan2008) { 46 DPMANT(r) |= DP_MBIT(DP_FBITS - 1); 47 } else { 48 DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1); 49 if (!ieee754dp_isnan(r)) 50 DPMANT(r) |= DP_MBIT(DP_FBITS - 2); 51 } 52 53 return r; 54 } 55 56 static u64 ieee754dp_get_rounding(int sn, u64 xm) 57 { 58 /* inexact must round of 3 bits 59 */ 60 if (xm & (DP_MBIT(3) - 1)) { 61 switch (ieee754_csr.rm) { 62 case FPU_CSR_RZ: 63 break; 64 case FPU_CSR_RN: 65 xm += 0x3 + ((xm >> 3) & 1); 66 /* xm += (xm&0x8)?0x4:0x3 */ 67 break; 68 case FPU_CSR_RU: /* toward +Infinity */ 69 if (!sn) /* ?? */ 70 xm += 0x8; 71 break; 72 case FPU_CSR_RD: /* toward -Infinity */ 73 if (sn) /* ?? */ 74 xm += 0x8; 75 break; 76 } 77 } 78 return xm; 79 } 80 81 82 /* generate a normal/denormal number with over,under handling 83 * sn is sign 84 * xe is an unbiased exponent 85 * xm is 3bit extended precision value. 86 */ 87 union ieee754dp ieee754dp_format(int sn, int xe, u64 xm) 88 { 89 assert(xm); /* we don't gen exact zeros (probably should) */ 90 91 assert((xm >> (DP_FBITS + 1 + 3)) == 0); /* no excess */ 92 assert(xm & (DP_HIDDEN_BIT << 3)); 93 94 if (xe < DP_EMIN) { 95 /* strip lower bits */ 96 int es = DP_EMIN - xe; 97 98 if (ieee754_csr.nod) { 99 ieee754_setcx(IEEE754_UNDERFLOW); 100 ieee754_setcx(IEEE754_INEXACT); 101 102 switch(ieee754_csr.rm) { 103 case FPU_CSR_RN: 104 case FPU_CSR_RZ: 105 return ieee754dp_zero(sn); 106 case FPU_CSR_RU: /* toward +Infinity */ 107 if (sn == 0) 108 return ieee754dp_min(0); 109 else 110 return ieee754dp_zero(1); 111 case FPU_CSR_RD: /* toward -Infinity */ 112 if (sn == 0) 113 return ieee754dp_zero(0); 114 else 115 return ieee754dp_min(1); 116 } 117 } 118 119 if (xe == DP_EMIN - 1 && 120 ieee754dp_get_rounding(sn, xm) >> (DP_FBITS + 1 + 3)) 121 { 122 /* Not tiny after rounding */ 123 ieee754_setcx(IEEE754_INEXACT); 124 xm = ieee754dp_get_rounding(sn, xm); 125 xm >>= 1; 126 /* Clear grs bits */ 127 xm &= ~(DP_MBIT(3) - 1); 128 xe++; 129 } 130 else { 131 /* sticky right shift es bits 132 */ 133 xm = XDPSRS(xm, es); 134 xe += es; 135 assert((xm & (DP_HIDDEN_BIT << 3)) == 0); 136 assert(xe == DP_EMIN); 137 } 138 } 139 if (xm & (DP_MBIT(3) - 1)) { 140 ieee754_setcx(IEEE754_INEXACT); 141 if ((xm & (DP_HIDDEN_BIT << 3)) == 0) { 142 ieee754_setcx(IEEE754_UNDERFLOW); 143 } 144 145 /* inexact must round of 3 bits 146 */ 147 xm = ieee754dp_get_rounding(sn, xm); 148 /* adjust exponent for rounding add overflowing 149 */ 150 if (xm >> (DP_FBITS + 3 + 1)) { 151 /* add causes mantissa overflow */ 152 xm >>= 1; 153 xe++; 154 } 155 } 156 /* strip grs bits */ 157 xm >>= 3; 158 159 assert((xm >> (DP_FBITS + 1)) == 0); /* no excess */ 160 assert(xe >= DP_EMIN); 161 162 if (xe > DP_EMAX) { 163 ieee754_setcx(IEEE754_OVERFLOW); 164 ieee754_setcx(IEEE754_INEXACT); 165 /* -O can be table indexed by (rm,sn) */ 166 switch (ieee754_csr.rm) { 167 case FPU_CSR_RN: 168 return ieee754dp_inf(sn); 169 case FPU_CSR_RZ: 170 return ieee754dp_max(sn); 171 case FPU_CSR_RU: /* toward +Infinity */ 172 if (sn == 0) 173 return ieee754dp_inf(0); 174 else 175 return ieee754dp_max(1); 176 case FPU_CSR_RD: /* toward -Infinity */ 177 if (sn == 0) 178 return ieee754dp_max(0); 179 else 180 return ieee754dp_inf(1); 181 } 182 } 183 /* gen norm/denorm/zero */ 184 185 if ((xm & DP_HIDDEN_BIT) == 0) { 186 /* we underflow (tiny/zero) */ 187 assert(xe == DP_EMIN); 188 if (ieee754_csr.mx & IEEE754_UNDERFLOW) 189 ieee754_setcx(IEEE754_UNDERFLOW); 190 return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); 191 } else { 192 assert((xm >> (DP_FBITS + 1)) == 0); /* no excess */ 193 assert(xm & DP_HIDDEN_BIT); 194 195 return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); 196 } 197 } 198