]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/libbid/bid128_rem.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / libbid / bid128_rem.c
CommitLineData
83ffe9cd 1/* Copyright (C) 2007-2023 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#define BID_128RES
b2a00c89 25#include "bid_div_macros.h"
200359e8
L
26
27
b2a00c89 28BID128_FUNCTION_ARG2_NORND_CUSTOMRESTYPE (UINT128, bid128_rem, x, y)
200359e8 29
b2a00c89
L
30 UINT256 P256;
31 UINT128 CX, CY, CX2, CQ, CR, T, CXS, P128, res;
32 UINT64 sign_x, sign_y, valid_y;
33 SINT64 D;
34 int_float f64, fx;
35 int exponent_x, exponent_y, diff_expon, bin_expon_cx, scale,
36 scale0;
200359e8
L
37
38 // unpack arguments, check for NaN or Infinity
b2a00c89
L
39
40valid_y = unpack_BID128_value (&sign_y, &exponent_y, &CY, y);
41
42if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) {
200359e8 43#ifdef SET_STATUS_FLAGS
b2a00c89
L
44if ((y.w[1] & SNAN_MASK64) == SNAN_MASK64) // y is sNaN
45 __set_status_flags (pfpsf, INVALID_EXCEPTION);
200359e8
L
46#endif
47 // test if x is NaN
b2a00c89 48if ((x.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
200359e8 49#ifdef SET_STATUS_FLAGS
b2a00c89
L
50 if ((x.w[1] & SNAN_MASK64) == SNAN_MASK64) // y is sNaN
51 __set_status_flags (pfpsf, INVALID_EXCEPTION);
200359e8 52#endif
b2a00c89
L
53 res.w[1] = CX.w[1] & QUIET_MASK64;
54 res.w[0] = CX.w[0];
55 BID_RETURN (res);
56}
200359e8 57 // x is Infinity?
b2a00c89
L
58if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) {
59 // check if y is Inf.
60 if (((y.w[1] & 0x7c00000000000000ull) != 0x7c00000000000000ull))
61 // return NaN
62 {
200359e8 63#ifdef SET_STATUS_FLAGS
b2a00c89
L
64 // set status flags
65 __set_status_flags (pfpsf, INVALID_EXCEPTION);
200359e8 66#endif
b2a00c89
L
67 res.w[1] = 0x7c00000000000000ull;
68 res.w[0] = 0;
69 BID_RETURN (res);
70 }
200359e8 71
b2a00c89 72}
200359e8 73 // x is 0
b2a00c89 74if ((!CY.w[1]) && (!CY.w[0])) {
200359e8 75#ifdef SET_STATUS_FLAGS
b2a00c89
L
76 // set status flags
77 __set_status_flags (pfpsf, INVALID_EXCEPTION);
200359e8 78#endif
b2a00c89
L
79 // x=y=0, return NaN
80 res.w[1] = 0x7c00000000000000ull;
81 res.w[0] = 0;
82 BID_RETURN (res);
83}
84if (valid_y || ((y.w[1] & NAN_MASK64) == INFINITY_MASK64)) {
85 // return 0
86 if ((exponent_x > exponent_y)
87 && ((y.w[1] & NAN_MASK64) != INFINITY_MASK64))
88 exponent_x = exponent_y;
89
90 res.w[1] = sign_x | (((UINT64) exponent_x) << 49);
91 res.w[0] = 0;
92 BID_RETURN (res);
93}
94}
95if (!valid_y) {
96 // y is Inf. or NaN
200359e8 97
b2a00c89
L
98 // test if y is NaN
99 if ((y.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
200359e8 100#ifdef SET_STATUS_FLAGS
b2a00c89
L
101 if ((y.w[1] & SNAN_MASK64) == SNAN_MASK64) // y is sNaN
102 __set_status_flags (pfpsf, INVALID_EXCEPTION);
200359e8 103#endif
b2a00c89
L
104 res.w[1] = CY.w[1] & QUIET_MASK64;
105 res.w[0] = CY.w[0];
106 BID_RETURN (res);
107 }
108 // y is Infinity?
109 if ((y.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) {
110 // return x
111 res.w[1] = x.w[1];
112 res.w[0] = x.w[0];
113 BID_RETURN (res);
114 }
115 // y is 0
200359e8 116#ifdef SET_STATUS_FLAGS
b2a00c89
L
117 // set status flags
118 __set_status_flags (pfpsf, INVALID_EXCEPTION);
200359e8 119#endif
b2a00c89
L
120 res.w[1] = 0x7c00000000000000ull;
121 res.w[0] = 0;
122 BID_RETURN (res);
123}
124
125diff_expon = exponent_x - exponent_y;
126
127if (diff_expon <= 0) {
128 diff_expon = -diff_expon;
129
130 if (diff_expon > 34) {
131 // |x|<|y| in this case
132 res = x;
200359e8
L
133 BID_RETURN (res);
134 }
b2a00c89
L
135 // set exponent of y to exponent_x, scale coefficient_y
136 T = power10_table_128[diff_expon];
137 __mul_128x128_to_256 (P256, CY, T);
200359e8 138
b2a00c89
L
139 if (P256.w[2] || P256.w[3]) {
140 // |x|<|y| in this case
141 res = x;
200359e8
L
142 BID_RETURN (res);
143 }
200359e8
L
144
145 CX2.w[1] = (CX.w[1] << 1) | (CX.w[0] >> 63);
146 CX2.w[0] = CX.w[0] << 1;
b2a00c89
L
147 if (__unsigned_compare_ge_128 (P256, CX2)) {
148 // |x|<|y| in this case
149 res = x;
150 BID_RETURN (res);
151 }
152
153 P128.w[0] = P256.w[0];
154 P128.w[1] = P256.w[1];
155 __div_128_by_128 (&CQ, &CR, CX, P128);
156
157 CX2.w[1] = (CR.w[1] << 1) | (CR.w[0] >> 63);
158 CX2.w[0] = CR.w[0] << 1;
159 if ((__unsigned_compare_gt_128 (CX2, P256))
160 || (CX2.w[1] == P256.w[1] && CX2.w[0] == P256.w[0]
161 && (CQ.w[0] & 1))) {
162 __sub_128_128 (CR, P256, CR);
200359e8
L
163 sign_x ^= 0x8000000000000000ull;
164 }
165
b2a00c89 166 get_BID128_very_fast (&res, sign_x, exponent_x, CR);
200359e8 167 BID_RETURN (res);
b2a00c89
L
168}
169 // 2^64
170f64.i = 0x5f800000;
171
172scale0 = 38;
173if (!CY.w[1])
174 scale0 = 34;
175
176while (diff_expon > 0) {
177 // get number of digits in CX and scale=38-digits
178 // fx ~ CX
179 fx.d = (float) CX.w[1] * f64.d + (float) CX.w[0];
180 bin_expon_cx = ((fx.i >> 23) & 0xff) - 0x7f;
181 scale = scale0 - estimate_decimal_digits[bin_expon_cx];
182 // scale = 38-estimate_decimal_digits[bin_expon_cx];
183 D = CX.w[1] - power10_index_binexp_128[bin_expon_cx].w[1];
184 if (D > 0
185 || (!D && CX.w[0] >= power10_index_binexp_128[bin_expon_cx].w[0]))
186 scale--;
187
188 if (diff_expon >= scale)
189 diff_expon -= scale;
190 else {
191 scale = diff_expon;
192 diff_expon = 0;
193 }
194
195 T = power10_table_128[scale];
196 __mul_128x128_low (CXS, CX, T);
197
198 __div_128_by_128 (&CQ, &CX, CXS, CY);
199
200 // check for remainder == 0
201 if (!CX.w[1] && !CX.w[0]) {
202 get_BID128_very_fast (&res, sign_x, exponent_y, CX);
203 BID_RETURN (res);
204 }
205}
206
207CX2.w[1] = (CX.w[1] << 1) | (CX.w[0] >> 63);
208CX2.w[0] = CX.w[0] << 1;
209if ((__unsigned_compare_gt_128 (CX2, CY))
210 || (CX2.w[1] == CY.w[1] && CX2.w[0] == CY.w[0] && (CQ.w[0] & 1))) {
211 __sub_128_128 (CX, CY, CX);
212 sign_x ^= 0x8000000000000000ull;
213}
214
215get_BID128_very_fast (&res, sign_x, exponent_y, CX);
216BID_RETURN (res);
200359e8 217}