1*8feb0f0bSmrg /* Copyright (C) 2007-2020 Free Software Foundation, Inc.
236ac495dSmrg
336ac495dSmrg This file is part of GCC.
436ac495dSmrg
536ac495dSmrg GCC is free software; you can redistribute it and/or modify it under
636ac495dSmrg the terms of the GNU General Public License as published by the Free
736ac495dSmrg Software Foundation; either version 3, or (at your option) any later
836ac495dSmrg version.
936ac495dSmrg
1036ac495dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1136ac495dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1236ac495dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1336ac495dSmrg for more details.
1436ac495dSmrg
1536ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1636ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1736ac495dSmrg 3.1, as published by the Free Software Foundation.
1836ac495dSmrg
1936ac495dSmrg You should have received a copy of the GNU General Public License and
2036ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2136ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2236ac495dSmrg <http://www.gnu.org/licenses/>. */
2336ac495dSmrg
2436ac495dSmrg #include "bid_internal.h"
2536ac495dSmrg
2636ac495dSmrg #define MAX_FORMAT_DIGITS 16
2736ac495dSmrg #define DECIMAL_EXPONENT_BIAS 398
2836ac495dSmrg #define MAX_DECIMAL_EXPONENT 767
2936ac495dSmrg
3036ac495dSmrg #if DECIMAL_CALL_BY_REFERENCE
3136ac495dSmrg
3236ac495dSmrg void
bid64_quantize(UINT64 * pres,UINT64 * px,UINT64 * py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM)3336ac495dSmrg bid64_quantize (UINT64 * pres, UINT64 * px,
3436ac495dSmrg UINT64 *
3536ac495dSmrg py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
3636ac495dSmrg _EXC_INFO_PARAM) {
3736ac495dSmrg UINT64 x, y;
3836ac495dSmrg #else
3936ac495dSmrg
4036ac495dSmrg UINT64
4136ac495dSmrg bid64_quantize (UINT64 x,
4236ac495dSmrg UINT64 y _RND_MODE_PARAM _EXC_FLAGS_PARAM
4336ac495dSmrg _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
4436ac495dSmrg #endif
4536ac495dSmrg UINT128 CT;
4636ac495dSmrg UINT64 sign_x, sign_y, coefficient_x, coefficient_y, remainder_h, C64,
4736ac495dSmrg valid_x;
4836ac495dSmrg UINT64 tmp, carry, res;
4936ac495dSmrg int_float tempx;
5036ac495dSmrg int exponent_x, exponent_y, digits_x, extra_digits, amount, amount2;
5136ac495dSmrg int expon_diff, total_digits, bin_expon_cx;
5236ac495dSmrg unsigned rmode, status;
5336ac495dSmrg
5436ac495dSmrg #if DECIMAL_CALL_BY_REFERENCE
5536ac495dSmrg #if !DECIMAL_GLOBAL_ROUNDING
5636ac495dSmrg _IDEC_round rnd_mode = *prnd_mode;
5736ac495dSmrg #endif
5836ac495dSmrg x = *px;
5936ac495dSmrg y = *py;
6036ac495dSmrg #endif
6136ac495dSmrg
6236ac495dSmrg valid_x = unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x);
6336ac495dSmrg // unpack arguments, check for NaN or Infinity
6436ac495dSmrg if (!unpack_BID64 (&sign_y, &exponent_y, &coefficient_y, y)) {
6536ac495dSmrg // Inf. or NaN or 0
6636ac495dSmrg #ifdef SET_STATUS_FLAGS
6736ac495dSmrg if ((x & SNAN_MASK64) == SNAN_MASK64) // y is sNaN
6836ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
6936ac495dSmrg #endif
7036ac495dSmrg
7136ac495dSmrg // x=Inf, y=Inf?
7236ac495dSmrg if (((coefficient_x << 1) == 0xf000000000000000ull)
7336ac495dSmrg && ((coefficient_y << 1) == 0xf000000000000000ull)) {
7436ac495dSmrg res = coefficient_x;
7536ac495dSmrg BID_RETURN (res);
7636ac495dSmrg }
7736ac495dSmrg // Inf or NaN?
7836ac495dSmrg if ((y & 0x7800000000000000ull) == 0x7800000000000000ull) {
7936ac495dSmrg #ifdef SET_STATUS_FLAGS
8036ac495dSmrg if (((y & 0x7e00000000000000ull) == 0x7e00000000000000ull) // sNaN
8136ac495dSmrg || (((y & 0x7c00000000000000ull) == 0x7800000000000000ull) && //Inf
8236ac495dSmrg ((x & 0x7c00000000000000ull) < 0x7800000000000000ull)))
8336ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
8436ac495dSmrg #endif
8536ac495dSmrg if ((y & NAN_MASK64) != NAN_MASK64)
8636ac495dSmrg coefficient_y = 0;
8736ac495dSmrg if ((x & NAN_MASK64) != NAN_MASK64) {
8836ac495dSmrg res = 0x7c00000000000000ull | (coefficient_y & QUIET_MASK64);
8936ac495dSmrg if (((y & NAN_MASK64) != NAN_MASK64) && ((x & NAN_MASK64) == 0x7800000000000000ull))
9036ac495dSmrg res = x;
9136ac495dSmrg BID_RETURN (res);
9236ac495dSmrg }
9336ac495dSmrg }
9436ac495dSmrg }
9536ac495dSmrg // unpack arguments, check for NaN or Infinity
9636ac495dSmrg if (!valid_x) {
9736ac495dSmrg // x is Inf. or NaN or 0
9836ac495dSmrg
9936ac495dSmrg // Inf or NaN?
10036ac495dSmrg if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) {
10136ac495dSmrg #ifdef SET_STATUS_FLAGS
10236ac495dSmrg if (((x & 0x7e00000000000000ull) == 0x7e00000000000000ull) // sNaN
10336ac495dSmrg || ((x & 0x7c00000000000000ull) == 0x7800000000000000ull)) //Inf
10436ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
10536ac495dSmrg #endif
10636ac495dSmrg if ((x & NAN_MASK64) != NAN_MASK64)
10736ac495dSmrg coefficient_x = 0;
10836ac495dSmrg res = 0x7c00000000000000ull | (coefficient_x & QUIET_MASK64);
10936ac495dSmrg BID_RETURN (res);
11036ac495dSmrg }
11136ac495dSmrg
11236ac495dSmrg res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, 0);
11336ac495dSmrg BID_RETURN (res);
11436ac495dSmrg }
11536ac495dSmrg // get number of decimal digits in coefficient_x
11636ac495dSmrg tempx.d = (float) coefficient_x;
11736ac495dSmrg bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
11836ac495dSmrg digits_x = estimate_decimal_digits[bin_expon_cx];
11936ac495dSmrg if (coefficient_x >= power10_table_128[digits_x].w[0])
12036ac495dSmrg digits_x++;
12136ac495dSmrg
12236ac495dSmrg expon_diff = exponent_x - exponent_y;
12336ac495dSmrg total_digits = digits_x + expon_diff;
12436ac495dSmrg
12536ac495dSmrg // check range of scaled coefficient
12636ac495dSmrg if ((UINT32) (total_digits + 1) <= 17) {
12736ac495dSmrg if (expon_diff >= 0) {
12836ac495dSmrg coefficient_x *= power10_table_128[expon_diff].w[0];
12936ac495dSmrg res = very_fast_get_BID64 (sign_x, exponent_y, coefficient_x);
13036ac495dSmrg BID_RETURN (res);
13136ac495dSmrg }
13236ac495dSmrg // must round off -expon_diff digits
13336ac495dSmrg extra_digits = -expon_diff;
13436ac495dSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
13536ac495dSmrg #ifndef IEEE_ROUND_NEAREST
13636ac495dSmrg rmode = rnd_mode;
13736ac495dSmrg if (sign_x && (unsigned) (rmode - 1) < 2)
13836ac495dSmrg rmode = 3 - rmode;
13936ac495dSmrg #else
14036ac495dSmrg rmode = 0;
14136ac495dSmrg #endif
14236ac495dSmrg #else
14336ac495dSmrg rmode = 0;
14436ac495dSmrg #endif
14536ac495dSmrg coefficient_x += round_const_table[rmode][extra_digits];
14636ac495dSmrg
14736ac495dSmrg // get P*(2^M[extra_digits])/10^extra_digits
14836ac495dSmrg __mul_64x64_to_128 (CT, coefficient_x,
14936ac495dSmrg reciprocals10_64[extra_digits]);
15036ac495dSmrg
15136ac495dSmrg // now get P/10^extra_digits: shift C64 right by M[extra_digits]-128
15236ac495dSmrg amount = short_recip_scale[extra_digits];
15336ac495dSmrg C64 = CT.w[1] >> amount;
15436ac495dSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
15536ac495dSmrg #ifndef IEEE_ROUND_NEAREST
15636ac495dSmrg if (rnd_mode == 0)
15736ac495dSmrg #endif
15836ac495dSmrg if (C64 & 1) {
15936ac495dSmrg // check whether fractional part of initial_P/10^extra_digits
16036ac495dSmrg // is exactly .5
16136ac495dSmrg // this is the same as fractional part of
16236ac495dSmrg // (initial_P + 0.5*10^extra_digits)/10^extra_digits is exactly zero
16336ac495dSmrg
16436ac495dSmrg // get remainder
16536ac495dSmrg amount2 = 64 - amount;
16636ac495dSmrg remainder_h = 0;
16736ac495dSmrg remainder_h--;
16836ac495dSmrg remainder_h >>= amount2;
16936ac495dSmrg remainder_h = remainder_h & CT.w[1];
17036ac495dSmrg
17136ac495dSmrg // test whether fractional part is 0
17236ac495dSmrg if (!remainder_h && (CT.w[0] < reciprocals10_64[extra_digits])) {
17336ac495dSmrg C64--;
17436ac495dSmrg }
17536ac495dSmrg }
17636ac495dSmrg #endif
17736ac495dSmrg
17836ac495dSmrg #ifdef SET_STATUS_FLAGS
17936ac495dSmrg status = INEXACT_EXCEPTION;
18036ac495dSmrg // get remainder
18136ac495dSmrg remainder_h = CT.w[1] << (64 - amount);
18236ac495dSmrg switch (rmode) {
18336ac495dSmrg case ROUNDING_TO_NEAREST:
18436ac495dSmrg case ROUNDING_TIES_AWAY:
18536ac495dSmrg // test whether fractional part is 0
18636ac495dSmrg if ((remainder_h == 0x8000000000000000ull)
18736ac495dSmrg && (CT.w[0] < reciprocals10_64[extra_digits]))
18836ac495dSmrg status = EXACT_STATUS;
18936ac495dSmrg break;
19036ac495dSmrg case ROUNDING_DOWN:
19136ac495dSmrg case ROUNDING_TO_ZERO:
19236ac495dSmrg if (!remainder_h && (CT.w[0] < reciprocals10_64[extra_digits]))
19336ac495dSmrg status = EXACT_STATUS;
19436ac495dSmrg //if(!C64 && rmode==ROUNDING_DOWN) sign_s=sign_y;
19536ac495dSmrg break;
19636ac495dSmrg default:
19736ac495dSmrg // round up
19836ac495dSmrg __add_carry_out (tmp, carry, CT.w[0],
19936ac495dSmrg reciprocals10_64[extra_digits]);
20036ac495dSmrg if ((remainder_h >> (64 - amount)) + carry >=
20136ac495dSmrg (((UINT64) 1) << amount))
20236ac495dSmrg status = EXACT_STATUS;
20336ac495dSmrg break;
20436ac495dSmrg }
20536ac495dSmrg __set_status_flags (pfpsf, status);
20636ac495dSmrg #endif
20736ac495dSmrg
20836ac495dSmrg res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, C64);
20936ac495dSmrg BID_RETURN (res);
21036ac495dSmrg }
21136ac495dSmrg
21236ac495dSmrg if (total_digits < 0) {
21336ac495dSmrg #ifdef SET_STATUS_FLAGS
21436ac495dSmrg __set_status_flags (pfpsf, INEXACT_EXCEPTION);
21536ac495dSmrg #endif
21636ac495dSmrg C64 = 0;
21736ac495dSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
21836ac495dSmrg #ifndef IEEE_ROUND_NEAREST
21936ac495dSmrg rmode = rnd_mode;
22036ac495dSmrg if (sign_x && (unsigned) (rmode - 1) < 2)
22136ac495dSmrg rmode = 3 - rmode;
22236ac495dSmrg if (rmode == ROUNDING_UP)
22336ac495dSmrg C64 = 1;
22436ac495dSmrg #endif
22536ac495dSmrg #endif
22636ac495dSmrg res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, C64);
22736ac495dSmrg BID_RETURN (res);
22836ac495dSmrg }
22936ac495dSmrg // else more than 16 digits in coefficient
23036ac495dSmrg #ifdef SET_STATUS_FLAGS
23136ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION);
23236ac495dSmrg #endif
23336ac495dSmrg res = 0x7c00000000000000ull;
23436ac495dSmrg BID_RETURN (res);
23536ac495dSmrg
23636ac495dSmrg }
237