xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/config/libbid/bid64_quantize.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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