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