xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/config/libbid/bid32_to_bid64.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1 /* Copyright (C) 2007-2020 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 /*
27  * Takes a BID32 as input and converts it to a BID64 and returns it.
28  */
TYPE0_FUNCTION_ARGTYPE1_NORND(UINT64,bid32_to_bid64,UINT32,x)29 TYPE0_FUNCTION_ARGTYPE1_NORND (UINT64, bid32_to_bid64, UINT32, x)
30 
31      UINT64 res;
32      UINT32 sign_x;
33      int exponent_x;
34      UINT32 coefficient_x;
35 
36 if (!unpack_BID32 (&sign_x, &exponent_x, &coefficient_x, x)) {
37     // Inf, NaN, 0
38 if (((x) & 0x78000000) == 0x78000000) {
39   if (((x) & 0x7e000000) == 0x7e000000) {	// sNaN
40 #ifdef SET_STATUS_FLAGS
41     __set_status_flags (pfpsf, INVALID_EXCEPTION);
42 #endif
43   }
44   res = (coefficient_x & 0x000fffff);
45   res *= 1000000000;
46   res |= ((((UINT64) coefficient_x) << 32) & 0xfc00000000000000ull);
47 
48   BID_RETURN (res);
49 }
50 }
51 
52 res =
53 very_fast_get_BID64_small_mantissa (((UINT64) sign_x) << 32,
54 				    exponent_x +
55 				    DECIMAL_EXPONENT_BIAS -
56 				    DECIMAL_EXPONENT_BIAS_32,
57 				    (UINT64) coefficient_x);
58 BID_RETURN (res);
59 }	// convert_bid32_to_bid64
60 
61 
62 /*
63  * Takes a BID64 as input and converts it to a BID32 and returns it.
64  */
65 #if DECIMAL_CALL_BY_REFERENCE
66 
67 void
68 bid64_to_bid32 (UINT32 * pres,
69 		UINT64 *
70 		px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
71 		_EXC_INFO_PARAM) {
72   UINT64 x;
73 #else
74 
75 UINT32
76 bid64_to_bid32 (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM
77 		_EXC_MASKS_PARAM _EXC_INFO_PARAM) {
78 #endif
79   UINT128 Q;
80   UINT64 sign_x, coefficient_x, remainder_h, carry, Stemp;
81   UINT32 res;
82   int_float tempx;
83   int exponent_x, bin_expon_cx, extra_digits, rmode = 0, amount;
84   unsigned status = 0;
85 
86 #if DECIMAL_CALL_BY_REFERENCE
87 #if !DECIMAL_GLOBAL_ROUNDING
88   _IDEC_round rnd_mode = *prnd_mode;
89 #endif
90   x = *px;
91 #endif
92 
93   // unpack arguments, check for NaN or Infinity, 0
94   if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) {
95     if (((x) & 0x7800000000000000ull) == 0x7800000000000000ull) {
96       res = (coefficient_x & 0x0003ffffffffffffull);
97       res /= 1000000000ull;
98       res |= ((coefficient_x >> 32) & 0xfc000000);
99 #ifdef SET_STATUS_FLAGS
100       if ((x & SNAN_MASK64) == SNAN_MASK64)	// sNaN
101 	__set_status_flags (pfpsf, INVALID_EXCEPTION);
102 #endif
103       BID_RETURN (res);
104     }
105     exponent_x =
106       exponent_x - DECIMAL_EXPONENT_BIAS + DECIMAL_EXPONENT_BIAS_32;
107     if (exponent_x < 0)
108       exponent_x = 0;
109     if (exponent_x > DECIMAL_MAX_EXPON_32)
110       exponent_x = DECIMAL_MAX_EXPON_32;
111     res = (sign_x >> 32) | (exponent_x << 23);
112     BID_RETURN (res);
113   }
114 
115   exponent_x =
116     exponent_x - DECIMAL_EXPONENT_BIAS + DECIMAL_EXPONENT_BIAS_32;
117 
118   // check number of digits
119   if (coefficient_x >= 10000000) {
120     tempx.d = (float) coefficient_x;
121     bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
122     extra_digits = estimate_decimal_digits[bin_expon_cx] - 7;
123     // add test for range
124     if (coefficient_x >= power10_index_binexp[bin_expon_cx])
125       extra_digits++;
126 
127 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
128 #ifndef IEEE_ROUND_NEAREST
129     rmode = rnd_mode;
130     if (sign_x && (unsigned) (rmode - 1) < 2)
131       rmode = 3 - rmode;
132 #else
133     rmode = 0;
134 #endif
135 #else
136     rmode = 0;
137 #endif
138 
139     exponent_x += extra_digits;
140     if ((exponent_x < 0) && (exponent_x + MAX_FORMAT_DIGITS_32 >= 0)) {
141       status = UNDERFLOW_EXCEPTION;
142       if (exponent_x == -1)
143 	if (coefficient_x + round_const_table[rmode][extra_digits] >=
144 	    power10_table_128[extra_digits + 7].w[0])
145 	  status = 0;
146       extra_digits -= exponent_x;
147       exponent_x = 0;
148     }
149     coefficient_x += round_const_table[rmode][extra_digits];
150     __mul_64x64_to_128 (Q, coefficient_x,
151 			reciprocals10_64[extra_digits]);
152 
153     // now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
154     amount = short_recip_scale[extra_digits];
155 
156     coefficient_x = Q.w[1] >> amount;
157 
158 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
159 #ifndef IEEE_ROUND_NEAREST
160     if (rmode == 0)	//ROUNDING_TO_NEAREST
161 #endif
162       if (coefficient_x & 1) {
163 	// check whether fractional part of initial_P/10^extra_digits
164 	// is exactly .5
165 
166 	// get remainder
167 	remainder_h = Q.w[1] << (64 - amount);
168 
169 	if (!remainder_h && (Q.w[0] < reciprocals10_64[extra_digits]))
170 	  coefficient_x--;
171       }
172 #endif
173 
174 #ifdef SET_STATUS_FLAGS
175 
176     {
177       status |= INEXACT_EXCEPTION;
178       // get remainder
179       remainder_h = Q.w[1] << (64 - amount);
180 
181       switch (rmode) {
182       case ROUNDING_TO_NEAREST:
183       case ROUNDING_TIES_AWAY:
184 	// test whether fractional part is 0
185 	if (remainder_h == 0x8000000000000000ull
186 	    && (Q.w[0] < reciprocals10_64[extra_digits]))
187 	  status = EXACT_STATUS;
188 	break;
189       case ROUNDING_DOWN:
190       case ROUNDING_TO_ZERO:
191 	if (!remainder_h && (Q.w[0] < reciprocals10_64[extra_digits]))
192 	  status = EXACT_STATUS;
193 	break;
194       default:
195 	// round up
196 	__add_carry_out (Stemp, carry, Q.w[0],
197 			 reciprocals10_64[extra_digits]);
198 	if ((remainder_h >> (64 - amount)) + carry >=
199 	    (((UINT64) 1) << amount))
200 	  status = EXACT_STATUS;
201       }
202 
203       if (status != EXACT_STATUS)
204 	__set_status_flags (pfpsf, status);
205     }
206 
207 #endif
208 
209   }
210 
211   res =
212     get_BID32 ((UINT32) (sign_x >> 32),
213 	       exponent_x, coefficient_x, rnd_mode, pfpsf);
214   BID_RETURN (res);
215 
216 }
217