1 /* Copyright (C) 2007-2022 Free Software Foundation, Inc.
2 
3 This file is part of GCC.
4 
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 3, or (at your option) any later
8 version.
9 
10 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 for more details.
14 
15 Under Section 7 of GPL version 3, you are granted additional
16 permissions described in the GCC Runtime Library Exception, version
17 3.1, as published by the Free Software Foundation.
18 
19 You should have received a copy of the GNU General Public License and
20 a copy of the GCC Runtime Library Exception along with this program;
21 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22 <http://www.gnu.org/licenses/>.  */
23 
24 #include "bid_internal.h"
25 
26 #if DECIMAL_CALL_BY_REFERENCE
27 void
bid64dq_mul(UINT64 * pres,UINT64 * px,UINT128 * py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM)28 bid64dq_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;
32 #if !DECIMAL_GLOBAL_ROUNDING
33   unsigned int rnd_mode = *prnd_mode;
34 #endif
35 #else
36 UINT64
37 bid64dq_mul (UINT64 x, UINT128 y
38                _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
39                _EXC_INFO_PARAM) {
40 #endif
41   UINT64 res = 0xbaddbaddbaddbaddull;
42   UINT128 x1;
43 
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 }
57 
58 
59 #if DECIMAL_CALL_BY_REFERENCE
60 void
61 bid64qd_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
69 UINT64
70 bid64qd_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;
76 
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 }
90 
91 
92 #if DECIMAL_CALL_BY_REFERENCE
93 void
94 bid64qq_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
102 UINT64
103 bid64qq_mul (UINT128 x, UINT128 y
104                _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
105                _EXC_INFO_PARAM) {
106 #endif
107 
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;
115 
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           ;
145       }
146     }
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           ;
167       }
168     }
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 }
200 
201 
202 #if DECIMAL_CALL_BY_REFERENCE
203 void
204 bid128dd_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
212 UINT128
213 bid128dd_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;
220 
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 }
236 
237 
238 #if DECIMAL_CALL_BY_REFERENCE
239 void
240 bid128dq_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
248 UINT128
249 bid128dq_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;
256 
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 }
270 
271 
272 #if DECIMAL_CALL_BY_REFERENCE
273 void
274 bid128qd_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
282 UINT128
283 bid128qd_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;
290 
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 }
304 
305 
306 // bid128_mul stands for bid128qq_mul
307 #if DECIMAL_CALL_BY_REFERENCE
308 void
309 bid128_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;
314 
315 #if !DECIMAL_GLOBAL_ROUNDING
316   unsigned int rnd_mode = *prnd_mode;
317 
318 #endif
319 #else
320 UINT128
321 bid128_mul (UINT128 x,
322               UINT128 y _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
323               _EXC_INFO_PARAM) {
324 
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;
334 
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           ;
364       }
365     }
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           ;
385       }
386     }
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
407   }
408 
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
422   BID_RETURN (res);
423 }
424