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