LCOV - code coverage report
Current view: top level - asmjit - armoperand.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 0 5 0.0 %
Date: 2026-11-05 10:19:06 Functions: 0 5 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_ARMOPERAND_H_INCLUDED
       8             : #define ASMJIT_ARM_ARMOPERAND_H_INCLUDED
       9             : 
      10             : #include "archtraits.h"
      11             : #include "operand.h"
      12             : #include "type.h"
      13             : #include "armglobals.h"
      14             : 
      15             : ASMJIT_BEGIN_SUB_NAMESPACE(arm)
      16             : 
      17             : //! \addtogroup asmjit_arm
      18             : //! \{
      19             : 
      20             : class Reg;
      21             : class Mem;
      22             : 
      23             : class Gp;
      24             : class GpW;
      25             : class GpX;
      26             : 
      27             : class Vec;
      28             : class VecB;
      29             : class VecH;
      30             : class VecS;
      31             : class VecD;
      32             : class VecV;
      33             : 
      34             : //! Register traits (ARM/AArch64).
      35             : //!
      36             : //! Register traits contains information about a particular register type. It's used by asmjit to setup register
      37             : //! information on-the-fly and to populate tables that contain register information (this way it's possible to
      38             : //! change register types and groups without having to reorder these tables).
      39             : template<RegType kRegType>
      40             : struct RegTraits : public BaseRegTraits {};
      41             : 
      42             : //! \cond
      43             : // <--------------------+-----+-------------------------+------------------------+---+---+------------------+
      44             : //                      | Reg |        Reg-Type         |        Reg-Group       |Sz |Cnt|      TypeId      |
      45             : // <--------------------+-----+-------------------------+------------------------+---+---+------------------+
      46             : ASMJIT_DEFINE_REG_TRAITS(GpW  , RegType::kARM_GpW       , RegGroup::kGp          , 4 , 32, TypeId::kInt32   );
      47             : ASMJIT_DEFINE_REG_TRAITS(GpX  , RegType::kARM_GpX       , RegGroup::kGp          , 8 , 32, TypeId::kInt64   );
      48             : ASMJIT_DEFINE_REG_TRAITS(VecB , RegType::kARM_VecB      , RegGroup::kVec         , 1 , 32, TypeId::kVoid    );
      49             : ASMJIT_DEFINE_REG_TRAITS(VecH , RegType::kARM_VecH      , RegGroup::kVec         , 2 , 32, TypeId::kVoid    );
      50             : ASMJIT_DEFINE_REG_TRAITS(VecS , RegType::kARM_VecS      , RegGroup::kVec         , 4 , 32, TypeId::kInt32x1 );
      51             : ASMJIT_DEFINE_REG_TRAITS(VecD , RegType::kARM_VecD      , RegGroup::kVec         , 8 , 32, TypeId::kInt32x2 );
      52             : ASMJIT_DEFINE_REG_TRAITS(VecV , RegType::kARM_VecV      , RegGroup::kVec         , 16, 32, TypeId::kInt32x4 );
      53             : //! \endcond
      54             : 
      55             : //! Register (ARM).
      56             : class Reg : public BaseReg {
      57             : public:
      58             :   ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg)
      59             : 
      60             :   //! Gets whether the register is a `R|W` register (32-bit).
      61             :   inline constexpr bool isGpW() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
      62             :   //! Gets whether the register is an `X` register (64-bit).
      63             :   inline constexpr bool isGpX() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpX>::kSignature; }
      64             :   //! Gets whether the register is a VEC-B register (8-bit).
      65             :   inline constexpr bool isVecB() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
      66             :   //! Gets whether the register is a VEC-H register (16-bit).
      67             :   inline constexpr bool isVecH() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
      68             :   //! Gets whether the register is a VEC-S register (32-bit).
      69             :   inline constexpr bool isVecS() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
      70             :   //! Gets whether the register is a VEC-D register (64-bit).
      71             :   inline constexpr bool isVecD() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
      72             :   //! Gets whether the register is a VEC-Q register (128-bit).
      73             :   inline constexpr bool isVecQ() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
      74             : 
      75             :   //! Gets whether the register is either VEC-D (64-bit) or VEC-Q (128-bit).
      76             :   inline constexpr bool isVecDOrQ() const noexcept { return uint32_t(type()) - uint32_t(RegType::kARM_VecD) <= 1u; }
      77             : 
      78             :   //! Gets whether the register is a VEC-V register (128-bit).
      79             :   inline constexpr bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
      80             : 
      81             :   template<RegType kRegType>
      82             :   inline void setRegT(uint32_t id) noexcept {
      83             :     setSignature(RegTraits<kRegType>::kSignature);
      84             :     setId(id);
      85             :   }
      86             : 
      87             :   inline void setTypeAndId(RegType type, uint32_t id) noexcept {
      88             :     setSignature(signatureOf(type));
      89             :     setId(id);
      90             :   }
      91             : 
      92             :   static inline RegGroup groupOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToGroup(type); }
      93             :   static inline TypeId typeIdOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToTypeId(type); }
      94             :   static inline OperandSignature signatureOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToSignature(type); }
      95             : 
      96             :   template<RegType kRegType>
      97             :   static inline RegGroup groupOfT() noexcept { return RegTraits<kRegType>::kGroup; }
      98             : 
      99             :   template<RegType kRegType>
     100             :   static inline TypeId typeIdOfT() noexcept { return RegTraits<kRegType>::kTypeId; }
     101             : 
     102             :   template<RegType kRegType>
     103             :   static inline OperandSignature signatureOfT() noexcept { return RegTraits<kRegType>::kSignature; }
     104             : 
     105             :   static inline bool isGpW(const Operand_& op) noexcept { return op.as<Reg>().isGpW(); }
     106             :   static inline bool isGpX(const Operand_& op) noexcept { return op.as<Reg>().isGpX(); }
     107             :   static inline bool isVecB(const Operand_& op) noexcept { return op.as<Reg>().isVecB(); }
     108             :   static inline bool isVecH(const Operand_& op) noexcept { return op.as<Reg>().isVecH(); }
     109             :   static inline bool isVecS(const Operand_& op) noexcept { return op.as<Reg>().isVecS(); }
     110             :   static inline bool isVecD(const Operand_& op) noexcept { return op.as<Reg>().isVecD(); }
     111             :   static inline bool isVecQ(const Operand_& op) noexcept { return op.as<Reg>().isVecQ(); }
     112             :   static inline bool isVecV(const Operand_& op) noexcept { return op.as<Reg>().isVecV(); }
     113             : 
     114             :   static inline bool isGpW(const Operand_& op, uint32_t id) noexcept { return isGpW(op) & (op.id() == id); }
     115             :   static inline bool isGpX(const Operand_& op, uint32_t id) noexcept { return isGpX(op) & (op.id() == id); }
     116             :   static inline bool isVecB(const Operand_& op, uint32_t id) noexcept { return isVecB(op) & (op.id() == id); }
     117             :   static inline bool isVecH(const Operand_& op, uint32_t id) noexcept { return isVecH(op) & (op.id() == id); }
     118             :   static inline bool isVecS(const Operand_& op, uint32_t id) noexcept { return isVecS(op) & (op.id() == id); }
     119             :   static inline bool isVecD(const Operand_& op, uint32_t id) noexcept { return isVecD(op) & (op.id() == id); }
     120             :   static inline bool isVecQ(const Operand_& op, uint32_t id) noexcept { return isVecQ(op) & (op.id() == id); }
     121             :   static inline bool isVecV(const Operand_& op, uint32_t id) noexcept { return isVecV(op) & (op.id() == id); }
     122             : };
     123             : 
     124             : //! General purpose register (ARM).
     125             : class Gp : public Reg {
     126             : public:
     127             :   ASMJIT_DEFINE_ABSTRACT_REG(Gp, Reg)
     128             : 
     129             :   //! Special register id.
     130             :   enum Id : uint32_t {
     131             :     //! Register that depends on OS, could be used as TLS offset.
     132             :     kIdOs = 18,
     133             :     //! Frame pointer.
     134             :     kIdFp = 29,
     135             :     //! Link register.
     136             :     kIdLr = 30,
     137             :     //! Stack register id.
     138             :     kIdSp = 31,
     139             :     //! Zero register id.
     140             :     //!
     141             :     //! Although zero register has the same id as stack register it has a special treatment, because we need to be
     142             :     //! able to distinguish between these two at API level. Some intructions were designed to be used with SP and
     143             :     //! some other with ZR - so we need a way to distinguish these two to make sure we emit the right thing.
     144             :     //!
     145             :     //! The number 63 is not random, when you perform `id & 31` you would always get 31 for both SP and ZR inputs,
     146             :     //! which is the identifier used by AArch64 ISA to encode either SP or ZR depending on the instruction.
     147             :     kIdZr = 63
     148             :   };
     149             : 
     150             :   inline constexpr bool isZR() const noexcept { return id() == kIdZr; }
     151             :   inline constexpr bool isSP() const noexcept { return id() == kIdSp; }
     152             : 
     153             :   //! Cast this register to a 32-bit R|W.
     154             :   inline GpW w() const noexcept;
     155             :   //! Cast this register to a 64-bit X.
     156             :   inline GpX x() const noexcept;
     157             : };
     158             : 
     159             : //! Vector register (ARM).
     160             : class Vec : public Reg {
     161             : public:
     162             :   ASMJIT_DEFINE_ABSTRACT_REG(Vec, Reg)
     163             : 
     164             :   //! Additional signature bits used by arm::Vec.
     165             :   enum AdditionalBits : uint32_t {
     166             :     // Register element type (3 bits).
     167             :     // |........|........|.XXX....|........|
     168             :     kSignatureRegElementTypeShift = 12,
     169             :     kSignatureRegElementTypeMask = 0x07 << kSignatureRegElementTypeShift,
     170             : 
     171             :     // Register has element index (1 bit).
     172             :     // |........|........|X.......|........|
     173             :     kSignatureRegElementFlagShift = 15,
     174             :     kSignatureRegElementFlagMask = 0x01 << kSignatureRegElementFlagShift,
     175             : 
     176             :     // Register element index (4 bits).
     177             :     // |........|....XXXX|........|........|
     178             :     kSignatureRegElementIndexShift = 16,
     179             :     kSignatureRegElementIndexMask = 0x0F << kSignatureRegElementIndexShift
     180             :   };
     181             : 
     182             :   //! Element type.
     183             :   enum ElementType : uint32_t {
     184             :     //! No element type specified.
     185             :     kElementTypeNone = 0,
     186             :     //! Byte elements (B8 or B16).
     187             :     kElementTypeB,
     188             :     //! Halfword elements (H4 or H8).
     189             :     kElementTypeH,
     190             :     //! Singleword elements (S2 or S4).
     191             :     kElementTypeS,
     192             :     //! Doubleword elements (D2).
     193             :     kElementTypeD,
     194             :     //! Byte elements grouped by 4 bytes (B4).
     195             :     //!
     196             :     //! \note This element-type is only used by few instructions.
     197             :     kElementTypeB4,
     198             :     //! Halfword elements grouped by 2 halfwords (H2).
     199             :     //!
     200             :     //! \note This element-type is only used by few instructions.
     201             :     kElementTypeH2,
     202             : 
     203             :     //! Count of element types.
     204             :     kElementTypeCount
     205             :   };
     206             : 
     207             :   //! \cond
     208             :   //! Shortcuts.
     209             :   enum SignatureReg : uint32_t {
     210             :     kSignatureElementB  = kElementTypeB  << kSignatureRegElementTypeShift,
     211             :     kSignatureElementH  = kElementTypeH  << kSignatureRegElementTypeShift,
     212             :     kSignatureElementS  = kElementTypeS  << kSignatureRegElementTypeShift,
     213             :     kSignatureElementD  = kElementTypeD  << kSignatureRegElementTypeShift,
     214             :     kSignatureElementB4 = kElementTypeB4 << kSignatureRegElementTypeShift,
     215             :     kSignatureElementH2 = kElementTypeH2 << kSignatureRegElementTypeShift
     216             :   };
     217             :   //! \endcond
     218             : 
     219             :   //! Returns whether the register has associated an element type.
     220             :   inline constexpr bool hasElementType() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask>(); }
     221             :   //! Returns whether the register has element index (it's an element index access).
     222             :   inline constexpr bool hasElementIndex() const noexcept { return _signature.hasField<kSignatureRegElementFlagMask>(); }
     223             :   //! Returns whether the reggister has element type or element index (or both).
     224             :   inline constexpr bool hasElementTypeOrIndex() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask | kSignatureRegElementFlagMask>(); }
     225             : 
     226             :   //! Returns element type of the register.
     227             :   inline constexpr uint32_t elementType() const noexcept { return _signature.getField<kSignatureRegElementTypeMask>(); }
     228             :   //! Sets element type of the register to `elementType`.
     229             :   inline void setElementType(uint32_t elementType) noexcept { _signature.setField<kSignatureRegElementTypeMask>(elementType); }
     230             :   //! Resets element type to none.
     231             :   inline void resetElementType() noexcept { _signature.setField<kSignatureRegElementTypeMask>(0); }
     232             : 
     233             :   //! Returns element index of the register.
     234             :   inline constexpr uint32_t elementIndex() const noexcept { return _signature.getField<kSignatureRegElementIndexMask>(); }
     235             :   //! Sets element index of the register to `elementType`.
     236             :   inline void setElementIndex(uint32_t elementIndex) noexcept {
     237             :     _signature |= kSignatureRegElementFlagMask;
     238             :     _signature.setField<kSignatureRegElementIndexMask>(elementIndex);
     239             :   }
     240             :   //! Resets element index of the register.
     241             :   inline void resetElementIndex() noexcept {
     242             :     _signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask);
     243             :   }
     244             : 
     245             :   inline constexpr bool isVecB8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementB); }
     246             :   inline constexpr bool isVecH4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementH); }
     247             :   inline constexpr bool isVecS2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementS); }
     248             :   inline constexpr bool isVecD1() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature); }
     249             : 
     250             :   inline constexpr bool isVecB16() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB); }
     251             :   inline constexpr bool isVecH8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH); }
     252             :   inline constexpr bool isVecS4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementS); }
     253             :   inline constexpr bool isVecD2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementD); }
     254             :   inline constexpr bool isVecB4x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB4); }
     255             :   inline constexpr bool isVecH2x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH2); }
     256             : 
     257             :   //! Creates a cloned register with element access.
     258             :   inline Vec at(uint32_t elementIndex) const noexcept {
     259             :     return Vec((signature() & ~kSignatureRegElementIndexMask) | (elementIndex << kSignatureRegElementIndexShift) | kSignatureRegElementFlagMask, id());
     260             :   }
     261             : 
     262             :   //! Cast this register to an 8-bit B register (scalar).
     263             :   inline VecB b() const noexcept;
     264             :   //! Cast this register to a 16-bit H register (scalar).
     265             :   inline VecH h() const noexcept;
     266             :   //! Cast this register to a 32-bit S register (scalar).
     267             :   inline VecS s() const noexcept;
     268             :   //! Cast this register to a 64-bit D register (scalar).
     269             :   inline VecD d() const noexcept;
     270             :   //! Cast this register to a 128-bit Q register (scalar).
     271             :   inline VecV q() const noexcept;
     272             :   //! Cast this register to a 128-bit V register.
     273             :   inline VecV v() const noexcept;
     274             : 
     275             :   //! Cast this register to a 128-bit V.B[elementIndex] register.
     276             :   inline VecV b(uint32_t elementIndex) const noexcept;
     277             :   //! Cast this register to a 128-bit V.H[elementIndex] register.
     278             :   inline VecV h(uint32_t elementIndex) const noexcept;
     279             :   //! Cast this register to a 128-bit V.S[elementIndex] register.
     280             :   inline VecV s(uint32_t elementIndex) const noexcept;
     281             :   //! Cast this register to a 128-bit V.D[elementIndex] register.
     282             :   inline VecV d(uint32_t elementIndex) const noexcept;
     283             :   //! Cast this register to a 128-bit V.H2[elementIndex] register.
     284             :   inline VecV h2(uint32_t elementIndex) const noexcept;
     285             :   //! Cast this register to a 128-bit V.B4[elementIndex] register.
     286             :   inline VecV b4(uint32_t elementIndex) const noexcept;
     287             : 
     288             :   //! Cast this register to V.8B.
     289             :   inline VecD b8() const noexcept;
     290             :   //! Cast this register to V.16B.
     291             :   inline VecV b16() const noexcept;
     292             :   //! Cast this register to V.2H.
     293             :   inline VecS h2() const noexcept;
     294             :   //! Cast this register to V.4H.
     295             :   inline VecD h4() const noexcept;
     296             :   //! Cast this register to V.8H.
     297             :   inline VecV h8() const noexcept;
     298             :   //! Cast this register to V.2S.
     299             :   inline VecD s2() const noexcept;
     300             :   //! Cast this register to V.4S.
     301             :   inline VecV s4() const noexcept;
     302             :   //! Cast this register to V.2D.
     303             :   inline VecV d2() const noexcept;
     304             : 
     305             :   static inline constexpr OperandSignature _makeElementAccessSignature(uint32_t elementType, uint32_t elementIndex) noexcept {
     306             :     return OperandSignature{
     307             :       uint32_t(RegTraits<RegType::kARM_VecV>::kSignature)      |
     308             :       uint32_t(kSignatureRegElementFlagMask)                   |
     309             :       uint32_t(elementType << kSignatureRegElementTypeShift)   |
     310             :       uint32_t(elementIndex << kSignatureRegElementIndexShift)};
     311             :   }
     312             : };
     313             : 
     314             : //! 32-bit GPW (AArch64) and/or GPR (ARM/AArch32) register.
     315             : class GpW : public Gp { ASMJIT_DEFINE_FINAL_REG(GpW, Gp, RegTraits<RegType::kARM_GpW>) };
     316             : //! 64-bit GPX (AArch64) register.
     317             : class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<RegType::kARM_GpX>) };
     318             : 
     319             : //! 8-bit view (S) of VFP/SIMD register.
     320             : class VecB : public Vec { ASMJIT_DEFINE_FINAL_REG(VecB, Vec, RegTraits<RegType::kARM_VecB>) };
     321             : //! 16-bit view (S) of VFP/SIMD register.
     322             : class VecH : public Vec { ASMJIT_DEFINE_FINAL_REG(VecH, Vec, RegTraits<RegType::kARM_VecH>) };
     323             : //! 32-bit view (S) of VFP/SIMD register.
     324             : class VecS : public Vec { ASMJIT_DEFINE_FINAL_REG(VecS, Vec, RegTraits<RegType::kARM_VecS>) };
     325             : //! 64-bit view (D) of VFP/SIMD register.
     326             : class VecD : public Vec { ASMJIT_DEFINE_FINAL_REG(VecD, Vec, RegTraits<RegType::kARM_VecD>) };
     327             : //! 128-bit vector register (Q or V).
     328             : class VecV : public Vec { ASMJIT_DEFINE_FINAL_REG(VecV, Vec, RegTraits<RegType::kARM_VecV>) };
     329             : 
     330             : inline GpW Gp::w() const noexcept { return GpW(id()); }
     331             : inline GpX Gp::x() const noexcept { return GpX(id()); }
     332             : 
     333             : inline VecB Vec::b() const noexcept { return VecB(id()); }
     334             : inline VecH Vec::h() const noexcept { return VecH(id()); }
     335             : inline VecS Vec::s() const noexcept { return VecS(id()); }
     336             : inline VecD Vec::d() const noexcept { return VecD(id()); }
     337             : inline VecV Vec::q() const noexcept { return VecV(id()); }
     338             : inline VecV Vec::v() const noexcept { return VecV(id()); }
     339             : 
     340             : inline VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB, elementIndex), id()); }
     341             : inline VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH, elementIndex), id()); }
     342             : inline VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeS, elementIndex), id()); }
     343             : inline VecV Vec::d(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeD, elementIndex), id()); }
     344             : inline VecV Vec::h2(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH2, elementIndex), id()); }
     345             : inline VecV Vec::b4(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB4, elementIndex), id()); }
     346             : 
     347             : inline VecD Vec::b8() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementB}, id()); }
     348             : inline VecS Vec::h2() const noexcept { return VecS(OperandSignature{VecS::kSignature | kSignatureElementH}, id()); }
     349             : inline VecD Vec::h4() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementH}, id()); }
     350             : inline VecD Vec::s2() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementS}, id()); }
     351             : inline VecV Vec::b16() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementB}, id()); }
     352             : inline VecV Vec::h8() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementH}, id()); }
     353             : inline VecV Vec::s4() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementS}, id()); }
     354             : inline VecV Vec::d2() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementD}, id()); }
     355             : 
     356             : #ifndef _DOXYGEN
     357             : namespace regs {
     358             : #endif
     359             : 
     360             : //! Creates a 32-bit W register operand (ARM/AArch64).
     361             : static inline constexpr GpW w(uint32_t id) noexcept { return GpW(id); }
     362             : //! Creates a 64-bit X register operand (AArch64).
     363             : static inline constexpr GpX x(uint32_t id) noexcept { return GpX(id); }
     364             : //! Creates a 32-bit S register operand (ARM/AArch64).
     365             : static inline constexpr VecS s(uint32_t id) noexcept { return VecS(id); }
     366             : //! Creates a 64-bit D register operand (ARM/AArch64).
     367             : static inline constexpr VecD d(uint32_t id) noexcept { return VecD(id); }
     368             : //! Creates a 1282-bit V register operand (ARM/AArch64).
     369             : static inline constexpr VecV v(uint32_t id) noexcept { return VecV(id); }
     370             : 
     371             : #ifndef _DOXYGEN
     372             : } // {regs}
     373             : 
     374             : // Make `arm::regs` accessible through `arm` namespace as well.
     375             : using namespace regs;
     376             : #endif
     377             : 
     378             : //! Memory operand (ARM).
     379             : class Mem : public BaseMem {
     380             : public:
     381             :   //! \cond INTERNAL
     382             :   //! Additional bits of operand's signature used by `arm::Mem`.
     383             :   enum AdditionalBits : uint32_t {
     384             :     // Index shift value (5 bits).
     385             :     // |........|.....XXX|XX......|........|
     386             :     kSignatureMemShiftValueShift = 14,
     387             :     kSignatureMemShiftValueMask = 0x1Fu << kSignatureMemShiftValueShift,
     388             : 
     389             :     // Shift operation type (4 bits).
     390             :     // |........|XXXX....|........|........|
     391             :     kSignatureMemPredicateShift = 20,
     392             :     kSignatureMemPredicateMask = 0x0Fu << kSignatureMemPredicateShift
     393             :   };
     394             :   //! \endcond
     395             : 
     396             :   //! Memory offset mode.
     397             :   //!
     398             :   //! Additional constants that can be used with the `predicate`.
     399             :   enum OffsetMode : uint32_t {
     400             :     //! Pre-index "[BASE, #Offset {, <shift>}]!" with write-back.
     401             :     kOffsetPreIndex = 0xE,
     402             :     //! Post-index "[BASE], #Offset {, <shift>}" with write-back.
     403             :     kOffsetPostIndex = 0xF
     404             :   };
     405             : 
     406             :   //! \name Construction & Destruction
     407             :   //! \{
     408             : 
     409             :   //! Construct a default `Mem` operand, that points to [0].
     410             :   inline constexpr Mem() noexcept
     411             :     : BaseMem() {}
     412             : 
     413             :   inline constexpr Mem(const Mem& other) noexcept
     414             :     : BaseMem(other) {}
     415             : 
     416             :   inline explicit Mem(Globals::NoInit_) noexcept
     417             :     : BaseMem(Globals::NoInit) {}
     418             : 
     419             :   inline constexpr Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept
     420             :     : BaseMem(signature, baseId, indexId, offset) {}
     421             : 
     422             :   inline constexpr explicit Mem(const Label& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
     423             :     : BaseMem(Signature::fromOpType(OperandType::kMem) |
     424             :               Signature::fromMemBaseType(RegType::kLabelTag) |
     425             :               signature, base.id(), 0, off) {}
     426             : 
     427             :   inline constexpr explicit Mem(const BaseReg& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
     428             :     : BaseMem(Signature::fromOpType(OperandType::kMem) |
     429             :               Signature::fromMemBaseType(base.type()) |
     430             :               signature, base.id(), 0, off) {}
     431             : 
     432             :   inline constexpr Mem(const BaseReg& base, const BaseReg& index, Signature signature = Signature{0}) noexcept
     433             :     : BaseMem(Signature::fromOpType(OperandType::kMem) |
     434             :               Signature::fromMemBaseType(base.type()) |
     435             :               Signature::fromMemIndexType(index.type()) |
     436             :               signature, base.id(), index.id(), 0) {}
     437             : 
     438             :   inline constexpr Mem(const BaseReg& base, const BaseReg& index, const Shift& shift, Signature signature = Signature{0}) noexcept
     439             :     : BaseMem(Signature::fromOpType(OperandType::kMem) |
     440             :               Signature::fromMemBaseType(base.type()) |
     441             :               Signature::fromMemIndexType(index.type()) |
     442             :               Signature::fromValue<kSignatureMemPredicateMask>(uint32_t(shift.op())) |
     443             :               Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) |
     444             :               signature, base.id(), index.id(), 0) {}
     445             : 
     446             :   inline constexpr Mem(uint64_t base, Signature signature = Signature{0}) noexcept
     447             :     : BaseMem(Signature::fromOpType(OperandType::kMem) |
     448             :               signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {}
     449             : 
     450             :   //! \}
     451             : 
     452             :   //! \name Overloaded Operators
     453             :   //! \{
     454             : 
     455             :   inline Mem& operator=(const Mem& other) noexcept = default;
     456             : 
     457             :   //! \}
     458             : 
     459             :   //! \name Clone
     460             :   //! \{
     461             : 
     462             :   //! Clones the memory operand.
     463             :   inline constexpr Mem clone() const noexcept { return Mem(*this); }
     464             : 
     465             :   //! Gets new memory operand adjusted by `off`.
     466             :   inline Mem cloneAdjusted(int64_t off) const noexcept {
     467             :     Mem result(*this);
     468             :     result.addOffset(off);
     469             :     return result;
     470             :   }
     471             : 
     472             :   //! Clones the memory operand and makes it pre-index.
     473             :   inline Mem pre() const noexcept {
     474             :     Mem result(*this);
     475             :     result.setPredicate(kOffsetPreIndex);
     476             :     return result;
     477             :   }
     478             : 
     479             :   //! Clones the memory operand, applies a given offset `off` and makes it pre-index.
     480             :   inline Mem pre(int64_t off) const noexcept {
     481             :     Mem result(*this);
     482             :     result.setPredicate(kOffsetPreIndex);
     483             :     result.addOffset(off);
     484             :     return result;
     485             :   }
     486             : 
     487             :   //! Clones the memory operand and makes it post-index.
     488             :   inline Mem post() const noexcept {
     489             :     Mem result(*this);
     490             :     result.setPredicate(kOffsetPreIndex);
     491             :     return result;
     492             :   }
     493             : 
     494             :   //! Clones the memory operand, applies a given offset `off` and makes it post-index.
     495             :   inline Mem post(int64_t off) const noexcept {
     496             :     Mem result(*this);
     497             :     result.setPredicate(kOffsetPostIndex);
     498             :     result.addOffset(off);
     499             :     return result;
     500             :   }
     501             : 
     502             :   //! \}
     503             : 
     504             :   //! \name Base & Index
     505             :   //! \{
     506             : 
     507             :   //! Converts memory `baseType` and `baseId` to `arm::Reg` instance.
     508             :   //!
     509             :   //! The memory must have a valid base register otherwise the result will be wrong.
     510             :   inline Reg baseReg() const noexcept { return Reg::fromTypeAndId(baseType(), baseId()); }
     511             : 
     512             :   //! Converts memory `indexType` and `indexId` to `arm::Reg` instance.
     513             :   //!
     514             :   //! The memory must have a valid index register otherwise the result will be wrong.
     515             :   inline Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); }
     516             : 
     517             :   using BaseMem::setIndex;
     518             : 
     519             :   inline void setIndex(const BaseReg& index, uint32_t shift) noexcept {
     520             :     setIndex(index);
     521             :     setShift(shift);
     522             :   }
     523             : 
     524             :   //! \}
     525             : 
     526             :   //! \name ARM Specific Features
     527             :   //! \{
     528             : 
     529             :   //! Gets whether the memory operand has shift (aka scale) constant.
     530             :   inline constexpr bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); }
     531             :   //! Gets the memory operand's shift (aka scale) constant.
     532             :   inline constexpr uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); }
     533             :   //! Sets the memory operand's shift (aka scale) constant.
     534             :   inline void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); }
     535             :   //! Resets the memory operand's shift (aka scale) constant to zero.
     536             :   inline void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); }
     537             : 
     538             :   //! Gets memory predicate (shift mode or offset mode), see \ref ShiftOp and \ref OffsetMode.
     539             :   inline constexpr uint32_t predicate() const noexcept { return _signature.getField<kSignatureMemPredicateMask>(); }
     540             :   //! Sets memory predicate to `predicate`, see `Mem::ShiftOp`.
     541             :   inline void setPredicate(uint32_t predicate) noexcept { _signature.setField<kSignatureMemPredicateMask>(predicate); }
     542             :   //! Resets shift mode to LSL (default).
     543             :   inline void resetPredicate() noexcept { _signature.setField<kSignatureMemPredicateMask>(0); }
     544             : 
     545             :   inline constexpr bool isFixedOffset() const noexcept { return predicate() < kOffsetPreIndex; }
     546           0 :   inline constexpr bool isPreOrPost() const noexcept { return predicate() >= kOffsetPreIndex; }
     547           0 :   inline constexpr bool isPreIndex() const noexcept { return predicate() == kOffsetPreIndex; }
     548           0 :   inline constexpr bool isPostIndex() const noexcept { return predicate() == kOffsetPostIndex; }
     549             : 
     550             :   inline void resetToFixedOffset() noexcept { resetPredicate(); }
     551           0 :   inline void makePreIndex() noexcept { setPredicate(kOffsetPreIndex); }
     552           0 :   inline void makePostIndex() noexcept { setPredicate(kOffsetPostIndex); }
     553             : 
     554             :   //! \}
     555             : };
     556             : 
     557             : //! Creates `[base.reg, offset]` memory operand (offset mode).
     558             : static inline constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept {
     559             :   return Mem(base, offset);
     560             : }
     561             : 
     562             : //! Creates `[base.reg, offset]!` memory operand (pre-index mode).
     563             : static inline constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept {
     564             :   return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPreIndex));
     565             : }
     566             : 
     567             : //! Creates `[base.reg], offset` memory operand (post-index mode).
     568             : static inline constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept {
     569             :   return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
     570             : }
     571             : 
     572             : //! Creates `[base.reg, index]` memory operand.
     573             : static inline constexpr Mem ptr(const Gp& base, const Gp& index) noexcept {
     574             :   return Mem(base, index);
     575             : }
     576             : 
     577             : //! Creates `[base.reg], index` memory operand (post-index mode).
     578             : static inline constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept {
     579             :   return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
     580             : }
     581             : 
     582             : //! Creates `[base.reg, index, SHIFT_OP #shift]` memory operand.
     583             : static inline constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept {
     584             :   return Mem(base, index, shift);
     585             : }
     586             : 
     587             : //! Creates `[base + offset]` memory operand.
     588             : static inline constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept {
     589             :   return Mem(base, offset);
     590             : }
     591             : 
     592             : // TODO: [ARM] PC + offset address.
     593             : #if 0
     594             : //! Creates `[PC + offset]` (relative) memory operand.
     595             : static inline constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept {
     596             :   return Mem(pc, offset);
     597             : }
     598             : #endif
     599             : 
     600             : //! Creates `[base]` absolute memory operand.
     601             : //!
     602             : //! \note The concept of absolute memory operands doesn't exist on ARM, the ISA only provides PC relative addressing.
     603             : //! Absolute memory operands can only be used if it's known that the PC relative offset is encodable and that it
     604             : //! would be within the limits. Absolute address is also often output from disassemblers, so AsmJit support it so it
     605             : //! can assemble it back.
     606             : static inline constexpr Mem ptr(uint64_t base) noexcept { return Mem(base); }
     607             : 
     608             : //! \}
     609             : 
     610             : ASMJIT_END_SUB_NAMESPACE
     611             : 
     612             : //! \cond INTERNAL
     613             : ASMJIT_BEGIN_NAMESPACE
     614             : ASMJIT_DEFINE_TYPE_ID(arm::GpW, TypeId::kInt32);
     615             : ASMJIT_DEFINE_TYPE_ID(arm::GpX, TypeId::kInt64);
     616             : ASMJIT_DEFINE_TYPE_ID(arm::VecS, TypeId::kFloat32x1);
     617             : ASMJIT_DEFINE_TYPE_ID(arm::VecD, TypeId::kFloat64x1);
     618             : ASMJIT_DEFINE_TYPE_ID(arm::VecV, TypeId::kInt32x4);
     619             : ASMJIT_END_NAMESPACE
     620             : //! \endcond
     621             : 
     622             : #endif // ASMJIT_ARM_ARMOPERAND_H_INCLUDED
     623             : 
     624             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16