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/dfdiv.c $Revision: 1.1 $ |
13 | * |
14 | * Purpose: |
15 | * Double Precision Floating-point Divide |
16 | * |
17 | * External Interfaces: |
18 | * dbl_fdiv(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 "dbl_float.h" |
31 | |
32 | /* |
33 | * Double Precision Floating-point Divide |
34 | */ |
35 | |
36 | int |
37 | dbl_fdiv (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2, |
38 | dbl_floating_point * dstptr, unsigned int *status) |
39 | { |
40 | register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2; |
41 | register unsigned int opnd3p1, opnd3p2, resultp1, resultp2; |
42 | register int dest_exponent, count; |
43 | register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE; |
44 | boolean is_tiny; |
45 | |
46 | Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2); |
47 | Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2); |
48 | /* |
49 | * set sign bit of result |
50 | */ |
51 | if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) |
52 | Dbl_setnegativezerop1(resultp1); |
53 | else Dbl_setzerop1(resultp1); |
54 | /* |
55 | * check first operand for NaN's or infinity |
56 | */ |
57 | if (Dbl_isinfinity_exponent(opnd1p1)) { |
58 | if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { |
59 | if (Dbl_isnotnan(opnd2p1,opnd2p2)) { |
60 | if (Dbl_isinfinity(opnd2p1,opnd2p2)) { |
61 | /* |
62 | * invalid since both operands |
63 | * are infinity |
64 | */ |
65 | if (Is_invalidtrap_enabled()) |
66 | return(INVALIDEXCEPTION); |
67 | Set_invalidflag(); |
68 | Dbl_makequietnan(resultp1,resultp2); |
69 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
70 | return(NOEXCEPTION); |
71 | } |
72 | /* |
73 | * return infinity |
74 | */ |
75 | Dbl_setinfinity_exponentmantissa(resultp1,resultp2); |
76 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
77 | return(NOEXCEPTION); |
78 | } |
79 | } |
80 | else { |
81 | /* |
82 | * is NaN; signaling or quiet? |
83 | */ |
84 | if (Dbl_isone_signaling(opnd1p1)) { |
85 | /* trap if INVALIDTRAP enabled */ |
86 | if (Is_invalidtrap_enabled()) |
87 | return(INVALIDEXCEPTION); |
88 | /* make NaN quiet */ |
89 | Set_invalidflag(); |
90 | Dbl_set_quiet(opnd1p1); |
91 | } |
92 | /* |
93 | * is second operand a signaling NaN? |
94 | */ |
95 | else if (Dbl_is_signalingnan(opnd2p1)) { |
96 | /* trap if INVALIDTRAP enabled */ |
97 | if (Is_invalidtrap_enabled()) |
98 | return(INVALIDEXCEPTION); |
99 | /* make NaN quiet */ |
100 | Set_invalidflag(); |
101 | Dbl_set_quiet(opnd2p1); |
102 | Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); |
103 | return(NOEXCEPTION); |
104 | } |
105 | /* |
106 | * return quiet NaN |
107 | */ |
108 | Dbl_copytoptr(opnd1p1,opnd1p2,dstptr); |
109 | return(NOEXCEPTION); |
110 | } |
111 | } |
112 | /* |
113 | * check second operand for NaN's or infinity |
114 | */ |
115 | if (Dbl_isinfinity_exponent(opnd2p1)) { |
116 | if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) { |
117 | /* |
118 | * return zero |
119 | */ |
120 | Dbl_setzero_exponentmantissa(resultp1,resultp2); |
121 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
122 | return(NOEXCEPTION); |
123 | } |
124 | /* |
125 | * is NaN; signaling or quiet? |
126 | */ |
127 | if (Dbl_isone_signaling(opnd2p1)) { |
128 | /* trap if INVALIDTRAP enabled */ |
129 | if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); |
130 | /* make NaN quiet */ |
131 | Set_invalidflag(); |
132 | Dbl_set_quiet(opnd2p1); |
133 | } |
134 | /* |
135 | * return quiet NaN |
136 | */ |
137 | Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); |
138 | return(NOEXCEPTION); |
139 | } |
140 | /* |
141 | * check for division by zero |
142 | */ |
143 | if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) { |
144 | if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) { |
145 | /* invalid since both operands are zero */ |
146 | if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); |
147 | Set_invalidflag(); |
148 | Dbl_makequietnan(resultp1,resultp2); |
149 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
150 | return(NOEXCEPTION); |
151 | } |
152 | if (Is_divisionbyzerotrap_enabled()) |
153 | return(DIVISIONBYZEROEXCEPTION); |
154 | Set_divisionbyzeroflag(); |
155 | Dbl_setinfinity_exponentmantissa(resultp1,resultp2); |
156 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
157 | return(NOEXCEPTION); |
158 | } |
159 | /* |
160 | * Generate exponent |
161 | */ |
162 | dest_exponent = Dbl_exponent(opnd1p1) - Dbl_exponent(opnd2p1) + DBL_BIAS; |
163 | |
164 | /* |
165 | * Generate mantissa |
166 | */ |
167 | if (Dbl_isnotzero_exponent(opnd1p1)) { |
168 | /* set hidden bit */ |
169 | Dbl_clear_signexponent_set_hidden(opnd1p1); |
170 | } |
171 | else { |
172 | /* check for zero */ |
173 | if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { |
174 | Dbl_setzero_exponentmantissa(resultp1,resultp2); |
175 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
176 | return(NOEXCEPTION); |
177 | } |
178 | /* is denormalized, want to normalize */ |
179 | Dbl_clear_signexponent(opnd1p1); |
180 | Dbl_leftshiftby1(opnd1p1,opnd1p2); |
181 | Dbl_normalize(opnd1p1,opnd1p2,dest_exponent); |
182 | } |
183 | /* opnd2 needs to have hidden bit set with msb in hidden bit */ |
184 | if (Dbl_isnotzero_exponent(opnd2p1)) { |
185 | Dbl_clear_signexponent_set_hidden(opnd2p1); |
186 | } |
187 | else { |
188 | /* is denormalized; want to normalize */ |
189 | Dbl_clear_signexponent(opnd2p1); |
190 | Dbl_leftshiftby1(opnd2p1,opnd2p2); |
191 | while (Dbl_iszero_hiddenhigh7mantissa(opnd2p1)) { |
192 | dest_exponent+=8; |
193 | Dbl_leftshiftby8(opnd2p1,opnd2p2); |
194 | } |
195 | if (Dbl_iszero_hiddenhigh3mantissa(opnd2p1)) { |
196 | dest_exponent+=4; |
197 | Dbl_leftshiftby4(opnd2p1,opnd2p2); |
198 | } |
199 | while (Dbl_iszero_hidden(opnd2p1)) { |
200 | dest_exponent++; |
201 | Dbl_leftshiftby1(opnd2p1,opnd2p2); |
202 | } |
203 | } |
204 | |
205 | /* Divide the source mantissas */ |
206 | |
207 | /* |
208 | * A non-restoring divide algorithm is used. |
209 | */ |
210 | Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2); |
211 | Dbl_setzero(opnd3p1,opnd3p2); |
212 | for (count=1; count <= DBL_P && (opnd1p1 || opnd1p2); count++) { |
213 | Dbl_leftshiftby1(opnd1p1,opnd1p2); |
214 | Dbl_leftshiftby1(opnd3p1,opnd3p2); |
215 | if (Dbl_iszero_sign(opnd1p1)) { |
216 | Dbl_setone_lowmantissap2(opnd3p2); |
217 | Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2); |
218 | } |
219 | else { |
220 | Twoword_add(opnd1p1, opnd1p2, opnd2p1, opnd2p2); |
221 | } |
222 | } |
223 | if (count <= DBL_P) { |
224 | Dbl_leftshiftby1(opnd3p1,opnd3p2); |
225 | Dbl_setone_lowmantissap2(opnd3p2); |
226 | Dbl_leftshift(opnd3p1,opnd3p2,(DBL_P-count)); |
227 | if (Dbl_iszero_hidden(opnd3p1)) { |
228 | Dbl_leftshiftby1(opnd3p1,opnd3p2); |
229 | dest_exponent--; |
230 | } |
231 | } |
232 | else { |
233 | if (Dbl_iszero_hidden(opnd3p1)) { |
234 | /* need to get one more bit of result */ |
235 | Dbl_leftshiftby1(opnd1p1,opnd1p2); |
236 | Dbl_leftshiftby1(opnd3p1,opnd3p2); |
237 | if (Dbl_iszero_sign(opnd1p1)) { |
238 | Dbl_setone_lowmantissap2(opnd3p2); |
239 | Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2); |
240 | } |
241 | else { |
242 | Twoword_add(opnd1p1,opnd1p2,opnd2p1,opnd2p2); |
243 | } |
244 | dest_exponent--; |
245 | } |
246 | if (Dbl_iszero_sign(opnd1p1)) guardbit = TRUE; |
247 | stickybit = Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2); |
248 | } |
249 | inexact = guardbit | stickybit; |
250 | |
251 | /* |
252 | * round result |
253 | */ |
254 | if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) { |
255 | Dbl_clear_signexponent(opnd3p1); |
256 | switch (Rounding_mode()) { |
257 | case ROUNDPLUS: |
258 | if (Dbl_iszero_sign(resultp1)) |
259 | Dbl_increment(opnd3p1,opnd3p2); |
260 | break; |
261 | case ROUNDMINUS: |
262 | if (Dbl_isone_sign(resultp1)) |
263 | Dbl_increment(opnd3p1,opnd3p2); |
264 | break; |
265 | case ROUNDNEAREST: |
266 | if (guardbit && (stickybit || |
267 | Dbl_isone_lowmantissap2(opnd3p2))) { |
268 | Dbl_increment(opnd3p1,opnd3p2); |
269 | } |
270 | } |
271 | if (Dbl_isone_hidden(opnd3p1)) dest_exponent++; |
272 | } |
273 | Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2); |
274 | |
275 | /* |
276 | * Test for overflow |
277 | */ |
278 | if (dest_exponent >= DBL_INFINITY_EXPONENT) { |
279 | /* trap if OVERFLOWTRAP enabled */ |
280 | if (Is_overflowtrap_enabled()) { |
281 | /* |
282 | * Adjust bias of result |
283 | */ |
284 | Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl); |
285 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
286 | if (inexact) |
287 | if (Is_inexacttrap_enabled()) |
288 | return(OVERFLOWEXCEPTION | INEXACTEXCEPTION); |
289 | else Set_inexactflag(); |
290 | return(OVERFLOWEXCEPTION); |
291 | } |
292 | Set_overflowflag(); |
293 | /* set result to infinity or largest number */ |
294 | Dbl_setoverflow(resultp1,resultp2); |
295 | inexact = TRUE; |
296 | } |
297 | /* |
298 | * Test for underflow |
299 | */ |
300 | else if (dest_exponent <= 0) { |
301 | /* trap if UNDERFLOWTRAP enabled */ |
302 | if (Is_underflowtrap_enabled()) { |
303 | /* |
304 | * Adjust bias of result |
305 | */ |
306 | Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl); |
307 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
308 | if (inexact) |
309 | if (Is_inexacttrap_enabled()) |
310 | return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION); |
311 | else Set_inexactflag(); |
312 | return(UNDERFLOWEXCEPTION); |
313 | } |
314 | |
315 | /* Determine if should set underflow flag */ |
316 | is_tiny = TRUE; |
317 | if (dest_exponent == 0 && inexact) { |
318 | switch (Rounding_mode()) { |
319 | case ROUNDPLUS: |
320 | if (Dbl_iszero_sign(resultp1)) { |
321 | Dbl_increment(opnd3p1,opnd3p2); |
322 | if (Dbl_isone_hiddenoverflow(opnd3p1)) |
323 | is_tiny = FALSE; |
324 | Dbl_decrement(opnd3p1,opnd3p2); |
325 | } |
326 | break; |
327 | case ROUNDMINUS: |
328 | if (Dbl_isone_sign(resultp1)) { |
329 | Dbl_increment(opnd3p1,opnd3p2); |
330 | if (Dbl_isone_hiddenoverflow(opnd3p1)) |
331 | is_tiny = FALSE; |
332 | Dbl_decrement(opnd3p1,opnd3p2); |
333 | } |
334 | break; |
335 | case ROUNDNEAREST: |
336 | if (guardbit && (stickybit || |
337 | Dbl_isone_lowmantissap2(opnd3p2))) { |
338 | Dbl_increment(opnd3p1,opnd3p2); |
339 | if (Dbl_isone_hiddenoverflow(opnd3p1)) |
340 | is_tiny = FALSE; |
341 | Dbl_decrement(opnd3p1,opnd3p2); |
342 | } |
343 | break; |
344 | } |
345 | } |
346 | |
347 | /* |
348 | * denormalize result or set to signed zero |
349 | */ |
350 | stickybit = inexact; |
351 | Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit, |
352 | stickybit,inexact); |
353 | |
354 | /* return rounded number */ |
355 | if (inexact) { |
356 | switch (Rounding_mode()) { |
357 | case ROUNDPLUS: |
358 | if (Dbl_iszero_sign(resultp1)) { |
359 | Dbl_increment(opnd3p1,opnd3p2); |
360 | } |
361 | break; |
362 | case ROUNDMINUS: |
363 | if (Dbl_isone_sign(resultp1)) { |
364 | Dbl_increment(opnd3p1,opnd3p2); |
365 | } |
366 | break; |
367 | case ROUNDNEAREST: |
368 | if (guardbit && (stickybit || |
369 | Dbl_isone_lowmantissap2(opnd3p2))) { |
370 | Dbl_increment(opnd3p1,opnd3p2); |
371 | } |
372 | break; |
373 | } |
374 | if (is_tiny) Set_underflowflag(); |
375 | } |
376 | Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2); |
377 | } |
378 | else Dbl_set_exponent(resultp1,dest_exponent); |
379 | Dbl_copytoptr(resultp1,resultp2,dstptr); |
380 | |
381 | /* check for inexact */ |
382 | if (inexact) { |
383 | if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION); |
384 | else Set_inexactflag(); |
385 | } |
386 | return(NOEXCEPTION); |
387 | } |
388 | |