]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/arm/fp16.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / arm / fp16.c
CommitLineData
d9dd51dc
PB
1/* Half-float conversion routines.
2
7adcbafe 3 Copyright (C) 2008-2022 Free Software Foundation, Inc.
d9dd51dc
PB
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
8630cadb
JG
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
bea64ca3
JG
46static const struct format
47binary64 =
48{
49 64, /* size. */
50 1023, /* bias. */
51 11, /* exponent. */
52 52 /* significand. */
53};
54
9fcedcc3
CL
55/* Function prototypes. */
56unsigned short __gnu_f2h_ieee (unsigned int a);
57unsigned int __gnu_h2f_ieee (unsigned short a);
58unsigned short __gnu_f2h_alternative (unsigned int x);
59unsigned int __gnu_h2f_alternative (unsigned short a);
60unsigned short __gnu_d2h_ieee (unsigned long long a);
61unsigned short __gnu_d2h_alternative (unsigned long long x);
62
d9dd51dc 63static inline unsigned short
8630cadb
JG
64__gnu_float2h_internal (const struct format* fmt,
65 unsigned long long a, int ieee)
d9dd51dc 66{
8630cadb
JG
67 unsigned long long point = 1ULL << fmt->significand;
68 unsigned short sign = (a >> (fmt->size - 16)) & 0x8000;
69 int aexp;
70 unsigned long long mantissa;
71 unsigned long long mask;
72 unsigned long long increment;
73
74 /* Get the exponent and mantissa encodings. */
75 mantissa = a & (point - 1);
d9dd51dc 76
8630cadb
JG
77 mask = (1 << fmt->exponent) - 1;
78 aexp = (a >> fmt->significand) & mask;
79
80 /* Infinity, NaN and alternative format special case. */
81 if (((unsigned int) aexp) == mask)
d9dd51dc
PB
82 {
83 if (!ieee)
84 return sign;
4dfe21ac
RE
85 if (mantissa == 0)
86 return sign | 0x7c00; /* Infinity. */
87 /* Remaining cases are NaNs. Convert SNaN to QNaN. */
8630cadb 88 return sign | 0x7e00 | (mantissa >> (fmt->significand - 10));
d9dd51dc 89 }
4dfe21ac 90
8630cadb 91 /* Zero. */
d9dd51dc
PB
92 if (aexp == 0 && mantissa == 0)
93 return sign;
94
8630cadb
JG
95 /* Construct the exponent and mantissa. */
96 aexp -= fmt->bias;
97
98 /* Decimal point is immediately after the significand. */
99 mantissa |= point;
d9dd51dc 100
d9dd51dc
PB
101 if (aexp < -14)
102 {
8630cadb
JG
103 mask = point | (point - 1);
104 /* Minimum exponent for half-precision is 2^-24. */
65f14117 105 if (aexp >= -25)
4dfe21ac 106 mask >>= 25 + aexp;
d9dd51dc
PB
107 }
108 else
8630cadb 109 mask = (point - 1) >> 10;
d9dd51dc
PB
110
111 /* Round. */
112 if (mantissa & mask)
113 {
114 increment = (mask + 1) >> 1;
115 if ((mantissa & mask) == increment)
116 increment = mantissa & (increment << 1);
117 mantissa += increment;
8630cadb
JG
118 if (mantissa >= (point << 1))
119 {
d9dd51dc
PB
120 mantissa >>= 1;
121 aexp++;
122 }
123 }
124
125 if (ieee)
126 {
127 if (aexp > 15)
128 return sign | 0x7c00;
129 }
130 else
131 {
132 if (aexp > 16)
133 return sign | 0x7fff;
134 }
135
136 if (aexp < -24)
137 return sign;
138
139 if (aexp < -14)
140 {
141 mantissa >>= -14 - aexp;
142 aexp = -14;
143 }
144
8630cadb
JG
145 /* Encode the final 16-bit floating-point value.
146
147 This is formed of the sign bit, the bias-adjusted exponent, and the
148 calculated mantissa, with the following caveats:
149
150 1. The mantissa calculated after rounding could have a leading 1.
151 To compensate for this, subtract one from the exponent bias (15)
152 before adding it to the calculated exponent.
153 2. When we were calculating rounding, we left the mantissa with the
154 number of bits of the source operand, it needs reduced to ten
155 bits (+1 for the afforementioned leading 1) by shifting right by
156 the number of bits in the source mantissa - 10.
157 3. To ensure the leading 1 in the mantissa is applied to the exponent
158 we need to add the mantissa rather than apply an arithmetic "or"
159 to it. */
160
161 return sign | (((aexp + 14) << 10) + (mantissa >> (fmt->significand - 10)));
162}
163
164static inline unsigned short
165__gnu_f2h_internal (unsigned int a, int ieee)
166{
167 return __gnu_float2h_internal (&binary32, (unsigned long long) a, ieee);
d9dd51dc
PB
168}
169
bea64ca3
JG
170static inline unsigned short
171__gnu_d2h_internal (unsigned long long a, int ieee)
172{
173 return __gnu_float2h_internal (&binary64, a, ieee);
174}
175
9fcedcc3 176static inline unsigned int
d9dd51dc
PB
177__gnu_h2f_internal(unsigned short a, int ieee)
178{
179 unsigned int sign = (unsigned int)(a & 0x8000) << 16;
180 int aexp = (a >> 10) & 0x1f;
181 unsigned int mantissa = a & 0x3ff;
182
183 if (aexp == 0x1f && ieee)
184 return sign | 0x7f800000 | (mantissa << 13);
185
186 if (aexp == 0)
187 {
188 int shift;
189
190 if (mantissa == 0)
191 return sign;
192
193 shift = __builtin_clz(mantissa) - 21;
194 mantissa <<= shift;
195 aexp = -shift;
196 }
197
198 return sign | (((aexp + 0x70) << 23) + (mantissa << 13));
199}
200
201unsigned short
202__gnu_f2h_ieee(unsigned int a)
203{
204 return __gnu_f2h_internal(a, 1);
205}
206
207unsigned int
208__gnu_h2f_ieee(unsigned short a)
209{
210 return __gnu_h2f_internal(a, 1);
211}
212
213unsigned short
214__gnu_f2h_alternative(unsigned int x)
215{
216 return __gnu_f2h_internal(x, 0);
217}
218
219unsigned int
220__gnu_h2f_alternative(unsigned short a)
221{
222 return __gnu_h2f_internal(a, 0);
223}
bea64ca3
JG
224
225unsigned short
226__gnu_d2h_ieee (unsigned long long a)
227{
228 return __gnu_d2h_internal (a, 1);
229}
230
231unsigned short
232__gnu_d2h_alternative (unsigned long long x)
233{
234 return __gnu_d2h_internal (x, 0);
235}