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) <bame@debian.org> |
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 | |