1/* Half-float conversion routines.
2
3   Copyright (C) 2008-2020 Free Software Foundation, Inc.
4   Contributed by CodeSourcery.
5
6   This file is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; either version 3, or (at your option) any
9   later version.
10
11   This file is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   General Public License for more details.
15
16   Under Section 7 of GPL version 3, you are granted additional
17   permissions described in the GCC Runtime Library Exception, version
18   3.1, as published by the Free Software Foundation.
19
20   You should have received a copy of the GNU General Public License and
21   a copy of the GCC Runtime Library Exception along with this program;
22   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23   <http://www.gnu.org/licenses/>.  */
24
25struct format
26{
27  /* Number of bits.  */
28  unsigned long long size;
29  /* Exponent bias.  */
30  unsigned long long bias;
31  /* Exponent width in bits.  */
32  unsigned long long exponent;
33  /* Significand precision in explicitly stored bits.  */
34  unsigned long long significand;
35};
36
37static const struct format
38binary32 =
39{
40  32,   /* size.  */
41  127,  /* bias.  */
42  8,    /* exponent.  */
43  23    /* significand.  */
44};
45
46static const struct format
47binary64 =
48{
49  64,    /* size.  */
50  1023,  /* bias.  */
51  11,    /* exponent.  */
52  52     /* significand.  */
53};
54
55static inline unsigned short
56__gnu_float2h_internal (const struct format* fmt,
57			unsigned long long a, int ieee)
58{
59  unsigned long long point = 1ULL << fmt->significand;
60  unsigned short sign = (a >> (fmt->size - 16)) & 0x8000;
61  int aexp;
62  unsigned long long mantissa;
63  unsigned long long mask;
64  unsigned long long increment;
65
66  /* Get the exponent and mantissa encodings.  */
67  mantissa = a & (point - 1);
68
69  mask = (1 << fmt->exponent) - 1;
70  aexp = (a >> fmt->significand) & mask;
71
72  /* Infinity, NaN and alternative format special case.  */
73  if (((unsigned int) aexp) == mask)
74    {
75      if (!ieee)
76	return sign;
77      if (mantissa == 0)
78	return sign | 0x7c00;	/* Infinity.  */
79      /* Remaining cases are NaNs.  Convert SNaN to QNaN.  */
80      return sign | 0x7e00 | (mantissa >> (fmt->significand - 10));
81    }
82
83  /* Zero.  */
84  if (aexp == 0 && mantissa == 0)
85    return sign;
86
87  /* Construct the exponent and mantissa.  */
88  aexp -= fmt->bias;
89
90  /* Decimal point is immediately after the significand.  */
91  mantissa |= point;
92
93  if (aexp < -14)
94    {
95      mask = point | (point - 1);
96      /* Minimum exponent for half-precision is 2^-24.  */
97      if (aexp >= -25)
98	mask >>= 25 + aexp;
99    }
100  else
101    mask = (point - 1) >> 10;
102
103  /* Round.  */
104  if (mantissa & mask)
105    {
106      increment = (mask + 1) >> 1;
107      if ((mantissa & mask) == increment)
108	increment = mantissa & (increment << 1);
109      mantissa += increment;
110      if (mantissa >= (point << 1))
111	{
112	  mantissa >>= 1;
113	  aexp++;
114	}
115    }
116
117  if (ieee)
118    {
119      if (aexp > 15)
120	return sign | 0x7c00;
121    }
122  else
123    {
124      if (aexp > 16)
125	return sign | 0x7fff;
126    }
127
128  if (aexp < -24)
129    return sign;
130
131  if (aexp < -14)
132    {
133      mantissa >>= -14 - aexp;
134      aexp = -14;
135    }
136
137  /* Encode the final 16-bit floating-point value.
138
139     This is formed of the sign bit, the bias-adjusted exponent, and the
140     calculated mantissa, with the following caveats:
141
142     1.  The mantissa calculated after rounding could have a leading 1.
143	 To compensate for this, subtract one from the exponent bias (15)
144	 before adding it to the calculated exponent.
145     2.  When we were calculating rounding, we left the mantissa with the
146	 number of bits of the source operand, it needs reduced to ten
147	 bits (+1 for the afforementioned leading 1) by shifting right by
148	 the number of bits in the source mantissa - 10.
149     3.  To ensure the leading 1 in the mantissa is applied to the exponent
150	 we need to add the mantissa rather than apply an arithmetic "or"
151	 to it.  */
152
153  return sign | (((aexp + 14) << 10) + (mantissa >> (fmt->significand - 10)));
154}
155
156static inline unsigned short
157__gnu_f2h_internal (unsigned int a, int ieee)
158{
159  return __gnu_float2h_internal (&binary32, (unsigned long long) a, ieee);
160}
161
162static inline unsigned short
163__gnu_d2h_internal (unsigned long long a, int ieee)
164{
165  return __gnu_float2h_internal (&binary64, a, ieee);
166}
167
168unsigned int
169__gnu_h2f_internal(unsigned short a, int ieee)
170{
171  unsigned int sign = (unsigned int)(a & 0x8000) << 16;
172  int aexp = (a >> 10) & 0x1f;
173  unsigned int mantissa = a & 0x3ff;
174
175  if (aexp == 0x1f && ieee)
176    return sign | 0x7f800000 | (mantissa << 13);
177
178  if (aexp == 0)
179    {
180      int shift;
181
182      if (mantissa == 0)
183	return sign;
184
185      shift = __builtin_clz(mantissa) - 21;
186      mantissa <<= shift;
187      aexp = -shift;
188    }
189
190  return sign | (((aexp + 0x70) << 23) + (mantissa << 13));
191}
192
193unsigned short
194__gnu_f2h_ieee(unsigned int a)
195{
196  return __gnu_f2h_internal(a, 1);
197}
198
199unsigned int
200__gnu_h2f_ieee(unsigned short a)
201{
202  return __gnu_h2f_internal(a, 1);
203}
204
205unsigned short
206__gnu_f2h_alternative(unsigned int x)
207{
208  return __gnu_f2h_internal(x, 0);
209}
210
211unsigned int
212__gnu_h2f_alternative(unsigned short a)
213{
214  return __gnu_h2f_internal(a, 0);
215}
216
217unsigned short
218__gnu_d2h_ieee (unsigned long long a)
219{
220  return __gnu_d2h_internal (a, 1);
221}
222
223unsigned short
224__gnu_d2h_alternative (unsigned long long x)
225{
226  return __gnu_d2h_internal (x, 0);
227}
228