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