]>
git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/config/arm/fp16.c
1 /* Half-float conversion routines.
3 Copyright (C) 2008-2022 Free Software Foundation, Inc.
4 Contributed by CodeSourcery.
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
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.
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.
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/>. */
28 unsigned long long size
;
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
;
37 static const struct format
46 static const struct format
55 /* Function prototypes. */
56 unsigned short __gnu_f2h_ieee (unsigned int a
);
57 unsigned int __gnu_h2f_ieee (unsigned short a
);
58 unsigned short __gnu_f2h_alternative (unsigned int x
);
59 unsigned int __gnu_h2f_alternative (unsigned short a
);
60 unsigned short __gnu_d2h_ieee (unsigned long long a
);
61 unsigned short __gnu_d2h_alternative (unsigned long long x
);
63 static inline unsigned short
64 __gnu_float2h_internal (const struct format
* fmt
,
65 unsigned long long a
, int ieee
)
67 unsigned long long point
= 1ULL << fmt
->significand
;
68 unsigned short sign
= (a
>> (fmt
->size
- 16)) & 0x8000;
70 unsigned long long mantissa
;
71 unsigned long long mask
;
72 unsigned long long increment
;
74 /* Get the exponent and mantissa encodings. */
75 mantissa
= a
& (point
- 1);
77 mask
= (1 << fmt
->exponent
) - 1;
78 aexp
= (a
>> fmt
->significand
) & mask
;
80 /* Infinity, NaN and alternative format special case. */
81 if (((unsigned int) aexp
) == mask
)
86 return sign
| 0x7c00; /* Infinity. */
87 /* Remaining cases are NaNs. Convert SNaN to QNaN. */
88 return sign
| 0x7e00 | (mantissa
>> (fmt
->significand
- 10));
92 if (aexp
== 0 && mantissa
== 0)
95 /* Construct the exponent and mantissa. */
98 /* Decimal point is immediately after the significand. */
103 mask
= point
| (point
- 1);
104 /* Minimum exponent for half-precision is 2^-24. */
109 mask
= (point
- 1) >> 10;
114 increment
= (mask
+ 1) >> 1;
115 if ((mantissa
& mask
) == increment
)
116 increment
= mantissa
& (increment
<< 1);
117 mantissa
+= increment
;
118 if (mantissa
>= (point
<< 1))
128 return sign
| 0x7c00;
133 return sign
| 0x7fff;
141 mantissa
>>= -14 - aexp
;
145 /* Encode the final 16-bit floating-point value.
147 This is formed of the sign bit, the bias-adjusted exponent, and the
148 calculated mantissa, with the following caveats:
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"
161 return sign
| (((aexp
+ 14) << 10) + (mantissa
>> (fmt
->significand
- 10)));
164 static inline unsigned short
165 __gnu_f2h_internal (unsigned int a
, int ieee
)
167 return __gnu_float2h_internal (&binary32
, (unsigned long long) a
, ieee
);
170 static inline unsigned short
171 __gnu_d2h_internal (unsigned long long a
, int ieee
)
173 return __gnu_float2h_internal (&binary64
, a
, ieee
);
176 static inline unsigned int
177 __gnu_h2f_internal(unsigned short a
, int ieee
)
179 unsigned int sign
= (unsigned int)(a
& 0x8000) << 16;
180 int aexp
= (a
>> 10) & 0x1f;
181 unsigned int mantissa
= a
& 0x3ff;
183 if (aexp
== 0x1f && ieee
)
184 return sign
| 0x7f800000 | (mantissa
<< 13);
193 shift
= __builtin_clz(mantissa
) - 21;
198 return sign
| (((aexp
+ 0x70) << 23) + (mantissa
<< 13));
202 __gnu_f2h_ieee(unsigned int a
)
204 return __gnu_f2h_internal(a
, 1);
208 __gnu_h2f_ieee(unsigned short a
)
210 return __gnu_h2f_internal(a
, 1);
214 __gnu_f2h_alternative(unsigned int x
)
216 return __gnu_f2h_internal(x
, 0);
220 __gnu_h2f_alternative(unsigned short a
)
222 return __gnu_h2f_internal(a
, 0);
226 __gnu_d2h_ieee (unsigned long long a
)
228 return __gnu_d2h_internal (a
, 1);
232 __gnu_d2h_alternative (unsigned long long x
)
234 return __gnu_d2h_internal (x
, 0);