OSDN Git Service

Licensing changes to GPLv3 resp. GPLv3 with GCC Runtime Exception.
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid32_to_bid64.c
1 /* Copyright (C) 2007, 2009  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  */
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 }