(root)/
gcc-13.2.0/
libgcc/
config/
libbid/
bid32_to_bid128.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  #define BID_128RES
      25  #include "bid_internal.h"
      26  
      27  /* 
      28   * Takes a BID32 as input and converts it to a BID128 and returns it.
      29   */
      30  TYPE0_FUNCTION_ARGTYPE1_NORND (UINT128, bid32_to_bid128, UINT32, x)
      31  
      32       UINT128 new_coeff, res;
      33       UINT32 sign_x;
      34       int exponent_x;
      35       UINT32 coefficient_x;
      36  
      37  if (!unpack_BID32 (&sign_x, &exponent_x, &coefficient_x, x)) {
      38  if (((x) & 0x78000000) == 0x78000000) {
      39  #ifdef SET_STATUS_FLAGS
      40    if (((x) & 0x7e000000) == 0x7e000000)	// sNaN
      41      __set_status_flags (pfpsf, INVALID_EXCEPTION);
      42  #endif
      43    res.w[0] = (coefficient_x & 0x000fffff);
      44    __mul_64x128_low (res, res.w[0], power10_table_128[27]);
      45    res.w[1] |=
      46      ((((UINT64) coefficient_x) << 32) & 0xfc00000000000000ull);
      47  
      48    BID_RETURN (res);
      49  }
      50  }
      51  
      52  new_coeff.w[0] = coefficient_x;
      53  new_coeff.w[1] = 0;
      54  get_BID128_very_fast (&res, ((UINT64) sign_x) << 32,
      55  		      exponent_x + DECIMAL_EXPONENT_BIAS_128 -
      56  		      DECIMAL_EXPONENT_BIAS_32, new_coeff);
      57  BID_RETURN (res);
      58  }	// convert_bid32_to_bid128
      59  
      60  
      61  /*
      62   * Takes a BID128 as input and converts it to a BID32 and returns it.
      63   */
      64  #if DECIMAL_CALL_BY_REFERENCE
      65  
      66  void
      67  bid128_to_bid32 (UINT32 * pres,
      68  		 UINT128 *
      69  		 px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      70  		 _EXC_INFO_PARAM) {
      71    UINT128 x = *px;
      72  #else
      73  
      74  UINT32
      75  bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM
      76  		 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
      77  #endif
      78    UINT128 CX, T128, TP128, Qh, Ql, Qh1, Stemp, Tmp, Tmp1, CX1;
      79    UINT64 sign_x, carry, cy;
      80    SINT64 D;
      81    UINT32 res;
      82    int_float f64, fx;
      83    int exponent_x, extra_digits, amount, bin_expon_cx, uf_check = 0;
      84    unsigned rmode, status;
      85  
      86  #if DECIMAL_CALL_BY_REFERENCE
      87  #if !DECIMAL_GLOBAL_ROUNDING
      88    _IDEC_round rnd_mode = *prnd_mode;
      89  #endif
      90  #endif
      91  
      92    BID_SWAP128 (x);
      93    // unpack arguments, check for NaN or Infinity or 0
      94    if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) {
      95      if (((x.w[1]) & 0x7800000000000000ull) == 0x7800000000000000ull) {
      96        Tmp.w[1] = (CX.w[1] & 0x00003fffffffffffull);
      97        Tmp.w[0] = CX.w[0];
      98        TP128 = reciprocals10_128[27];
      99        __mul_128x128_full (Qh, Ql, Tmp, TP128);
     100        amount = recip_scale[27] - 64;
     101        res = ((CX.w[1] >> 32) & 0xfc000000) | (Qh.w[1] >> amount);
     102  #ifdef SET_STATUS_FLAGS
     103        if ((x.w[1] & SNAN_MASK64) == SNAN_MASK64)	// sNaN
     104  	__set_status_flags (pfpsf, INVALID_EXCEPTION);
     105  #endif
     106        BID_RETURN_VAL (res);
     107      }
     108      // x is 0
     109      exponent_x =
     110        exponent_x - DECIMAL_EXPONENT_BIAS_128 + DECIMAL_EXPONENT_BIAS_32;
     111      if (exponent_x < 0)
     112        exponent_x = 0;
     113      if (exponent_x > DECIMAL_MAX_EXPON_32)
     114        exponent_x = DECIMAL_MAX_EXPON_32;
     115      res = (sign_x >> 32) | (exponent_x << 23);
     116      BID_RETURN_VAL (res);
     117  
     118    }
     119  
     120    if (CX.w[1] || (CX.w[0] >= 10000000)) {
     121      // find number of digits in coefficient
     122      // 2^64
     123      f64.i = 0x5f800000;
     124      // fx ~ CX
     125      fx.d = (float) CX.w[1] * f64.d + (float) CX.w[0];
     126      bin_expon_cx = ((fx.i >> 23) & 0xff) - 0x7f;
     127      extra_digits = estimate_decimal_digits[bin_expon_cx] - 7;
     128      // scale = 38-estimate_decimal_digits[bin_expon_cx];
     129      D = CX.w[1] - power10_index_binexp_128[bin_expon_cx].w[1];
     130      if (D > 0
     131  	|| (!D
     132  	    && CX.w[0] >= power10_index_binexp_128[bin_expon_cx].w[0]))
     133        extra_digits++;
     134  
     135      exponent_x += extra_digits;
     136  
     137  #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
     138  #ifndef IEEE_ROUND_NEAREST
     139      rmode = rnd_mode;
     140      if (sign_x && (unsigned) (rmode - 1) < 2)
     141        rmode = 3 - rmode;
     142  #else
     143      rmode = 0;
     144  #endif
     145  #else
     146      rmode = 0;
     147  #endif
     148      if (exponent_x <
     149  	DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32) {
     150        uf_check = 1;
     151        if (-extra_digits + exponent_x - DECIMAL_EXPONENT_BIAS_128 +
     152  	  DECIMAL_EXPONENT_BIAS_32 + 35 >= 0) {
     153  	if (exponent_x ==
     154  	    DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32 - 1) {
     155  	  T128 = round_const_table_128[rmode][extra_digits];
     156  	  __add_carry_out (CX1.w[0], carry, T128.w[0], CX.w[0]);
     157  	  CX1.w[1] = CX.w[1] + T128.w[1] + carry;
     158  	  if (__unsigned_compare_ge_128
     159  	      (CX1, power10_table_128[extra_digits + 7]))
     160  	    uf_check = 0;
     161  	}
     162  	extra_digits =
     163  	  extra_digits + DECIMAL_EXPONENT_BIAS_128 -
     164  	  DECIMAL_EXPONENT_BIAS_32 - exponent_x;
     165  	exponent_x =
     166  	  DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32;
     167        } else
     168  	rmode = ROUNDING_TO_ZERO;
     169      }
     170  
     171      T128 = round_const_table_128[rmode][extra_digits];
     172      __add_carry_out (CX.w[0], carry, T128.w[0], CX.w[0]);
     173      CX.w[1] = CX.w[1] + T128.w[1] + carry;
     174  
     175      TP128 = reciprocals10_128[extra_digits];
     176      __mul_128x128_full (Qh, Ql, CX, TP128);
     177      amount = recip_scale[extra_digits];
     178  
     179      if (amount >= 64) {
     180        CX.w[0] = Qh.w[1] >> (amount - 64);
     181        CX.w[1] = 0;
     182      } else {
     183        __shr_128 (CX, Qh, amount);
     184      }
     185  
     186  #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
     187  #ifndef IEEE_ROUND_NEAREST
     188      if (!(rnd_mode))
     189  #endif
     190        if (CX.w[0] & 1) {
     191  	// check whether fractional part of initial_P/10^ed1 is exactly .5
     192  
     193  	// get remainder
     194  	__shl_128_long (Qh1, Qh, (128 - amount));
     195  
     196  	if (!Qh1.w[1] && !Qh1.w[0]
     197  	    && (Ql.w[1] < reciprocals10_128[extra_digits].w[1]
     198  		|| (Ql.w[1] == reciprocals10_128[extra_digits].w[1]
     199  		    && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) {
     200  	  CX.w[0]--;
     201  	}
     202        }
     203  #endif
     204  
     205  
     206      {
     207        status = INEXACT_EXCEPTION;
     208        // get remainder
     209        __shl_128_long (Qh1, Qh, (128 - amount));
     210  
     211        switch (rmode) {
     212        case ROUNDING_TO_NEAREST:
     213        case ROUNDING_TIES_AWAY:
     214  	// test whether fractional part is 0
     215  	if (Qh1.w[1] == 0x8000000000000000ull && (!Qh1.w[0])
     216  	    && (Ql.w[1] < reciprocals10_128[extra_digits].w[1]
     217  		|| (Ql.w[1] == reciprocals10_128[extra_digits].w[1]
     218  		    && Ql.w[0] < reciprocals10_128[extra_digits].w[0])))
     219  	  status = EXACT_STATUS;
     220  	break;
     221        case ROUNDING_DOWN:
     222        case ROUNDING_TO_ZERO:
     223  	if ((!Qh1.w[1]) && (!Qh1.w[0])
     224  	    && (Ql.w[1] < reciprocals10_128[extra_digits].w[1]
     225  		|| (Ql.w[1] == reciprocals10_128[extra_digits].w[1]
     226  		    && Ql.w[0] < reciprocals10_128[extra_digits].w[0])))
     227  	  status = EXACT_STATUS;
     228  	break;
     229        default:
     230  	// round up
     231  	__add_carry_out (Stemp.w[0], cy, Ql.w[0],
     232  			 reciprocals10_128[extra_digits].w[0]);
     233  	__add_carry_in_out (Stemp.w[1], carry, Ql.w[1],
     234  			    reciprocals10_128[extra_digits].w[1], cy);
     235  	__shr_128_long (Qh, Qh1, (128 - amount));
     236  	Tmp.w[0] = 1;
     237  	Tmp.w[1] = 0;
     238  	__shl_128_long (Tmp1, Tmp, amount);
     239  	Qh.w[0] += carry;
     240  	if (Qh.w[0] < carry)
     241  	  Qh.w[1]++;
     242  	if (__unsigned_compare_ge_128 (Qh, Tmp1))
     243  	  status = EXACT_STATUS;
     244        }
     245  
     246        if (status != EXACT_STATUS) {
     247  	if (uf_check) {
     248  	  status |= UNDERFLOW_EXCEPTION;
     249  	}
     250  #ifdef SET_STATUS_FLAGS
     251  	__set_status_flags (pfpsf, status);
     252  #endif
     253        }
     254      }
     255  
     256    }
     257  
     258    res =
     259      get_BID32 ((UINT32) (sign_x >> 32),
     260  	       exponent_x - DECIMAL_EXPONENT_BIAS_128 +
     261  	       DECIMAL_EXPONENT_BIAS_32, CX.w[0], rnd_mode, pfpsf);
     262    BID_RETURN_VAL (res);
     263  
     264  }