|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // ---------------------------------------------------------------------------- | 
|  | // Copyright 2011-2020 Arm Limited | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
|  | // use this file except in compliance with the License. You may obtain a copy | 
|  | // of the License at: | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | // License for the specific language governing permissions and limitations | 
|  | // under the License. | 
|  | // ---------------------------------------------------------------------------- | 
|  |  | 
|  | /** | 
|  | * @brief Soft-float library for IEEE-754. | 
|  | */ | 
|  |  | 
|  | #include "astc_mathlib.h" | 
|  |  | 
|  | /****************************************** | 
|  | helper functions and their lookup tables | 
|  | ******************************************/ | 
|  | /* count leading zeros functions. Only used when the input is nonzero. */ | 
|  |  | 
|  | #if defined(__GNUC__) && (defined(__i386) || defined(__amd64)) | 
|  | #elif defined(__arm__) && defined(__ARMCC_VERSION) | 
|  | #elif defined(__arm__) && defined(__GNUC__) | 
|  | #else | 
|  | /* table used for the slow default versions. */ | 
|  | static const uint8_t clz_table[256] = | 
|  | { | 
|  | 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, | 
|  | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | 
|  | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
|  | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | 
|  | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
|  | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
|  | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
|  | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | 32-bit count-leading-zeros function: use the Assembly instruction whenever possible. */ | 
|  | uint32_t clz32(uint32_t inp) | 
|  | { | 
|  | #if defined(__GNUC__) && (defined(__i386) || defined(__amd64)) | 
|  | uint32_t bsr; | 
|  | __asm__("bsrl %1, %0": "=r"(bsr):"r"(inp | 1)); | 
|  | return 31 - bsr; | 
|  | #else | 
|  | #if defined(__arm__) && defined(__ARMCC_VERSION) | 
|  | return __clz(inp);			/* armcc builtin */ | 
|  | #else | 
|  | #if defined(__arm__) && defined(__GNUC__) | 
|  | uint32_t lz; | 
|  | __asm__("clz %0, %1": "=r"(lz):"r"(inp)); | 
|  | return lz; | 
|  | #else | 
|  | /* slow default version */ | 
|  | uint32_t summa = 24; | 
|  | if (inp >= UINT32_C(0x10000)) | 
|  | { | 
|  | inp >>= 16; | 
|  | summa -= 16; | 
|  | } | 
|  | if (inp >= UINT32_C(0x100)) | 
|  | { | 
|  | inp >>= 8; | 
|  | summa -= 8; | 
|  | } | 
|  | return summa + clz_table[inp]; | 
|  | #endif | 
|  | #endif | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* convert from FP16 to FP32. */ | 
|  | sf32 sf16_to_sf32(sf16 inp) | 
|  | { | 
|  | uint32_t inpx = inp; | 
|  |  | 
|  | /* | 
|  | This table contains, for every FP16 sign/exponent value combination, | 
|  | the difference between the input FP16 value and the value obtained | 
|  | by shifting the correct FP32 result right by 13 bits. | 
|  | This table allows us to handle every case except denormals and NaN | 
|  | with just 1 table lookup, 2 shifts and 1 add. | 
|  | */ | 
|  |  | 
|  | #define WITH_MB(a) INT32_C((a) | (1 << 31)) | 
|  | static const int32_t tbl[64] = | 
|  | { | 
|  | WITH_MB(0x00000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), | 
|  | INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), | 
|  | INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), | 
|  | INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), INT32_C(0x1C000), WITH_MB(0x38000), | 
|  | WITH_MB(0x38000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), | 
|  | INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), | 
|  | INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), | 
|  | INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), INT32_C(0x54000), WITH_MB(0x70000) | 
|  | }; | 
|  |  | 
|  | int32_t res = tbl[inpx >> 10]; | 
|  | res += inpx; | 
|  |  | 
|  | /* the normal cases: the MSB of 'res' is not set. */ | 
|  | if (res >= 0)				/* signed compare */ | 
|  | return res << 13; | 
|  |  | 
|  | /* Infinity and Zero: the bottom 10 bits of 'res' are clear. */ | 
|  | if ((res & UINT32_C(0x3FF)) == 0) | 
|  | return res << 13; | 
|  |  | 
|  | /* NaN: the exponent field of 'inp' is not zero; NaNs must be quietened. */ | 
|  | if ((inpx & 0x7C00) != 0) | 
|  | return (res << 13) | UINT32_C(0x400000); | 
|  |  | 
|  | /* the remaining cases are Denormals. */ | 
|  | { | 
|  | uint32_t sign = (inpx & UINT32_C(0x8000)) << 16; | 
|  | uint32_t mskval = inpx & UINT32_C(0x7FFF); | 
|  | uint32_t leadingzeroes = clz32(mskval); | 
|  | mskval <<= leadingzeroes; | 
|  | return (mskval >> 8) + ((0x85 - leadingzeroes) << 23) + sign; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* convert from soft-float to native-float */ | 
|  | float sf16_to_float(sf16 p) | 
|  | { | 
|  | if32 i; | 
|  | i.u = sf16_to_sf32(p); | 
|  | return i.f; | 
|  | } | 
|  |  |