Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2022 Marvell.
3 : : */
4 : :
5 : : #include "mldev_utils_scalar.h"
6 : :
7 : : #include <eal_export.h>
8 : :
9 : : /* Description:
10 : : * This file implements scalar versions of Machine Learning utility functions used to convert data
11 : : * types from higher precision to lower precision and vice-versa, except bfloat16.
12 : : */
13 : :
14 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_int8, 22.11)
15 : : int
16 : 0 : rte_ml_io_float32_to_int8(const void *input, void *output, uint64_t nb_elements, float scale,
17 : : int8_t zero_point)
18 : : {
19 : : const float *input_buffer;
20 : : int8_t *output_buffer;
21 : : uint64_t i;
22 : : int i32;
23 : :
24 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
25 : : return -EINVAL;
26 : :
27 : : input_buffer = (const float *)input;
28 : : output_buffer = (int8_t *)output;
29 : :
30 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
31 : 0 : i32 = (int32_t)(round(*input_buffer / scale) + zero_point);
32 : :
33 : : if (i32 < INT8_MIN)
34 : : i32 = INT8_MIN;
35 : :
36 : : if (i32 > INT8_MAX)
37 : : i32 = INT8_MAX;
38 : :
39 : 0 : *output_buffer = (int8_t)i32;
40 : :
41 : 0 : input_buffer++;
42 : 0 : output_buffer++;
43 : : }
44 : :
45 : : return 0;
46 : : }
47 : :
48 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_int8_to_float32, 22.11)
49 : : int
50 : 0 : rte_ml_io_int8_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
51 : : int8_t zero_point)
52 : : {
53 : : const int8_t *input_buffer;
54 : : float *output_buffer;
55 : : uint64_t i;
56 : :
57 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
58 : : return -EINVAL;
59 : :
60 : : input_buffer = (const int8_t *)input;
61 : : output_buffer = (float *)output;
62 : :
63 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
64 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
65 : :
66 : 0 : input_buffer++;
67 : 0 : output_buffer++;
68 : : }
69 : :
70 : : return 0;
71 : : }
72 : :
73 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_uint8, 22.11)
74 : : int
75 : 0 : rte_ml_io_float32_to_uint8(const void *input, void *output, uint64_t nb_elements, float scale,
76 : : uint8_t zero_point)
77 : : {
78 : : const float *input_buffer;
79 : : uint8_t *output_buffer;
80 : : int32_t i32;
81 : : uint64_t i;
82 : :
83 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
84 : : return -EINVAL;
85 : :
86 : : input_buffer = (const float *)input;
87 : : output_buffer = (uint8_t *)output;
88 : :
89 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
90 : 0 : i32 = (int32_t)(round(*input_buffer / scale) + zero_point);
91 : :
92 : : if (i32 < 0)
93 : : i32 = 0;
94 : :
95 : : if (i32 > UINT8_MAX)
96 : : i32 = UINT8_MAX;
97 : :
98 : 0 : *output_buffer = (uint8_t)i32;
99 : :
100 : 0 : input_buffer++;
101 : 0 : output_buffer++;
102 : : }
103 : :
104 : : return 0;
105 : : }
106 : :
107 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_uint8_to_float32, 22.11)
108 : : int
109 : 0 : rte_ml_io_uint8_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
110 : : uint8_t zero_point)
111 : : {
112 : : const uint8_t *input_buffer;
113 : : float *output_buffer;
114 : : uint64_t i;
115 : :
116 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
117 : : return -EINVAL;
118 : :
119 : : input_buffer = (const uint8_t *)input;
120 : : output_buffer = (float *)output;
121 : :
122 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
123 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
124 : :
125 : 0 : input_buffer++;
126 : 0 : output_buffer++;
127 : : }
128 : :
129 : : return 0;
130 : : }
131 : :
132 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_int16, 22.11)
133 : : int
134 : 0 : rte_ml_io_float32_to_int16(const void *input, void *output, uint64_t nb_elements, float scale,
135 : : int16_t zero_point)
136 : : {
137 : : const float *input_buffer;
138 : : int16_t *output_buffer;
139 : : int32_t i32;
140 : : uint64_t i;
141 : :
142 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
143 : : return -EINVAL;
144 : :
145 : : input_buffer = (const float *)input;
146 : : output_buffer = (int16_t *)output;
147 : :
148 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
149 : 0 : i32 = (int32_t)(round(*input_buffer / scale) + zero_point);
150 : :
151 : : if (i32 < INT16_MIN)
152 : : i32 = INT16_MIN;
153 : :
154 : : if (i32 > INT16_MAX)
155 : : i32 = INT16_MAX;
156 : :
157 : 0 : *output_buffer = (int16_t)i32;
158 : :
159 : 0 : input_buffer++;
160 : 0 : output_buffer++;
161 : : }
162 : :
163 : : return 0;
164 : : }
165 : :
166 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_int16_to_float32, 22.11)
167 : : int
168 : 0 : rte_ml_io_int16_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
169 : : int16_t zero_point)
170 : : {
171 : : const int16_t *input_buffer;
172 : : float *output_buffer;
173 : : uint64_t i;
174 : :
175 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
176 : : return -EINVAL;
177 : :
178 : : input_buffer = (const int16_t *)input;
179 : : output_buffer = (float *)output;
180 : :
181 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
182 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
183 : :
184 : 0 : input_buffer++;
185 : 0 : output_buffer++;
186 : : }
187 : :
188 : : return 0;
189 : : }
190 : :
191 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_uint16, 22.11)
192 : : int
193 : 0 : rte_ml_io_float32_to_uint16(const void *input, void *output, uint64_t nb_elements, float scale,
194 : : uint16_t zero_point)
195 : : {
196 : : const float *input_buffer;
197 : : uint16_t *output_buffer;
198 : : int32_t i32;
199 : : uint64_t i;
200 : :
201 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
202 : : return -EINVAL;
203 : :
204 : : input_buffer = (const float *)input;
205 : : output_buffer = (uint16_t *)output;
206 : :
207 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
208 : 0 : i32 = (int32_t)(round(*input_buffer / scale) + zero_point);
209 : :
210 : : if (i32 < 0)
211 : : i32 = 0;
212 : :
213 : : if (i32 > UINT16_MAX)
214 : : i32 = UINT16_MAX;
215 : :
216 : 0 : *output_buffer = (uint16_t)i32;
217 : :
218 : 0 : input_buffer++;
219 : 0 : output_buffer++;
220 : : }
221 : :
222 : : return 0;
223 : : }
224 : :
225 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_uint16_to_float32, 22.11)
226 : : int
227 : 0 : rte_ml_io_uint16_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
228 : : uint16_t zero_point)
229 : : {
230 : : const uint16_t *input_buffer;
231 : : float *output_buffer;
232 : : uint64_t i;
233 : :
234 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
235 : : return -EINVAL;
236 : :
237 : : input_buffer = (const uint16_t *)input;
238 : : output_buffer = (float *)output;
239 : :
240 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
241 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
242 : :
243 : 0 : input_buffer++;
244 : 0 : output_buffer++;
245 : : }
246 : :
247 : : return 0;
248 : : }
249 : :
250 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_int32, 22.11)
251 : : int
252 : 0 : rte_ml_io_float32_to_int32(const void *input, void *output, uint64_t nb_elements, float scale,
253 : : int32_t zero_point)
254 : : {
255 : : const float *input_buffer;
256 : : int32_t *output_buffer;
257 : : uint64_t i;
258 : :
259 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
260 : : return -EINVAL;
261 : :
262 : : input_buffer = (const float *)input;
263 : : output_buffer = (int32_t *)output;
264 : :
265 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
266 : 0 : *output_buffer = (int32_t)(round(*input_buffer / scale) + zero_point);
267 : :
268 : 0 : input_buffer++;
269 : 0 : output_buffer++;
270 : : }
271 : :
272 : : return 0;
273 : : }
274 : :
275 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_int32_to_float32, 22.11)
276 : : int
277 : 0 : rte_ml_io_int32_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
278 : : int32_t zero_point)
279 : : {
280 : : const int32_t *input_buffer;
281 : : float *output_buffer;
282 : : uint64_t i;
283 : :
284 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
285 : : return -EINVAL;
286 : :
287 : : input_buffer = (const int32_t *)input;
288 : : output_buffer = (float *)output;
289 : :
290 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
291 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
292 : :
293 : 0 : input_buffer++;
294 : 0 : output_buffer++;
295 : : }
296 : :
297 : : return 0;
298 : : }
299 : :
300 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_uint32, 22.11)
301 : : int
302 : 0 : rte_ml_io_float32_to_uint32(const void *input, void *output, uint64_t nb_elements, float scale,
303 : : uint32_t zero_point)
304 : : {
305 : : const float *input_buffer;
306 : : uint32_t *output_buffer;
307 : : int32_t i32;
308 : : uint64_t i;
309 : :
310 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
311 : : return -EINVAL;
312 : :
313 : : input_buffer = (const float *)input;
314 : : output_buffer = (uint32_t *)output;
315 : :
316 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
317 : 0 : i32 = (int32_t)(round(*input_buffer / scale) + zero_point);
318 : :
319 : : if (i32 < 0)
320 : : i32 = 0;
321 : :
322 : 0 : *output_buffer = (uint32_t)i32;
323 : :
324 : 0 : input_buffer++;
325 : 0 : output_buffer++;
326 : : }
327 : :
328 : : return 0;
329 : : }
330 : :
331 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_uint32_to_float32, 22.11)
332 : : int
333 : 0 : rte_ml_io_uint32_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
334 : : uint32_t zero_point)
335 : : {
336 : : const uint32_t *input_buffer;
337 : : float *output_buffer;
338 : : uint64_t i;
339 : :
340 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
341 : : return -EINVAL;
342 : :
343 : : input_buffer = (const uint32_t *)input;
344 : : output_buffer = (float *)output;
345 : :
346 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
347 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
348 : :
349 : 0 : input_buffer++;
350 : 0 : output_buffer++;
351 : : }
352 : :
353 : : return 0;
354 : : }
355 : :
356 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_int64, 22.11)
357 : : int
358 : 0 : rte_ml_io_float32_to_int64(const void *input, void *output, uint64_t nb_elements, float scale,
359 : : int64_t zero_point)
360 : : {
361 : : const float *input_buffer;
362 : : int64_t *output_buffer;
363 : : uint64_t i;
364 : :
365 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
366 : : return -EINVAL;
367 : :
368 : : input_buffer = (const float *)input;
369 : : output_buffer = (int64_t *)output;
370 : :
371 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
372 : 0 : *output_buffer = (int64_t)(round(*input_buffer / scale) + zero_point);
373 : :
374 : 0 : input_buffer++;
375 : 0 : output_buffer++;
376 : : }
377 : :
378 : : return 0;
379 : : }
380 : :
381 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_int64_to_float32, 22.11)
382 : : int
383 : 0 : rte_ml_io_int64_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
384 : : int64_t zero_point)
385 : : {
386 : : const int64_t *input_buffer;
387 : : float *output_buffer;
388 : : uint64_t i;
389 : :
390 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
391 : : return -EINVAL;
392 : :
393 : : input_buffer = (const int64_t *)input;
394 : : output_buffer = (float *)output;
395 : :
396 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
397 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
398 : :
399 : 0 : input_buffer++;
400 : 0 : output_buffer++;
401 : : }
402 : :
403 : : return 0;
404 : : }
405 : :
406 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_uint64, 22.11)
407 : : int
408 : 0 : rte_ml_io_float32_to_uint64(const void *input, void *output, uint64_t nb_elements, float scale,
409 : : uint64_t zero_point)
410 : : {
411 : : const float *input_buffer;
412 : : uint64_t *output_buffer;
413 : : int64_t i64;
414 : : uint64_t i;
415 : :
416 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
417 : : return -EINVAL;
418 : :
419 : : input_buffer = (const float *)input;
420 : : output_buffer = (uint64_t *)output;
421 : :
422 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
423 : 0 : i64 = (int64_t)(round(*input_buffer / scale) + zero_point);
424 : :
425 : : if (i64 < 0)
426 : : i64 = 0;
427 : :
428 : 0 : *output_buffer = (uint64_t)i64;
429 : :
430 : 0 : input_buffer++;
431 : 0 : output_buffer++;
432 : : }
433 : :
434 : : return 0;
435 : : }
436 : :
437 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_uint64_to_float32, 22.11)
438 : : int
439 : 0 : rte_ml_io_uint64_to_float32(const void *input, void *output, uint64_t nb_elements, float scale,
440 : : uint64_t zero_point)
441 : : {
442 : : const uint64_t *input_buffer;
443 : : float *output_buffer;
444 : : uint64_t i;
445 : :
446 [ # # # # ]: 0 : if ((scale == 0) || (nb_elements == 0) || (input == NULL) || (output == NULL))
447 : : return -EINVAL;
448 : :
449 : : input_buffer = (const uint64_t *)input;
450 : : output_buffer = (float *)output;
451 : :
452 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
453 : 0 : *output_buffer = scale * (float)(*input_buffer - zero_point);
454 : :
455 : 0 : input_buffer++;
456 : 0 : output_buffer++;
457 : : }
458 : :
459 : : return 0;
460 : : }
461 : :
462 : : /* Convert a single precision floating point number (float32) into a half precision
463 : : * floating point number (float16) using round to nearest rounding mode.
464 : : */
465 : : static uint16_t
466 : 0 : __float32_to_float16_scalar_rtn(float x)
467 : : {
468 : : union float32 f32; /* float32 input */
469 : : uint32_t f32_s; /* float32 sign */
470 : : uint32_t f32_e; /* float32 exponent */
471 : : uint32_t f32_m; /* float32 mantissa */
472 : : uint16_t f16_s; /* float16 sign */
473 : : uint16_t f16_e; /* float16 exponent */
474 : : uint16_t f16_m; /* float16 mantissa */
475 : : uint32_t tbits; /* number of truncated bits */
476 : : uint32_t tmsb; /* MSB position of truncated bits */
477 : : uint32_t m_32; /* temporary float32 mantissa */
478 : : uint16_t m_16; /* temporary float16 mantissa */
479 : : uint16_t u16; /* float16 output */
480 : : int be_16; /* float16 biased exponent, signed */
481 : :
482 : 0 : f32.f = x;
483 : 0 : f32_s = (f32.u & FP32_MASK_S) >> FP32_LSB_S;
484 : 0 : f32_e = (f32.u & FP32_MASK_E) >> FP32_LSB_E;
485 : 0 : f32_m = (f32.u & FP32_MASK_M) >> FP32_LSB_M;
486 : :
487 : : f16_s = f32_s;
488 : : f16_e = 0;
489 : : f16_m = 0;
490 : :
491 [ # # # ]: 0 : switch (f32_e) {
492 : : case (0): /* float32: zero or subnormal number */
493 : : f16_e = 0;
494 : : f16_m = 0; /* convert to zero */
495 : : break;
496 : 0 : case (FP32_MASK_E >> FP32_LSB_E): /* float32: infinity or nan */
497 : : f16_e = FP16_MASK_E >> FP16_LSB_E;
498 [ # # ]: 0 : if (f32_m == 0) { /* infinity */
499 : : f16_m = 0;
500 : : } else { /* nan, propagate mantissa and set MSB of mantissa to 1 */
501 : 0 : f16_m = f32_m >> (FP32_MSB_M - FP16_MSB_M);
502 : 0 : f16_m |= BIT(FP16_MSB_M);
503 : : }
504 : : break;
505 : 0 : default: /* float32: normal number */
506 : : /* compute biased exponent for float16 */
507 : 0 : be_16 = (int)f32_e - FP32_BIAS_E + FP16_BIAS_E;
508 : :
509 : : /* overflow, be_16 = [31-INF], set to infinity */
510 [ # # ]: 0 : if (be_16 >= (int)(FP16_MASK_E >> FP16_LSB_E)) {
511 : : f16_e = FP16_MASK_E >> FP16_LSB_E;
512 : : f16_m = 0;
513 [ # # ]: 0 : } else if ((be_16 >= 1) && (be_16 < (int)(FP16_MASK_E >> FP16_LSB_E))) {
514 : : /* normal float16, be_16 = [1:30]*/
515 : 0 : f16_e = be_16;
516 : 0 : m_16 = f32_m >> (FP32_LSB_E - FP16_LSB_E);
517 : : tmsb = FP32_MSB_M - FP16_MSB_M - 1;
518 [ # # ]: 0 : if ((f32_m & GENMASK_U32(tmsb, 0)) > BIT(tmsb)) {
519 : : /* round: non-zero truncated bits except MSB */
520 : 0 : m_16++;
521 : :
522 : : /* overflow into exponent */
523 [ # # ]: 0 : if (((m_16 & FP16_MASK_E) >> FP16_LSB_E) == 0x1)
524 : 0 : f16_e++;
525 [ # # ]: 0 : } else if ((f32_m & GENMASK_U32(tmsb, 0)) == BIT(tmsb)) {
526 : : /* round: MSB of truncated bits and LSB of m_16 is set */
527 [ # # ]: 0 : if ((m_16 & 0x1) == 0x1) {
528 : 0 : m_16++;
529 : :
530 : : /* overflow into exponent */
531 [ # # ]: 0 : if (((m_16 & FP16_MASK_E) >> FP16_LSB_E) == 0x1)
532 : 0 : f16_e++;
533 : : }
534 : : }
535 : 0 : f16_m = m_16 & FP16_MASK_M;
536 [ # # ]: 0 : } else if ((be_16 >= -(int)(FP16_MSB_M)) && (be_16 < 1)) {
537 : : /* underflow: zero / subnormal, be_16 = [-9:0] */
538 : : f16_e = 0;
539 : :
540 : : /* add implicit leading zero */
541 : 0 : m_32 = f32_m | BIT(FP32_LSB_E);
542 : 0 : tbits = FP32_LSB_E - FP16_LSB_E - be_16 + 1;
543 : 0 : m_16 = m_32 >> tbits;
544 : :
545 : : /* if non-leading truncated bits are set */
546 [ # # ]: 0 : if ((f32_m & GENMASK_U32(tbits - 1, 0)) > BIT(tbits - 1)) {
547 : 0 : m_16++;
548 : :
549 : : /* overflow into exponent */
550 [ # # ]: 0 : if (((m_16 & FP16_MASK_E) >> FP16_LSB_E) == 0x1)
551 : : f16_e++;
552 [ # # ]: 0 : } else if ((f32_m & GENMASK_U32(tbits - 1, 0)) == BIT(tbits - 1)) {
553 : : /* if leading truncated bit is set */
554 [ # # ]: 0 : if ((m_16 & 0x1) == 0x1) {
555 : 0 : m_16++;
556 : :
557 : : /* overflow into exponent */
558 [ # # ]: 0 : if (((m_16 & FP16_MASK_E) >> FP16_LSB_E) == 0x1)
559 : : f16_e++;
560 : : }
561 : : }
562 : 0 : f16_m = m_16 & FP16_MASK_M;
563 [ # # ]: 0 : } else if (be_16 == -(int)(FP16_MSB_M + 1)) {
564 : : /* underflow: zero, be_16 = [-10] */
565 : : f16_e = 0;
566 [ # # ]: 0 : if (f32_m != 0)
567 : : f16_m = 1;
568 : : else
569 : : f16_m = 0;
570 : : } else {
571 : : /* underflow: zero, be_16 = [-INF:-11] */
572 : : f16_e = 0;
573 : : f16_m = 0;
574 : : }
575 : :
576 : : break;
577 : : }
578 : :
579 : 0 : u16 = FP16_PACK(f16_s, f16_e, f16_m);
580 : :
581 : 0 : return u16;
582 : : }
583 : :
584 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float32_to_float16, 22.11)
585 : : int
586 : 0 : rte_ml_io_float32_to_float16(const void *input, void *output, uint64_t nb_elements)
587 : : {
588 : : const float *input_buffer;
589 : : uint16_t *output_buffer;
590 : : uint64_t i;
591 : :
592 [ # # # # ]: 0 : if ((nb_elements == 0) || (input == NULL) || (output == NULL))
593 : : return -EINVAL;
594 : :
595 : : input_buffer = (const float *)input;
596 : : output_buffer = (uint16_t *)output;
597 : :
598 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
599 : 0 : *output_buffer = __float32_to_float16_scalar_rtn(*input_buffer);
600 : :
601 : 0 : input_buffer = input_buffer + 1;
602 : 0 : output_buffer = output_buffer + 1;
603 : : }
604 : :
605 : : return 0;
606 : : }
607 : :
608 : : /* Convert a half precision floating point number (float16) into a single precision
609 : : * floating point number (float32).
610 : : */
611 : : static float
612 : 0 : __float16_to_float32_scalar_rtx(uint16_t f16)
613 : : {
614 : : union float32 f32; /* float32 output */
615 : : uint16_t f16_s; /* float16 sign */
616 : : uint16_t f16_e; /* float16 exponent */
617 : : uint16_t f16_m; /* float16 mantissa */
618 : : uint32_t f32_s; /* float32 sign */
619 : : uint32_t f32_e; /* float32 exponent */
620 : : uint32_t f32_m; /* float32 mantissa*/
621 : : uint8_t shift; /* number of bits to be shifted */
622 : : uint32_t clz; /* count of leading zeroes */
623 : : int e_16; /* float16 exponent unbiased */
624 : :
625 : 0 : f16_s = (f16 & FP16_MASK_S) >> FP16_LSB_S;
626 : 0 : f16_e = (f16 & FP16_MASK_E) >> FP16_LSB_E;
627 : 0 : f16_m = (f16 & FP16_MASK_M) >> FP16_LSB_M;
628 : :
629 : 0 : f32_s = f16_s;
630 [ # # # ]: 0 : switch (f16_e) {
631 : 0 : case (FP16_MASK_E >> FP16_LSB_E): /* float16: infinity or nan */
632 : : f32_e = FP32_MASK_E >> FP32_LSB_E;
633 [ # # ]: 0 : if (f16_m == 0x0) { /* infinity */
634 : : f32_m = f16_m;
635 : : } else { /* nan, propagate mantissa, set MSB of mantissa to 1 */
636 : 0 : f32_m = f16_m;
637 : : shift = FP32_MSB_M - FP16_MSB_M;
638 : 0 : f32_m = (f32_m << shift) & FP32_MASK_M;
639 : 0 : f32_m |= BIT(FP32_MSB_M);
640 : : }
641 : : break;
642 : 0 : case 0: /* float16: zero or sub-normal */
643 : 0 : f32_m = f16_m;
644 [ # # ]: 0 : if (f16_m == 0) { /* zero signed */
645 : : f32_e = 0;
646 : : } else { /* subnormal numbers */
647 : 0 : clz = rte_clz32((uint32_t)f16_m) - sizeof(uint32_t) * 8 + FP16_LSB_E;
648 : 0 : e_16 = (int)f16_e - clz;
649 : 0 : f32_e = FP32_BIAS_E + e_16 - FP16_BIAS_E;
650 : :
651 : 0 : shift = clz + (FP32_MSB_M - FP16_MSB_M) + 1;
652 : 0 : f32_m = (f32_m << shift) & FP32_MASK_M;
653 : : }
654 : : break;
655 : 0 : default: /* normal numbers */
656 : 0 : f32_m = f16_m;
657 : : e_16 = (int)f16_e;
658 : 0 : f32_e = FP32_BIAS_E + e_16 - FP16_BIAS_E;
659 : :
660 : : shift = (FP32_MSB_M - FP16_MSB_M);
661 : 0 : f32_m = (f32_m << shift) & FP32_MASK_M;
662 : : }
663 : :
664 : 0 : f32.u = FP32_PACK(f32_s, f32_e, f32_m);
665 : :
666 : 0 : return f32.f;
667 : : }
668 : :
669 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_ml_io_float16_to_float32, 22.11)
670 : : int
671 : 0 : rte_ml_io_float16_to_float32(const void *input, void *output, uint64_t nb_elements)
672 : : {
673 : : const uint16_t *input_buffer;
674 : : float *output_buffer;
675 : : uint64_t i;
676 : :
677 [ # # # # ]: 0 : if ((nb_elements == 0) || (input == NULL) || (output == NULL))
678 : : return -EINVAL;
679 : :
680 : : input_buffer = (const uint16_t *)input;
681 : : output_buffer = (float *)output;
682 : :
683 [ # # ]: 0 : for (i = 0; i < nb_elements; i++) {
684 : 0 : *output_buffer = __float16_to_float32_scalar_rtx(*input_buffer);
685 : :
686 : 0 : input_buffer = input_buffer + 1;
687 : 0 : output_buffer = output_buffer + 1;
688 : : }
689 : :
690 : : return 0;
691 : : }
|