]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/libbid/bid128_mul.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / libbid / bid128_mul.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#include "bid_internal.h"
25
26#if DECIMAL_CALL_BY_REFERENCE
27void
b2a00c89
L
28bid64dq_mul (UINT64 * pres, UINT64 * px, UINT128 * py
29 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
30 _EXC_INFO_PARAM) {
31 UINT64 x = *px;
200359e8
L
32#if !DECIMAL_GLOBAL_ROUNDING
33 unsigned int rnd_mode = *prnd_mode;
200359e8
L
34#endif
35#else
b2a00c89
L
36UINT64
37bid64dq_mul (UINT64 x, UINT128 y
38 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
39 _EXC_INFO_PARAM) {
200359e8 40#endif
b2a00c89
L
41 UINT64 res = 0xbaddbaddbaddbaddull;
42 UINT128 x1;
200359e8 43
b2a00c89
L
44#if DECIMAL_CALL_BY_REFERENCE
45 bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
46 bid64qq_mul (&res, &x1, py
47 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
48 _EXC_INFO_ARG);
49#else
50 x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
51 res = bid64qq_mul (x1, y
52 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
53 _EXC_INFO_ARG);
54#endif
55 BID_RETURN (res);
56}
200359e8 57
200359e8 58
b2a00c89
L
59#if DECIMAL_CALL_BY_REFERENCE
60void
61bid64qd_mul (UINT64 * pres, UINT128 * px, UINT64 * py
62 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
63 _EXC_INFO_PARAM) {
64 UINT64 y = *py;
65#if !DECIMAL_GLOBAL_ROUNDING
66 unsigned int rnd_mode = *prnd_mode;
67#endif
68#else
69UINT64
70bid64qd_mul (UINT128 x, UINT64 y
71 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
72 _EXC_INFO_PARAM) {
73#endif
74 UINT64 res = 0xbaddbaddbaddbaddull;
75 UINT128 y1;
200359e8 76
b2a00c89
L
77#if DECIMAL_CALL_BY_REFERENCE
78 bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
79 bid64qq_mul (&res, px, &y1
80 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
81 _EXC_INFO_ARG);
82#else
83 y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
84 res = bid64qq_mul (x, y1
85 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
86 _EXC_INFO_ARG);
87#endif
88 BID_RETURN (res);
89}
200359e8 90
200359e8 91
b2a00c89
L
92#if DECIMAL_CALL_BY_REFERENCE
93void
94bid64qq_mul (UINT64 * pres, UINT128 * px, UINT128 * py
95 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
96 _EXC_INFO_PARAM) {
97 UINT128 x = *px, y = *py;
98#if !DECIMAL_GLOBAL_ROUNDING
99 unsigned int rnd_mode = *prnd_mode;
100#endif
101#else
102UINT64
103bid64qq_mul (UINT128 x, UINT128 y
104 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
105 _EXC_INFO_PARAM) {
106#endif
200359e8 107
b2a00c89
L
108 UINT128 z = { {0x0000000000000000ull, 0x5ffe000000000000ull}
109 };
110 UINT64 res = 0xbaddbaddbaddbaddull;
111 UINT64 x_sign, y_sign, p_sign;
112 UINT64 x_exp, y_exp, p_exp;
113 int true_p_exp;
114 UINT128 C1, C2;
200359e8 115
b2a00c89
L
116 BID_SWAP128 (z);
117 // skip cases where at least one operand is NaN or infinity
118 if (!(((x.w[HIGH_128W] & MASK_NAN) == MASK_NAN) ||
119 ((y.w[HIGH_128W] & MASK_NAN) == MASK_NAN) ||
120 ((x.w[HIGH_128W] & MASK_ANY_INF) == MASK_INF) ||
121 ((y.w[HIGH_128W] & MASK_ANY_INF) == MASK_INF))) {
122 // x, y are 0 or f but not inf or NaN => unpack the arguments and check
123 // for non-canonical values
124
125 x_sign = x.w[HIGH_128W] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
126 C1.w[1] = x.w[HIGH_128W] & MASK_COEFF;
127 C1.w[0] = x.w[LOW_128W];
128 // check for non-canonical values - treated as zero
129 if ((x.w[HIGH_128W] & 0x6000000000000000ull) ==
130 0x6000000000000000ull) {
131 // G0_G1=11 => non-canonical
132 x_exp = (x.w[HIGH_128W] << 2) & MASK_EXP; // biased and shifted left 49 bits
133 C1.w[1] = 0; // significand high
134 C1.w[0] = 0; // significand low
135 } else { // G0_G1 != 11
136 x_exp = x.w[HIGH_128W] & MASK_EXP; // biased and shifted left 49 bits
137 if (C1.w[1] > 0x0001ed09bead87c0ull ||
138 (C1.w[1] == 0x0001ed09bead87c0ull &&
139 C1.w[0] > 0x378d8e63ffffffffull)) {
140 // x is non-canonical if coefficient is larger than 10^34 -1
141 C1.w[1] = 0;
142 C1.w[0] = 0;
143 } else { // canonical
144 ;
200359e8 145 }
200359e8 146 }
b2a00c89
L
147 y_sign = y.w[HIGH_128W] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
148 C2.w[1] = y.w[HIGH_128W] & MASK_COEFF;
149 C2.w[0] = y.w[LOW_128W];
150 // check for non-canonical values - treated as zero
151 if ((y.w[HIGH_128W] & 0x6000000000000000ull) ==
152 0x6000000000000000ull) {
153 // G0_G1=11 => non-canonical
154 y_exp = (y.w[HIGH_128W] << 2) & MASK_EXP; // biased and shifted left 49 bits
155 C2.w[1] = 0; // significand high
156 C2.w[0] = 0; // significand low
157 } else { // G0_G1 != 11
158 y_exp = y.w[HIGH_128W] & MASK_EXP; // biased and shifted left 49 bits
159 if (C2.w[1] > 0x0001ed09bead87c0ull ||
160 (C2.w[1] == 0x0001ed09bead87c0ull &&
161 C2.w[0] > 0x378d8e63ffffffffull)) {
162 // y is non-canonical if coefficient is larger than 10^34 -1
163 C2.w[1] = 0;
164 C2.w[0] = 0;
165 } else { // canonical
166 ;
200359e8
L
167 }
168 }
b2a00c89
L
169 p_sign = x_sign ^ y_sign; // sign of the product
170
171 true_p_exp = (x_exp >> 49) - 6176 + (y_exp >> 49) - 6176;
172 // true_p_exp, p_exp are used only for 0 * 0, 0 * f, or f * 0
173 if (true_p_exp < -398)
174 p_exp = 0; // cannot be less than EXP_MIN
175 else if (true_p_exp > 369)
176 p_exp = (UINT64) (369 + 398) << 53; // cannot be more than EXP_MAX
177 else
178 p_exp = (UINT64) (true_p_exp + 398) << 53;
179
180 if ((C1.w[1] == 0x0 && C1.w[0] == 0x0) ||
181 (C2.w[1] == 0x0 && C2.w[0] == 0x0)) {
182 // x = 0 or y = 0
183 // the result is 0
184 res = p_sign | p_exp; // preferred exponent in [EXP_MIN, EXP_MAX]
185 BID_RETURN (res)
186 } // else continue
187 }
188 // swap x and y - ensure that a NaN in x has 'higher precedence' than one in y
189#if DECIMAL_CALL_BY_REFERENCE
190 bid64qqq_fma (&res, &y, &x, &z
191 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
192 _EXC_INFO_ARG);
193#else
194 res = bid64qqq_fma (y, x, z
195 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
196 _EXC_INFO_ARG);
197#endif
198 BID_RETURN (res);
199}
200359e8 200
200359e8 201
b2a00c89
L
202#if DECIMAL_CALL_BY_REFERENCE
203void
204bid128dd_mul (UINT128 * pres, UINT64 * px, UINT64 * py
205 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
206 _EXC_INFO_PARAM) {
207 UINT64 x = *px, y = *py;
208#if !DECIMAL_GLOBAL_ROUNDING
209 unsigned int rnd_mode = *prnd_mode;
210#endif
211#else
212UINT128
213bid128dd_mul (UINT64 x, UINT64 y
214 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
215 _EXC_INFO_PARAM) {
216#endif
217 UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
218 };
219 UINT128 x1, y1;
200359e8 220
b2a00c89
L
221#if DECIMAL_CALL_BY_REFERENCE
222 bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
223 bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
224 bid128_mul (&res, &x1, &y1
225 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
226 _EXC_INFO_ARG);
227#else
228 x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
229 y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
230 res = bid128_mul (x1, y1
231 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
232 _EXC_INFO_ARG);
233#endif
234 BID_RETURN (res);
235}
200359e8 236
200359e8 237
b2a00c89
L
238#if DECIMAL_CALL_BY_REFERENCE
239void
240bid128dq_mul (UINT128 * pres, UINT64 * px, UINT128 * py
241 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
242 _EXC_INFO_PARAM) {
243 UINT64 x = *px;
244#if !DECIMAL_GLOBAL_ROUNDING
245 unsigned int rnd_mode = *prnd_mode;
246#endif
247#else
248UINT128
249bid128dq_mul (UINT64 x, UINT128 y
250 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
251 _EXC_INFO_PARAM) {
252#endif
253 UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
254 };
255 UINT128 x1;
200359e8 256
b2a00c89
L
257#if DECIMAL_CALL_BY_REFERENCE
258 bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
259 bid128_mul (&res, &x1, py
260 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
261 _EXC_INFO_ARG);
262#else
263 x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
264 res = bid128_mul (x1, y
265 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
266 _EXC_INFO_ARG);
267#endif
268 BID_RETURN (res);
269}
200359e8 270
200359e8 271
b2a00c89
L
272#if DECIMAL_CALL_BY_REFERENCE
273void
274bid128qd_mul (UINT128 * pres, UINT128 * px, UINT64 * py
275 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
276 _EXC_INFO_PARAM) {
277 UINT64 y = *py;
278#if !DECIMAL_GLOBAL_ROUNDING
279 unsigned int rnd_mode = *prnd_mode;
280#endif
281#else
282UINT128
283bid128qd_mul (UINT128 x, UINT64 y
284 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
285 _EXC_INFO_PARAM) {
286#endif
287 UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
288 };
289 UINT128 y1;
200359e8 290
b2a00c89
L
291#if DECIMAL_CALL_BY_REFERENCE
292 bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
293 bid128_mul (&res, px, &y1
294 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
295 _EXC_INFO_ARG);
296#else
297 y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
298 res = bid128_mul (x, y1
299 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
300 _EXC_INFO_ARG);
301#endif
302 BID_RETURN (res);
303}
200359e8 304
200359e8 305
b2a00c89
L
306// bid128_mul stands for bid128qq_mul
307#if DECIMAL_CALL_BY_REFERENCE
308void
309bid128_mul (UINT128 * pres, UINT128 * px,
310 UINT128 *
311 py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
312 _EXC_INFO_PARAM) {
313 UINT128 x = *px, y = *py;
200359e8 314
b2a00c89
L
315#if !DECIMAL_GLOBAL_ROUNDING
316 unsigned int rnd_mode = *prnd_mode;
200359e8 317
b2a00c89
L
318#endif
319#else
320UINT128
321bid128_mul (UINT128 x,
322 UINT128 y _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
323 _EXC_INFO_PARAM) {
200359e8 324
b2a00c89
L
325#endif
326 UINT128 z = { {0x0000000000000000ull, 0x5ffe000000000000ull}
327 };
328 UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
329 };
330 UINT64 x_sign, y_sign, p_sign;
331 UINT64 x_exp, y_exp, p_exp;
332 int true_p_exp;
333 UINT128 C1, C2;
200359e8 334
b2a00c89
L
335 BID_SWAP128 (x);
336 BID_SWAP128 (y);
337 // skip cases where at least one operand is NaN or infinity
338 if (!(((x.w[1] & MASK_NAN) == MASK_NAN) ||
339 ((y.w[1] & MASK_NAN) == MASK_NAN) ||
340 ((x.w[1] & MASK_ANY_INF) == MASK_INF) ||
341 ((y.w[1] & MASK_ANY_INF) == MASK_INF))) {
342 // x, y are 0 or f but not inf or NaN => unpack the arguments and check
343 // for non-canonical values
344
345 x_sign = x.w[1] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
346 C1.w[1] = x.w[1] & MASK_COEFF;
347 C1.w[0] = x.w[0];
348 // check for non-canonical values - treated as zero
349 if ((x.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) {
350 // G0_G1=11 => non-canonical
351 x_exp = (x.w[1] << 2) & MASK_EXP; // biased and shifted left 49 bits
352 C1.w[1] = 0; // significand high
353 C1.w[0] = 0; // significand low
354 } else { // G0_G1 != 11
355 x_exp = x.w[1] & MASK_EXP; // biased and shifted left 49 bits
356 if (C1.w[1] > 0x0001ed09bead87c0ull ||
357 (C1.w[1] == 0x0001ed09bead87c0ull &&
358 C1.w[0] > 0x378d8e63ffffffffull)) {
359 // x is non-canonical if coefficient is larger than 10^34 -1
360 C1.w[1] = 0;
361 C1.w[0] = 0;
362 } else { // canonical
363 ;
200359e8 364 }
200359e8 365 }
b2a00c89
L
366 y_sign = y.w[1] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
367 C2.w[1] = y.w[1] & MASK_COEFF;
368 C2.w[0] = y.w[0];
369 // check for non-canonical values - treated as zero
370 if ((y.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) {
371 // G0_G1=11 => non-canonical
372 y_exp = (y.w[1] << 2) & MASK_EXP; // biased and shifted left 49 bits
373 C2.w[1] = 0; // significand high
374 C2.w[0] = 0; // significand low
375 } else { // G0_G1 != 11
376 y_exp = y.w[1] & MASK_EXP; // biased and shifted left 49 bits
377 if (C2.w[1] > 0x0001ed09bead87c0ull ||
378 (C2.w[1] == 0x0001ed09bead87c0ull &&
379 C2.w[0] > 0x378d8e63ffffffffull)) {
380 // y is non-canonical if coefficient is larger than 10^34 -1
381 C2.w[1] = 0;
382 C2.w[0] = 0;
383 } else { // canonical
384 ;
200359e8 385 }
200359e8 386 }
b2a00c89
L
387 p_sign = x_sign ^ y_sign; // sign of the product
388
389 true_p_exp = (x_exp >> 49) - 6176 + (y_exp >> 49) - 6176;
390 // true_p_exp, p_exp are used only for 0 * 0, 0 * f, or f * 0
391 if (true_p_exp < -6176)
392 p_exp = 0; // cannot be less than EXP_MIN
393 else if (true_p_exp > 6111)
394 p_exp = (UINT64) (6111 + 6176) << 49; // cannot be more than EXP_MAX
395 else
396 p_exp = (UINT64) (true_p_exp + 6176) << 49;
397
398 if ((C1.w[1] == 0x0 && C1.w[0] == 0x0) ||
399 (C2.w[1] == 0x0 && C2.w[0] == 0x0)) {
400 // x = 0 or y = 0
401 // the result is 0
402 res.w[1] = p_sign | p_exp; // preferred exponent in [EXP_MIN, EXP_MAX]
403 res.w[0] = 0x0;
404 BID_SWAP128 (res);
405 BID_RETURN (res)
406 } // else continue
200359e8 407 }
200359e8 408
b2a00c89
L
409 BID_SWAP128 (x);
410 BID_SWAP128 (y);
411 BID_SWAP128 (z);
412 // swap x and y - ensure that a NaN in x has 'higher precedence' than one in y
413#if DECIMAL_CALL_BY_REFERENCE
414 bid128_fma (&res, &y, &x, &z
415 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
416 _EXC_INFO_ARG);
417#else
418 res = bid128_fma (y, x, z
419 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
420 _EXC_INFO_ARG);
421#endif
200359e8
L
422 BID_RETURN (res);
423}