(root)/
gcc-13.2.0/
libgcc/
config/
libbid/
bid128_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  #include "bid_internal.h"
      25  
      26  #if DECIMAL_CALL_BY_REFERENCE
      27  void
      28  bid64dq_mul (UINT64 * pres, UINT64 * px, UINT128 * py
      29  	     _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      30  	     _EXC_INFO_PARAM) {
      31    UINT64 x = *px;
      32  #if !DECIMAL_GLOBAL_ROUNDING
      33    unsigned int rnd_mode = *prnd_mode;
      34  #endif
      35  #else
      36  UINT64
      37  bid64dq_mul (UINT64 x, UINT128 y
      38  	     _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      39  	     _EXC_INFO_PARAM) {
      40  #endif
      41    UINT64 res = 0xbaddbaddbaddbaddull;
      42    UINT128 x1;
      43  
      44  #if DECIMAL_CALL_BY_REFERENCE
      45    bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
      46    bid64qq_mul (&res, &x1, py
      47  	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
      48  	       _EXC_INFO_ARG);
      49  #else
      50    x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
      51    res = bid64qq_mul (x1, y
      52  		     _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
      53  		     _EXC_INFO_ARG);
      54  #endif
      55    BID_RETURN (res);
      56  }
      57  
      58  
      59  #if DECIMAL_CALL_BY_REFERENCE
      60  void
      61  bid64qd_mul (UINT64 * pres, UINT128 * px, UINT64 * py
      62  	     _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      63  	     _EXC_INFO_PARAM) {
      64    UINT64 y = *py;
      65  #if !DECIMAL_GLOBAL_ROUNDING
      66    unsigned int rnd_mode = *prnd_mode;
      67  #endif
      68  #else
      69  UINT64
      70  bid64qd_mul (UINT128 x, UINT64 y
      71  	     _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      72  	     _EXC_INFO_PARAM) {
      73  #endif
      74    UINT64 res = 0xbaddbaddbaddbaddull;
      75    UINT128 y1;
      76  
      77  #if DECIMAL_CALL_BY_REFERENCE
      78    bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
      79    bid64qq_mul (&res, px, &y1
      80  	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
      81  	       _EXC_INFO_ARG);
      82  #else
      83    y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
      84    res = bid64qq_mul (x, y1
      85  		     _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
      86  		     _EXC_INFO_ARG);
      87  #endif
      88    BID_RETURN (res);
      89  }
      90  
      91  
      92  #if DECIMAL_CALL_BY_REFERENCE
      93  void
      94  bid64qq_mul (UINT64 * pres, UINT128 * px, UINT128 * py
      95  	     _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
      96  	     _EXC_INFO_PARAM) {
      97    UINT128 x = *px, y = *py;
      98  #if !DECIMAL_GLOBAL_ROUNDING
      99    unsigned int rnd_mode = *prnd_mode;
     100  #endif
     101  #else
     102  UINT64
     103  bid64qq_mul (UINT128 x, UINT128 y
     104  	     _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     105  	     _EXC_INFO_PARAM) {
     106  #endif
     107  
     108    UINT128 z = { {0x0000000000000000ull, 0x5ffe000000000000ull}
     109    };
     110    UINT64 res = 0xbaddbaddbaddbaddull;
     111    UINT64 x_sign, y_sign, p_sign;
     112    UINT64 x_exp, y_exp, p_exp;
     113    int true_p_exp;
     114    UINT128 C1, C2;
     115  
     116    BID_SWAP128 (z);
     117    // skip cases where at least one operand is NaN or infinity
     118    if (!(((x.w[HIGH_128W] & MASK_NAN) == MASK_NAN) ||
     119  	((y.w[HIGH_128W] & MASK_NAN) == MASK_NAN) ||
     120  	((x.w[HIGH_128W] & MASK_ANY_INF) == MASK_INF) ||
     121  	((y.w[HIGH_128W] & MASK_ANY_INF) == MASK_INF))) {
     122      // x, y are 0 or f but not inf or NaN => unpack the arguments and check
     123      // for non-canonical values
     124  
     125      x_sign = x.w[HIGH_128W] & MASK_SIGN;	// 0 for positive, MASK_SIGN for negative
     126      C1.w[1] = x.w[HIGH_128W] & MASK_COEFF;
     127      C1.w[0] = x.w[LOW_128W];
     128      // check for non-canonical values - treated as zero
     129      if ((x.w[HIGH_128W] & 0x6000000000000000ull) ==
     130  	0x6000000000000000ull) {
     131        // G0_G1=11 => non-canonical
     132        x_exp = (x.w[HIGH_128W] << 2) & MASK_EXP;	// biased and shifted left 49 bits
     133        C1.w[1] = 0;	// significand high
     134        C1.w[0] = 0;	// significand low
     135      } else {	// G0_G1 != 11
     136        x_exp = x.w[HIGH_128W] & MASK_EXP;	// biased and shifted left 49 bits
     137        if (C1.w[1] > 0x0001ed09bead87c0ull ||
     138  	  (C1.w[1] == 0x0001ed09bead87c0ull &&
     139  	   C1.w[0] > 0x378d8e63ffffffffull)) {
     140  	// x is non-canonical if coefficient is larger than 10^34 -1
     141  	C1.w[1] = 0;
     142  	C1.w[0] = 0;
     143        } else {	// canonical          
     144  	;
     145        }
     146      }
     147      y_sign = y.w[HIGH_128W] & MASK_SIGN;	// 0 for positive, MASK_SIGN for negative
     148      C2.w[1] = y.w[HIGH_128W] & MASK_COEFF;
     149      C2.w[0] = y.w[LOW_128W];
     150      // check for non-canonical values - treated as zero
     151      if ((y.w[HIGH_128W] & 0x6000000000000000ull) ==
     152  	0x6000000000000000ull) {
     153        // G0_G1=11 => non-canonical
     154        y_exp = (y.w[HIGH_128W] << 2) & MASK_EXP;	// biased and shifted left 49 bits
     155        C2.w[1] = 0;	// significand high
     156        C2.w[0] = 0;	// significand low 
     157      } else {	// G0_G1 != 11
     158        y_exp = y.w[HIGH_128W] & MASK_EXP;	// biased and shifted left 49 bits
     159        if (C2.w[1] > 0x0001ed09bead87c0ull ||
     160  	  (C2.w[1] == 0x0001ed09bead87c0ull &&
     161  	   C2.w[0] > 0x378d8e63ffffffffull)) {
     162  	// y is non-canonical if coefficient is larger than 10^34 -1
     163  	C2.w[1] = 0;
     164  	C2.w[0] = 0;
     165        } else {	// canonical
     166  	;
     167        }
     168      }
     169      p_sign = x_sign ^ y_sign;	// sign of the product
     170  
     171      true_p_exp = (x_exp >> 49) - 6176 + (y_exp >> 49) - 6176;
     172      // true_p_exp, p_exp are used only for 0 * 0, 0 * f, or f * 0 
     173      if (true_p_exp < -398)
     174        p_exp = 0;	// cannot be less than EXP_MIN
     175      else if (true_p_exp > 369)
     176        p_exp = (UINT64) (369 + 398) << 53;	// cannot be more than EXP_MAX
     177      else
     178        p_exp = (UINT64) (true_p_exp + 398) << 53;
     179  
     180      if ((C1.w[1] == 0x0 && C1.w[0] == 0x0) ||
     181  	(C2.w[1] == 0x0 && C2.w[0] == 0x0)) {
     182        // x = 0 or y = 0
     183        // the result is 0
     184        res = p_sign | p_exp;	// preferred exponent in [EXP_MIN, EXP_MAX]
     185        BID_RETURN (res)
     186      }	// else continue
     187    }
     188    // swap x and y - ensure that a NaN in x has 'higher precedence' than one in y
     189  #if DECIMAL_CALL_BY_REFERENCE
     190    bid64qqq_fma (&res, &y, &x, &z
     191  		_RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     192  		_EXC_INFO_ARG);
     193  #else
     194    res = bid64qqq_fma (y, x, z
     195  		      _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     196  		      _EXC_INFO_ARG);
     197  #endif
     198    BID_RETURN (res);
     199  }
     200  
     201  
     202  #if DECIMAL_CALL_BY_REFERENCE
     203  void
     204  bid128dd_mul (UINT128 * pres, UINT64 * px, UINT64 * py
     205  	      _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     206  	      _EXC_INFO_PARAM) {
     207    UINT64 x = *px, y = *py;
     208  #if !DECIMAL_GLOBAL_ROUNDING
     209    unsigned int rnd_mode = *prnd_mode;
     210  #endif
     211  #else
     212  UINT128
     213  bid128dd_mul (UINT64 x, UINT64 y
     214  	      _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     215  	      _EXC_INFO_PARAM) {
     216  #endif
     217    UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
     218    };
     219    UINT128 x1, y1;
     220  
     221  #if DECIMAL_CALL_BY_REFERENCE
     222    bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     223    bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     224    bid128_mul (&res, &x1, &y1
     225  	      _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     226  	      _EXC_INFO_ARG);
     227  #else
     228    x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     229    y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     230    res = bid128_mul (x1, y1
     231  		    _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     232  		    _EXC_INFO_ARG);
     233  #endif
     234    BID_RETURN (res);
     235  }
     236  
     237  
     238  #if DECIMAL_CALL_BY_REFERENCE
     239  void
     240  bid128dq_mul (UINT128 * pres, UINT64 * px, UINT128 * py
     241  	      _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     242  	      _EXC_INFO_PARAM) {
     243    UINT64 x = *px;
     244  #if !DECIMAL_GLOBAL_ROUNDING
     245    unsigned int rnd_mode = *prnd_mode;
     246  #endif
     247  #else
     248  UINT128
     249  bid128dq_mul (UINT64 x, UINT128 y
     250  	      _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     251  	      _EXC_INFO_PARAM) {
     252  #endif
     253    UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
     254    };
     255    UINT128 x1;
     256  
     257  #if DECIMAL_CALL_BY_REFERENCE
     258    bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     259    bid128_mul (&res, &x1, py
     260  	      _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     261  	      _EXC_INFO_ARG);
     262  #else
     263    x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     264    res = bid128_mul (x1, y
     265  		    _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     266  		    _EXC_INFO_ARG);
     267  #endif
     268    BID_RETURN (res);
     269  }
     270  
     271  
     272  #if DECIMAL_CALL_BY_REFERENCE
     273  void
     274  bid128qd_mul (UINT128 * pres, UINT128 * px, UINT64 * py
     275  	      _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     276  	      _EXC_INFO_PARAM) {
     277    UINT64 y = *py;
     278  #if !DECIMAL_GLOBAL_ROUNDING
     279    unsigned int rnd_mode = *prnd_mode;
     280  #endif
     281  #else
     282  UINT128
     283  bid128qd_mul (UINT128 x, UINT64 y
     284  	      _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     285  	      _EXC_INFO_PARAM) {
     286  #endif
     287    UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
     288    };
     289    UINT128 y1;
     290  
     291  #if DECIMAL_CALL_BY_REFERENCE
     292    bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     293    bid128_mul (&res, px, &y1
     294  	      _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     295  	      _EXC_INFO_ARG);
     296  #else
     297    y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
     298    res = bid128_mul (x, y1
     299  		    _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     300  		    _EXC_INFO_ARG);
     301  #endif
     302    BID_RETURN (res);
     303  }
     304  
     305  
     306  // bid128_mul stands for bid128qq_mul
     307  #if DECIMAL_CALL_BY_REFERENCE
     308  void
     309  bid128_mul (UINT128 * pres, UINT128 * px,
     310  	    UINT128 *
     311  	    py _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     312  	    _EXC_INFO_PARAM) {
     313    UINT128 x = *px, y = *py;
     314  
     315  #if !DECIMAL_GLOBAL_ROUNDING
     316    unsigned int rnd_mode = *prnd_mode;
     317  
     318  #endif
     319  #else
     320  UINT128
     321  bid128_mul (UINT128 x,
     322  	    UINT128 y _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
     323  	    _EXC_INFO_PARAM) {
     324  
     325  #endif
     326    UINT128 z = { {0x0000000000000000ull, 0x5ffe000000000000ull}
     327    };
     328    UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull}
     329    };
     330    UINT64 x_sign, y_sign, p_sign;
     331    UINT64 x_exp, y_exp, p_exp;
     332    int true_p_exp;
     333    UINT128 C1, C2;
     334  
     335    BID_SWAP128 (x);
     336    BID_SWAP128 (y);
     337    // skip cases where at least one operand is NaN or infinity
     338    if (!(((x.w[1] & MASK_NAN) == MASK_NAN) ||
     339  	((y.w[1] & MASK_NAN) == MASK_NAN) ||
     340  	((x.w[1] & MASK_ANY_INF) == MASK_INF) ||
     341  	((y.w[1] & MASK_ANY_INF) == MASK_INF))) {
     342      // x, y are 0 or f but not inf or NaN => unpack the arguments and check
     343      // for non-canonical values
     344  
     345      x_sign = x.w[1] & MASK_SIGN;	// 0 for positive, MASK_SIGN for negative
     346      C1.w[1] = x.w[1] & MASK_COEFF;
     347      C1.w[0] = x.w[0];
     348      // check for non-canonical values - treated as zero
     349      if ((x.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) {
     350        // G0_G1=11 => non-canonical
     351        x_exp = (x.w[1] << 2) & MASK_EXP;	// biased and shifted left 49 bits
     352        C1.w[1] = 0;	// significand high
     353        C1.w[0] = 0;	// significand low
     354      } else {	// G0_G1 != 11
     355        x_exp = x.w[1] & MASK_EXP;	// biased and shifted left 49 bits
     356        if (C1.w[1] > 0x0001ed09bead87c0ull ||
     357  	  (C1.w[1] == 0x0001ed09bead87c0ull &&
     358  	   C1.w[0] > 0x378d8e63ffffffffull)) {
     359  	// x is non-canonical if coefficient is larger than 10^34 -1
     360  	C1.w[1] = 0;
     361  	C1.w[0] = 0;
     362        } else {	// canonical          
     363  	;
     364        }
     365      }
     366      y_sign = y.w[1] & MASK_SIGN;	// 0 for positive, MASK_SIGN for negative
     367      C2.w[1] = y.w[1] & MASK_COEFF;
     368      C2.w[0] = y.w[0];
     369      // check for non-canonical values - treated as zero
     370      if ((y.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) {
     371        // G0_G1=11 => non-canonical
     372        y_exp = (y.w[1] << 2) & MASK_EXP;	// biased and shifted left 49 bits
     373        C2.w[1] = 0;	// significand high
     374        C2.w[0] = 0;	// significand low 
     375      } else {	// G0_G1 != 11
     376        y_exp = y.w[1] & MASK_EXP;	// biased and shifted left 49 bits
     377        if (C2.w[1] > 0x0001ed09bead87c0ull ||
     378  	  (C2.w[1] == 0x0001ed09bead87c0ull &&
     379  	   C2.w[0] > 0x378d8e63ffffffffull)) {
     380  	// y is non-canonical if coefficient is larger than 10^34 -1
     381  	C2.w[1] = 0;
     382  	C2.w[0] = 0;
     383        } else {	// canonical
     384  	;
     385        }
     386      }
     387      p_sign = x_sign ^ y_sign;	// sign of the product
     388  
     389      true_p_exp = (x_exp >> 49) - 6176 + (y_exp >> 49) - 6176;
     390      // true_p_exp, p_exp are used only for 0 * 0, 0 * f, or f * 0 
     391      if (true_p_exp < -6176)
     392        p_exp = 0;	// cannot be less than EXP_MIN
     393      else if (true_p_exp > 6111)
     394        p_exp = (UINT64) (6111 + 6176) << 49;	// cannot be more than EXP_MAX
     395      else
     396        p_exp = (UINT64) (true_p_exp + 6176) << 49;
     397  
     398      if ((C1.w[1] == 0x0 && C1.w[0] == 0x0) ||
     399  	(C2.w[1] == 0x0 && C2.w[0] == 0x0)) {
     400        // x = 0 or y = 0
     401        // the result is 0
     402        res.w[1] = p_sign | p_exp;	// preferred exponent in [EXP_MIN, EXP_MAX]
     403        res.w[0] = 0x0;
     404        BID_SWAP128 (res);
     405        BID_RETURN (res)
     406      }	// else continue
     407    }
     408  
     409    BID_SWAP128 (x);
     410    BID_SWAP128 (y);
     411    BID_SWAP128 (z);
     412    // swap x and y - ensure that a NaN in x has 'higher precedence' than one in y
     413  #if DECIMAL_CALL_BY_REFERENCE
     414    bid128_fma (&res, &y, &x, &z
     415  	      _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     416  	      _EXC_INFO_ARG);
     417  #else
     418    res = bid128_fma (y, x, z
     419  		    _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
     420  		    _EXC_INFO_ARG);
     421  #endif
     422    BID_RETURN (res);
     423  }