LCOV - code coverage report
Current view: top level - acl/aclrt_impl/types - fp16_impl.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 49.3 % 75 37
Test Date: 2026-07-28 10:53:01 Functions: 60.0 % 5 3

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : #include "fp16_impl.h"
      12              : 
      13              : namespace acl {
      14              : /**
      15              :  * @ingroup fp16_t global filed
      16              :  * @brief   round mode of last valid digital
      17              :  */
      18              : 
      19              : union TypeUnion {
      20              :     float32_t fVal;
      21              :     uint32_t uVal;
      22              : };
      23              : 
      24            0 : static void ExtractFP16(const uint16_t val, uint16_t* const s, int16_t* const e, uint16_t* const m)
      25              : {
      26              :     // 1.Extract
      27            0 :     *s = FP16_EXTRAC_SIGN(val);
      28            0 :     *e = static_cast<int16_t>(FP16_EXTRAC_EXP(val));
      29            0 :     *m = FP16_EXTRAC_MAN(val);
      30              : 
      31              :     // Denormal
      32            0 :     if ((*e) == 0) {
      33            0 :         *e = 1;
      34              :     }
      35            0 : }
      36              : 
      37              : /**
      38              :  * @ingroup fp16_t static method
      39              :  * @param [in] man       truncated mantissa
      40              :  * @param [in] shiftOut left shift bits based on ten bits
      41              :  * @brief   judge whether to add one to the result while converting fp16_t to other datatype
      42              :  * @return  Return true if add one, otherwise false
      43              :  */
      44            3 : static bool IsRoundOne(const uint64_t man, const uint16_t truncLen)
      45              : {
      46            3 :     uint64_t mask0 = 0x4UL;
      47            3 :     uint64_t mask1 = 0x2UL;
      48              :     uint64_t mask2;
      49            3 :     const uint64_t shiftOut = static_cast<uint64_t>(truncLen - 2U); // shift 2 byte
      50            3 :     mask0 = mask0 << shiftOut;
      51            3 :     mask1 = mask1 << shiftOut;
      52            3 :     mask2 = mask1 - 1U;
      53              : 
      54            3 :     const bool lastBit = ((man & mask0) > 0UL);
      55            3 :     const bool truncHigh = ((man & mask1) > 0UL);
      56            3 :     const bool truncLeft = ((man & mask2) > 0UL);
      57            3 :     return (truncHigh && (truncLeft || lastBit));
      58              : }
      59              : 
      60              : /**
      61              :  * @ingroup fp16_t public method
      62              :  * @param [in] exp       exponent of fp16_t value
      63              :  * @param [in] man       exponent of fp16_t value
      64              :  * @brief   normalize fp16_t value
      65              :  * @return
      66              :  */
      67            6 : static void Fp16Normalize(uint16_t& expVal, uint16_t& man)
      68              : {
      69            6 :     if (expVal >= FP16_MAX_EXP) {
      70            0 :         expVal = FP16_MAX_EXP - 1U;
      71            0 :         man = FP16_MAX_MAN;
      72            0 :         return;
      73              :     }
      74            6 :     if ((expVal == 0U) && (man == FP16_MAN_HIDE_BIT)) {
      75            0 :         expVal++;
      76            0 :         man = 0U;
      77            0 :         return;
      78              :     }
      79              : }
      80              : 
      81            0 : float32_t Fp16ToFloat(const uint16_t val)
      82              : {
      83              :     uint16_t hfSign;
      84              :     uint16_t hfMan;
      85              :     int16_t hfExp;
      86            0 :     ExtractFP16(val, &hfSign, &hfExp, &hfMan);
      87              : 
      88            0 :     while ((hfMan != 0U) && ((hfMan & FP16_MAN_HIDE_BIT) == 0U)) {
      89            0 :         hfMan <<= 1U;
      90            0 :         hfExp--;
      91              :     }
      92              : 
      93              :     uint32_t eRet;
      94              :     uint32_t mRet;
      95            0 :     if (hfMan == 0U) {
      96            0 :         eRet = 0U;
      97            0 :         mRet = 0U;
      98              :     } else {
      99            0 :         eRet = static_cast<uint32_t>(hfExp + static_cast<int16_t>(FP32_EXP_BIAS - FP16_EXP_BIAS));
     100            0 :         mRet = static_cast<uint32_t>(hfMan & FP16_MAN_MASK);
     101            0 :         mRet = mRet << (FP32_MAN_LEN - FP16_MAN_LEN);
     102              :     }
     103              : 
     104            0 :     const uint32_t sRet = hfSign;
     105              :     TypeUnion u;
     106            0 :     u.uVal = FP32_CONSTRUCTOR(sRet, eRet, mRet);
     107            0 :     const auto ret = u.fVal;
     108            0 :     return ret;
     109              : }
     110              : 
     111            6 : uint16_t FloatToFp16(const float32_t val)
     112              : {
     113              :     TypeUnion u;
     114            6 :     u.fVal = val;
     115            6 :     const uint32_t ui32V = u.uVal;                                                        // 1:8:23bit sign:exp:man
     116            6 :     const auto sRet = static_cast<uint16_t>((ui32V & FP32_SIGN_MASK) >> FP32_SIGN_INDEX); // 4Byte->2Byte
     117            6 :     const uint32_t eF = (ui32V & FP32_EXP_MASK) >> FP32_MAN_LEN;                          // 8 bit exponent
     118            6 :     uint32_t mF = (ui32V & FP32_MAN_MASK); // 23 bit mantissa dont't need to care about denormal
     119              : 
     120              :     uint16_t mRet;
     121              :     uint16_t eRet;
     122              :     // Exponent overflow/NaN converts to signed inf/NaN
     123            6 :     if (eF > 0x8FU) { // 0x8Fu:142=127+15
     124            2 :         eRet = FP16_MAX_EXP - 1U;
     125            2 :         mRet = FP16_MAX_MAN;
     126            4 :     } else if (eF <= 0x70U) { // 0x70u:112=127-15 Exponent underflow converts to denormalized half or signed zero
     127            1 :         eRet = 0U;
     128            1 :         if (eF >= 0x67U) {    // 0x67:103=127-24 Denormal
     129            0 :             mF = (mF | FP32_MAN_HIDE_BIT);
     130            0 :             const uint16_t shiftOut = FP32_MAN_LEN;
     131            0 :             const uint64_t mTmp = (static_cast<uint64_t>(mF)) << (eF - 0x67U);
     132              : 
     133            0 :             const bool needRound = IsRoundOne(mTmp, shiftOut);
     134            0 :             mRet = static_cast<uint16_t>(mTmp >> shiftOut);
     135            0 :             if (needRound) {
     136            0 :                 mRet++;
     137              :             }
     138            1 :         } else if ((eF == 0x66U) && (mF > 0U)) { // 0x66:102 Denormal 0<f_v<min(Denormal)
     139            0 :             mRet = 1U;
     140              :         } else {
     141            1 :             mRet = 0U;
     142              :         }
     143              :     } else { // Regular case with no overflow or underflow
     144            3 :         const uint32_t mLenDelta = FP32_MAN_LEN - FP16_MAN_LEN;
     145            3 :         eRet = static_cast<uint16_t>(eF - 0x70U);
     146            3 :         const bool needRound = IsRoundOne(static_cast<uint64_t>(mF), static_cast<uint16_t>(mLenDelta));
     147            3 :         mRet = static_cast<uint16_t>(mF >> mLenDelta);
     148            3 :         if (needRound) {
     149            0 :             mRet++;
     150              :         }
     151            3 :         if ((mRet & FP16_MAN_HIDE_BIT) != 0U) {
     152            0 :             eRet++;
     153              :         }
     154              :     }
     155              : 
     156            6 :     Fp16Normalize(eRet, mRet);
     157            6 :     const uint16_t ret = static_cast<uint16_t>(FP16_CONSTRUCTOR(sRet, eRet, mRet));
     158            6 :     return ret;
     159              : }
     160              : } // namespace acl
        

Generated by: LCOV version 2.0-1