Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/parisc/math-emu/sfmpy.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Linux/PA-RISC Project (http://www.parisc-linux.org/)
4
*
5
* Floating-point emulation code
6
* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>
7
*/
8
/*
9
* BEGIN_DESC
10
*
11
* File:
12
* @(#) pa/spmath/sfmpy.c $Revision: 1.1 $
13
*
14
* Purpose:
15
* Single Precision Floating-point Multiply
16
*
17
* External Interfaces:
18
* sgl_fmpy(srcptr1,srcptr2,dstptr,status)
19
*
20
* Internal Interfaces:
21
*
22
* Theory:
23
* <<please update with a overview of the operation of this file>>
24
*
25
* END_DESC
26
*/
27
28
29
#include "float.h"
30
#include "sgl_float.h"
31
32
/*
33
* Single Precision Floating-point Multiply
34
*/
35
36
int
37
sgl_fmpy(
38
sgl_floating_point *srcptr1,
39
sgl_floating_point *srcptr2,
40
sgl_floating_point *dstptr,
41
unsigned int *status)
42
{
43
register unsigned int opnd1, opnd2, opnd3, result;
44
register int dest_exponent, count;
45
register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
46
boolean is_tiny;
47
48
opnd1 = *srcptr1;
49
opnd2 = *srcptr2;
50
/*
51
* set sign bit of result
52
*/
53
if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
54
else Sgl_setzero(result);
55
/*
56
* check first operand for NaN's or infinity
57
*/
58
if (Sgl_isinfinity_exponent(opnd1)) {
59
if (Sgl_iszero_mantissa(opnd1)) {
60
if (Sgl_isnotnan(opnd2)) {
61
if (Sgl_iszero_exponentmantissa(opnd2)) {
62
/*
63
* invalid since operands are infinity
64
* and zero
65
*/
66
if (Is_invalidtrap_enabled())
67
return(INVALIDEXCEPTION);
68
Set_invalidflag();
69
Sgl_makequietnan(result);
70
*dstptr = result;
71
return(NOEXCEPTION);
72
}
73
/*
74
* return infinity
75
*/
76
Sgl_setinfinity_exponentmantissa(result);
77
*dstptr = result;
78
return(NOEXCEPTION);
79
}
80
}
81
else {
82
/*
83
* is NaN; signaling or quiet?
84
*/
85
if (Sgl_isone_signaling(opnd1)) {
86
/* trap if INVALIDTRAP enabled */
87
if (Is_invalidtrap_enabled())
88
return(INVALIDEXCEPTION);
89
/* make NaN quiet */
90
Set_invalidflag();
91
Sgl_set_quiet(opnd1);
92
}
93
/*
94
* is second operand a signaling NaN?
95
*/
96
else if (Sgl_is_signalingnan(opnd2)) {
97
/* trap if INVALIDTRAP enabled */
98
if (Is_invalidtrap_enabled())
99
return(INVALIDEXCEPTION);
100
/* make NaN quiet */
101
Set_invalidflag();
102
Sgl_set_quiet(opnd2);
103
*dstptr = opnd2;
104
return(NOEXCEPTION);
105
}
106
/*
107
* return quiet NaN
108
*/
109
*dstptr = opnd1;
110
return(NOEXCEPTION);
111
}
112
}
113
/*
114
* check second operand for NaN's or infinity
115
*/
116
if (Sgl_isinfinity_exponent(opnd2)) {
117
if (Sgl_iszero_mantissa(opnd2)) {
118
if (Sgl_iszero_exponentmantissa(opnd1)) {
119
/* invalid since operands are zero & infinity */
120
if (Is_invalidtrap_enabled())
121
return(INVALIDEXCEPTION);
122
Set_invalidflag();
123
Sgl_makequietnan(opnd2);
124
*dstptr = opnd2;
125
return(NOEXCEPTION);
126
}
127
/*
128
* return infinity
129
*/
130
Sgl_setinfinity_exponentmantissa(result);
131
*dstptr = result;
132
return(NOEXCEPTION);
133
}
134
/*
135
* is NaN; signaling or quiet?
136
*/
137
if (Sgl_isone_signaling(opnd2)) {
138
/* trap if INVALIDTRAP enabled */
139
if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
140
141
/* make NaN quiet */
142
Set_invalidflag();
143
Sgl_set_quiet(opnd2);
144
}
145
/*
146
* return quiet NaN
147
*/
148
*dstptr = opnd2;
149
return(NOEXCEPTION);
150
}
151
/*
152
* Generate exponent
153
*/
154
dest_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
155
156
/*
157
* Generate mantissa
158
*/
159
if (Sgl_isnotzero_exponent(opnd1)) {
160
/* set hidden bit */
161
Sgl_clear_signexponent_set_hidden(opnd1);
162
}
163
else {
164
/* check for zero */
165
if (Sgl_iszero_mantissa(opnd1)) {
166
Sgl_setzero_exponentmantissa(result);
167
*dstptr = result;
168
return(NOEXCEPTION);
169
}
170
/* is denormalized, adjust exponent */
171
Sgl_clear_signexponent(opnd1);
172
Sgl_leftshiftby1(opnd1);
173
Sgl_normalize(opnd1,dest_exponent);
174
}
175
/* opnd2 needs to have hidden bit set with msb in hidden bit */
176
if (Sgl_isnotzero_exponent(opnd2)) {
177
Sgl_clear_signexponent_set_hidden(opnd2);
178
}
179
else {
180
/* check for zero */
181
if (Sgl_iszero_mantissa(opnd2)) {
182
Sgl_setzero_exponentmantissa(result);
183
*dstptr = result;
184
return(NOEXCEPTION);
185
}
186
/* is denormalized; want to normalize */
187
Sgl_clear_signexponent(opnd2);
188
Sgl_leftshiftby1(opnd2);
189
Sgl_normalize(opnd2,dest_exponent);
190
}
191
192
/* Multiply two source mantissas together */
193
194
Sgl_leftshiftby4(opnd2); /* make room for guard bits */
195
Sgl_setzero(opnd3);
196
/*
197
* Four bits at a time are inspected in each loop, and a
198
* simple shift and add multiply algorithm is used.
199
*/
200
for (count=1;count<SGL_P;count+=4) {
201
stickybit |= Slow4(opnd3);
202
Sgl_rightshiftby4(opnd3);
203
if (Sbit28(opnd1)) Sall(opnd3) += (Sall(opnd2) << 3);
204
if (Sbit29(opnd1)) Sall(opnd3) += (Sall(opnd2) << 2);
205
if (Sbit30(opnd1)) Sall(opnd3) += (Sall(opnd2) << 1);
206
if (Sbit31(opnd1)) Sall(opnd3) += Sall(opnd2);
207
Sgl_rightshiftby4(opnd1);
208
}
209
/* make sure result is left-justified */
210
if (Sgl_iszero_sign(opnd3)) {
211
Sgl_leftshiftby1(opnd3);
212
}
213
else {
214
/* result mantissa >= 2. */
215
dest_exponent++;
216
}
217
/* check for denormalized result */
218
while (Sgl_iszero_sign(opnd3)) {
219
Sgl_leftshiftby1(opnd3);
220
dest_exponent--;
221
}
222
/*
223
* check for guard, sticky and inexact bits
224
*/
225
stickybit |= Sgl_all(opnd3) << (SGL_BITLENGTH - SGL_EXP_LENGTH + 1);
226
guardbit = Sbit24(opnd3);
227
inexact = guardbit | stickybit;
228
229
/* re-align mantissa */
230
Sgl_rightshiftby8(opnd3);
231
232
/*
233
* round result
234
*/
235
if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
236
Sgl_clear_signexponent(opnd3);
237
switch (Rounding_mode()) {
238
case ROUNDPLUS:
239
if (Sgl_iszero_sign(result))
240
Sgl_increment(opnd3);
241
break;
242
case ROUNDMINUS:
243
if (Sgl_isone_sign(result))
244
Sgl_increment(opnd3);
245
break;
246
case ROUNDNEAREST:
247
if (guardbit) {
248
if (stickybit || Sgl_isone_lowmantissa(opnd3))
249
Sgl_increment(opnd3);
250
}
251
}
252
if (Sgl_isone_hidden(opnd3)) dest_exponent++;
253
}
254
Sgl_set_mantissa(result,opnd3);
255
256
/*
257
* Test for overflow
258
*/
259
if (dest_exponent >= SGL_INFINITY_EXPONENT) {
260
/* trap if OVERFLOWTRAP enabled */
261
if (Is_overflowtrap_enabled()) {
262
/*
263
* Adjust bias of result
264
*/
265
Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
266
*dstptr = result;
267
if (inexact)
268
if (Is_inexacttrap_enabled())
269
return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
270
else Set_inexactflag();
271
return(OVERFLOWEXCEPTION);
272
}
273
inexact = TRUE;
274
Set_overflowflag();
275
/* set result to infinity or largest number */
276
Sgl_setoverflow(result);
277
}
278
/*
279
* Test for underflow
280
*/
281
else if (dest_exponent <= 0) {
282
/* trap if UNDERFLOWTRAP enabled */
283
if (Is_underflowtrap_enabled()) {
284
/*
285
* Adjust bias of result
286
*/
287
Sgl_setwrapped_exponent(result,dest_exponent,unfl);
288
*dstptr = result;
289
if (inexact)
290
if (Is_inexacttrap_enabled())
291
return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
292
else Set_inexactflag();
293
return(UNDERFLOWEXCEPTION);
294
}
295
296
/* Determine if should set underflow flag */
297
is_tiny = TRUE;
298
if (dest_exponent == 0 && inexact) {
299
switch (Rounding_mode()) {
300
case ROUNDPLUS:
301
if (Sgl_iszero_sign(result)) {
302
Sgl_increment(opnd3);
303
if (Sgl_isone_hiddenoverflow(opnd3))
304
is_tiny = FALSE;
305
Sgl_decrement(opnd3);
306
}
307
break;
308
case ROUNDMINUS:
309
if (Sgl_isone_sign(result)) {
310
Sgl_increment(opnd3);
311
if (Sgl_isone_hiddenoverflow(opnd3))
312
is_tiny = FALSE;
313
Sgl_decrement(opnd3);
314
}
315
break;
316
case ROUNDNEAREST:
317
if (guardbit && (stickybit ||
318
Sgl_isone_lowmantissa(opnd3))) {
319
Sgl_increment(opnd3);
320
if (Sgl_isone_hiddenoverflow(opnd3))
321
is_tiny = FALSE;
322
Sgl_decrement(opnd3);
323
}
324
break;
325
}
326
}
327
328
/*
329
* denormalize result or set to signed zero
330
*/
331
stickybit = inexact;
332
Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
333
334
/* return zero or smallest number */
335
if (inexact) {
336
switch (Rounding_mode()) {
337
case ROUNDPLUS:
338
if (Sgl_iszero_sign(result)) {
339
Sgl_increment(opnd3);
340
}
341
break;
342
case ROUNDMINUS:
343
if (Sgl_isone_sign(result)) {
344
Sgl_increment(opnd3);
345
}
346
break;
347
case ROUNDNEAREST:
348
if (guardbit && (stickybit ||
349
Sgl_isone_lowmantissa(opnd3))) {
350
Sgl_increment(opnd3);
351
}
352
break;
353
}
354
if (is_tiny) Set_underflowflag();
355
}
356
Sgl_set_exponentmantissa(result,opnd3);
357
}
358
else Sgl_set_exponent(result,dest_exponent);
359
*dstptr = result;
360
361
/* check for inexact */
362
if (inexact) {
363
if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
364
else Set_inexactflag();
365
}
366
return(NOEXCEPTION);
367
}
368
369