Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/math-emu/ieee754dp.c
26442 views
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
199