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-08-12 11:03:50 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              : // FP16转FP32:不保留NaN/Inf语义,+Inf转65536.0,-Inf转-65536.0,NaN转98304.0,适用于所有形态
      82            0 : float32_t Fp16ToFloat(const uint16_t val)
      83              : {
      84              :     uint16_t hfSign;
      85              :     uint16_t hfMan;
      86              :     int16_t hfExp;
      87            0 :     ExtractFP16(val, &hfSign, &hfExp, &hfMan);
      88              : 
      89            0 :     while ((hfMan != 0U) && ((hfMan & FP16_MAN_HIDE_BIT) == 0U)) {
      90            0 :         hfMan <<= 1U;
      91            0 :         hfExp--;
      92              :     }
      93              : 
      94              :     uint32_t eRet;
      95              :     uint32_t mRet;
      96            0 :     if (hfMan == 0U) {
      97            0 :         eRet = 0U;
      98            0 :         mRet = 0U;
      99              :     } else {
     100            0 :         eRet = static_cast<uint32_t>(hfExp + static_cast<int16_t>(FP32_EXP_BIAS - FP16_EXP_BIAS));
     101            0 :         mRet = static_cast<uint32_t>(hfMan & FP16_MAN_MASK);
     102            0 :         mRet = mRet << (FP32_MAN_LEN - FP16_MAN_LEN);
     103              :     }
     104              : 
     105            0 :     const uint32_t sRet = hfSign;
     106              :     TypeUnion u;
     107            0 :     u.uVal = FP32_CONSTRUCTOR(sRet, eRet, mRet);
     108            0 :     const auto ret = u.fVal;
     109            0 :     return ret;
     110              : }
     111              : 
     112              : // FP32转FP16:按饱和模式处理,NaN和Inf转65504.0(0x7BFF),负Inf转-65504.0(0xFBFF),适用于所有形态
     113            6 : uint16_t FloatToFp16(const float32_t val)
     114              : {
     115              :     TypeUnion u;
     116            6 :     u.fVal = val;
     117            6 :     const uint32_t ui32V = u.uVal;                                                        // 1:8:23bit sign:exp:man
     118            6 :     const auto sRet = static_cast<uint16_t>((ui32V & FP32_SIGN_MASK) >> FP32_SIGN_INDEX); // 4Byte->2Byte
     119            6 :     const uint32_t eF = (ui32V & FP32_EXP_MASK) >> FP32_MAN_LEN;                          // 8 bit exponent
     120            6 :     uint32_t mF = (ui32V & FP32_MAN_MASK); // 23 bit mantissa dont't need to care about denormal
     121              : 
     122              :     uint16_t mRet;
     123              :     uint16_t eRet;
     124              :     // 指数溢出/NaN/Inf按饱和模式处理,转换为有符号MAX
     125            6 :     if (eF > 0x8FU) { // 0x8Fu:142=127+15
     126            2 :         eRet = FP16_MAX_EXP - 1U;
     127            2 :         mRet = FP16_MAX_MAN;
     128            4 :     } else if (eF <= 0x70U) { // 0x70u:112=127-15 Exponent underflow converts to denormalized half or signed zero
     129            1 :         eRet = 0U;
     130            1 :         if (eF >= 0x67U) {    // 0x67:103=127-24 Denormal
     131            0 :             mF = (mF | FP32_MAN_HIDE_BIT);
     132            0 :             const uint16_t shiftOut = FP32_MAN_LEN;
     133            0 :             const uint64_t mTmp = (static_cast<uint64_t>(mF)) << (eF - 0x67U);
     134              : 
     135            0 :             const bool needRound = IsRoundOne(mTmp, shiftOut);
     136            0 :             mRet = static_cast<uint16_t>(mTmp >> shiftOut);
     137            0 :             if (needRound) {
     138            0 :                 mRet++;
     139              :             }
     140            1 :         } else if ((eF == 0x66U) && (mF > 0U)) { // 0x66:102 Denormal 0<f_v<min(Denormal)
     141            0 :             mRet = 1U;
     142              :         } else {
     143            1 :             mRet = 0U;
     144              :         }
     145              :     } else { // Regular case with no overflow or underflow
     146            3 :         const uint32_t mLenDelta = FP32_MAN_LEN - FP16_MAN_LEN;
     147            3 :         eRet = static_cast<uint16_t>(eF - 0x70U);
     148            3 :         const bool needRound = IsRoundOne(static_cast<uint64_t>(mF), static_cast<uint16_t>(mLenDelta));
     149            3 :         mRet = static_cast<uint16_t>(mF >> mLenDelta);
     150            3 :         if (needRound) {
     151            0 :             mRet++;
     152              :         }
     153            3 :         if ((mRet & FP16_MAN_HIDE_BIT) != 0U) {
     154            0 :             eRet++;
     155              :         }
     156              :     }
     157              : 
     158            6 :     Fp16Normalize(eRet, mRet);
     159            6 :     const uint16_t ret = static_cast<uint16_t>(FP16_CONSTRUCTOR(sRet, eRet, mRet));
     160            6 :     return ret;
     161              : }
     162              : } // namespace acl
        

Generated by: LCOV version 2.0-1