LCOV - code coverage report
Current view: top level - asmjit - a64utils.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 0 24 0.0 %
Date: 2026-11-05 10:19:06 Functions: 0 1 0.0 %

          Line data    Source code
       1             : #ifdef __PLUMED_HAS_ASMJIT
       2             : // This file is part of AsmJit project <https://asmjit.com>
       3             : //
       4             : // See asmjit.h or LICENSE.md for license and copyright information
       5             : // SPDX-License-Identifier: Zlib
       6             : 
       7             : #ifndef ASMJIT_ARM_A64UTILS_H_INCLUDED
       8             : #define ASMJIT_ARM_A64UTILS_H_INCLUDED
       9             : 
      10             : #include "a64globals.h"
      11             : 
      12             : ASMJIT_BEGIN_SUB_NAMESPACE(a64)
      13             : 
      14             : //! \addtogroup asmjit_a64
      15             : //! \{
      16             : 
      17             : //! Public utilities and helpers for targeting AArch64 architecture.
      18             : namespace Utils {
      19             : 
      20             : //! Decomposed fields of a logical immediate value (AArch64).
      21             : struct LogicalImm {
      22             :   uint32_t n;
      23             :   uint32_t s;
      24             :   uint32_t r;
      25             : };
      26             : 
      27             : //! Encodes the given `imm` value of the given `width` to a logical immediate value represented as N, S, and R fields
      28             : //! and writes these fields to `out`.
      29             : //!
      30             : //! Encoding Table:
      31             : //!
      32             : //! ```
      33             : //! +---+--------+--------+------+
      34             : //! | N |  ImmS  |  ImmR  | Size |
      35             : //! +---+--------+--------+------+
      36             : //! | 1 | ssssss | rrrrrr |  64  |
      37             : //! | 0 | 0sssss | .rrrrr |  32  |
      38             : //! | 0 | 10ssss | ..rrrr |  16  |
      39             : //! | 0 | 110sss | ...rrr |  8   |
      40             : //! | 0 | 1110ss | ....rr |  4   |
      41             : //! | 0 | 11110s | .....r |  2   |
      42             : //! +---+--------+--------+------+
      43             : //! ```
      44             : ASMJIT_MAYBE_UNUSED
      45           0 : static bool encodeLogicalImm(uint64_t imm, uint32_t width, a64::Utils::LogicalImm* out) noexcept {
      46             :   // Determine the element width, which must be 2, 4, 8, 16, 32, or 64 bits.
      47             :   do {
      48           0 :     width /= 2;
      49             :     uint64_t mask = (uint64_t(1) << width) - 1u;
      50           0 :     if ((imm & mask) != ((imm >> width) & mask)) {
      51           0 :       width *= 2;
      52           0 :       break;
      53             :     }
      54           0 :   } while (width > 2);
      55             : 
      56             :   // Patterns of all zeros and all ones are not encodable.
      57             :   uint64_t lsbMask = Support::lsbMask<uint64_t>(width);
      58           0 :   imm &= lsbMask;
      59             : 
      60           0 :   if (imm == 0 || imm == lsbMask)
      61             :     return false;
      62             : 
      63             :   // Inspect the pattern and get the most important bit indexes.
      64             :   //
      65             :   //         oIndex <-+      +-> zIndex
      66             :   //                  |      |
      67             :   // |..zeros..|oCount|zCount|..ones..|
      68             :   // |000000000|111111|000000|11111111|
      69             : 
      70           0 :   uint32_t zIndex = Support::ctz(~imm);
      71           0 :   uint64_t zImm = imm ^ ((uint64_t(1) << zIndex) - 1);
      72           0 :   uint32_t zCount = (zImm ? Support::ctz(zImm) : width) - zIndex;
      73             : 
      74             :   uint32_t oIndex = zIndex + zCount;
      75           0 :   uint64_t oImm = ~(zImm ^ Support::lsbMask<uint64_t>(oIndex));
      76           0 :   uint32_t oCount = (oImm ? Support::ctz(oImm) : width) - (oIndex);
      77             : 
      78             :   // Verify whether the bit-pattern is encodable.
      79             :   uint64_t mustBeZero = oImm ^ ~Support::lsbMask<uint64_t>(oIndex + oCount);
      80           0 :   if (mustBeZero != 0 || (zIndex > 0 && width - (oIndex + oCount) != 0))
      81             :     return false;
      82             : 
      83           0 :   out->n = width == 64;
      84           0 :   out->s = (oCount + zIndex - 1) | (Support::neg(width * 2) & 0x3F);
      85           0 :   out->r = width - oIndex;
      86           0 :   return true;
      87             : }
      88             : 
      89             : //! Returns true if the given `imm` value is encodable as a logical immediate. The `width` argument describes the
      90             : //! width of the operation, and must be either 32 or 64. This function can be used to test whether an immediate
      91             : //! value can be used with AND, ANDS, BIC, BICS, EON, EOR, ORN, and ORR instruction.
      92             : ASMJIT_MAYBE_UNUSED
      93             : static inline bool isLogicalImm(uint64_t imm, uint32_t width) noexcept {
      94             :   LogicalImm dummy;
      95             :   return encodeLogicalImm(imm, width, &dummy);
      96             : }
      97             : 
      98             : //! Returns true if the given `imm` value is a byte mask. Byte mask has each byte part of the value set to either
      99             : //! 0x00 or 0xFF. Some ARM instructions accept immediates that form a byte-mask and this function can be used to
     100             : //! verify that the immediate is encodable before using the value.
     101             : template<typename T>
     102             : static inline bool isByteMaskImm8(const T& imm) noexcept {
     103             :   constexpr T kMask = T(0x0101010101010101 & Support::allOnes<T>());
     104           0 :   return imm == (imm & kMask) * T(255);
     105             : }
     106             : 
     107             : //! \cond
     108             : //! A generic implementation that checjs whether a floating point value can be converted to ARM Imm8.
     109             : template<typename T, uint32_t kNumBBits, uint32_t kNumCDEFGHBits, uint32_t kNumZeroBits>
     110             : static inline bool isFPImm8Generic(T val) noexcept {
     111             :   constexpr uint32_t kAllBsMask = Support::lsbMask<uint32_t>(kNumBBits);
     112             :   constexpr uint32_t kB0Pattern = Support::bitMask(kNumBBits - 1);
     113             :   constexpr uint32_t kB1Pattern = kAllBsMask ^ kB0Pattern;
     114             : 
     115           0 :   T immZ = val & Support::lsbMask<T>(kNumZeroBits);
     116           0 :   uint32_t immB = uint32_t(val >> (kNumZeroBits + kNumCDEFGHBits)) & kAllBsMask;
     117             : 
     118             :   // ImmZ must be all zeros and ImmB must either be B0 or B1 pattern.
     119           0 :   return immZ == 0 && (immB == kB0Pattern || immB == kB1Pattern);
     120             : }
     121             : //! \endcond
     122             : 
     123             : //! Returns true if the given half precision floating point `val` can be encoded as ARM IMM8 value, which represents
     124             : //! a limited set of floating point immediate values, which can be used with FMOV instruction.
     125             : //!
     126             : //! The floating point must have bits distributed in the following way:
     127             : //!
     128             : //! ```
     129             : //! [aBbbcdef|gh000000]
     130             : //! ```
     131             : static inline bool isFP16Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 3, 6, 6>(val); }
     132             : 
     133             : //! Returns true if the given single precision floating point `val` can be encoded as ARM IMM8 value, which represents
     134             : //! a limited set of floating point immediate values, which can be used with FMOV instruction.
     135             : //!
     136             : //! The floating point must have bits distributed in the following way:
     137             : //!
     138             : //! ```
     139             : //! [aBbbbbbc|defgh000|00000000|00000000]
     140             : //! ```
     141             : static inline bool isFP32Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 6, 6, 19>(val); }
     142             : //! \overload
     143             : static inline bool isFP32Imm8(float val) noexcept { return isFP32Imm8(Support::bitCast<uint32_t>(val)); }
     144             : 
     145             : //! Returns true if the given double precision floating point `val` can be encoded as ARM IMM8 value, which represents
     146             : //! a limited set of floating point immediate values, which can be used with FMOV instruction.
     147             : //!
     148             : //! The floating point must have bits distributed in the following way:
     149             : //!
     150             : //! ```
     151             : //! [aBbbbbbb|bbcdefgh|00000000|00000000|00000000|00000000|00000000|00000000]
     152             : //! ```
     153             : static inline bool isFP64Imm8(uint64_t val) noexcept { return isFPImm8Generic<uint64_t, 9, 6, 48>(val); }
     154             : //! \overload
     155             : static inline bool isFP64Imm8(double val) noexcept { return isFP64Imm8(Support::bitCast<uint64_t>(val)); }
     156             : 
     157             : //! \cond
     158             : template<typename T, uint32_t kNumBBits, uint32_t kNumCDEFGHBits, uint32_t kNumZeroBits>
     159             : static inline uint32_t encodeFPToImm8Generic(T val) noexcept {
     160           0 :   uint32_t bits = uint32_t(val >> kNumZeroBits);
     161           0 :   return ((bits >> (kNumBBits + kNumCDEFGHBits - 7)) & 0x80u) | (bits & 0x7F);
     162             : }
     163             : //! \endcond
     164             : 
     165             : //! Encodes a double precision floating point value into IMM8 format.
     166             : //!
     167             : //! \note This function expects that `isFP64Imm8(val) == true` so it doesn't perform any checks of the value and just
     168             : //! rearranges some bits into Imm8 order.
     169             : static inline uint32_t encodeFP64ToImm8(uint64_t val) noexcept { return encodeFPToImm8Generic<uint64_t, 9, 6, 48>(val); }
     170             : //! \overload
     171             : static inline uint32_t encodeFP64ToImm8(double val) noexcept { return encodeFP64ToImm8(Support::bitCast<uint64_t>(val)); }
     172             : 
     173             : } // {Utils}
     174             : 
     175             : //! \}
     176             : 
     177             : ASMJIT_END_SUB_NAMESPACE
     178             : 
     179             : #endif // ASMJIT_ARM_A64UTILS_H_INCLUDED
     180             : 
     181             : 
     182             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16