1/* Copyright (C) 2007, 2009  Free Software Foundation, Inc.
2
3This file is part of GCC.
4
5GCC is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free
7Software Foundation; either version 3, or (at your option) any later
8version.
9
10GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or
12FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13for more details.
14
15Under Section 7 of GPL version 3, you are granted additional
16permissions described in the GCC Runtime Library Exception, version
173.1, as published by the Free Software Foundation.
18
19You should have received a copy of the GNU General Public License and
20a copy of the GCC Runtime Library Exception along with this program;
21see 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 */
29TYPE0_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
36if (!unpack_BID32 (&sign_x, &exponent_x, &coefficient_x, x)) {
37    // Inf, NaN, 0
38if (((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
52res =
53very_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);
58BID_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
67void
68bid64_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
75UINT32
76bid64_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