]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/libbid/bid64_rem.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / libbid / bid64_rem.c
CommitLineData
99dee823 1/* Copyright (C) 2007-2021 Free Software Foundation, Inc.
200359e8
L
2
3This file is part of GCC.
4
5GCC is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free
748086b7 7Software Foundation; either version 3, or (at your option) any later
200359e8
L
8version.
9
200359e8
L
10GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or
12FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13for more details.
14
748086b7
JJ
15Under Section 7 of GPL version 3, you are granted additional
16permissions described in the GCC Runtime Library Exception, version
173.1, as published by the Free Software Foundation.
18
19You should have received a copy of the GNU General Public License and
20a copy of the GCC Runtime Library Exception along with this program;
21see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
22<http://www.gnu.org/licenses/>. */
200359e8
L
23
24/*****************************************************************************
25 * BID64 remainder
26 *****************************************************************************
27 *
28 * Algorithm description:
29 *
30 * if(exponent_x < exponent_y)
31 * scale coefficient_y so exponents are aligned
32 * perform coefficient divide (64-bit integer divide), unless
33 * coefficient_y is longer than 64 bits (clearly larger
34 * than coefficient_x)
35 * else // exponent_x > exponent_y
36 * use a loop to scale coefficient_x to 18_digits, divide by
37 * coefficient_y (64-bit integer divide), calculate remainder
38 * as new_coefficient_x and repeat until final remainder is obtained
39 * (when new_exponent_x < exponent_y)
40 *
41 ****************************************************************************/
42
43#include "bid_internal.h"
44
45#define MAX_FORMAT_DIGITS 16
46#define DECIMAL_EXPONENT_BIAS 398
47#define MASK_BINARY_EXPONENT 0x7ff0000000000000ull
48#define BINARY_EXPONENT_BIAS 0x3ff
49#define UPPER_EXPON_LIMIT 51
50
51#if DECIMAL_CALL_BY_REFERENCE
52
53void
b2a00c89 54bid64_rem (UINT64 * pres, UINT64 * px,
200359e8 55 UINT64 *
b2a00c89 56 py _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
57 UINT64 x, y;
58#else
59
60UINT64
b2a00c89
L
61bid64_rem (UINT64 x,
62 UINT64 y _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
200359e8
L
63#endif
64 UINT128 CY;
65 UINT64 sign_x, sign_y, coefficient_x, coefficient_y, res;
b2a00c89 66 UINT64 Q, R, R2, T, valid_y, valid_x;
200359e8 67 int_float tempx;
b2a00c89 68 int exponent_x, exponent_y, bin_expon, e_scale;
200359e8
L
69 int digits_x, diff_expon;
70
71#if DECIMAL_CALL_BY_REFERENCE
72 x = *px;
73 y = *py;
74#endif
75
b2a00c89
L
76 valid_y = unpack_BID64 (&sign_y, &exponent_y, &coefficient_y, y);
77 valid_x = unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x);
78
200359e8 79 // unpack arguments, check for NaN or Infinity
b2a00c89 80 if (!valid_x) {
200359e8
L
81 // x is Inf. or NaN or 0
82#ifdef SET_STATUS_FLAGS
83 if ((y & SNAN_MASK64) == SNAN_MASK64) // y is sNaN
84 __set_status_flags (pfpsf, INVALID_EXCEPTION);
85#endif
86
87 // test if x is NaN
88 if ((x & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
89#ifdef SET_STATUS_FLAGS
90 if (((x & SNAN_MASK64) == SNAN_MASK64))
91 __set_status_flags (pfpsf, INVALID_EXCEPTION);
92#endif
b2a00c89 93 res = coefficient_x & QUIET_MASK64;;
200359e8
L
94 BID_RETURN (res);
95 }
96 // x is Infinity?
97 if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) {
b2a00c89 98 if (((y & NAN_MASK64) != NAN_MASK64)) {
200359e8 99#ifdef SET_STATUS_FLAGS
200359e8
L
100 __set_status_flags (pfpsf, INVALID_EXCEPTION);
101#endif
b2a00c89
L
102 // return NaN
103 res = 0x7c00000000000000ull;
104 BID_RETURN (res);
105 }
200359e8
L
106 }
107 // x is 0
108 // return x if y != 0
109 if (((y & 0x7800000000000000ull) < 0x7800000000000000ull) &&
b2a00c89 110 coefficient_y) {
200359e8
L
111 if ((y & 0x6000000000000000ull) == 0x6000000000000000ull)
112 exponent_y = (y >> 51) & 0x3ff;
113 else
114 exponent_y = (y >> 53) & 0x3ff;
115
116 if (exponent_y < exponent_x)
117 exponent_x = exponent_y;
118
119 x = exponent_x;
120 x <<= 53;
121
122 res = x | sign_x;
123 BID_RETURN (res);
124 }
125
126 }
b2a00c89 127 if (!valid_y) {
200359e8
L
128 // y is Inf. or NaN
129
130 // test if y is NaN
131 if ((y & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
132#ifdef SET_STATUS_FLAGS
133 if (((y & SNAN_MASK64) == SNAN_MASK64))
134 __set_status_flags (pfpsf, INVALID_EXCEPTION);
135#endif
b2a00c89 136 res = coefficient_y & QUIET_MASK64;;
200359e8
L
137 BID_RETURN (res);
138 }
139 // y is Infinity?
140 if ((y & 0x7800000000000000ull) == 0x7800000000000000ull) {
b2a00c89 141 res = very_fast_get_BID64 (sign_x, exponent_x, coefficient_x);
200359e8
L
142 BID_RETURN (res);
143 }
144 // y is 0, return NaN
145 {
146#ifdef SET_STATUS_FLAGS
147 __set_status_flags (pfpsf, INVALID_EXCEPTION);
148#endif
149 res = 0x7c00000000000000ull;
150 BID_RETURN (res);
151 }
152 }
153
154
155 diff_expon = exponent_x - exponent_y;
156 if (diff_expon <= 0) {
157 diff_expon = -diff_expon;
158
159 if (diff_expon > 16) {
160 // |x|<|y| in this case
161 res = x;
162 BID_RETURN (res);
163 }
164 // set exponent of y to exponent_x, scale coefficient_y
b2a00c89 165 T = power10_table_128[diff_expon].w[0];
200359e8
L
166 __mul_64x64_to_128 (CY, coefficient_y, T);
167
168 if (CY.w[1] || CY.w[0] > (coefficient_x << 1)) {
169 res = x;
170 BID_RETURN (res);
171 }
172
173 Q = coefficient_x / CY.w[0];
174 R = coefficient_x - Q * CY.w[0];
175
176 R2 = R + R;
177 if (R2 > CY.w[0] || (R2 == CY.w[0] && (Q & 1))) {
178 R = CY.w[0] - R;
179 sign_x ^= 0x8000000000000000ull;
180 }
181
182 res = very_fast_get_BID64 (sign_x, exponent_x, R);
183 BID_RETURN (res);
184 }
185
186
187 while (diff_expon > 0) {
188 // get number of digits in coeff_x
189 tempx.d = (float) coefficient_x;
190 bin_expon = ((tempx.i >> 23) & 0xff) - 0x7f;
b2a00c89 191 digits_x = estimate_decimal_digits[bin_expon];
200359e8 192 // will not use this test, dividend will have 18 or 19 digits
b2a00c89 193 //if(coefficient_x >= power10_table_128[digits_x].w[0])
200359e8
L
194 // digits_x++;
195
196 e_scale = 18 - digits_x;
197 if (diff_expon >= e_scale) {
198 diff_expon -= e_scale;
199 } else {
200 e_scale = diff_expon;
201 diff_expon = 0;
202 }
203
204 // scale dividend to 18 or 19 digits
b2a00c89 205 coefficient_x *= power10_table_128[e_scale].w[0];
200359e8
L
206
207 // quotient
208 Q = coefficient_x / coefficient_y;
209 // remainder
210 coefficient_x -= Q * coefficient_y;
211
212 // check for remainder == 0
213 if (!coefficient_x) {
214 res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, 0);
215 BID_RETURN (res);
216 }
217 }
218
219 R2 = coefficient_x + coefficient_x;
220 if (R2 > coefficient_y || (R2 == coefficient_y && (Q & 1))) {
221 coefficient_x = coefficient_y - coefficient_x;
222 sign_x ^= 0x8000000000000000ull;
223 }
224
225 res = very_fast_get_BID64 (sign_x, exponent_y, coefficient_x);
226 BID_RETURN (res);
227
228}