1 /* Copyright (C) 2007 Free Software Foundation, Inc.
3 This file is part of GCC.
5 GCC is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2, or (at your option) any later
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file. (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
19 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
20 WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 You should have received a copy of the GNU General Public License
25 along with GCC; see the file COPYING. If not, write to the Free
26 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30 #include "div_macros.h"
32 extern UINT32 __bid_convert_table
[5][128][2];
33 extern SINT8 __bid_factors
[][2];
34 extern UINT8 __bid_packed_10000_zeros
[];
36 BID128_FUNCTION_ARG2(__bid128_div
, x
, y
)
38 UINT256 CA4
, CA4r
, P256
;
39 UINT128 CX
, CY
, T128
, CQ
, CR
, CA
, TP128
, Qh
, Ql
, res
;
40 UINT64 sign_x
, sign_y
, T
, carry64
, D
, Q_high
, Q_low
, QX
, X
, PD
;
41 int_float fx
, fy
, f64
;
42 UINT32 QX32
, tdigit
[3], digit
, digit_h
, digit_low
;
43 int exponent_x
= 0, exponent_y
, bin_index
, bin_expon
, diff_expon
, ed2
,
45 int nzeros
, i
, j
, k
, d5
;
49 // unpack arguments, check for NaN or Infinity
50 if (!unpack_BID128_value (&sign_x
, &exponent_x
, &CX
, x
)) {
52 if ((x
.w
[1] & 0x7c00000000000000ull
) == 0x7c00000000000000ull
) {
53 #ifdef SET_STATUS_FLAGS
54 if ((x
.w
[1] & 0x7e00000000000000ull
) == 0x7e00000000000000ull
|| // sNaN
55 (y
.w
[1] & 0x7e00000000000000ull
) == 0x7e00000000000000ull
)
56 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
58 res
.w
[1] = (x
.w
[1]) & QUIET_MASK64
;
63 if ((x
.w
[1] & 0x7800000000000000ull
) == 0x7800000000000000ull
) {
65 if (((y
.w
[1] & 0x7c00000000000000ull
) == 0x7800000000000000ull
))
68 #ifdef SET_STATUS_FLAGS
69 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
71 res
.w
[1] = 0x7c00000000000000ull
;
76 if (((y
.w
[1] & 0x7c00000000000000ull
) != 0x7c00000000000000ull
))
80 res
.w
[1] = ((x
.w
[1] ^ y
.w
[1]) & 0x8000000000000000ull
) |
81 0x7800000000000000ull
;
87 if ((y
.w
[1] & 0x7800000000000000ull
) < 0x7800000000000000ull
) {
88 if ((!y
.w
[0]) && !(y
.w
[1] & 0x0001ffffffffffffull
)) {
89 #ifdef SET_STATUS_FLAGS
90 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
93 res
.w
[1] = 0x7c00000000000000ull
;
98 res
.w
[1] = (x
.w
[1] ^ y
.w
[1]) & 0x8000000000000000ull
;
99 X
= ((y
.w
[1]) << 1) >> 50;
100 exponent_x
= exponent_x
- (int) X
+ DECIMAL_EXPONENT_BIAS_128
;
101 if (exponent_x
> DECIMAL_MAX_EXPON_128
)
102 exponent_x
= DECIMAL_MAX_EXPON_128
;
103 else if (exponent_x
< 0)
105 res
.w
[1] |= (((UINT64
) exponent_x
) << 49);
110 if (!unpack_BID128_value (&sign_y
, &exponent_y
, &CY
, y
)) {
114 if ((y
.w
[1] & 0x7c00000000000000ull
) == 0x7c00000000000000ull
) {
115 #ifdef SET_STATUS_FLAGS
116 if ((y
.w
[1] & 0x7e00000000000000ull
) == 0x7e00000000000000ull
) // sNaN
117 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
119 res
.w
[1] = y
.w
[1] & QUIET_MASK64
;
124 if ((y
.w
[1] & 0x7800000000000000ull
) == 0x7800000000000000ull
) {
126 res
.w
[1] = sign_x
^ sign_y
;
130 // y is 0, return +/-Inf
131 #ifdef SET_STATUS_FLAGS
132 __set_status_flags (pfpsf
, ZERO_DIVIDE_EXCEPTION
);
135 ((x
.w
[1] ^ y
.w
[1]) & 0x8000000000000000ull
) | 0x7800000000000000ull
;
139 diff_expon
= exponent_x
- exponent_y
+ DECIMAL_EXPONENT_BIAS_128
;
141 if (__unsigned_compare_gt_128 (CY
, CX
)) {
148 fx
.d
= (float) CX
.w
[1] * f64
.d
+ (float) CX
.w
[0];
149 fy
.d
= (float) CY
.w
[1] * f64
.d
+ (float) CY
.w
[0];
150 // expon_cy - expon_cx
151 bin_index
= (fy
.i
- fx
.i
) >> 23;
154 T
= __bid_power10_index_binexp_128
[bin_index
].w
[0];
155 __mul_64x128_short (CA
, T
, CX
);
157 T128
= __bid_power10_index_binexp_128
[bin_index
];
158 __mul_64x128_short (CA
, CX
.w
[0], T128
);
162 if (__unsigned_compare_gt_128 (CY
, CA
))
165 T128
= __bid_power10_table_128
[ed2
];
166 __mul_128x128_to_256 (CA4
, CA
, T128
);
168 ed2
+= __bid_estimate_decimal_digits
[bin_index
];
169 CQ
.w
[0] = CQ
.w
[1] = 0;
170 diff_expon
= diff_expon
- ed2
;
174 __div_128_by_128 (&CQ
, &CR
, CX
, CY
);
176 if (!CR
.w
[1] && !CR
.w
[0]) {
177 get_BID128 (&res
, sign_x
^ sign_y
, diff_expon
, CQ
, &rnd_mode
,
181 // get number of decimal digits in CQ
184 fx
.d
= (float) CQ
.w
[1] * f64
.d
+ (float) CQ
.w
[0];
185 // binary expon. of CQ
186 bin_expon
= (fx
.i
- 0x3f800000) >> 23;
188 digits_q
= __bid_estimate_decimal_digits
[bin_expon
];
189 TP128
.w
[0] = __bid_power10_index_binexp_128
[bin_expon
].w
[0];
190 TP128
.w
[1] = __bid_power10_index_binexp_128
[bin_expon
].w
[1];
191 if (__unsigned_compare_ge_128 (CQ
, TP128
))
195 T128
.w
[0] = __bid_power10_table_128
[ed2
].w
[0];
196 T128
.w
[1] = __bid_power10_table_128
[ed2
].w
[1];
197 __mul_128x128_to_256 (CA4
, CR
, T128
);
198 diff_expon
= diff_expon
- ed2
;
199 __mul_128x128_low (CQ
, CQ
, T128
);
203 __div_256_by_128 (&CQ
, &CA4
, CY
);
205 #ifdef SET_STATUS_FLAGS
206 if (CA4
.w
[0] || CA4
.w
[1]) {
208 __set_status_flags (pfpsf
, INEXACT_EXCEPTION
);
210 #ifndef LEAVE_TRAILING_ZEROS
214 #ifndef LEAVE_TRAILING_ZEROS
215 if (!CA4
.w
[0] && !CA4
.w
[1])
218 #ifndef LEAVE_TRAILING_ZEROS
219 // check whether result is exact
221 // check whether CX, CY are short
222 if (!CX
.w
[1] && !CY
.w
[1] && (CX
.w
[0] <= 1024) && (CY
.w
[0] <= 1024)) {
223 i
= (int) CY
.w
[0] - 1;
224 j
= (int) CX
.w
[0] - 1;
225 // difference in powers of 2 __bid_factors for Y and X
226 nzeros
= ed2
- __bid_factors
[i
][0] + __bid_factors
[j
][0];
227 // difference in powers of 5 __bid_factors
228 d5
= ed2
- __bid_factors
[i
][1] + __bid_factors
[j
][1];
231 // get P*(2^M[extra_digits])/10^extra_digits
232 __mul_128x128_full (Qh
, Ql
, CQ
, __bid_reciprocals10_128
[nzeros
]);
234 // now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
235 amount
= __bid_recip_scale
[nzeros
];
236 __shr_128_long (CQ
, Qh
, amount
);
238 diff_expon
+= nzeros
;
240 // decompose Q as Qh*10^17 + Ql
241 //T128 = __bid_reciprocals10_128[17];
242 T128
.w
[0] = 0x44909befeb9fad49ull
;
243 T128
.w
[1] = 0x000b877aa3236a4bull
;
244 __mul_128x128_to_256 (P256
, CQ
, T128
);
245 //amount = __bid_recip_scale[17];
246 Q_high
= (P256
.w
[2] >> 44) | (P256
.w
[3] << (64 - 44));
247 Q_low
= CQ
.w
[0] - Q_high
* 100000000000000000ull;
252 tdigit
[0] = Q_high
& 0x3ffffff;
258 for (j
= 0; QX32
; j
++, QX32
>>= 7) {
260 tdigit
[0] += __bid_convert_table
[j
][k
][0];
261 tdigit
[1] += __bid_convert_table
[j
][k
][1];
262 if (tdigit
[0] >= 100000000) {
263 tdigit
[0] -= 100000000;
268 if (tdigit
[1] >= 100000000) {
269 tdigit
[1] -= 100000000;
270 if (tdigit
[1] >= 100000000)
271 tdigit
[1] -= 100000000;
275 if (!digit
&& !tdigit
[1])
283 PD
= (UINT64
) digit
*0x068DB8BBull
;
284 digit_h
= (UINT32
) (PD
>> 40);
285 digit_low
= digit
- digit_h
* 10000;
294 3 & (UINT32
) (__bid_packed_10000_zeros
[digit_h
>> 3] >>
299 __mul_64x64_to_128 (CQ
, Q_high
, __bid_reciprocals10_64
[nzeros
]);
301 // now get P/10^extra_digits: shift C64 right by M[extra_digits]-64
302 amount
= __bid_short_recip_scale
[nzeros
];
303 CQ
.w
[0] = CQ
.w
[1] >> amount
;
308 diff_expon
+= nzeros
;
310 tdigit
[0] = Q_low
& 0x3ffffff;
316 for (j
= 0; QX32
; j
++, QX32
>>= 7) {
318 tdigit
[0] += __bid_convert_table
[j
][k
][0];
319 tdigit
[1] += __bid_convert_table
[j
][k
][1];
320 if (tdigit
[0] >= 100000000) {
321 tdigit
[0] -= 100000000;
326 if (tdigit
[1] >= 100000000) {
327 tdigit
[1] -= 100000000;
328 if (tdigit
[1] >= 100000000)
329 tdigit
[1] -= 100000000;
333 if (!digit
&& !tdigit
[1])
341 PD
= (UINT64
) digit
*0x068DB8BBull
;
342 digit_h
= (UINT32
) (PD
>> 40);
343 digit_low
= digit
- digit_h
* 10000;
352 3 & (UINT32
) (__bid_packed_10000_zeros
[digit_h
>> 3] >>
357 // get P*(2^M[extra_digits])/10^extra_digits
358 __mul_128x128_full (Qh
, Ql
, CQ
, __bid_reciprocals10_128
[nzeros
]);
360 //now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
361 amount
= __bid_recip_scale
[nzeros
];
362 __shr_128 (CQ
, Qh
, amount
);
364 diff_expon
+= nzeros
;
368 get_BID128 (&res
, sign_x
^ sign_y
, diff_expon
, CQ
, &rnd_mode
,
374 if (diff_expon
>= 0) {
375 #ifdef IEEE_ROUND_NEAREST
378 CA4r
.w
[1] = (CA4
.w
[1] + CA4
.w
[1]) | (CA4
.w
[0] >> 63);
379 CA4r
.w
[0] = CA4
.w
[0] + CA4
.w
[0];
380 __sub_borrow_out (CA4r
.w
[0], carry64
, CA4r
.w
[0], CY
.w
[0]);
381 CA4r
.w
[1] = CA4r
.w
[1] - CY
.w
[1] - carry64
;
383 D
= (CA4r
.w
[1] | CA4r
.w
[0]) ? 1 : 0;
384 carry64
= (1 + (((SINT64
) CA4r
.w
[1]) >> 63)) & ((CQ
.w
[0]) | D
);
387 if (CQ
.w
[0] < carry64
)
390 #ifdef IEEE_ROUND_NEAREST_TIES_AWAY
393 CA4r
.w
[1] = (CA4
.w
[1] + CA4
.w
[1]) | (CA4
.w
[0] >> 63);
394 CA4r
.w
[0] = CA4
.w
[0] + CA4
.w
[0];
395 __sub_borrow_out (CA4r
.w
[0], carry64
, CA4r
.w
[0], CY
.w
[0]);
396 CA4r
.w
[1] = CA4r
.w
[1] - CY
.w
[1] - carry64
;
398 D
= (CA4r
.w
[1] | CA4r
.w
[0]) ? 0 : 1;
399 carry64
= (1 + (((SINT64
) CA4r
.w
[1]) >> 63)) | D
;
402 if (CQ
.w
[0] < carry64
)
406 if (sign_x
^ sign_y
&& (unsigned) (rmode
- 1) < 2)
409 case ROUNDING_TO_NEAREST
: // round to nearest code
412 CA4r
.w
[1] = (CA4
.w
[1] + CA4
.w
[1]) | (CA4
.w
[0] >> 63);
413 CA4r
.w
[0] = CA4
.w
[0] + CA4
.w
[0];
414 __sub_borrow_out (CA4r
.w
[0], carry64
, CA4r
.w
[0], CY
.w
[0]);
415 CA4r
.w
[1] = CA4r
.w
[1] - CY
.w
[1] - carry64
;
416 D
= (CA4r
.w
[1] | CA4r
.w
[0]) ? 1 : 0;
417 carry64
= (1 + (((SINT64
) CA4r
.w
[1]) >> 63)) & ((CQ
.w
[0]) | D
);
419 if (CQ
.w
[0] < carry64
)
422 case ROUNDING_TIES_AWAY
:
425 CA4r
.w
[1] = (CA4
.w
[1] + CA4
.w
[1]) | (CA4
.w
[0] >> 63);
426 CA4r
.w
[0] = CA4
.w
[0] + CA4
.w
[0];
427 __sub_borrow_out (CA4r
.w
[0], carry64
, CA4r
.w
[0], CY
.w
[0]);
428 CA4r
.w
[1] = CA4r
.w
[1] - CY
.w
[1] - carry64
;
429 D
= (CA4r
.w
[1] | CA4r
.w
[0]) ? 0 : 1;
430 carry64
= (1 + (((SINT64
) CA4r
.w
[1]) >> 63)) | D
;
432 if (CQ
.w
[0] < carry64
)
436 case ROUNDING_TO_ZERO
:
438 default: // rounding up
448 #ifdef SET_STATUS_FLAGS
449 if (CA4
.w
[0] || CA4
.w
[1]) {
451 __set_status_flags (pfpsf
, INEXACT_EXCEPTION
);
455 handle_UF_128_rem (&res
, sign_x
^ sign_y
, diff_expon
, CQ
,
456 CA4
.w
[1] | CA4
.w
[0], &rnd_mode
, pfpsf
);
461 get_BID128 (&res
, sign_x
^ sign_y
, diff_expon
, CQ
, &rnd_mode
, pfpsf
);