LCOV - code coverage report
Current view: top level - acl/aclrt_impl/types - fp16_impl.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 39 80 48.8 %
Date: 2026-08-27 13:24:42 Functions: 3 5 60.0 %

          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           0 :     uint16_t hfSign;
      84           0 :     uint16_t hfMan;
      85           0 :     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           6 :     uint16_t mRet;
     121           6 :     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 1.14