(root)/
gcc-13.2.0/
libgcc/
config/
libbid/
bid64_mul.c
       1  /* Copyright (C) 2007-2023 Free Software Foundation, Inc.
       2  
       3  This file is part of GCC.
       4  
       5  GCC is free software; you can redistribute it and/or modify it under
       6  the terms of the GNU General Public License as published by the Free
       7  Software Foundation; either version 3, or (at your option) any later
       8  version.
       9  
      10  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13  for more details.
      14  
      15  Under Section 7 of GPL version 3, you are granted additional
      16  permissions described in the GCC Runtime Library Exception, version
      17  3.1, as published by the Free Software Foundation.
      18  
      19  You should have received a copy of the GNU General Public License and
      20  a copy of the GCC Runtime Library Exception along with this program;
      21  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      22  <http://www.gnu.org/licenses/>.  */
      23  
      24  /*****************************************************************************
      25   *    BID64 multiply
      26   *****************************************************************************
      27   *
      28   *  Algorithm description:
      29   *
      30   *  if(number_digits(coefficient_x)+number_digits(coefficient_y) guaranteed
      31   *       below 16)
      32   *      return get_BID64(sign_x^sign_y, exponent_x + exponent_y - dec_bias,
      33   *                     coefficient_x*coefficient_y)
      34   *  else
      35   *      get long product: coefficient_x*coefficient_y
      36   *      determine number of digits to round off (extra_digits)
      37   *      rounding is performed as a 128x128-bit multiplication by 
      38   *         2^M[extra_digits]/10^extra_digits, followed by a shift
      39   *         M[extra_digits] is sufficiently large for required accuracy 
      40   *
      41   ****************************************************************************/
      42  
      43  #include "bid_internal.h"
      44  
      45  #if DECIMAL_CALL_BY_REFERENCE
      46  
      47  void
      48  bid64_mul (UINT64 * pres, UINT64 * px,
      49  	   UINT64 *
      50  	   py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      51  	   _EXC_INFO_PARAM) {
      52    UINT64 x, y;
      53  #else
      54  
      55  UINT64
      56  bid64_mul (UINT64 x,
      57  	   UINT64 y _RND_MODE_PARAM _EXC_FLAGS_PARAM
      58  	   _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      59  #endif
      60    UINT128 P, PU, C128, Q_high, Q_low, Stemp;
      61    UINT64 sign_x, sign_y, coefficient_x, coefficient_y;
      62    UINT64 C64, remainder_h, carry, CY, res;
      63    UINT64 valid_x, valid_y;
      64    int_double tempx, tempy;
      65    int extra_digits, exponent_x, exponent_y, bin_expon_cx, bin_expon_cy,
      66      bin_expon_product;
      67    int rmode, digits_p, bp, amount, amount2, final_exponent, round_up;
      68    unsigned status, uf_status;
      69  
      70  #if DECIMAL_CALL_BY_REFERENCE
      71  #if !DECIMAL_GLOBAL_ROUNDING
      72    _IDEC_round rnd_mode = *prnd_mode;
      73  #endif
      74    x = *px;
      75    y = *py;
      76  #endif
      77  
      78    valid_x = unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x);
      79    valid_y = unpack_BID64 (&sign_y, &exponent_y, &coefficient_y, y);
      80  
      81    // unpack arguments, check for NaN or Infinity
      82    if (!valid_x) {
      83  
      84  #ifdef SET_STATUS_FLAGS
      85      if ((y & SNAN_MASK64) == SNAN_MASK64)	// y is sNaN
      86        __set_status_flags (pfpsf, INVALID_EXCEPTION);
      87  #endif
      88      // x is Inf. or NaN
      89  
      90      // test if x is NaN
      91      if ((x & NAN_MASK64) == NAN_MASK64) {
      92  #ifdef SET_STATUS_FLAGS
      93        if ((x & SNAN_MASK64) == SNAN_MASK64)	// sNaN
      94  	__set_status_flags (pfpsf, INVALID_EXCEPTION);
      95  #endif
      96        BID_RETURN (coefficient_x & QUIET_MASK64);
      97      }
      98      // x is Infinity?
      99      if ((x & INFINITY_MASK64) == INFINITY_MASK64) {
     100        // check if y is 0
     101        if (((y & INFINITY_MASK64) != INFINITY_MASK64)
     102  	  && !coefficient_y) {
     103  #ifdef SET_STATUS_FLAGS
     104  	__set_status_flags (pfpsf, INVALID_EXCEPTION);
     105  #endif
     106  	// y==0 , return NaN
     107  	BID_RETURN (NAN_MASK64);
     108        }
     109        // check if y is NaN
     110        if ((y & NAN_MASK64) == NAN_MASK64)
     111  	// y==NaN , return NaN
     112  	BID_RETURN (coefficient_y & QUIET_MASK64);
     113        // otherwise return +/-Inf
     114        BID_RETURN (((x ^ y) & 0x8000000000000000ull) | INFINITY_MASK64);
     115      }
     116      // x is 0
     117      if (((y & INFINITY_MASK64) != INFINITY_MASK64)) {
     118        if ((y & SPECIAL_ENCODING_MASK64) == SPECIAL_ENCODING_MASK64)
     119  	exponent_y = ((UINT32) (y >> 51)) & 0x3ff;
     120        else
     121  	exponent_y = ((UINT32) (y >> 53)) & 0x3ff;
     122        sign_y = y & 0x8000000000000000ull;
     123  
     124        exponent_x += exponent_y - DECIMAL_EXPONENT_BIAS;
     125        if (exponent_x > DECIMAL_MAX_EXPON_64)
     126  	exponent_x = DECIMAL_MAX_EXPON_64;
     127        else if (exponent_x < 0)
     128  	exponent_x = 0;
     129        BID_RETURN ((sign_x ^ sign_y) | (((UINT64) exponent_x) << 53));
     130      }
     131    }
     132    if (!valid_y) {
     133      // y is Inf. or NaN
     134  
     135      // test if y is NaN
     136      if ((y & NAN_MASK64) == NAN_MASK64) {
     137  #ifdef SET_STATUS_FLAGS
     138        if ((y & SNAN_MASK64) == SNAN_MASK64)	// sNaN
     139  	__set_status_flags (pfpsf, INVALID_EXCEPTION);
     140  #endif
     141        BID_RETURN (coefficient_y & QUIET_MASK64);
     142      }
     143      // y is Infinity?
     144      if ((y & INFINITY_MASK64) == INFINITY_MASK64) {
     145        // check if x is 0
     146        if (!coefficient_x) {
     147  	__set_status_flags (pfpsf, INVALID_EXCEPTION);
     148  	// x==0, return NaN
     149  	BID_RETURN (NAN_MASK64);
     150        }
     151        // otherwise return +/-Inf
     152        BID_RETURN (((x ^ y) & 0x8000000000000000ull) | INFINITY_MASK64);
     153      }
     154      // y is 0
     155      exponent_x += exponent_y - DECIMAL_EXPONENT_BIAS;
     156      if (exponent_x > DECIMAL_MAX_EXPON_64)
     157        exponent_x = DECIMAL_MAX_EXPON_64;
     158      else if (exponent_x < 0)
     159        exponent_x = 0;
     160      BID_RETURN ((sign_x ^ sign_y) | (((UINT64) exponent_x) << 53));
     161    }
     162    //--- get number of bits in the coefficients of x and y ---
     163    // version 2 (original)
     164    tempx.d = (double) coefficient_x;
     165    bin_expon_cx = ((tempx.i & MASK_BINARY_EXPONENT) >> 52);
     166    tempy.d = (double) coefficient_y;
     167    bin_expon_cy = ((tempy.i & MASK_BINARY_EXPONENT) >> 52);
     168  
     169    // magnitude estimate for coefficient_x*coefficient_y is 
     170    //        2^(unbiased_bin_expon_cx + unbiased_bin_expon_cx)
     171    bin_expon_product = bin_expon_cx + bin_expon_cy;
     172  
     173    // check if coefficient_x*coefficient_y<2^(10*k+3)
     174    // equivalent to unbiased_bin_expon_cx + unbiased_bin_expon_cx < 10*k+1
     175    if (bin_expon_product < UPPER_EXPON_LIMIT + 2 * BINARY_EXPONENT_BIAS) {
     176      //  easy multiply
     177      C64 = coefficient_x * coefficient_y;
     178  
     179      res =
     180        get_BID64_small_mantissa (sign_x ^ sign_y,
     181  				exponent_x + exponent_y -
     182  				DECIMAL_EXPONENT_BIAS, C64, rnd_mode,
     183  				pfpsf);
     184      BID_RETURN (res);
     185    } else {
     186      uf_status = 0;
     187      // get 128-bit product: coefficient_x*coefficient_y
     188      __mul_64x64_to_128 (P, coefficient_x, coefficient_y);
     189  
     190      // tighten binary range of P:  leading bit is 2^bp
     191      // unbiased_bin_expon_product <= bp <= unbiased_bin_expon_product+1
     192      bin_expon_product -= 2 * BINARY_EXPONENT_BIAS;
     193  
     194      __tight_bin_range_128 (bp, P, bin_expon_product);
     195  
     196      // get number of decimal digits in the product
     197      digits_p = estimate_decimal_digits[bp];
     198      if (!(__unsigned_compare_gt_128 (power10_table_128[digits_p], P)))
     199        digits_p++;	// if power10_table_128[digits_p] <= P
     200  
     201      // determine number of decimal digits to be rounded out
     202      extra_digits = digits_p - MAX_FORMAT_DIGITS;
     203      final_exponent =
     204        exponent_x + exponent_y + extra_digits - DECIMAL_EXPONENT_BIAS;
     205  
     206  #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
     207  #ifndef IEEE_ROUND_NEAREST
     208      rmode = rnd_mode;
     209      if (sign_x ^ sign_y && (unsigned) (rmode - 1) < 2)
     210        rmode = 3 - rmode;
     211  #else
     212      rmode = 0;
     213  #endif
     214  #else
     215      rmode = 0;
     216  #endif
     217  
     218      round_up = 0;
     219      if (((unsigned) final_exponent) >= 3 * 256) {
     220        if (final_exponent < 0) {
     221  	// underflow
     222  	if (final_exponent + 16 < 0) {
     223  	  res = sign_x ^ sign_y;
     224  	  __set_status_flags (pfpsf,
     225  			      UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION);
     226  	  if (rmode == ROUNDING_UP)
     227  	    res |= 1;
     228  	  BID_RETURN (res);
     229  	}
     230  
     231  	uf_status = UNDERFLOW_EXCEPTION;
     232  	if (final_exponent == -1) {
     233  	  __add_128_64 (PU, P, round_const_table[rmode][extra_digits]);
     234  	  if (__unsigned_compare_ge_128
     235  	      (PU, power10_table_128[extra_digits + 16]))
     236  	    uf_status = 0;
     237  	}
     238  	extra_digits -= final_exponent;
     239  	final_exponent = 0;
     240  
     241  	if (extra_digits > 17) {
     242  	  __mul_128x128_full (Q_high, Q_low, P, reciprocals10_128[16]);
     243  
     244  	  amount = recip_scale[16];
     245  	  __shr_128 (P, Q_high, amount);
     246  
     247  	  // get sticky bits
     248  	  amount2 = 64 - amount;
     249  	  remainder_h = 0;
     250  	  remainder_h--;
     251  	  remainder_h >>= amount2;
     252  	  remainder_h = remainder_h & Q_high.w[0];
     253  
     254  	  extra_digits -= 16;
     255  	  if (remainder_h || (Q_low.w[1] > reciprocals10_128[16].w[1]
     256  			      || (Q_low.w[1] ==
     257  				  reciprocals10_128[16].w[1]
     258  				  && Q_low.w[0] >=
     259  				  reciprocals10_128[16].w[0]))) {
     260  	    round_up = 1;
     261  	    __set_status_flags (pfpsf,
     262  				UNDERFLOW_EXCEPTION |
     263  				INEXACT_EXCEPTION);
     264  	    P.w[0] = (P.w[0] << 3) + (P.w[0] << 1);
     265  	    P.w[0] |= 1;
     266  	    extra_digits++;
     267  	  }
     268  	}
     269        } else {
     270  	res =
     271  	  fast_get_BID64_check_OF (sign_x ^ sign_y, final_exponent,
     272  				   1000000000000000ull, rnd_mode,
     273  				   pfpsf);
     274  	BID_RETURN (res);
     275        }
     276      }
     277  
     278  
     279      if (extra_digits > 0) {
     280        // will divide by 10^(digits_p - 16)
     281  
     282        // add a constant to P, depending on rounding mode
     283        // 0.5*10^(digits_p - 16) for round-to-nearest
     284        __add_128_64 (P, P, round_const_table[rmode][extra_digits]);
     285  
     286        // get P*(2^M[extra_digits])/10^extra_digits
     287        __mul_128x128_full (Q_high, Q_low, P,
     288  			  reciprocals10_128[extra_digits]);
     289  
     290        // now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
     291        amount = recip_scale[extra_digits];
     292        __shr_128 (C128, Q_high, amount);
     293  
     294        C64 = __low_64 (C128);
     295  
     296  #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
     297  #ifndef IEEE_ROUND_NEAREST
     298        if (rmode == 0)	//ROUNDING_TO_NEAREST
     299  #endif
     300  	if ((C64 & 1) && !round_up) {
     301  	  // check whether fractional part of initial_P/10^extra_digits 
     302  	  // is exactly .5
     303  	  // this is the same as fractional part of 
     304  	  // (initial_P + 0.5*10^extra_digits)/10^extra_digits is exactly zero
     305  
     306  	  // get remainder
     307  	  remainder_h = Q_high.w[0] << (64 - amount);
     308  
     309  	  // test whether fractional part is 0
     310  	  if (!remainder_h
     311  	      && (Q_low.w[1] < reciprocals10_128[extra_digits].w[1]
     312  		  || (Q_low.w[1] == reciprocals10_128[extra_digits].w[1]
     313  		      && Q_low.w[0] <
     314  		      reciprocals10_128[extra_digits].w[0]))) {
     315  	    C64--;
     316  	  }
     317  	}
     318  #endif
     319  
     320  #ifdef SET_STATUS_FLAGS
     321        status = INEXACT_EXCEPTION | uf_status;
     322  
     323        // get remainder
     324        remainder_h = Q_high.w[0] << (64 - amount);
     325  
     326        switch (rmode) {
     327        case ROUNDING_TO_NEAREST:
     328        case ROUNDING_TIES_AWAY:
     329  	// test whether fractional part is 0
     330  	if (remainder_h == 0x8000000000000000ull
     331  	    && (Q_low.w[1] < reciprocals10_128[extra_digits].w[1]
     332  		|| (Q_low.w[1] == reciprocals10_128[extra_digits].w[1]
     333  		    && Q_low.w[0] <
     334  		    reciprocals10_128[extra_digits].w[0])))
     335  	  status = EXACT_STATUS;
     336  	break;
     337        case ROUNDING_DOWN:
     338        case ROUNDING_TO_ZERO:
     339  	if (!remainder_h
     340  	    && (Q_low.w[1] < reciprocals10_128[extra_digits].w[1]
     341  		|| (Q_low.w[1] == reciprocals10_128[extra_digits].w[1]
     342  		    && Q_low.w[0] <
     343  		    reciprocals10_128[extra_digits].w[0])))
     344  	  status = EXACT_STATUS;
     345  	break;
     346        default:
     347  	// round up
     348  	__add_carry_out (Stemp.w[0], CY, Q_low.w[0],
     349  			 reciprocals10_128[extra_digits].w[0]);
     350  	__add_carry_in_out (Stemp.w[1], carry, Q_low.w[1],
     351  			    reciprocals10_128[extra_digits].w[1], CY);
     352  	if ((remainder_h >> (64 - amount)) + carry >=
     353  	    (((UINT64) 1) << amount))
     354  	  status = EXACT_STATUS;
     355        }
     356  
     357        __set_status_flags (pfpsf, status);
     358  #endif
     359  
     360        // convert to BID and return
     361        res =
     362  	fast_get_BID64_check_OF (sign_x ^ sign_y, final_exponent, C64,
     363  				 rmode, pfpsf);
     364        BID_RETURN (res);
     365      }
     366      // go to convert_format and exit
     367      C64 = __low_64 (P);
     368      res =
     369        get_BID64 (sign_x ^ sign_y,
     370  		 exponent_x + exponent_y - DECIMAL_EXPONENT_BIAS, C64,
     371  		 rmode, pfpsf);
     372      BID_RETURN (res);
     373    }
     374  }