]> 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
8d9254fc 3 Copyright (C) 2008-2020 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
d9dd51dc 55static inline unsigned short
8630cadb
JG
56__gnu_float2h_internal (const struct format* fmt,
57 unsigned long long a, int ieee)
d9dd51dc 58{
8630cadb
JG
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);
d9dd51dc 68
8630cadb
JG
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)
d9dd51dc
PB
74 {
75 if (!ieee)
76 return sign;
4dfe21ac
RE
77 if (mantissa == 0)
78 return sign | 0x7c00; /* Infinity. */
79 /* Remaining cases are NaNs. Convert SNaN to QNaN. */
8630cadb 80 return sign | 0x7e00 | (mantissa >> (fmt->significand - 10));
d9dd51dc 81 }
4dfe21ac 82
8630cadb 83 /* Zero. */
d9dd51dc
PB
84 if (aexp == 0 && mantissa == 0)
85 return sign;
86
8630cadb
JG
87 /* Construct the exponent and mantissa. */
88 aexp -= fmt->bias;
89
90 /* Decimal point is immediately after the significand. */
91 mantissa |= point;
d9dd51dc 92
d9dd51dc
PB
93 if (aexp < -14)
94 {
8630cadb
JG
95 mask = point | (point - 1);
96 /* Minimum exponent for half-precision is 2^-24. */
65f14117 97 if (aexp >= -25)
4dfe21ac 98 mask >>= 25 + aexp;
d9dd51dc
PB
99 }
100 else
8630cadb 101 mask = (point - 1) >> 10;
d9dd51dc
PB
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;
8630cadb
JG
110 if (mantissa >= (point << 1))
111 {
d9dd51dc
PB
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
8630cadb
JG
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);
d9dd51dc
PB
160}
161
bea64ca3
JG
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
d9dd51dc
PB
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}
bea64ca3
JG
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}