1 /* Copyright 2022 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19 * OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * Authors: AMD
22 *
23 */
24
25 #include "vpe_assert.h"
26 #include "custom_fp16.h"
27 #include <math.h>
28 #include <stdbool.h>
29
build_custom_float(double value,const struct vpe_custom_float_format2 * fmt,bool * pbNegative,unsigned int * pexponent,unsigned int * pmantissa)30 static bool build_custom_float(double value, const struct vpe_custom_float_format2 *fmt,
31 bool *pbNegative, unsigned int *pexponent, unsigned int *pmantissa)
32 {
33 bool bRet = false;
34 double mantissaConstant = 1.0;
35 double base = 2.0;
36 int expOffset = (int)(pow(2.0, fmt->exponentaBits - 1) - 1);
37 double maxFraction = 1.0 - pow(0.5, fmt->mantissaBits);
38 unsigned int exponent;
39 double mantissa;
40 unsigned int Mantissa;
41 int i;
42 bool bAlwaysFalse = false;
43
44 // if value negative and we should consider this otherwize just ignore
45 if (value < 0 && fmt->flags.bits.sign == 1)
46 *pbNegative = true;
47 else
48 *pbNegative = false;
49
50 do {
51
52 if (value == 0.0) {
53 *pexponent = 0;
54 *pmantissa = 0;
55 bRet = true;
56 break;
57 }
58
59 if (value < 0)
60 value = (-1.0) * value;
61
62 if (value < mantissaConstant) {
63 /*if log works faster then remove the loops!*/
64 for (i = 1;; i++) {
65 value *= base;
66 if (value >= mantissaConstant)
67 break;
68 }
69 if (expOffset <= i) {
70 *pexponent = 0;
71 *pmantissa = 0;
72 bRet = true;
73 break;
74 }
75 exponent = (unsigned int)(expOffset - i);
76 } else if (value >= mantissaConstant + maxFraction) {
77 for (i = 1;; i++) {
78 value /= base;
79 if (value <= mantissaConstant + maxFraction)
80 break;
81 }
82 exponent = (unsigned int)(expOffset + i);
83 } else
84 exponent = (unsigned int)expOffset;
85
86 mantissa = value - mantissaConstant;
87
88 if (mantissa < 0.0 || mantissa > 1.0)
89 mantissa = 0;
90 else
91 mantissa *= pow(2.0, fmt->mantissaBits);
92
93 Mantissa = (unsigned int)mantissa;
94
95 *pexponent = exponent;
96 *pmantissa = Mantissa;
97
98 bRet = true;
99
100 } while (bAlwaysFalse);
101
102 return bRet;
103 }
104
setup_custom_float(const struct vpe_custom_float_format2 * fmt,bool bNegative,unsigned int exponent,unsigned int mantissa,uint16_t * pvalue)105 static bool setup_custom_float(const struct vpe_custom_float_format2 *fmt, bool bNegative,
106 unsigned int exponent, unsigned int mantissa, uint16_t *pvalue)
107 {
108 unsigned int value = 0;
109 unsigned int mask;
110 unsigned int i;
111 unsigned int j;
112
113 if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 0) {
114 if (exponent & ~(unsigned int)0x3F)
115 exponent = 0x3F;
116 if (mantissa & ~(unsigned int)0xFFF)
117 mantissa = 0xFFF;
118 } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 10 && fmt->flags.bits.sign == 0) {
119 if (exponent & ~(unsigned int)0x3F)
120 exponent = 0x3F;
121 if (mantissa & ~(unsigned int)0x3FF)
122 mantissa = 0x3FF;
123 } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 1) {
124 if (exponent & ~(unsigned int)0x3F)
125 exponent = 0x3F;
126 if (mantissa & ~(unsigned int)0xFFF)
127 mantissa = 0xFFF;
128 } else if (fmt->exponentaBits == 5 && fmt->mantissaBits == 10 && fmt->flags.bits.sign == 1) {
129 if (exponent & ~(unsigned int)0x1F)
130 exponent = 0x1F;
131 if (mantissa & ~(unsigned int)0x3FF)
132 mantissa = 0x3FF;
133 } else
134 return false;
135
136 for (i = 0; i < fmt->mantissaBits; i++) {
137 mask = 1 << i;
138
139 if (mantissa & mask)
140 value |= mask;
141 }
142 for (j = 0; j < fmt->exponentaBits; j++) {
143 mask = 1 << j;
144
145 if (exponent & mask)
146 value |= mask << i;
147 }
148
149 if (bNegative == true && fmt->flags.bits.sign == 1)
150 value |= 1 << (i + j);
151
152 *pvalue = (uint16_t)value;
153
154 return true;
155 }
156
vpe_convert_from_float_to_custom_float(double value,const struct vpe_custom_float_format2 * fmt,uint16_t * pvalue)157 bool vpe_convert_from_float_to_custom_float(
158 double value, const struct vpe_custom_float_format2 *fmt, uint16_t *pvalue)
159 {
160 bool isNegative;
161 unsigned int exponent;
162 unsigned int mantissa;
163 bool ret = false;
164
165 VPE_ASSERT(
166 (fmt->flags.bits.sign == 1) && (fmt->mantissaBits == 10) && (fmt->exponentaBits == 5));
167
168 if (!build_custom_float(value, fmt, &isNegative, &exponent, &mantissa))
169 goto release;
170 if (!setup_custom_float(fmt, isNegative, exponent, mantissa, pvalue))
171 goto release;
172 ret = true;
173 release:
174 return ret;
175 }
176
setup_custom_float_generic(const struct vpe_custom_float_format2 * fmt,bool bNegative,unsigned int exponent,unsigned int mantissa,int * pvalue)177 static bool setup_custom_float_generic(const struct vpe_custom_float_format2 *fmt, bool bNegative,
178 unsigned int exponent, unsigned int mantissa, int *pvalue)
179 {
180 unsigned int value = 0;
181
182 int mask;
183
184 if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 0) {
185 if (exponent & ~0x3F)
186 exponent = 0x3F;
187 if (mantissa & ~0xFFF)
188 mantissa = 0xFFF;
189 } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 10 && fmt->flags.bits.sign == 0) {
190 if (exponent & ~0x3F)
191 exponent = 0x3F;
192 if (mantissa & ~0x3FF)
193 mantissa = 0x3FF;
194
195 } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 1) {
196 if (exponent & ~0x3F)
197 exponent = 0x3F;
198 if (mantissa & ~0xFFF)
199 mantissa = 0xFFF;
200
201 } else
202 return false;
203
204 unsigned int i;
205 unsigned int j;
206
207 for (i = 0; i < fmt->mantissaBits; i++) {
208 mask = 1 << i;
209
210 if (mantissa & mask)
211 value |= mask;
212 }
213 for (j = 0; j < fmt->exponentaBits; j++) {
214 mask = 1 << j;
215
216 if (exponent & mask)
217 value |= mask << i;
218 }
219
220 if (bNegative == true && fmt->flags.bits.sign == 1)
221 value |= 1 << (i + j);
222
223 *pvalue = value;
224
225 return true;
226 }
227
vpe_convert_to_custom_float_generic(double value,const struct vpe_custom_float_format2 * fmt,int * pvalue)228 bool vpe_convert_to_custom_float_generic(
229 double value, const struct vpe_custom_float_format2 *fmt, int *pvalue)
230 {
231 bool isNegative;
232 unsigned int exponent;
233 unsigned int mantissa;
234
235 bool ret = false;
236
237 if (!build_custom_float(value, fmt, &isNegative, &exponent, &mantissa))
238 goto release;
239 if (!setup_custom_float_generic(fmt, isNegative, exponent, mantissa, pvalue))
240 goto release;
241 ret = true;
242 release:
243 return ret;
244 }
245
vpe_convert_to_custom_float_ex_generic(double value,const struct vpe_custom_float_format2 * fmt,struct vpe_custom_float_value2 * pvalue)246 bool vpe_convert_to_custom_float_ex_generic(double value,
247 const struct vpe_custom_float_format2 *fmt, struct vpe_custom_float_value2 *pvalue)
248 {
249 bool ret = false;
250
251 if (!build_custom_float(value, fmt, &pvalue->isNegative, &pvalue->exponenta, &pvalue->mantissa))
252 goto release;
253 if (!setup_custom_float_generic(
254 fmt, pvalue->isNegative, pvalue->exponenta, pvalue->mantissa, &pvalue->value))
255 goto release;
256
257 ret = true;
258 release:
259 return ret;
260 }
261
vpe_from_1_6_12_to_double(bool bIsNegative,unsigned int E,unsigned int F,double * DoubleFloat)262 bool vpe_from_1_6_12_to_double(
263 bool bIsNegative, unsigned int E, unsigned int F, double *DoubleFloat)
264 {
265 double ret = 0;
266
267 double M, F1, A, B, C, D2, e12;
268
269 A = 2.0;
270 B = 31.0;
271 C = 1.0;
272 D2 = -30.0;
273 e12 = pow(2, 12);
274
275 M = F / e12;
276
277 if (bIsNegative == false)
278 F1 = 1.0;
279 else
280 F1 = -1.0;
281
282 if (E > 0 && E < 63)
283 ret = F1 * (C + M) * pow(A, E - B);
284 else if (E == 0 && F != 0)
285 ret = F1 * M * pow(A, D2);
286 else if (E == 0 && F == 0 && bIsNegative == true)
287 ret = -0;
288 else if (E == 0 && F == 0 && bIsNegative == false)
289 ret = 0;
290 else if (E == 63 && F != 0)
291 return false; // -1; /* Not a number*/
292 else if (E == 63 && F == 0 && bIsNegative == true)
293 return false; //-2; /* -Infinity*/
294 else if (E == 63 && F == 0 && bIsNegative == false)
295 return false; // -3; /* Infinity */
296
297 *DoubleFloat = ret;
298
299 return true;
300 }
301
vpe_convert_from_float_to_fp16(double value,uint16_t * pvalue)302 bool vpe_convert_from_float_to_fp16(double value, uint16_t *pvalue)
303 {
304 struct vpe_custom_float_format2 fmt;
305
306 fmt.flags.Uint = 0;
307 fmt.flags.bits.sign = 1;
308 fmt.mantissaBits = 10;
309 fmt.exponentaBits = 5;
310
311 return vpe_convert_from_float_to_custom_float(value, &fmt, pvalue);
312 }
313