1*ec02198aSmrg /* Copyright (C) 2007-2020 Free Software Foundation, Inc.
263d1a8abSmrg
363d1a8abSmrg This file is part of GCC.
463d1a8abSmrg
563d1a8abSmrg GCC is free software; you can redistribute it and/or modify it under
663d1a8abSmrg the terms of the GNU General Public License as published by the Free
763d1a8abSmrg Software Foundation; either version 3, or (at your option) any later
863d1a8abSmrg version.
963d1a8abSmrg
1063d1a8abSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1163d1a8abSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1263d1a8abSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1363d1a8abSmrg for more details.
1463d1a8abSmrg
1563d1a8abSmrg Under Section 7 of GPL version 3, you are granted additional
1663d1a8abSmrg permissions described in the GCC Runtime Library Exception, version
1763d1a8abSmrg 3.1, as published by the Free Software Foundation.
1863d1a8abSmrg
1963d1a8abSmrg You should have received a copy of the GNU General Public License and
2063d1a8abSmrg a copy of the GCC Runtime Library Exception along with this program;
2163d1a8abSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2263d1a8abSmrg <http://www.gnu.org/licenses/>. */
2363d1a8abSmrg
2463d1a8abSmrg #include "bid_internal.h"
2563d1a8abSmrg
2663d1a8abSmrg #define MAX_FORMAT_DIGITS 16
2763d1a8abSmrg #define DECIMAL_EXPONENT_BIAS 398
2863d1a8abSmrg #define MAX_DECIMAL_EXPONENT 767
2963d1a8abSmrg
3063d1a8abSmrg #if DECIMAL_CALL_BY_REFERENCE
3163d1a8abSmrg
3263d1a8abSmrg void
bid64_quantize(UINT64 * pres,UINT64 * px,UINT64 * py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM)3363d1a8abSmrg bid64_quantize (UINT64 * pres, UINT64 * px,
3463d1a8abSmrg UINT64 *
3563d1a8abSmrg py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
3663d1a8abSmrg _EXC_INFO_PARAM) {
3763d1a8abSmrg UINT64 x, y;
3863d1a8abSmrg #else
3963d1a8abSmrg
4063d1a8abSmrg UINT64
4163d1a8abSmrg bid64_quantize (UINT64 x,
4263d1a8abSmrg UINT64 y _RND_MODE_PARAM _EXC_FLAGS_PARAM
4363d1a8abSmrg _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
4463d1a8abSmrg #endif
4563d1a8abSmrg UINT128 CT;
4663d1a8abSmrg UINT64 sign_x, sign_y, coefficient_x, coefficient_y, remainder_h, C64,
4763d1a8abSmrg valid_x;
4863d1a8abSmrg UINT64 tmp, carry, res;
4963d1a8abSmrg int_float tempx;
5063d1a8abSmrg int exponent_x, exponent_y, digits_x, extra_digits, amount, amount2;
5163d1a8abSmrg int expon_diff, total_digits, bin_expon_cx;
5263d1a8abSmrg unsigned rmode, status;
5363d1a8abSmrg
5463d1a8abSmrg #if DECIMAL_CALL_BY_REFERENCE
5563d1a8abSmrg #if !DECIMAL_GLOBAL_ROUNDING
5663d1a8abSmrg _IDEC_round rnd_mode = *prnd_mode;
5763d1a8abSmrg #endif
5863d1a8abSmrg x = *px;
5963d1a8abSmrg y = *py;
6063d1a8abSmrg #endif
6163d1a8abSmrg
6263d1a8abSmrg valid_x = unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x);
6363d1a8abSmrg // unpack arguments, check for NaN or Infinity
6463d1a8abSmrg if (!unpack_BID64 (&sign_y, &exponent_y, &coefficient_y, y)) {
6563d1a8abSmrg // Inf. or NaN or 0
6663d1a8abSmrg #ifdef SET_STATUS_FLAGS
6763d1a8abSmrg if ((x & SNAN_MASK64) == SNAN_MASK64) // y is sNaN
6863d1a8abSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
6963d1a8abSmrg #endif
7063d1a8abSmrg
7163d1a8abSmrg // x=Inf, y=Inf?
7263d1a8abSmrg if (((coefficient_x << 1) == 0xf000000000000000ull)
7363d1a8abSmrg && ((coefficient_y << 1) == 0xf000000000000000ull)) {
7463d1a8abSmrg res = coefficient_x;
7563d1a8abSmrg BID_RETURN (res);
7663d1a8abSmrg }
7763d1a8abSmrg // Inf or NaN?
7863d1a8abSmrg if ((y & 0x7800000000000000ull) == 0x7800000000000000ull) {
7963d1a8abSmrg #ifdef SET_STATUS_FLAGS
8063d1a8abSmrg if (((y & 0x7e00000000000000ull) == 0x7e00000000000000ull) // sNaN
8163d1a8abSmrg || (((y & 0x7c00000000000000ull) == 0x7800000000000000ull) && //Inf
8263d1a8abSmrg ((x & 0x7c00000000000000ull) < 0x7800000000000000ull)))
8363d1a8abSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
8463d1a8abSmrg #endif
8563d1a8abSmrg if ((y & NAN_MASK64) != NAN_MASK64)
8663d1a8abSmrg coefficient_y = 0;
8763d1a8abSmrg if ((x & NAN_MASK64) != NAN_MASK64) {
8863d1a8abSmrg res = 0x7c00000000000000ull | (coefficient_y & QUIET_MASK64);
8963d1a8abSmrg if (((y & NAN_MASK64) != NAN_MASK64) && ((x & NAN_MASK64) == 0x7800000000000000ull))
9063d1a8abSmrg res = x;
9163d1a8abSmrg BID_RETURN (res);
9263d1a8abSmrg }
9363d1a8abSmrg }
9463d1a8abSmrg }
9563d1a8abSmrg // unpack arguments, check for NaN or Infinity
9663d1a8abSmrg if (!valid_x) {
9763d1a8abSmrg // x is Inf. or NaN or 0
9863d1a8abSmrg
9963d1a8abSmrg // Inf or NaN?
10063d1a8abSmrg if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) {
10163d1a8abSmrg #ifdef SET_STATUS_FLAGS
10263d1a8abSmrg if (((x & 0x7e00000000000000ull) == 0x7e00000000000000ull) // sNaN
10363d1a8abSmrg || ((x & 0x7c00000000000000ull) == 0x7800000000000000ull)) //Inf
10463d1a8abSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
10563d1a8abSmrg #endif
10663d1a8abSmrg if ((x & NAN_MASK64) != NAN_MASK64)
10763d1a8abSmrg coefficient_x = 0;
10863d1a8abSmrg res = 0x7c00000000000000ull | (coefficient_x & QUIET_MASK64);
10963d1a8abSmrg BID_RETURN (res);
11063d1a8abSmrg }
11163d1a8abSmrg
11263d1a8abSmrg res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, 0);
11363d1a8abSmrg BID_RETURN (res);
11463d1a8abSmrg }
11563d1a8abSmrg // get number of decimal digits in coefficient_x
11663d1a8abSmrg tempx.d = (float) coefficient_x;
11763d1a8abSmrg bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
11863d1a8abSmrg digits_x = estimate_decimal_digits[bin_expon_cx];
11963d1a8abSmrg if (coefficient_x >= power10_table_128[digits_x].w[0])
12063d1a8abSmrg digits_x++;
12163d1a8abSmrg
12263d1a8abSmrg expon_diff = exponent_x - exponent_y;
12363d1a8abSmrg total_digits = digits_x + expon_diff;
12463d1a8abSmrg
12563d1a8abSmrg // check range of scaled coefficient
12663d1a8abSmrg if ((UINT32) (total_digits + 1) <= 17) {
12763d1a8abSmrg if (expon_diff >= 0) {
12863d1a8abSmrg coefficient_x *= power10_table_128[expon_diff].w[0];
12963d1a8abSmrg res = very_fast_get_BID64 (sign_x, exponent_y, coefficient_x);
13063d1a8abSmrg BID_RETURN (res);
13163d1a8abSmrg }
13263d1a8abSmrg // must round off -expon_diff digits
13363d1a8abSmrg extra_digits = -expon_diff;
13463d1a8abSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
13563d1a8abSmrg #ifndef IEEE_ROUND_NEAREST
13663d1a8abSmrg rmode = rnd_mode;
13763d1a8abSmrg if (sign_x && (unsigned) (rmode - 1) < 2)
13863d1a8abSmrg rmode = 3 - rmode;
13963d1a8abSmrg #else
14063d1a8abSmrg rmode = 0;
14163d1a8abSmrg #endif
14263d1a8abSmrg #else
14363d1a8abSmrg rmode = 0;
14463d1a8abSmrg #endif
14563d1a8abSmrg coefficient_x += round_const_table[rmode][extra_digits];
14663d1a8abSmrg
14763d1a8abSmrg // get P*(2^M[extra_digits])/10^extra_digits
14863d1a8abSmrg __mul_64x64_to_128 (CT, coefficient_x,
14963d1a8abSmrg reciprocals10_64[extra_digits]);
15063d1a8abSmrg
15163d1a8abSmrg // now get P/10^extra_digits: shift C64 right by M[extra_digits]-128
15263d1a8abSmrg amount = short_recip_scale[extra_digits];
15363d1a8abSmrg C64 = CT.w[1] >> amount;
15463d1a8abSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
15563d1a8abSmrg #ifndef IEEE_ROUND_NEAREST
15663d1a8abSmrg if (rnd_mode == 0)
15763d1a8abSmrg #endif
15863d1a8abSmrg if (C64 & 1) {
15963d1a8abSmrg // check whether fractional part of initial_P/10^extra_digits
16063d1a8abSmrg // is exactly .5
16163d1a8abSmrg // this is the same as fractional part of
16263d1a8abSmrg // (initial_P + 0.5*10^extra_digits)/10^extra_digits is exactly zero
16363d1a8abSmrg
16463d1a8abSmrg // get remainder
16563d1a8abSmrg amount2 = 64 - amount;
16663d1a8abSmrg remainder_h = 0;
16763d1a8abSmrg remainder_h--;
16863d1a8abSmrg remainder_h >>= amount2;
16963d1a8abSmrg remainder_h = remainder_h & CT.w[1];
17063d1a8abSmrg
17163d1a8abSmrg // test whether fractional part is 0
17263d1a8abSmrg if (!remainder_h && (CT.w[0] < reciprocals10_64[extra_digits])) {
17363d1a8abSmrg C64--;
17463d1a8abSmrg }
17563d1a8abSmrg }
17663d1a8abSmrg #endif
17763d1a8abSmrg
17863d1a8abSmrg #ifdef SET_STATUS_FLAGS
17963d1a8abSmrg status = INEXACT_EXCEPTION;
18063d1a8abSmrg // get remainder
18163d1a8abSmrg remainder_h = CT.w[1] << (64 - amount);
18263d1a8abSmrg switch (rmode) {
18363d1a8abSmrg case ROUNDING_TO_NEAREST:
18463d1a8abSmrg case ROUNDING_TIES_AWAY:
18563d1a8abSmrg // test whether fractional part is 0
18663d1a8abSmrg if ((remainder_h == 0x8000000000000000ull)
18763d1a8abSmrg && (CT.w[0] < reciprocals10_64[extra_digits]))
18863d1a8abSmrg status = EXACT_STATUS;
18963d1a8abSmrg break;
19063d1a8abSmrg case ROUNDING_DOWN:
19163d1a8abSmrg case ROUNDING_TO_ZERO:
19263d1a8abSmrg if (!remainder_h && (CT.w[0] < reciprocals10_64[extra_digits]))
19363d1a8abSmrg status = EXACT_STATUS;
19463d1a8abSmrg //if(!C64 && rmode==ROUNDING_DOWN) sign_s=sign_y;
19563d1a8abSmrg break;
19663d1a8abSmrg default:
19763d1a8abSmrg // round up
19863d1a8abSmrg __add_carry_out (tmp, carry, CT.w[0],
19963d1a8abSmrg reciprocals10_64[extra_digits]);
20063d1a8abSmrg if ((remainder_h >> (64 - amount)) + carry >=
20163d1a8abSmrg (((UINT64) 1) << amount))
20263d1a8abSmrg status = EXACT_STATUS;
20363d1a8abSmrg break;
20463d1a8abSmrg }
20563d1a8abSmrg __set_status_flags (pfpsf, status);
20663d1a8abSmrg #endif
20763d1a8abSmrg
20863d1a8abSmrg res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, C64);
20963d1a8abSmrg BID_RETURN (res);
21063d1a8abSmrg }
21163d1a8abSmrg
21263d1a8abSmrg if (total_digits < 0) {
21363d1a8abSmrg #ifdef SET_STATUS_FLAGS
21463d1a8abSmrg __set_status_flags (pfpsf, INEXACT_EXCEPTION);
21563d1a8abSmrg #endif
21663d1a8abSmrg C64 = 0;
21763d1a8abSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
21863d1a8abSmrg #ifndef IEEE_ROUND_NEAREST
21963d1a8abSmrg rmode = rnd_mode;
22063d1a8abSmrg if (sign_x && (unsigned) (rmode - 1) < 2)
22163d1a8abSmrg rmode = 3 - rmode;
22263d1a8abSmrg if (rmode == ROUNDING_UP)
22363d1a8abSmrg C64 = 1;
22463d1a8abSmrg #endif
22563d1a8abSmrg #endif
22663d1a8abSmrg res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, C64);
22763d1a8abSmrg BID_RETURN (res);
22863d1a8abSmrg }
22963d1a8abSmrg // else more than 16 digits in coefficient
23063d1a8abSmrg #ifdef SET_STATUS_FLAGS
23163d1a8abSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
23263d1a8abSmrg #endif
23363d1a8abSmrg res = 0x7c00000000000000ull;
23463d1a8abSmrg BID_RETURN (res);
23563d1a8abSmrg
23663d1a8abSmrg }
237