1/* Copyright (C) 2007-2022 Free Software Foundation, Inc.
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
7Software Foundation; either version 3, or (at your option) any later
8version.
9
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
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/>.  */
23
24#include "bid_internal.h"
25
26/*****************************************************************************
27 *  BID64_round_integral_exact
28 ****************************************************************************/
29
30#if DECIMAL_CALL_BY_REFERENCE
31void
32bid64_from_int32 (UINT64 * pres,
33		  int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
34  int x = *px;
35#else
36UINT64
37bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
38#endif
39  UINT64 res;
40
41  // if integer is negative, put the absolute value
42  // in the lowest 32bits of the result
43  if ((x & SIGNMASK32) == SIGNMASK32) {
44    // negative int32
45    x = ~x + 1;	// 2's complement of x
46    res = (unsigned int) x | 0xb1c0000000000000ull;
47    // (exp << 53)) = biased exp. is 0
48  } else {	// positive int32
49    res = x | 0x31c0000000000000ull;	// (exp << 53)) = biased exp. is 0
50  }
51  BID_RETURN (res);
52}
53
54#if DECIMAL_CALL_BY_REFERENCE
55void
56bid64_from_uint32 (UINT64 * pres, unsigned int *px
57		   _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
58  unsigned int x = *px;
59#else
60UINT64
61bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
62#endif
63  UINT64 res;
64
65  res = x | 0x31c0000000000000ull;	// (exp << 53)) = biased exp. is 0
66  BID_RETURN (res);
67}
68
69#if DECIMAL_CALL_BY_REFERENCE
70void
71bid64_from_int64 (UINT64 * pres, SINT64 * px
72		  _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
73		  _EXC_INFO_PARAM) {
74  SINT64 x = *px;
75#if !DECIMAL_GLOBAL_ROUNDING
76  unsigned int rnd_mode = *prnd_mode;
77#endif
78#else
79UINT64
80bid64_from_int64 (SINT64 x
81		  _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
82		  _EXC_INFO_PARAM) {
83#endif
84
85  UINT64 res;
86  UINT64 x_sign, C;
87  unsigned int q, ind;
88  int incr_exp = 0;
89  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
90  int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
91
92  x_sign = x & 0x8000000000000000ull;
93  // if the integer is negative, use the absolute value
94  if (x_sign)
95    C = ~((UINT64) x) + 1;
96  else
97    C = x;
98  if (C <= BID64_SIG_MAX) {	// |C| <= 10^16-1 and the result is exact
99    if (C < 0x0020000000000000ull) {	// C < 2^53
100      res = x_sign | 0x31c0000000000000ull | C;
101    } else {	// C >= 2^53
102      res =
103	x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull);
104    }
105  } else {	// |C| >= 10^16 and the result may be inexact
106    // the smallest |C| is 10^16 which has 17 decimal digits
107    // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
108    if (C < 0x16345785d8a0000ull) {	// x < 10^17
109      q = 17;
110      ind = 1;	// number of digits to remove for q = 17
111    } else if (C < 0xde0b6b3a7640000ull) {	// C < 10^18
112      q = 18;
113      ind = 2;	// number of digits to remove for q = 18
114    } else {	// C < 10^19
115      q = 19;
116      ind = 3;	// number of digits to remove for q = 19
117    }
118    // overflow and underflow are not possible
119    // Note: performace can be improved by inlining this call
120    round64_2_18 (	// will work for 19 digits too if C fits in 64 bits
121		   q, ind, C, &res, &incr_exp,
122		   &is_midpoint_lt_even, &is_midpoint_gt_even,
123		   &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
124    if (incr_exp)
125      ind++;
126    // set the inexact flag
127    if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
128	is_midpoint_lt_even || is_midpoint_gt_even)
129      *pfpsf |= INEXACT_EXCEPTION;
130    // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
131    if (rnd_mode != ROUNDING_TO_NEAREST) {
132      if ((!x_sign
133	   && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint)
134	       ||
135	       ((rnd_mode == ROUNDING_TIES_AWAY
136		 || rnd_mode == ROUNDING_UP) && is_midpoint_gt_even)))
137	  || (x_sign
138	      && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint)
139		  ||
140		  ((rnd_mode == ROUNDING_TIES_AWAY
141		    || rnd_mode == ROUNDING_DOWN)
142		   && is_midpoint_gt_even)))) {
143	res = res + 1;
144	if (res == 0x002386f26fc10000ull) {	// res = 10^16 => rounding overflow
145	  res = 0x00038d7ea4c68000ull;	// 10^15
146	  ind = ind + 1;
147	}
148      } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
149		 ((x_sign && (rnd_mode == ROUNDING_UP ||
150			      rnd_mode == ROUNDING_TO_ZERO)) ||
151		  (!x_sign && (rnd_mode == ROUNDING_DOWN ||
152			       rnd_mode == ROUNDING_TO_ZERO)))) {
153	res = res - 1;
154	// check if we crossed into the lower decade
155	if (res == 0x00038d7ea4c67fffull) {	// 10^15 - 1
156	  res = 0x002386f26fc0ffffull;	// 10^16 - 1
157	  ind = ind - 1;
158	}
159      } else {
160	;	// exact, the result is already correct
161      }
162    }
163    if (res < 0x0020000000000000ull) {	// res < 2^53
164      res = x_sign | (((UINT64) ind + 398) << 53) | res;
165    } else {	// res >= 2^53
166      res =
167	x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
168	(res & 0x0007ffffffffffffull);
169    }
170  }
171  BID_RETURN (res);
172}
173
174#if DECIMAL_CALL_BY_REFERENCE
175void
176bid64_from_uint64 (UINT64 * pres, UINT64 * px
177		   _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
178		   _EXC_INFO_PARAM) {
179  UINT64 x = *px;
180#if !DECIMAL_GLOBAL_ROUNDING
181  unsigned int rnd_mode = *prnd_mode;
182#endif
183#else
184UINT64
185bid64_from_uint64 (UINT64 x
186		   _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
187		   _EXC_INFO_PARAM) {
188#endif
189
190  UINT64 res;
191  UINT128 x128, res128;
192  unsigned int q, ind;
193  int incr_exp = 0;
194  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
195  int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
196
197  if (x <= BID64_SIG_MAX) {	// x <= 10^16-1 and the result is exact
198    if (x < 0x0020000000000000ull) {	// x < 2^53
199      res = 0x31c0000000000000ull | x;
200    } else {	// x >= 2^53
201      res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull);
202    }
203  } else {	// x >= 10^16 and the result may be inexact
204    // the smallest x is 10^16 which has 17 decimal digits
205    // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits
206    if (x < 0x16345785d8a0000ull) {	// x < 10^17
207      q = 17;
208      ind = 1;	// number of digits to remove for q = 17
209    } else if (x < 0xde0b6b3a7640000ull) {	// x < 10^18
210      q = 18;
211      ind = 2;	// number of digits to remove for q = 18
212    } else if (x < 0x8ac7230489e80000ull) {	// x < 10^19
213      q = 19;
214      ind = 3;	// number of digits to remove for q = 19
215    } else {	// x < 10^20
216      q = 20;
217      ind = 4;	// number of digits to remove for q = 20
218    }
219    // overflow and underflow are not possible
220    // Note: performace can be improved by inlining this call
221    if (q <= 19) {
222      round64_2_18 (	// will work for 20 digits too if x fits in 64 bits
223		     q, ind, x, &res, &incr_exp,
224		     &is_midpoint_lt_even, &is_midpoint_gt_even,
225		     &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
226    } else {	// q = 20
227      x128.w[1] = 0x0;
228      x128.w[0] = x;
229      round128_19_38 (q, ind, x128, &res128, &incr_exp,
230		      &is_midpoint_lt_even, &is_midpoint_gt_even,
231		      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
232      res = res128.w[0];	// res.w[1] is 0
233    }
234    if (incr_exp)
235      ind++;
236    // set the inexact flag
237    if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
238	is_midpoint_lt_even || is_midpoint_gt_even)
239      *pfpsf |= INEXACT_EXCEPTION;
240    // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
241    if (rnd_mode != ROUNDING_TO_NEAREST) {
242      if ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) ||
243	  ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP)
244	   && is_midpoint_gt_even)) {
245	res = res + 1;
246	if (res == 0x002386f26fc10000ull) {	// res = 10^16 => rounding overflow
247	  res = 0x00038d7ea4c68000ull;	// 10^15
248	  ind = ind + 1;
249	}
250      } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
251		 (rnd_mode == ROUNDING_DOWN ||
252		  rnd_mode == ROUNDING_TO_ZERO)) {
253	res = res - 1;
254	// check if we crossed into the lower decade
255	if (res == 0x00038d7ea4c67fffull) {	// 10^15 - 1
256	  res = 0x002386f26fc0ffffull;	// 10^16 - 1
257	  ind = ind - 1;
258	}
259      } else {
260	;	// exact, the result is already correct
261      }
262    }
263    if (res < 0x0020000000000000ull) {	// res < 2^53
264      res = (((UINT64) ind + 398) << 53) | res;
265    } else {	// res >= 2^53
266      res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
267	(res & 0x0007ffffffffffffull);
268    }
269  }
270  BID_RETURN (res);
271}
272
273#if DECIMAL_CALL_BY_REFERENCE
274void
275bid128_from_int32 (UINT128 * pres,
276		   int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
277  int x = *px;
278#else
279UINT128
280bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
281#endif
282  UINT128 res;
283
284  // if integer is negative, use the absolute value
285  if ((x & SIGNMASK32) == SIGNMASK32) {
286    res.w[HIGH_128W] = 0xb040000000000000ull;
287    res.w[LOW_128W] = ~((unsigned int) x) + 1;	// 2's complement of x
288  } else {
289    res.w[HIGH_128W] = 0x3040000000000000ull;
290    res.w[LOW_128W] = (unsigned int) x;
291  }
292  BID_RETURN (res);
293}
294
295#if DECIMAL_CALL_BY_REFERENCE
296void
297bid128_from_uint32 (UINT128 * pres, unsigned int *px
298		    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
299  unsigned int x = *px;
300#else
301UINT128
302bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
303#endif
304  UINT128 res;
305
306  res.w[HIGH_128W] = 0x3040000000000000ull;
307  res.w[LOW_128W] = x;
308  BID_RETURN (res);
309}
310
311#if DECIMAL_CALL_BY_REFERENCE
312void
313bid128_from_int64 (UINT128 * pres, SINT64 * px
314		   _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
315  SINT64 x = *px;
316#else
317UINT128
318bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
319#endif
320
321  UINT128 res;
322
323  // if integer is negative, use the absolute value
324  if ((x & SIGNMASK64) == SIGNMASK64) {
325    res.w[HIGH_128W] = 0xb040000000000000ull;
326    res.w[LOW_128W] = ~x + 1;	// 2's complement of x
327  } else {
328    res.w[HIGH_128W] = 0x3040000000000000ull;
329    res.w[LOW_128W] = x;
330  }
331  BID_RETURN (res);
332}
333
334#if DECIMAL_CALL_BY_REFERENCE
335void
336bid128_from_uint64 (UINT128 * pres, UINT64 * px
337		    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
338  UINT64 x = *px;
339#else
340UINT128
341bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
342#endif
343
344  UINT128 res;
345
346  res.w[HIGH_128W] = 0x3040000000000000ull;
347  res.w[LOW_128W] = x;
348  BID_RETURN (res);
349}
350