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 #define BID_128RES 2536ac495dSmrg #include "bid_internal.h" 2636ac495dSmrg 2736ac495dSmrg BID128_FUNCTION_ARG2 (bid128_quantize, x, y) 2836ac495dSmrg 2936ac495dSmrg UINT256 CT; 3036ac495dSmrg UINT128 CX, CY, T, CX2, CR, Stemp, res, REM_H, C2N; 3136ac495dSmrg UINT64 sign_x, sign_y, remainder_h, carry, CY64, valid_x; 3236ac495dSmrg int_float tempx; 3336ac495dSmrg int exponent_x, exponent_y, digits_x, extra_digits, amount; 3436ac495dSmrg int expon_diff, total_digits, bin_expon_cx, rmode, status; 3536ac495dSmrg 3636ac495dSmrg valid_x = unpack_BID128_value (&sign_x, &exponent_x, &CX, x); 3736ac495dSmrg 3836ac495dSmrg // unpack arguments, check for NaN or Infinity 3936ac495dSmrg if (!unpack_BID128_value (&sign_y, &exponent_y, &CY, y)) { 4036ac495dSmrg // y is Inf. or NaN 4136ac495dSmrg #ifdef SET_STATUS_FLAGS 4236ac495dSmrg if ((x.w[1] & SNAN_MASK64) == SNAN_MASK64) // y is sNaN 4336ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION); 4436ac495dSmrg #endif 4536ac495dSmrg 4636ac495dSmrg // test if y is NaN 4736ac495dSmrg if ((y.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) { 4836ac495dSmrg #ifdef SET_STATUS_FLAGS 4936ac495dSmrg if ((y.w[1] & 0x7e00000000000000ull) == 0x7e00000000000000ull) { 5036ac495dSmrg // set status flags 5136ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION); 5236ac495dSmrg } 5336ac495dSmrg #endif 5436ac495dSmrg if ((x.w[1] & 0x7c00000000000000ull) != 0x7c00000000000000ull) { 5536ac495dSmrg res.w[1] = CY.w[1] & QUIET_MASK64; 5636ac495dSmrg res.w[0] = CY.w[0]; 5736ac495dSmrg } else { 5836ac495dSmrg res.w[1] = CX.w[1] & QUIET_MASK64; 5936ac495dSmrg res.w[0] = CX.w[0]; 6036ac495dSmrg } 6136ac495dSmrg BID_RETURN (res); 6236ac495dSmrg } 6336ac495dSmrg // y is Infinity? 6436ac495dSmrg if ((y.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) { 6536ac495dSmrg // check if x is not Inf. 6636ac495dSmrg if (((x.w[1] & 0x7c00000000000000ull) < 0x7800000000000000ull)) { 6736ac495dSmrg // return NaN 6836ac495dSmrg #ifdef SET_STATUS_FLAGS 6936ac495dSmrg // set status flags 7036ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION); 7136ac495dSmrg #endif 7236ac495dSmrg res.w[1] = 0x7c00000000000000ull; 7336ac495dSmrg res.w[0] = 0; 7436ac495dSmrg BID_RETURN (res); 7536ac495dSmrg } else 7636ac495dSmrg if (((x.w[1] & 0x7c00000000000000ull) <= 0x7800000000000000ull)) { 7736ac495dSmrg res.w[1] = CX.w[1] & QUIET_MASK64; 7836ac495dSmrg res.w[0] = CX.w[0]; 7936ac495dSmrg BID_RETURN (res); 8036ac495dSmrg } 8136ac495dSmrg } 8236ac495dSmrg 8336ac495dSmrg } 8436ac495dSmrg 8536ac495dSmrg if (!valid_x) { 8636ac495dSmrg // test if x is NaN or Inf 8736ac495dSmrg if ((x.w[1] & 0x7c00000000000000ull) == 0x7800000000000000ull) { 8836ac495dSmrg #ifdef SET_STATUS_FLAGS 8936ac495dSmrg // set status flags 9036ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION); 9136ac495dSmrg #endif 9236ac495dSmrg res.w[1] = 0x7c00000000000000ull; 9336ac495dSmrg res.w[0] = 0; 9436ac495dSmrg BID_RETURN (res); 9536ac495dSmrg } else if ((x.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) { 9636ac495dSmrg if ((x.w[1] & 0x7e00000000000000ull) == 0x7e00000000000000ull) { 9736ac495dSmrg #ifdef SET_STATUS_FLAGS 9836ac495dSmrg // set status flags 9936ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION); 10036ac495dSmrg #endif 10136ac495dSmrg } 10236ac495dSmrg res.w[1] = CX.w[1] & QUIET_MASK64; 10336ac495dSmrg res.w[0] = CX.w[0]; 10436ac495dSmrg BID_RETURN (res); 10536ac495dSmrg } 10636ac495dSmrg if (!CX.w[1] && !CX.w[0]) { 10736ac495dSmrg get_BID128_very_fast (&res, sign_x, exponent_y, CX); 10836ac495dSmrg BID_RETURN (res); 10936ac495dSmrg } 11036ac495dSmrg } 11136ac495dSmrg // get number of decimal digits in coefficient_x 11236ac495dSmrg if (CX.w[1]) { 11336ac495dSmrg tempx.d = (float) CX.w[1]; 11436ac495dSmrg bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f + 64; 11536ac495dSmrg } else { 11636ac495dSmrg tempx.d = (float) CX.w[0]; 11736ac495dSmrg bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f; 11836ac495dSmrg } 11936ac495dSmrg 12036ac495dSmrg digits_x = estimate_decimal_digits[bin_expon_cx]; 12136ac495dSmrg if (CX.w[1] > power10_table_128[digits_x].w[1] 12236ac495dSmrg || (CX.w[1] == power10_table_128[digits_x].w[1] 12336ac495dSmrg && CX.w[0] >= power10_table_128[digits_x].w[0])) 12436ac495dSmrg digits_x++; 12536ac495dSmrg 12636ac495dSmrg expon_diff = exponent_x - exponent_y; 12736ac495dSmrg total_digits = digits_x + expon_diff; 12836ac495dSmrg 12936ac495dSmrg if ((UINT32) total_digits <= 34) { 13036ac495dSmrg if (expon_diff >= 0) { 13136ac495dSmrg T = power10_table_128[expon_diff]; 13236ac495dSmrg __mul_128x128_low (CX2, T, CX); 13336ac495dSmrg get_BID128_very_fast (&res, sign_x, exponent_y, CX2); 13436ac495dSmrg BID_RETURN (res); 13536ac495dSmrg } 13636ac495dSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY 13736ac495dSmrg #ifndef IEEE_ROUND_NEAREST 13836ac495dSmrg rmode = rnd_mode; 13936ac495dSmrg if (sign_x && (unsigned) (rmode - 1) < 2) 14036ac495dSmrg rmode = 3 - rmode; 14136ac495dSmrg #else 14236ac495dSmrg rmode = 0; 14336ac495dSmrg #endif 14436ac495dSmrg #else 14536ac495dSmrg rmode = 0; 14636ac495dSmrg #endif 14736ac495dSmrg // must round off -expon_diff digits 14836ac495dSmrg extra_digits = -expon_diff; 14936ac495dSmrg __add_128_128 (CX, CX, round_const_table_128[rmode][extra_digits]); 15036ac495dSmrg 15136ac495dSmrg // get P*(2^M[extra_digits])/10^extra_digits 15236ac495dSmrg __mul_128x128_to_256 (CT, CX, reciprocals10_128[extra_digits]); 15336ac495dSmrg 15436ac495dSmrg // now get P/10^extra_digits: shift C64 right by M[extra_digits]-128 15536ac495dSmrg amount = recip_scale[extra_digits]; 15636ac495dSmrg CX2.w[0] = CT.w[2]; 15736ac495dSmrg CX2.w[1] = CT.w[3]; 15836ac495dSmrg if (amount >= 64) { 15936ac495dSmrg CR.w[1] = 0; 16036ac495dSmrg CR.w[0] = CX2.w[1] >> (amount - 64); 16136ac495dSmrg } else { 16236ac495dSmrg __shr_128 (CR, CX2, amount); 16336ac495dSmrg } 16436ac495dSmrg 16536ac495dSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY 16636ac495dSmrg #ifndef IEEE_ROUND_NEAREST 16736ac495dSmrg if (rnd_mode == 0) 16836ac495dSmrg #endif 16936ac495dSmrg if (CR.w[0] & 1) { 17036ac495dSmrg // check whether fractional part of initial_P/10^extra_digits is 17136ac495dSmrg // exactly .5 this is the same as fractional part of 17236ac495dSmrg // (initial_P + 0.5*10^extra_digits)/10^extra_digits is exactly zero 17336ac495dSmrg 17436ac495dSmrg // get remainder 17536ac495dSmrg if (amount >= 64) { 17636ac495dSmrg remainder_h = CX2.w[0] | (CX2.w[1] << (128 - amount)); 17736ac495dSmrg } else 17836ac495dSmrg remainder_h = CX2.w[0] << (64 - amount); 17936ac495dSmrg 18036ac495dSmrg // test whether fractional part is 0 18136ac495dSmrg if (!remainder_h 18236ac495dSmrg && (CT.w[1] < reciprocals10_128[extra_digits].w[1] 18336ac495dSmrg || (CT.w[1] == reciprocals10_128[extra_digits].w[1] 18436ac495dSmrg && CT.w[0] < reciprocals10_128[extra_digits].w[0]))) { 18536ac495dSmrg CR.w[0]--; 18636ac495dSmrg } 18736ac495dSmrg } 18836ac495dSmrg #endif 18936ac495dSmrg 19036ac495dSmrg #ifdef SET_STATUS_FLAGS 19136ac495dSmrg status = INEXACT_EXCEPTION; 19236ac495dSmrg 19336ac495dSmrg // get remainder 19436ac495dSmrg if (amount >= 64) { 19536ac495dSmrg REM_H.w[1] = (CX2.w[1] << (128 - amount)); 19636ac495dSmrg REM_H.w[0] = CX2.w[0]; 19736ac495dSmrg } else { 19836ac495dSmrg REM_H.w[1] = CX2.w[0] << (64 - amount); 19936ac495dSmrg REM_H.w[0] = 0; 20036ac495dSmrg } 20136ac495dSmrg 20236ac495dSmrg switch (rmode) { 20336ac495dSmrg case ROUNDING_TO_NEAREST: 20436ac495dSmrg case ROUNDING_TIES_AWAY: 20536ac495dSmrg // test whether fractional part is 0 20636ac495dSmrg if (REM_H.w[1] == 0x8000000000000000ull && !REM_H.w[0] 20736ac495dSmrg && (CT.w[1] < reciprocals10_128[extra_digits].w[1] 20836ac495dSmrg || (CT.w[1] == reciprocals10_128[extra_digits].w[1] 20936ac495dSmrg && CT.w[0] < reciprocals10_128[extra_digits].w[0]))) 21036ac495dSmrg status = EXACT_STATUS; 21136ac495dSmrg break; 21236ac495dSmrg case ROUNDING_DOWN: 21336ac495dSmrg case ROUNDING_TO_ZERO: 21436ac495dSmrg if (!(REM_H.w[1] | REM_H.w[0]) 21536ac495dSmrg && (CT.w[1] < reciprocals10_128[extra_digits].w[1] 21636ac495dSmrg || (CT.w[1] == reciprocals10_128[extra_digits].w[1] 21736ac495dSmrg && CT.w[0] < reciprocals10_128[extra_digits].w[0]))) 21836ac495dSmrg status = EXACT_STATUS; 21936ac495dSmrg break; 22036ac495dSmrg default: 22136ac495dSmrg // round up 22236ac495dSmrg __add_carry_out (Stemp.w[0], CY64, CT.w[0], 22336ac495dSmrg reciprocals10_128[extra_digits].w[0]); 22436ac495dSmrg __add_carry_in_out (Stemp.w[1], carry, CT.w[1], 22536ac495dSmrg reciprocals10_128[extra_digits].w[1], CY64); 22636ac495dSmrg if (amount < 64) { 22736ac495dSmrg C2N.w[1] = 0; 22836ac495dSmrg C2N.w[0] = ((UINT64) 1) << amount; 22936ac495dSmrg REM_H.w[0] = REM_H.w[1] >> (64 - amount); 23036ac495dSmrg REM_H.w[1] = 0; 23136ac495dSmrg } else { 23236ac495dSmrg C2N.w[1] = ((UINT64) 1) << (amount - 64); 23336ac495dSmrg C2N.w[0] = 0; 23436ac495dSmrg REM_H.w[1] >>= (128 - amount); 23536ac495dSmrg } 23636ac495dSmrg REM_H.w[0] += carry; 23736ac495dSmrg if (REM_H.w[0] < carry) 23836ac495dSmrg REM_H.w[1]++; 23936ac495dSmrg if (__unsigned_compare_ge_128 (REM_H, C2N)) 24036ac495dSmrg status = EXACT_STATUS; 24136ac495dSmrg } 24236ac495dSmrg 24336ac495dSmrg __set_status_flags (pfpsf, status); 24436ac495dSmrg 24536ac495dSmrg #endif 24636ac495dSmrg get_BID128_very_fast (&res, sign_x, exponent_y, CR); 24736ac495dSmrg BID_RETURN (res); 24836ac495dSmrg } 24936ac495dSmrg if (total_digits < 0) { 25036ac495dSmrg CR.w[1] = CR.w[0] = 0; 25136ac495dSmrg #ifndef IEEE_ROUND_NEAREST_TIES_AWAY 25236ac495dSmrg #ifndef IEEE_ROUND_NEAREST 25336ac495dSmrg rmode = rnd_mode; 25436ac495dSmrg if (sign_x && (unsigned) (rmode - 1) < 2) 25536ac495dSmrg rmode = 3 - rmode; 25636ac495dSmrg if (rmode == ROUNDING_UP) 25736ac495dSmrg CR.w[0] = 1; 25836ac495dSmrg #endif 25936ac495dSmrg #endif 26036ac495dSmrg #ifdef SET_STATUS_FLAGS 26136ac495dSmrg __set_status_flags (pfpsf, INEXACT_EXCEPTION); 26236ac495dSmrg #endif 26336ac495dSmrg get_BID128_very_fast (&res, sign_x, exponent_y, CR); 26436ac495dSmrg BID_RETURN (res); 26536ac495dSmrg } 26636ac495dSmrg // else more than 34 digits in coefficient 26736ac495dSmrg #ifdef SET_STATUS_FLAGS 26836ac495dSmrg __set_status_flags (pfpsf, INVALID_EXCEPTION); 26936ac495dSmrg #endif 27036ac495dSmrg res.w[1] = 0x7c00000000000000ull; 27136ac495dSmrg res.w[0] = 0; 27236ac495dSmrg BID_RETURN (res); 27336ac495dSmrg 27436ac495dSmrg } 275