LCOV - code coverage report
Current view: top level - asmjit - operand.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 49 90 54.4 %
Date: 2024-10-11 08:09:49 Functions: 0 0 -

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2008-2017, Petr Kobalicek
       3             : 
       4             : This software is provided 'as-is', without any express or implied
       5             : warranty. In no event will the authors be held liable for any damages
       6             : arising from the use of this software.
       7             : 
       8             : Permission is granted to anyone to use this software for any purpose,
       9             : including commercial applications, and to alter it and redistribute it
      10             : freely, subject to the following restrictions:
      11             : 
      12             : 1. The origin of this software must not be misrepresented; you must not
      13             :    claim that you wrote the original software. If you use this software
      14             :    in a product, an acknowledgment in the product documentation would be
      15             :    appreciated but is not required.
      16             : 2. Altered source versions must be plainly marked as such, and must not be
      17             :    misrepresented as being the original software.
      18             : 3. This notice may not be removed or altered from any source distribution.
      19             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      20             : #ifndef __PLUMED_asmjit_operand_h
      21             : #define __PLUMED_asmjit_operand_h
      22             : #ifdef __PLUMED_HAS_ASMJIT
      23             : #pragma GCC diagnostic push
      24             : #pragma GCC diagnostic ignored "-Wpedantic"
      25             : // [AsmJit]
      26             : // Complete x86/x64 JIT and Remote Assembler for C++.
      27             : //
      28             : // [License]
      29             : // Zlib - See LICENSE.md file in the package.
      30             : 
      31             : // [Guard]
      32             : #ifndef _ASMJIT_BASE_OPERAND_H
      33             : #define _ASMJIT_BASE_OPERAND_H
      34             : 
      35             : // [Dependencies]
      36             : #include "./utils.h"
      37             : 
      38             : // [Api-Begin]
      39             : #include "./asmjit_apibegin.h"
      40             : 
      41             : namespace PLMD {
      42             : namespace asmjit {
      43             : 
      44             : //! \addtogroup asmjit_base
      45             : //! \{
      46             : 
      47             : // ============================================================================
      48             : // [asmjit::Operand_]
      49             : // ============================================================================
      50             : 
      51             : //! Constructor-less \ref Operand.
      52             : //!
      53             : //! Contains no initialization code and can be used safely to define an array
      54             : //! of operands that won't be initialized. This is a \ref Operand compatible
      55             : //! data structure designed to be statically initialized or `static const`.
      56             : struct Operand_ {
      57             :   // --------------------------------------------------------------------------
      58             :   // [Operand Type]
      59             :   // --------------------------------------------------------------------------
      60             : 
      61             :   //! Operand types that can be encoded in \ref Operand.
      62             :   ASMJIT_ENUM(OpType) {
      63             :     kOpNone  = 0,                        //!< Not an operand or not initialized.
      64             :     kOpReg   = 1,                        //!< Operand is a register.
      65             :     kOpMem   = 2,                        //!< Operand is a memory.
      66             :     kOpImm   = 3,                        //!< Operand is an immediate value.
      67             :     kOpLabel = 4                         //!< Operand is a label.
      68             :   };
      69             : 
      70             :   // --------------------------------------------------------------------------
      71             :   // [Operand Signature (Bits)]
      72             :   // --------------------------------------------------------------------------
      73             : 
      74             :   ASMJIT_ENUM(SignatureBits) {
      75             :     // Operand type (3 least significant bits).
      76             :     // |........|........|........|.....XXX|
      77             :     kSignatureOpShift           = 0,
      78             :     kSignatureOpBits            = 0x07U,
      79             :     kSignatureOpMask            = kSignatureOpBits << kSignatureOpShift,
      80             : 
      81             :     // Operand size (8 most significant bits).
      82             :     // |XXXXXXXX|........|........|........|
      83             :     kSignatureSizeShift         = 24,
      84             :     kSignatureSizeBits          = 0xFFU,
      85             :     kSignatureSizeMask          = kSignatureSizeBits << kSignatureSizeShift,
      86             : 
      87             :     // Register type (5 bits).
      88             :     // |........|........|........|XXXXX...|
      89             :     kSignatureRegTypeShift      = 3,
      90             :     kSignatureRegTypeBits       = 0x1FU,
      91             :     kSignatureRegTypeMask       = kSignatureRegTypeBits << kSignatureRegTypeShift,
      92             : 
      93             :     // Register kind (4 bits).
      94             :     // |........|........|....XXXX|........|
      95             :     kSignatureRegKindShift      = 8,
      96             :     kSignatureRegKindBits       = 0x0FU,
      97             :     kSignatureRegKindMask       = kSignatureRegKindBits << kSignatureRegKindShift,
      98             : 
      99             :     // Memory base type (5 bits).
     100             :     // |........|........|........|XXXXX...|
     101             :     kSignatureMemBaseTypeShift  = 3,
     102             :     kSignatureMemBaseTypeBits   = 0x1FU,
     103             :     kSignatureMemBaseTypeMask   = kSignatureMemBaseTypeBits << kSignatureMemBaseTypeShift,
     104             : 
     105             :     // Memory index type (5 bits).
     106             :     // |........|........|...XXXXX|........|
     107             :     kSignatureMemIndexTypeShift = 8,
     108             :     kSignatureMemIndexTypeBits  = 0x1FU,
     109             :     kSignatureMemIndexTypeMask  = kSignatureMemIndexTypeBits << kSignatureMemIndexTypeShift,
     110             : 
     111             :     // Memory base+index combined (10 bits).
     112             :     // |........|........|...XXXXX|XXXXX...|
     113             :     kSignatureMemBaseIndexShift = 3,
     114             :     kSignatureMemBaseIndexBits  = 0x3FFU,
     115             :     kSignatureMemBaseIndexMask  = kSignatureMemBaseIndexBits << kSignatureMemBaseIndexShift,
     116             : 
     117             :     // Memory should be encoded as absolute immediate (X86|X64).
     118             :     // |........|........|.XX.....|........|
     119             :     kSignatureMemAddrTypeShift  = 13,
     120             :     kSignatureMemAddrTypeBits   = 0x03U,
     121             :     kSignatureMemAddrTypeMask   = kSignatureMemAddrTypeBits << kSignatureMemAddrTypeShift,
     122             : 
     123             :     // This memory operand represents a function argument's stack location (CodeCompiler)
     124             :     // |........|........|.X......|........|
     125             :     kSignatureMemArgHomeShift   = 15,
     126             :     kSignatureMemArgHomeBits    = 0x01U,
     127             :     kSignatureMemArgHomeFlag    = kSignatureMemArgHomeBits << kSignatureMemArgHomeShift,
     128             : 
     129             :     // This memory operand represents a virtual register's home-slot (CodeCompiler).
     130             :     // |........|........|X.......|........|
     131             :     kSignatureMemRegHomeShift   = 16,
     132             :     kSignatureMemRegHomeBits    = 0x01U,
     133             :     kSignatureMemRegHomeFlag    = kSignatureMemRegHomeBits << kSignatureMemRegHomeShift
     134             :   };
     135             : 
     136             :   // --------------------------------------------------------------------------
     137             :   // [Operand Id]
     138             :   // --------------------------------------------------------------------------
     139             : 
     140             :   //! Operand id helpers useful for id <-> index translation.
     141             :   ASMJIT_ENUM(PackedId) {
     142             :     //! Minimum valid packed-id.
     143             :     kPackedIdMin    = 0x00000100U,
     144             :     //! Maximum valid packed-id.
     145             :     kPackedIdMax    = 0xFFFFFFFFU,
     146             :     //! Count of valid packed-ids.
     147             :     kPackedIdCount  = kPackedIdMax - kPackedIdMin + 1
     148             :   };
     149             : 
     150             :   // --------------------------------------------------------------------------
     151             :   // [Operand Utilities]
     152             :   // --------------------------------------------------------------------------
     153             : 
     154             :   //! Get if the given `id` is a valid packed-id that can be used by Operand.
     155             :   //! Packed ids are those equal or greater than `kPackedIdMin` and lesser or
     156             :   //! equal to `kPackedIdMax`. This concept was created to support virtual
     157             :   //! registers and to make them distinguishable from physical ones. It allows
     158             :   //! a single uint32_t to contain either physical register id or virtual
     159             :   //! register id represented as `packed-id`. This concept is used also for
     160             :   //! labels to make the API consistent.
     161      123906 :   static ASMJIT_INLINE bool isPackedId(uint32_t id) noexcept { return id - kPackedIdMin < kPackedIdCount; }
     162             :   //! Convert a real-id into a packed-id that can be stored in Operand.
     163       27628 :   static ASMJIT_INLINE uint32_t packId(uint32_t id) noexcept { return id + kPackedIdMin; }
     164             :   //! Convert a packed-id back to real-id.
     165       13844 :   static ASMJIT_INLINE uint32_t unpackId(uint32_t id) noexcept { return id - kPackedIdMin; }
     166             : 
     167             :   // --------------------------------------------------------------------------
     168             :   // [Operand Data]
     169             :   // --------------------------------------------------------------------------
     170             : 
     171             :   //! Any operand.
     172             :   struct AnyData {
     173             :     uint32_t signature;                  //!< Type of the operand (see \ref OpType) and other data.
     174             :     uint32_t id;                         //!< Operand id or `0`.
     175             :     uint32_t reserved8_4;                //!< \internal
     176             :     uint32_t reserved12_4;               //!< \internal
     177             :   };
     178             : 
     179             :   //! Register operand data.
     180             :   struct RegData {
     181             :     uint32_t signature;                  //!< Type of the operand (always \ref kOpReg) and other data.
     182             :     uint32_t id;                         //!< Physical or virtual register id.
     183             :     uint32_t reserved8_4;                //!< \internal
     184             :     uint32_t reserved12_4;               //!< \internal
     185             :   };
     186             : 
     187             :   //! Memory operand data.
     188             :   struct MemData {
     189             :     uint32_t signature;                  //!< Type of the operand (always \ref kOpMem) and other data.
     190             :     uint32_t index;                      //!< INDEX register id or `0`.
     191             : 
     192             :     // [BASE + OFF32] vs just [OFF64].
     193             :     union {
     194             :       uint64_t offset64;                 //!< 64-bit offset, combining low and high 32-bit parts.
     195             :       struct {
     196             : #if ASMJIT_ARCH_LE
     197             :         uint32_t offsetLo32;             //!< 32-bit low offset part.
     198             :         uint32_t base;                   //!< 32-bit high offset part or BASE.
     199             : #else
     200             :         uint32_t base;                   //!< 32-bit high offset part or BASE.
     201             :         uint32_t offsetLo32;             //!< 32-bit low offset part.
     202             : #endif
     203             :       };
     204             :     };
     205             :   };
     206             : 
     207             :   //! Immediate operand data.
     208             :   struct ImmData {
     209             :     uint32_t signature;                  //!< Type of the operand (always \ref kOpImm) and other data.
     210             :     uint32_t id;                         //!< Immediate id (always `0`).
     211             :     UInt64 value;                        //!< Immediate value.
     212             :   };
     213             : 
     214             :   //! Label operand data.
     215             :   struct LabelData {
     216             :     uint32_t signature;                  //!< Type of the operand (always \ref kOpLabel) and other data.
     217             :     uint32_t id;                         //!< Label id (`0` if not initialized).
     218             :     uint32_t reserved8_4;                //!< \internal
     219             :     uint32_t reserved12_4;               //!< \internal
     220             :   };
     221             : 
     222             :   // --------------------------------------------------------------------------
     223             :   // [Init & Copy]
     224             :   // --------------------------------------------------------------------------
     225             : 
     226             :   //! \internal
     227             :   //!
     228             :   //! Initialize the operand to `other` (used by constructors).
     229             :   ASMJIT_INLINE void _init(const Operand_& other) noexcept { ::memcpy(this, &other, sizeof(Operand_)); }
     230             : 
     231             :   //! \internal
     232             :   ASMJIT_INLINE void _initReg(uint32_t signature, uint32_t rd) {
     233             :     _init_packed_d0_d1(signature, rd);
     234             :     _init_packed_d2_d3(0, 0);
     235             :   }
     236             : 
     237             :   //! \internal
     238             :   ASMJIT_INLINE void _init_packed_d0_d1(uint32_t d0, uint32_t d1) noexcept { _packed[0].setPacked_2x32(d0, d1); }
     239             :   //! \internal
     240             :   ASMJIT_INLINE void _init_packed_d2_d3(uint32_t d2, uint32_t d3) noexcept { _packed[1].setPacked_2x32(d2, d3); }
     241             : 
     242             :   //! \internal
     243             :   //!
     244             :   //! Initialize the operand from `other` (used by operator overloads).
     245       87252 :   ASMJIT_INLINE void copyFrom(const Operand_& other) noexcept { ::memcpy(this, &other, sizeof(Operand_)); }
     246             : 
     247             :   // --------------------------------------------------------------------------
     248             :   // [Accessors]
     249             :   // --------------------------------------------------------------------------
     250             : 
     251             :   //! Get if the operand matches the given signature `sign`.
     252           0 :   ASMJIT_INLINE bool hasSignature(uint32_t signature) const noexcept { return _signature == signature; }
     253             : 
     254             :   //! Get if the operand matches a signature of the `other` operand.
     255             :   ASMJIT_INLINE bool hasSignature(const Operand_& other) const noexcept {
     256             :     return _signature == other.getSignature();
     257             :   }
     258             : 
     259             :   //! Get a 32-bit operand signature.
     260             :   //!
     261             :   //! Signature is first 4 bytes of the operand data. It's used mostly for
     262             :   //! operand checking as it's much faster to check 4 bytes at once than having
     263             :   //! to check these bytes individually.
     264           0 :   ASMJIT_INLINE uint32_t getSignature() const noexcept { return _signature; }
     265             : 
     266             :   //! Set the operand signature (see \ref getSignature).
     267             :   //!
     268             :   //! Improper use of `setSignature()` can lead to hard-to-debug errors.
     269         404 :   ASMJIT_INLINE void setSignature(uint32_t signature) noexcept { _signature = signature; }
     270             : 
     271       41128 :   ASMJIT_INLINE bool _hasSignatureData(uint32_t bits) const noexcept { return (_signature & bits) != 0; }
     272             : 
     273             :   //! \internal
     274             :   //!
     275             :   //! Unpacks information from operand's signature.
     276      297092 :   ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; }
     277             : 
     278             :   //! \internal
     279             :   //!
     280             :   //! Packs information to operand's signature.
     281             :   ASMJIT_INLINE void _setSignatureData(uint32_t value, uint32_t bits, uint32_t shift) noexcept {
     282             :     ASMJIT_ASSERT(value <= bits);
     283        8428 :     _signature = (_signature & ~(bits << shift)) | (value << shift);
     284             :   }
     285             : 
     286             :   ASMJIT_INLINE void _addSignatureData(uint32_t data) noexcept { _signature |= data; }
     287             : 
     288             :   //! Clears specified bits in operand's signature.
     289             :   ASMJIT_INLINE void _clearSignatureData(uint32_t bits, uint32_t shift) noexcept { _signature &= ~(bits << shift); }
     290             : 
     291             :   //! Get type of the operand, see \ref OpType.
     292             :   ASMJIT_INLINE uint32_t getOp() const noexcept { return _getSignatureData(kSignatureOpBits, kSignatureOpShift); }
     293             :   //! Get if the operand is none (\ref kOpNone).
     294             :   ASMJIT_INLINE bool isNone() const noexcept { return getOp() == 0; }
     295             :   //! Get if the operand is a register (\ref kOpReg).
     296             :   ASMJIT_INLINE bool isReg() const noexcept { return getOp() == kOpReg; }
     297             :   //! Get if the operand is a memory location (\ref kOpMem).
     298             :   ASMJIT_INLINE bool isMem() const noexcept { return getOp() == kOpMem; }
     299             :   //! Get if the operand is an immediate (\ref kOpImm).
     300             :   ASMJIT_INLINE bool isImm() const noexcept { return getOp() == kOpImm; }
     301             :   //! Get if the operand is a label (\ref kOpLabel).
     302             :   ASMJIT_INLINE bool isLabel() const noexcept { return getOp() == kOpLabel; }
     303             : 
     304             :   //! Get if the operand is a physical register.
     305             :   ASMJIT_INLINE bool isPhysReg() const noexcept { return isReg() && _reg.id < Globals::kInvalidRegId; }
     306             :   //! Get if the operand is a virtual register.
     307      146082 :   ASMJIT_INLINE bool isVirtReg() const noexcept { return isReg() && isPackedId(_reg.id); }
     308             : 
     309             :   //! Get if the operand specifies a size (i.e. the size is not zero).
     310             :   ASMJIT_INLINE bool hasSize() const noexcept { return _hasSignatureData(kSignatureSizeMask); }
     311             :   //! Get if the size of the operand matches `size`.
     312             :   ASMJIT_INLINE bool hasSize(uint32_t size) const noexcept { return getSize() == size; }
     313             : 
     314             :   //! Get size of the operand (in bytes).
     315             :   //!
     316             :   //! The value returned depends on the operand type:
     317             :   //!   * None  - Should always return zero size.
     318             :   //!   * Reg   - Should always return the size of the register. If the register
     319             :   //!             size depends on architecture (like \ref X86CReg and \ref X86DReg)
     320             :   //!             the size returned should be the greatest possible (so it should
     321             :   //!             return 64-bit size in such case).
     322             :   //!   * Mem   - Size is optional and will be in most cases zero.
     323             :   //!   * Imm   - Should always return zero size.
     324             :   //!   * Label - Should always return zero size.
     325             :   ASMJIT_INLINE uint32_t getSize() const noexcept { return _getSignatureData(kSignatureSizeBits, kSignatureSizeShift); }
     326             : 
     327             :   //! Get the operand id.
     328             :   //!
     329             :   //! The value returned should be interpreted accordingly to the operand type:
     330             :   //!   * None  - Should be `0`.
     331             :   //!   * Reg   - Physical or virtual register id.
     332             :   //!   * Mem   - Multiple meanings - BASE address (register or label id), or
     333             :   //!             high value of a 64-bit absolute address.
     334             :   //!   * Imm   - Should be `0`.
     335             :   //!   * Label - Label id if it was created by using `newLabel()` or `0`
     336             :   //!             if the label is invalid or uninitialized.
     337       54402 :   ASMJIT_INLINE uint32_t getId() const noexcept { return _any.id; }
     338             : 
     339             :   //! Get if the operand is 100% equal to `other`.
     340             :   ASMJIT_INLINE bool isEqual(const Operand_& other) const noexcept {
     341             :     return (_packed[0] == other._packed[0]) &
     342             :            (_packed[1] == other._packed[1]) ;
     343             :   }
     344             : 
     345             :   //! Get if the operand is a register matching `rType`.
     346             :   ASMJIT_INLINE bool isReg(uint32_t rType) const noexcept {
     347             :     const uint32_t kMsk = (kSignatureOpBits << kSignatureOpShift) | (kSignatureRegTypeBits << kSignatureRegTypeShift);
     348             :     const uint32_t kSgn = (kOpReg           << kSignatureOpShift) | (rType                 << kSignatureRegTypeShift);
     349             :     return (_signature & kMsk) == kSgn;
     350             :   }
     351             : 
     352             :   //! Get whether the operand is register and of `type` and `id`.
     353             :   ASMJIT_INLINE bool isReg(uint32_t rType, uint32_t rId) const noexcept {
     354             :     return isReg(rType) && getId() == rId;
     355             :   }
     356             : 
     357             :   //! Get whether the operand is a register or memory.
     358             :   ASMJIT_INLINE bool isRegOrMem() const noexcept {
     359             :     ASMJIT_ASSERT(kOpMem - kOpReg == 1);
     360             :     return Utils::inInterval<uint32_t>(getOp(), kOpReg, kOpMem);
     361             :   }
     362             : 
     363             :   //! Cast this operand to `T` type.
     364             :   template<typename T>
     365             :   ASMJIT_INLINE T& as() noexcept { return static_cast<T&>(*this); }
     366             :   //! Cast this operand to `T` type (const).
     367             :   template<typename T>
     368             :   ASMJIT_INLINE const T& as() const noexcept { return static_cast<const T&>(*this); }
     369             : 
     370             :   // --------------------------------------------------------------------------
     371             :   // [Reset]
     372             :   // --------------------------------------------------------------------------
     373             : 
     374             :   //! Reset the `Operand` to none.
     375             :   //!
     376             :   //! None operand is defined the following way:
     377             :   //!   - Its signature is zero (kOpNone, and the rest zero as well).
     378             :   //!   - Its id is `0`.
     379             :   //!   - The reserved8_4 field is set to `0`.
     380             :   //!   - The reserved12_4 field is set to zero.
     381             :   //!
     382             :   //! In other words, reset operands have all members set to zero. Reset operand
     383             :   //! must match the Operand state right after its construction. Alternatively,
     384             :   //! if you have an array of operands, you can simply use `memset()`.
     385             :   //!
     386             :   //! ```
     387             :   //! using namespace asmjit;
     388             :   //!
     389             :   //! Operand a;
     390             :   //! Operand b;
     391             :   //! assert(a == b);
     392             :   //!
     393             :   //! b = x86::eax;
     394             :   //! assert(a != b);
     395             :   //!
     396             :   //! b.reset();
     397             :   //! assert(a == b);
     398             :   //!
     399             :   //! memset(&b, 0, sizeof(Operand));
     400             :   //! assert(a == b);
     401             :   //! ```
     402             :   ASMJIT_INLINE void reset() noexcept {
     403             :     _init_packed_d0_d1(kOpNone, 0);
     404             :     _init_packed_d2_d3(0, 0);
     405           0 :   }
     406             : 
     407             :   // --------------------------------------------------------------------------
     408             :   // [Operator Overload]
     409             :   // --------------------------------------------------------------------------
     410             : 
     411             :   template<typename T>
     412             :   ASMJIT_INLINE bool operator==(const T& other) const noexcept { return  isEqual(other); }
     413             :   template<typename T>
     414             :   ASMJIT_INLINE bool operator!=(const T& other) const noexcept { return !isEqual(other); }
     415             : 
     416             :   // --------------------------------------------------------------------------
     417             :   // [Members]
     418             :   // --------------------------------------------------------------------------
     419             : 
     420             :   union {
     421             :     AnyData _any;                        //!< Generic data.
     422             :     RegData _reg;                        //!< Physical or virtual register data.
     423             :     MemData _mem;                        //!< Memory address data.
     424             :     ImmData _imm;                        //!< Immediate value data.
     425             :     LabelData _label;                    //!< Label data.
     426             : 
     427             :     uint32_t _signature;                 //!< Operand signature (first 32-bits).
     428             :     UInt64 _packed[2];                   //!< Operand packed into two 64-bit integers.
     429             :   };
     430             : };
     431             : 
     432             : // ============================================================================
     433             : // [asmjit::Operand]
     434             : // ============================================================================
     435             : 
     436             : //! Operand can contain register, memory location, immediate, or label.
     437             : class Operand : public Operand_ {
     438             : public:
     439             :   // --------------------------------------------------------------------------
     440             :   // [Construction / Destruction]
     441             :   // --------------------------------------------------------------------------
     442             : 
     443             :   //! Create an uninitialized operand.
     444       24672 :   ASMJIT_INLINE Operand() noexcept { reset(); }
     445             :   //! Create a reference to `other` operand.
     446        4292 :   ASMJIT_INLINE Operand(const Operand& other) noexcept { _init(other); }
     447             :   //! Create a reference to `other` operand.
     448        9084 :   explicit ASMJIT_INLINE Operand(const Operand_& other) noexcept { _init(other); }
     449             :   //! Create a completely uninitialized operand (dangerous).
     450        1984 :   explicit ASMJIT_INLINE Operand(const _NoInit&) noexcept {}
     451             : 
     452             :   // --------------------------------------------------------------------------
     453             :   // [Clone]
     454             :   // --------------------------------------------------------------------------
     455             : 
     456             :   //! Clone the `Operand`.
     457             :   ASMJIT_INLINE Operand clone() const noexcept { return Operand(*this); }
     458             : 
     459             :   ASMJIT_INLINE Operand& operator=(const Operand_& other) noexcept { copyFrom(other); return *this; }
     460             : };
     461             : 
     462             : // ============================================================================
     463             : // [asmjit::Label]
     464             : // ============================================================================
     465             : 
     466             : //! Label (jump target or data location).
     467             : //!
     468             : //! Label represents a location in code typically used as a jump target, but
     469             : //! may be also a reference to some data or a static variable. Label has to be
     470             : //! explicitly created by CodeEmitter.
     471             : //!
     472             : //! Example of using labels:
     473             : //!
     474             : //! ~~~
     475             : //! // Create a CodeEmitter (for example X86Assembler).
     476             : //! X86Assembler a;
     477             : //!
     478             : //! // Create Label instance.
     479             : //! Label L1 = a.newLabel();
     480             : //!
     481             : //! // ... your code ...
     482             : //!
     483             : //! // Using label.
     484             : //! a.jump(L1);
     485             : //!
     486             : //! // ... your code ...
     487             : //!
     488             : //! // Bind label to the current position, see `CodeEmitter::bind()`.
     489             : //! a.bind(L1);
     490             : //! ~~~
     491             : class Label : public Operand {
     492             : public:
     493             :   //! Type of the Label.
     494             :   enum Type {
     495             :     kTypeAnonymous = 0,                  //!< Anonymous (unnamed) label.
     496             :     kTypeLocal     = 1,                  //!< Local label (always has parentId).
     497             :     kTypeGlobal    = 2,                  //!< Global label (never has parentId).
     498             :     kTypeCount     = 3                   //!< Number of label types.
     499             :   };
     500             : 
     501             :   // TODO: Find a better place, find a better name.
     502             :   enum {
     503             :     //! Label tag is used as a sub-type, forming a unique signature across all
     504             :     //! operand types as 0x1 is never associated with any register (reg-type).
     505             :     //! This means that a memory operand's BASE register can be constructed
     506             :     //! from virtually any operand (register vs. label) by just assigning its
     507             :     //! type (reg type or label-tag) and operand id.
     508             :     kLabelTag = 0x1
     509             :   };
     510             : 
     511             :   // --------------------------------------------------------------------------
     512             :   // [Construction / Destruction]
     513             :   // --------------------------------------------------------------------------
     514             : 
     515             :   //! Create new, unassociated label.
     516             :   ASMJIT_INLINE Label() noexcept : Operand(NoInit) { reset(); }
     517             :   //! Create a reference to another label.
     518             :   ASMJIT_INLINE Label(const Label& other) noexcept : Operand(other) {}
     519             : 
     520             :   explicit ASMJIT_INLINE Label(uint32_t id) noexcept : Operand(NoInit) {
     521             :     _init_packed_d0_d1(kOpLabel, id);
     522             :     _init_packed_d2_d3(0, 0);
     523             :   }
     524             : 
     525             :   explicit ASMJIT_INLINE Label(const _NoInit&) noexcept : Operand(NoInit) {}
     526             : 
     527             :   // --------------------------------------------------------------------------
     528             :   // [Reset]
     529             :   // --------------------------------------------------------------------------
     530             : 
     531             :   // TODO: I think that if operand is reset it shouldn't say it's a Label, it
     532             :   // should be none like all other operands.
     533             :   ASMJIT_INLINE void reset() noexcept {
     534             :     _init_packed_d0_d1(kOpLabel, 0);
     535             :     _init_packed_d2_d3(0, 0);
     536             :   }
     537             : 
     538             :   // --------------------------------------------------------------------------
     539             :   // [Label Specific]
     540             :   // --------------------------------------------------------------------------
     541             : 
     542             :   //! Get if the label was created by CodeEmitter and has an assigned id.
     543             :   ASMJIT_INLINE bool isValid() const noexcept { return _label.id != 0; }
     544             :   //! Set label id.
     545             :   ASMJIT_INLINE void setId(uint32_t id) { _label.id = id; }
     546             : 
     547             :   // --------------------------------------------------------------------------
     548             :   // [Operator Overload]
     549             :   // --------------------------------------------------------------------------
     550             : 
     551             :   ASMJIT_INLINE Label& operator=(const Label& other) noexcept { copyFrom(other); return *this; }
     552             : };
     553             : 
     554             : // ============================================================================
     555             : // [asmjit::Reg]
     556             : // ============================================================================
     557             : 
     558             : #define ASMJIT_DEFINE_REG_TRAITS(TRAITS_T, REG_T, TYPE, KIND, SIZE, COUNT, TYPE_ID) \
     559             : template<>                                                                    \
     560             : struct TRAITS_T < TYPE > {                                                    \
     561             :   typedef REG_T Reg;                                                          \
     562             :                                                                               \
     563             :   enum {                                                                      \
     564             :     kValid     = 1,                                                           \
     565             :     kCount     = COUNT,                                                       \
     566             :     kTypeId    = TYPE_ID,                                                     \
     567             :                                                                               \
     568             :     kType      = TYPE,                                                        \
     569             :     kKind      = KIND,                                                        \
     570             :     kSize      = SIZE,                                                        \
     571             :     kSignature = (Operand::kOpReg << Operand::kSignatureOpShift     ) |       \
     572             :                  (kType           << Operand::kSignatureRegTypeShift) |       \
     573             :                  (kKind           << Operand::kSignatureRegKindShift) |       \
     574             :                  (kSize           << Operand::kSignatureSizeShift   )         \
     575             :   };                                                                          \
     576             : }                                                                             \
     577             : 
     578             : #define ASMJIT_DEFINE_ABSTRACT_REG(REG_T, BASE_T)                             \
     579             : public:                                                                       \
     580             :   /*! Default constructor doesn't setup anything, it's like `Operand()`. */   \
     581             :   ASMJIT_INLINE REG_T() ASMJIT_NOEXCEPT                                       \
     582             :     : BASE_T() {}                                                             \
     583             :                                                                               \
     584             :   /*! Copy the `other` REG_T register operand. */                             \
     585             :   ASMJIT_INLINE REG_T(const REG_T& other) ASMJIT_NOEXCEPT                     \
     586             :     : BASE_T(other) {}                                                        \
     587             :                                                                               \
     588             :   /*! Copy the `other` REG_T register operand having its id set to `rId` */   \
     589             :   ASMJIT_INLINE REG_T(const Reg& other, uint32_t rId) ASMJIT_NOEXCEPT         \
     590             :     : BASE_T(other, rId) {}                                                   \
     591             :                                                                               \
     592             :   /*! Create a REG_T register operand based on `signature` and `rId`. */      \
     593             :   ASMJIT_INLINE REG_T(const _Init& init, uint32_t signature, uint32_t rId) ASMJIT_NOEXCEPT \
     594             :     : BASE_T(init, signature, rId) {}                                         \
     595             :                                                                               \
     596             :   /*! Create a completely uninitialized REG_T register operand (garbage). */  \
     597             :   explicit ASMJIT_INLINE REG_T(const _NoInit&) ASMJIT_NOEXCEPT                \
     598             :     : BASE_T(NoInit) {}                                                       \
     599             :                                                                               \
     600             :   /*! Clone the register operand. */                                          \
     601             :   ASMJIT_INLINE REG_T clone() const ASMJIT_NOEXCEPT { return REG_T(*this); }  \
     602             :                                                                               \
     603             :   /*! Create a new register from register type and id. */                     \
     604             :   static ASMJIT_INLINE REG_T fromTypeAndId(uint32_t rType, uint32_t rId) ASMJIT_NOEXCEPT { \
     605             :     return REG_T(Init, signatureOf(rType), rId);                              \
     606             :   }                                                                           \
     607             :                                                                               \
     608             :   /*! Create a new register from signature and id. */                         \
     609             :   static ASMJIT_INLINE REG_T fromSignature(uint32_t signature, uint32_t rId) ASMJIT_NOEXCEPT { \
     610             :     return REG_T(Init, signature, rId);                                       \
     611             :   }                                                                           \
     612             :                                                                               \
     613             :   ASMJIT_INLINE REG_T& operator=(const REG_T& other) ASMJIT_NOEXCEPT {        \
     614             :     copyFrom(other); return *this;                                            \
     615             :   }
     616             : 
     617             : #define ASMJIT_DEFINE_FINAL_REG(REG_T, BASE_T, TRAITS_T)                      \
     618             :   ASMJIT_DEFINE_ABSTRACT_REG(REG_T, BASE_T)                                   \
     619             :                                                                               \
     620             :   /*! Create a REG_T register with `id`. */                                   \
     621             :   explicit ASMJIT_INLINE REG_T(uint32_t rId) ASMJIT_NOEXCEPT                  \
     622             :     : BASE_T(Init, kSignature, rId) {}                                        \
     623             :                                                                               \
     624             :   enum {                                                                      \
     625             :     kThisType  = TRAITS_T::kType,                                             \
     626             :     kThisKind  = TRAITS_T::kKind,                                             \
     627             :     kThisSize  = TRAITS_T::kSize,                                             \
     628             :     kSignature = TRAITS_T::kSignature                                         \
     629             :   };
     630             : 
     631             : //! Structure that contains core register information.
     632             : //!
     633             : //! This information is compatible with operand's signature (32-bit integer)
     634             : //! and `RegInfo` just provides easy way to access it.
     635             : struct RegInfo {
     636             :   ASMJIT_INLINE uint32_t getSignature() const noexcept {
     637       78516 :     return _signature;
     638             :   }
     639             : 
     640             :   ASMJIT_INLINE uint32_t getOp() const noexcept {
     641             :     return (_signature >> Operand::kSignatureOpShift) & Operand::kSignatureOpBits;
     642             :   }
     643             : 
     644             :   ASMJIT_INLINE uint32_t getType() const noexcept {
     645             :     return (_signature >> Operand::kSignatureRegTypeShift) & Operand::kSignatureRegTypeBits;
     646             :   }
     647             : 
     648             :   ASMJIT_INLINE uint32_t getKind() const noexcept {
     649      182676 :     return (_signature >> Operand::kSignatureRegKindShift) & Operand::kSignatureRegKindBits;
     650             :   }
     651             : 
     652             :   ASMJIT_INLINE uint32_t getSize() const noexcept {
     653             :     return (_signature >> Operand::kSignatureSizeShift) & Operand::kSignatureSizeBits;
     654             :   }
     655             : 
     656             :   uint32_t _signature;
     657             : };
     658             : 
     659             : //! Physical/Virtual register operand.
     660             : class Reg : public Operand {
     661             : public:
     662             :   //! Architecture neutral register types.
     663             :   //!
     664             :   //! These must be reused by any platform that contains that types. All GP
     665             :   //! and VEC registers are also allowed by design to be part of a BASE|INDEX
     666             :   //! of a memory operand.
     667             :   ASMJIT_ENUM(RegType) {
     668             :     kRegNone      = 0,                   //!< No register - unused, invalid, multiple meanings.
     669             :     // (1 is used as a LabelTag)
     670             :     kRegGp8Lo     = 2,                   //!< 8-bit low general purpose register (X86).
     671             :     kRegGp8Hi     = 3,                   //!< 8-bit high general purpose register (X86).
     672             :     kRegGp16      = 4,                   //!< 16-bit general purpose register (X86).
     673             :     kRegGp32      = 5,                   //!< 32-bit general purpose register (X86|ARM).
     674             :     kRegGp64      = 6,                   //!< 64-bit general purpose register (X86|ARM).
     675             :     kRegVec32     = 7,                   //!< 32-bit view of a vector register (ARM).
     676             :     kRegVec64     = 8,                   //!< 64-bit view of a vector register (ARM).
     677             :     kRegVec128    = 9,                   //!< 128-bit view of a vector register (X86|ARM).
     678             :     kRegVec256    = 10,                  //!< 256-bit view of a vector register (X86).
     679             :     kRegVec512    = 11,                  //!< 512-bit view of a vector register (X86).
     680             :     kRegVec1024   = 12,                  //!< 1024-bit view of a vector register (future).
     681             :     kRegVec2048   = 13,                  //!< 2048-bit view of a vector register (future).
     682             :     kRegIP        = 14,                  //!< Universal id of IP/PC register (if separate).
     683             :     kRegCustom    = 15,                  //!< Start of platform dependent register types (must be honored).
     684             :     kRegMax       = 31                   //!< Maximum possible register id of all architectures.
     685             :   };
     686             : 
     687             :   //! Architecture neutral register kinds.
     688             :   ASMJIT_ENUM(Kind) {
     689             :     kKindGp       = 0,                   //!< General purpose register (X86|ARM).
     690             :     kKindVec      = 1,                   //!< Vector register (X86|ARM).
     691             :     kKindMax      = 15                   //!< Maximum possible register kind of all architectures.
     692             :   };
     693             : 
     694             :   // --------------------------------------------------------------------------
     695             :   // [Construction / Destruction]
     696             :   // --------------------------------------------------------------------------
     697             : 
     698             :   //! Create a dummy register operand.
     699             :   ASMJIT_INLINE Reg() noexcept : Operand() {}
     700             :   //! Create a new register operand which is the same as `other` .
     701             :   ASMJIT_INLINE Reg(const Reg& other) noexcept : Operand(other) {}
     702             :   //! Create a new register operand compatible with `other`, but with a different `rId`.
     703             :   ASMJIT_INLINE Reg(const Reg& other, uint32_t rId) noexcept : Operand(NoInit) {
     704             :     _init_packed_d0_d1(other._signature, rId);
     705             :     _packed[1] = other._packed[1];
     706             :   }
     707             : 
     708             :   //! Create a register initialized to `signature` and `rId`.
     709             :   ASMJIT_INLINE Reg(const _Init&, uint32_t signature, uint32_t rId) noexcept : Operand(NoInit) {
     710             :     _initReg(signature, rId);
     711             :   }
     712             :   explicit ASMJIT_INLINE Reg(const _NoInit&) noexcept : Operand(NoInit) {}
     713             : 
     714             :   //! Create a new register based on `signature` and `rId`.
     715             :   static ASMJIT_INLINE Reg fromSignature(uint32_t signature, uint32_t rId) noexcept { return Reg(Init, signature, rId); }
     716             : 
     717             :   // --------------------------------------------------------------------------
     718             :   // [Reg Specific]
     719             :   // --------------------------------------------------------------------------
     720             : 
     721             :   //! Get if the register is valid (either virtual or physical).
     722        1944 :   ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; }
     723             :   //! Get if this is a physical register.
     724             :   ASMJIT_INLINE bool isPhysReg() const noexcept { return _reg.id < Globals::kInvalidRegId; }
     725             :   //! Get if this is a virtual register (used by \ref CodeCompiler).
     726           0 :   ASMJIT_INLINE bool isVirtReg() const noexcept { return isPackedId(_reg.id); }
     727             : 
     728             :   //! Get if this register is the same as `other`.
     729             :   //!
     730             :   //! This is just an optimization. Registers by default only use the first
     731             :   //! 8 bytes of the Operand, so this method takes advantage of this knowledge
     732             :   //! and only compares these 8 bytes. If both operands were created correctly
     733             :   //! then `isEqual()` and `isSame()` should give the same answer, however, if
     734             :   //! some operands contains a garbage or other metadata in the upper 8 bytes
     735             :   //! then `isSame()` may return `true` in cases where `isEqual()` returns
     736             :   //! false. However. no such case is known at the moment.
     737             :   ASMJIT_INLINE bool isSame(const Reg& other) const noexcept { return _packed[0] == other._packed[0]; }
     738             : 
     739             :   //! Get if the register type matches `rType` - same as `isReg(rType)`, provided for convenience.
     740             :   ASMJIT_INLINE bool isType(uint32_t rType) const noexcept { return (_signature & kSignatureRegTypeMask) == (rType << kSignatureRegTypeShift); }
     741             :   //! Get if the register kind matches `rKind`.
     742       21852 :   ASMJIT_INLINE bool isKind(uint32_t rKind) const noexcept { return (_signature & kSignatureRegKindMask) == (rKind << kSignatureRegKindShift); }
     743             : 
     744             :   //! Get if the register is a general purpose register (any size).
     745             :   ASMJIT_INLINE bool isGp() const noexcept { return isKind(kKindGp); }
     746             :   //! Get if the register is a vector register.
     747             :   ASMJIT_INLINE bool isVec() const noexcept { return isKind(kKindVec); }
     748             : 
     749             :   using Operand_::isReg;
     750             : 
     751             :   //! Same as `isType()`, provided for convenience.
     752             :   ASMJIT_INLINE bool isReg(uint32_t rType) const noexcept { return isType(rType); }
     753             :   //! Get if the register type matches `type` and register id matches `rId`.
     754             :   ASMJIT_INLINE bool isReg(uint32_t rType, uint32_t rId) const noexcept { return isType(rType) && getId() == rId; }
     755             : 
     756             :   //! Get the register type.
     757             :   ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(kSignatureRegTypeBits, kSignatureRegTypeShift); }
     758             :   //! Get the register kind.
     759             :   ASMJIT_INLINE uint32_t getKind() const noexcept { return _getSignatureData(kSignatureRegKindBits, kSignatureRegKindShift); }
     760             : 
     761             :   //! Clone the register operand.
     762             :   ASMJIT_INLINE Reg clone() const noexcept { return Reg(*this); }
     763             : 
     764             :   //! Cast this register to `RegT` by also changing its signature.
     765             :   //!
     766             :   //! NOTE: Improper use of `cloneAs()` can lead to hard-to-debug errors.
     767             :   template<typename RegT>
     768             :   ASMJIT_INLINE RegT cloneAs() const noexcept { return RegT(Init, RegT::kSignature, getId()); }
     769             : 
     770             :   //! Cast this register to `other` by also changing its signature.
     771             :   //!
     772             :   //! NOTE: Improper use of `cloneAs()` can lead to hard-to-debug errors.
     773             :   template<typename RegT>
     774             :   ASMJIT_INLINE RegT cloneAs(const RegT& other) const noexcept { return RegT(Init, other.getSignature(), getId()); }
     775             : 
     776             :   //! Set the register id to `id`.
     777        2620 :   ASMJIT_INLINE void setId(uint32_t rId) noexcept { _reg.id = rId; }
     778             : 
     779             :   //! Set a 32-bit operand signature based on traits of `RegT`.
     780             :   template<typename RegT>
     781             :   ASMJIT_INLINE void setSignatureT() noexcept { _signature = RegT::kSignature; }
     782             : 
     783             :   //! Set register's `signature` and `rId`.
     784             :   ASMJIT_INLINE void setSignatureAndId(uint32_t signature, uint32_t rId) noexcept {
     785             :     _signature = signature;
     786             :     _reg.id = rId;
     787             :   }
     788             : 
     789             :   // --------------------------------------------------------------------------
     790             :   // [Reg Statics]
     791             :   // --------------------------------------------------------------------------
     792             : 
     793             :   static ASMJIT_INLINE bool isGp(const Operand_& op) noexcept {
     794             :     // Check operand type and register kind. Not interested in register type and size.
     795             :     const uint32_t kSgn = (kOpReg  << kSignatureOpShift     ) |
     796             :                           (kKindGp << kSignatureRegKindShift) ;
     797           0 :     return (op.getSignature() & (kSignatureOpMask | kSignatureRegKindMask)) == kSgn;
     798             :   }
     799             : 
     800             :   //! Get if the `op` operand is either a low or high 8-bit GPB register.
     801             :   static ASMJIT_INLINE bool isVec(const Operand_& op) noexcept {
     802             :     // Check operand type and register kind. Not interested in register type and size.
     803             :     const uint32_t kSgn = (kOpReg   << kSignatureOpShift     ) |
     804             :                           (kKindVec << kSignatureRegKindShift) ;
     805             :     return (op.getSignature() & (kSignatureOpMask | kSignatureRegKindMask)) == kSgn;
     806             :   }
     807             : 
     808           0 :   static ASMJIT_INLINE bool isGp(const Operand_& op, uint32_t rId) noexcept { return isGp(op) & (op.getId() == rId); }
     809             :   static ASMJIT_INLINE bool isVec(const Operand_& op, uint32_t rId) noexcept { return isVec(op) & (op.getId() == rId); }
     810             : };
     811             : 
     812             : // ============================================================================
     813             : // [asmjit::RegOnly]
     814             : // ============================================================================
     815             : 
     816             : //! RegOnly is 8-byte version of `Reg` that only allows to store either `Reg`
     817             : //! or nothing. This class was designed to decrease the space consumed by each
     818             : //! extra "operand" in `CodeEmitter` and `CBInst` classes.
     819             : struct RegOnly {
     820             :   // --------------------------------------------------------------------------
     821             :   // [Init / Reset]
     822             :   // --------------------------------------------------------------------------
     823             : 
     824             :   //! Initialize the `RegOnly` instance to hold register `signature` and `id`.
     825             :   ASMJIT_INLINE void init(uint32_t signature, uint32_t id) noexcept {
     826      143126 :     _signature = signature;
     827      143126 :     _id = id;
     828             :   }
     829             : 
     830             :   ASMJIT_INLINE void init(const Reg& reg) noexcept { init(reg.getSignature(), reg.getId()); }
     831             :   ASMJIT_INLINE void init(const RegOnly& reg) noexcept { init(reg.getSignature(), reg.getId()); }
     832             : 
     833             :   //! Reset the `RegOnly` to none.
     834             :   ASMJIT_INLINE void reset() noexcept { init(0, 0); }
     835             : 
     836             :   // --------------------------------------------------------------------------
     837             :   // [Accessors]
     838             :   // --------------------------------------------------------------------------
     839             : 
     840             :   //! Get if the `ExtraReg` is none (same as calling `Operand_::isNone()`).
     841           0 :   ASMJIT_INLINE bool isNone() const noexcept { return _signature == 0; }
     842             :   //! Get if the register is valid (either virtual or physical).
     843       62212 :   ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; }
     844             : 
     845             :   //! Get if this is a physical register.
     846             :   ASMJIT_INLINE bool isPhysReg() const noexcept { return _id < Globals::kInvalidRegId; }
     847             :   //! Get if this is a virtual register (used by \ref CodeCompiler).
     848             :   ASMJIT_INLINE bool isVirtReg() const noexcept { return Operand::isPackedId(_id); }
     849             : 
     850             :   //! Get register signature or 0.
     851       48254 :   ASMJIT_INLINE uint32_t getSignature() const noexcept { return _signature; }
     852             :   //! Get register id or 0.
     853       48254 :   ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
     854             : 
     855             :   //! \internal
     856             :   //!
     857             :   //! Unpacks information from operand's signature.
     858           0 :   ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; }
     859             : 
     860             :   //! Get the register type.
     861             :   ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(Operand::kSignatureRegTypeBits, Operand::kSignatureRegTypeShift); }
     862             :   //! Get the register kind.
     863             :   ASMJIT_INLINE uint32_t getKind() const noexcept { return _getSignatureData(Operand::kSignatureRegKindBits, Operand::kSignatureRegKindShift); }
     864             : 
     865             :   // --------------------------------------------------------------------------
     866             :   // [ToReg]
     867             :   // --------------------------------------------------------------------------
     868             : 
     869             :   //! Convert back to `RegT` operand.
     870             :   template<typename RegT>
     871           0 :   ASMJIT_INLINE RegT toReg() const noexcept { return RegT(Init, _signature, _id); }
     872             : 
     873             :   // --------------------------------------------------------------------------
     874             :   // [Members]
     875             :   // --------------------------------------------------------------------------
     876             : 
     877             :   //! Type of the operand, either `kOpNone` or `kOpReg`.
     878             :   uint32_t _signature;
     879             :   //! Physical or virtual register id.
     880             :   uint32_t _id;
     881             : };
     882             : 
     883             : // ============================================================================
     884             : // [asmjit::Mem]
     885             : // ============================================================================
     886             : 
     887             : //! Base class for all memory operands.
     888             : //!
     889             : //! NOTE: It's tricky to pack all possible cases that define a memory operand
     890             : //! into just 16 bytes. The `Mem` splits data into the following parts:
     891             : //!
     892             : //!   BASE - Base register or label - requires 36 bits total. 4 bits are used
     893             : //!     to encode the type of the BASE operand (label vs. register type) and
     894             : //!     the remaining 32 bits define the BASE id, which can be a physical or
     895             : //!     virtual register index. If BASE type is zero, which is never used as
     896             : //!     a register-type and label doesn't use it as well then BASE field
     897             : //!     contains a high DWORD of a possible 64-bit absolute address, which is
     898             : //!     possible on X64.
     899             : //!
     900             : //!   INDEX - Index register (or theoretically Label, which doesn't make sense).
     901             : //!     Encoding is similar to BASE - it also requires 36 bits and splits the
     902             : //!     encoding to INDEX type (4 bits defining the register type) and id (32-bits).
     903             : //!
     904             : //!   OFFSET - A relative offset of the address. Basically if BASE is specified
     905             : //!     the relative displacement adjusts BASE and an optional INDEX. if BASE is
     906             : //!     not specified then the OFFSET should be considered as ABSOLUTE address
     907             : //!     (at least on X86/X64). In that case its low 32 bits are stored in
     908             : //!     DISPLACEMENT field and the remaining high 32 bits are stored in BASE.
     909             : //!
     910             : //!   OTHER FIELDS - There is rest 8 bits that can be used for whatever purpose.
     911             : //!          The X86Mem operand uses these bits to store segment override
     912             : //!          prefix and index shift (scale).
     913             : class Mem : public Operand {
     914             : public:
     915             :   enum AddrType {
     916             :     kAddrTypeDefault = 0,
     917             :     kAddrTypeAbs     = 1,
     918             :     kAddrTypeRel     = 2,
     919             :     kAddrTypeWrt     = 3
     920             :   };
     921             : 
     922             :   // Shortcuts.
     923             :   enum SignatureMem {
     924             :     kSignatureMemAbs = kAddrTypeAbs << kSignatureMemAddrTypeShift,
     925             :     kSignatureMemRel = kAddrTypeRel << kSignatureMemAddrTypeShift,
     926             :     kSignatureMemWrt = kAddrTypeWrt << kSignatureMemAddrTypeShift
     927             :   };
     928             : 
     929             :   // --------------------------------------------------------------------------
     930             :   // [Construction / Destruction]
     931             :   // --------------------------------------------------------------------------
     932             : 
     933             :   //! Construct a default `Mem` operand, that points to [0].
     934             :   ASMJIT_INLINE Mem() noexcept : Operand(NoInit) { reset(); }
     935             :   ASMJIT_INLINE Mem(const Mem& other) noexcept : Operand(other) {}
     936             : 
     937             :   ASMJIT_INLINE Mem(const _Init&,
     938             :     uint32_t baseType, uint32_t baseId,
     939             :     uint32_t indexType, uint32_t indexId,
     940             :     int32_t off, uint32_t size, uint32_t flags) noexcept : Operand(NoInit) {
     941             : 
     942        8428 :     uint32_t signature = (baseType  << kSignatureMemBaseTypeShift ) |
     943             :                          (indexType << kSignatureMemIndexTypeShift) |
     944           0 :                          (size      << kSignatureSizeShift        ) ;
     945             : 
     946        8428 :     _init_packed_d0_d1(kOpMem | signature | flags, indexId);
     947        8428 :     _mem.base = baseId;
     948        8428 :     _mem.offsetLo32 = static_cast<uint32_t>(off);
     949             :   }
     950             :   explicit ASMJIT_INLINE Mem(const _NoInit&) noexcept : Operand(NoInit) {}
     951             : 
     952             :   // --------------------------------------------------------------------------
     953             :   // [Mem Specific]
     954             :   // --------------------------------------------------------------------------
     955             : 
     956             :   //! Clone `Mem` operand.
     957             :   ASMJIT_INLINE Mem clone() const noexcept { return Mem(*this); }
     958             : 
     959             :   //! Reset the memory operand - after reset the memory points to [0].
     960             :   ASMJIT_INLINE void reset() noexcept {
     961             :     _init_packed_d0_d1(kOpMem, 0);
     962             :     _init_packed_d2_d3(0, 0);
     963             :   }
     964             : 
     965             :   ASMJIT_INLINE bool hasAddrType() const noexcept { return _hasSignatureData(kSignatureMemAddrTypeMask); }
     966             :   ASMJIT_INLINE uint32_t getAddrType() const noexcept { return _getSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
     967             :   ASMJIT_INLINE void setAddrType(uint32_t addrType) noexcept { return _setSignatureData(addrType, kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
     968             :   ASMJIT_INLINE void resetAddrType() noexcept { return _clearSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
     969             : 
     970             :   ASMJIT_INLINE bool isAbs() const noexcept { return getAddrType() == kAddrTypeAbs; }
     971             :   ASMJIT_INLINE bool isRel() const noexcept { return getAddrType() == kAddrTypeRel; }
     972             :   ASMJIT_INLINE bool isWrt() const noexcept { return getAddrType() == kAddrTypeWrt; }
     973             : 
     974             :   ASMJIT_INLINE void setAbs() noexcept { setAddrType(kAddrTypeAbs); }
     975             :   ASMJIT_INLINE void setRel() noexcept { setAddrType(kAddrTypeRel); }
     976             :   ASMJIT_INLINE void setWrt() noexcept { setAddrType(kAddrTypeWrt); }
     977             : 
     978             :   ASMJIT_INLINE bool isArgHome() const noexcept { return _hasSignatureData(kSignatureMemArgHomeFlag); }
     979             :   ASMJIT_INLINE bool isRegHome() const noexcept { return _hasSignatureData(kSignatureMemRegHomeFlag); }
     980             : 
     981           0 :   ASMJIT_INLINE void setArgHome() noexcept { _signature |= kSignatureMemArgHomeFlag; }
     982             :   ASMJIT_INLINE void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; }
     983             : 
     984           0 :   ASMJIT_INLINE void clearArgHome() noexcept { _signature &= ~kSignatureMemArgHomeFlag; }
     985        8428 :   ASMJIT_INLINE void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; }
     986             : 
     987             :   //! Get if the memory operand has a BASE register or label specified.
     988           0 :   ASMJIT_INLINE bool hasBase() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0; }
     989             :   //! Get if the memory operand has an INDEX register specified.
     990           0 :   ASMJIT_INLINE bool hasIndex() const noexcept { return (_signature & kSignatureMemIndexTypeMask) != 0; }
     991             :   //! Get whether the memory operand has BASE and INDEX register.
     992           0 :   ASMJIT_INLINE bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; }
     993             :   //! Get whether the memory operand has BASE and INDEX register.
     994             :   ASMJIT_INLINE bool hasBaseAndIndex() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0 && (_signature & kSignatureMemIndexTypeMask) != 0; }
     995             : 
     996             :   //! Get if the BASE operand is a register (registers start after `kLabelTag`).
     997       12136 :   ASMJIT_INLINE bool hasBaseReg() const noexcept { return (_signature & kSignatureMemBaseTypeMask) > (Label::kLabelTag << kSignatureMemBaseTypeShift); }
     998             :   //! Get if the BASE operand is a label.
     999             :   ASMJIT_INLINE bool hasBaseLabel() const noexcept { return (_signature & kSignatureMemBaseTypeMask) == (Label::kLabelTag << kSignatureMemBaseTypeShift); }
    1000             :   //! Get if the INDEX operand is a register (registers start after `kLabelTag`).
    1001       12136 :   ASMJIT_INLINE bool hasIndexReg() const noexcept { return (_signature & kSignatureMemIndexTypeMask) > (Label::kLabelTag << kSignatureMemIndexTypeShift); }
    1002             : 
    1003             :   //! Get type of a BASE register (0 if this memory operand doesn't use the BASE register).
    1004             :   //!
    1005             :   //! NOTE: If the returned type is one (a value never associated to a register
    1006             :   //! type) the BASE is not register, but it's a label. One equals to `kLabelTag`.
    1007             :   //! You should always check `hasBaseLabel()` before using `getBaseId()` result.
    1008             :   ASMJIT_INLINE uint32_t getBaseType() const noexcept { return _getSignatureData(kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift); }
    1009             :   //! Get type of an INDEX register (0 if this memory operand doesn't use the INDEX register).
    1010             :   ASMJIT_INLINE uint32_t getIndexType() const noexcept { return _getSignatureData(kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift); }
    1011             : 
    1012             :   //! Get both BASE (4:0 bits) and INDEX (9:5 bits) types combined into a single integer.
    1013             :   //!
    1014             :   //! This is used internally for BASE+INDEX validation.
    1015             :   ASMJIT_INLINE uint32_t getBaseIndexType() const noexcept { return _getSignatureData(kSignatureMemBaseIndexBits, kSignatureMemBaseIndexShift); }
    1016             : 
    1017             :   //! Get id of the BASE register or label (if the BASE was specified as label).
    1018       20564 :   ASMJIT_INLINE uint32_t getBaseId() const noexcept { return _mem.base; }
    1019             :   //! Get id of the INDEX register.
    1020       14496 :   ASMJIT_INLINE uint32_t getIndexId() const noexcept { return _mem.index; }
    1021             : 
    1022             :   ASMJIT_INLINE void _setBase(uint32_t rType, uint32_t rId) noexcept {
    1023             :     _setSignatureData(rType, kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift);
    1024        8428 :     _mem.base = rId;
    1025             :   }
    1026             : 
    1027             :   ASMJIT_INLINE void _setIndex(uint32_t rType, uint32_t rId) noexcept {
    1028             :     _setSignatureData(rType, kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift);
    1029             :     _mem.index = rId;
    1030             :   }
    1031             : 
    1032             :   ASMJIT_INLINE void setBase(const Reg& base) noexcept { return _setBase(base.getType(), base.getId()); }
    1033             :   ASMJIT_INLINE void setIndex(const Reg& index) noexcept { return _setIndex(index.getType(), index.getId()); }
    1034             : 
    1035             :   //! Reset the memory operand's BASE register / label.
    1036             :   ASMJIT_INLINE void resetBase() noexcept { _setBase(0, 0); }
    1037             :   //! Reset the memory operand's INDEX register.
    1038             :   ASMJIT_INLINE void resetIndex() noexcept { _setIndex(0, 0); }
    1039             : 
    1040             :   //! Set memory operand size.
    1041             :   ASMJIT_INLINE void setSize(uint32_t size) noexcept {
    1042             :     _setSignatureData(size, kSignatureSizeBits, kSignatureSizeShift);
    1043        8428 :   }
    1044             : 
    1045             :   ASMJIT_INLINE bool hasOffset() const noexcept {
    1046           0 :     int32_t lo = static_cast<int32_t>(_mem.offsetLo32);
    1047           0 :     int32_t hi = static_cast<int32_t>(_mem.base) & -static_cast<int32_t>(getBaseType() == 0);
    1048           0 :     return (lo | hi) != 0;
    1049             :   }
    1050             : 
    1051             :   //! Get if the memory operand has 64-bit offset or absolute address.
    1052             :   //!
    1053             :   //! If this is true then `hasBase()` must always report false.
    1054             :   ASMJIT_INLINE bool has64BitOffset() const noexcept { return getBaseType() == 0; }
    1055             : 
    1056             :   //! Get a 64-bit offset or absolute address.
    1057             :   ASMJIT_INLINE int64_t getOffset() const noexcept {
    1058             :     return has64BitOffset()
    1059           0 :       ? static_cast<int64_t>(_mem.offset64)
    1060           0 :       : static_cast<int64_t>(static_cast<int32_t>(_mem.offsetLo32)); // Sign-Extend.
    1061             :   }
    1062             : 
    1063             :   //! Get a lower part of a 64-bit offset or absolute address.
    1064       14496 :   ASMJIT_INLINE int32_t getOffsetLo32() const noexcept { return static_cast<int32_t>(_mem.offsetLo32); }
    1065             :   //! Get a higher part of a 64-bit offset or absolute address.
    1066             :   //!
    1067             :   //! NOTE: This function is UNSAFE and returns garbage if `has64BitOffset()`
    1068             :   //! returns false. Never use it blindly without checking it.
    1069           0 :   ASMJIT_INLINE int32_t getOffsetHi32() const noexcept { return static_cast<int32_t>(_mem.base); }
    1070             : 
    1071             :   //! Set a 64-bit offset or an absolute address to `offset`.
    1072             :   //!
    1073             :   //! NOTE: This functions attempts to set both high and low parts of a 64-bit
    1074             :   //! offset, however, if the operand has a BASE register it will store only the
    1075             :   //! low 32 bits of the offset / address as there is no way to store both BASE
    1076             :   //! and 64-bit offset, and there is currently no architecture that has such
    1077             :   //! capability targeted by AsmJit.
    1078             :   ASMJIT_INLINE void setOffset(int64_t offset) noexcept {
    1079             :     if (has64BitOffset())
    1080             :       _mem.offset64 = static_cast<uint64_t>(offset);
    1081             :     else
    1082             :       _mem.offsetLo32 = static_cast<int32_t>(offset & 0xFFFFFFFF);
    1083             :   }
    1084             :   //! Adjust the offset by a 64-bit `off`.
    1085             :   ASMJIT_INLINE void addOffset(int64_t off) noexcept {
    1086           0 :     if (has64BitOffset())
    1087           0 :       _mem.offset64 += static_cast<uint64_t>(off);
    1088             :     else
    1089           0 :       _mem.offsetLo32 += static_cast<uint32_t>(off & 0xFFFFFFFF);
    1090             :   }
    1091             :   //! Reset the memory offset to zero.
    1092             :   ASMJIT_INLINE void resetOffset() noexcept { setOffset(0); }
    1093             : 
    1094             :   //! Set a low 32-bit offset to `off`.
    1095             :   ASMJIT_INLINE void setOffsetLo32(int32_t off) noexcept {
    1096             :     _mem.offsetLo32 = static_cast<uint32_t>(off);
    1097             :   }
    1098             :   //! Adjust the offset by `off`.
    1099             :   //!
    1100             :   //! NOTE: This is a fast function that doesn't use the HI 32-bits of a
    1101             :   //! 64-bit offset. Use it only if you know that there is a BASE register
    1102             :   //! and the offset is only 32 bits anyway.
    1103             :   ASMJIT_INLINE void addOffsetLo32(int32_t off) noexcept {
    1104        8428 :     _mem.offsetLo32 += static_cast<uint32_t>(off);
    1105           0 :   }
    1106             :   //! Reset the memory offset to zero.
    1107             :   ASMJIT_INLINE void resetOffsetLo32() noexcept { setOffsetLo32(0); }
    1108             : 
    1109             :   // --------------------------------------------------------------------------
    1110             :   // [Operator Overload]
    1111             :   // --------------------------------------------------------------------------
    1112             : 
    1113           0 :   ASMJIT_INLINE Mem& operator=(const Mem& other) noexcept { copyFrom(other); return *this; }
    1114             : };
    1115             : 
    1116             : // ============================================================================
    1117             : // [asmjit::Imm]
    1118             : // ============================================================================
    1119             : 
    1120             : //! Immediate operand.
    1121             : //!
    1122             : //! Immediate operand is usually part of instruction itself. It's inlined after
    1123             : //! or before the instruction opcode. Immediates can be only signed or unsigned
    1124             : //! integers.
    1125             : //!
    1126             : //! To create immediate operand use `imm()` or `imm_u()` non-members or `Imm`
    1127             : //! constructors.
    1128             : class Imm : public Operand {
    1129             : public:
    1130             :   // --------------------------------------------------------------------------
    1131             :   // [Construction / Destruction]
    1132             :   // --------------------------------------------------------------------------
    1133             : 
    1134             :   //! Create a new immediate value (initial value is 0).
    1135             :   Imm() noexcept : Operand(NoInit) {
    1136             :     _init_packed_d0_d1(kOpImm, 0);
    1137             :     _imm.value.i64 = 0;
    1138             :   }
    1139             : 
    1140             :   //! Create a new signed immediate value, assigning the value to `val`.
    1141             :   explicit Imm(int64_t val) noexcept : Operand(NoInit) {
    1142             :     _init_packed_d0_d1(kOpImm, 0);
    1143        9434 :     _imm.value.i64 = val;
    1144             :   }
    1145             : 
    1146             :   //! Create a new immediate value from `other`.
    1147             :   ASMJIT_INLINE Imm(const Imm& other) noexcept : Operand(other) {}
    1148             : 
    1149             :   explicit ASMJIT_INLINE Imm(const _NoInit&) noexcept : Operand(NoInit) {}
    1150             : 
    1151             :   // --------------------------------------------------------------------------
    1152             :   // [Immediate Specific]
    1153             :   // --------------------------------------------------------------------------
    1154             : 
    1155             :   //! Clone `Imm` operand.
    1156             :   ASMJIT_INLINE Imm clone() const noexcept { return Imm(*this); }
    1157             : 
    1158             :   //! Get whether the immediate can be casted to 8-bit signed integer.
    1159             :   ASMJIT_INLINE bool isInt8() const noexcept { return Utils::isInt8(_imm.value.i64); }
    1160             :   //! Get whether the immediate can be casted to 8-bit unsigned integer.
    1161             :   ASMJIT_INLINE bool isUInt8() const noexcept { return Utils::isUInt8(_imm.value.i64); }
    1162             : 
    1163             :   //! Get whether the immediate can be casted to 16-bit signed integer.
    1164             :   ASMJIT_INLINE bool isInt16() const noexcept { return Utils::isInt16(_imm.value.i64); }
    1165             :   //! Get whether the immediate can be casted to 16-bit unsigned integer.
    1166             :   ASMJIT_INLINE bool isUInt16() const noexcept { return Utils::isUInt16(_imm.value.i64); }
    1167             : 
    1168             :   //! Get whether the immediate can be casted to 32-bit signed integer.
    1169             :   ASMJIT_INLINE bool isInt32() const noexcept { return Utils::isInt32(_imm.value.i64); }
    1170             :   //! Get whether the immediate can be casted to 32-bit unsigned integer.
    1171             :   ASMJIT_INLINE bool isUInt32() const noexcept { return Utils::isUInt32(_imm.value.i64); }
    1172             : 
    1173             :   //! Get immediate value as 8-bit signed integer.
    1174             :   ASMJIT_INLINE int8_t getInt8() const noexcept { return static_cast<int8_t>(_imm.value.i32Lo & 0xFF); }
    1175             :   //! Get immediate value as 8-bit unsigned integer.
    1176           0 :   ASMJIT_INLINE uint8_t getUInt8() const noexcept { return static_cast<uint8_t>(_imm.value.u32Lo & 0xFFU); }
    1177             :   //! Get immediate value as 16-bit signed integer.
    1178             :   ASMJIT_INLINE int16_t getInt16() const noexcept { return static_cast<int16_t>(_imm.value.i32Lo & 0xFFFF);}
    1179             :   //! Get immediate value as 16-bit unsigned integer.
    1180           0 :   ASMJIT_INLINE uint16_t getUInt16() const noexcept { return static_cast<uint16_t>(_imm.value.u32Lo & 0xFFFFU);}
    1181             : 
    1182             :   //! Get immediate value as 32-bit signed integer.
    1183             :   ASMJIT_INLINE int32_t getInt32() const noexcept { return _imm.value.i32Lo; }
    1184             :   //! Get low 32-bit signed integer.
    1185             :   ASMJIT_INLINE int32_t getInt32Lo() const noexcept { return _imm.value.i32Lo; }
    1186             :   //! Get high 32-bit signed integer.
    1187             :   ASMJIT_INLINE int32_t getInt32Hi() const noexcept { return _imm.value.i32Hi; }
    1188             : 
    1189             :   //! Get immediate value as 32-bit unsigned integer.
    1190           0 :   ASMJIT_INLINE uint32_t getUInt32() const noexcept { return _imm.value.u32Lo; }
    1191             :   //! Get low 32-bit signed integer.
    1192             :   ASMJIT_INLINE uint32_t getUInt32Lo() const noexcept { return _imm.value.u32Lo; }
    1193             :   //! Get high 32-bit signed integer.
    1194             :   ASMJIT_INLINE uint32_t getUInt32Hi() const noexcept { return _imm.value.u32Hi; }
    1195             : 
    1196             :   //! Get immediate value as 64-bit signed integer.
    1197        9636 :   ASMJIT_INLINE int64_t getInt64() const noexcept { return _imm.value.i64; }
    1198             :   //! Get immediate value as 64-bit unsigned integer.
    1199           0 :   ASMJIT_INLINE uint64_t getUInt64() const noexcept { return _imm.value.u64; }
    1200             : 
    1201             :   //! Get immediate value as `intptr_t`.
    1202             :   ASMJIT_INLINE intptr_t getIntPtr() const noexcept {
    1203             :     if (sizeof(intptr_t) == sizeof(int64_t))
    1204             :       return static_cast<intptr_t>(getInt64());
    1205             :     else
    1206             :       return static_cast<intptr_t>(getInt32());
    1207             :   }
    1208             : 
    1209             :   //! Get immediate value as `uintptr_t`.
    1210             :   ASMJIT_INLINE uintptr_t getUIntPtr() const noexcept {
    1211             :     if (sizeof(uintptr_t) == sizeof(uint64_t))
    1212             :       return static_cast<uintptr_t>(getUInt64());
    1213             :     else
    1214             :       return static_cast<uintptr_t>(getUInt32());
    1215             :   }
    1216             : 
    1217             :   //! Set immediate value to 8-bit signed integer `val`.
    1218             :   ASMJIT_INLINE void setInt8(int8_t val) noexcept { _imm.value.i64 = static_cast<int64_t>(val); }
    1219             :   //! Set immediate value to 8-bit unsigned integer `val`.
    1220             :   ASMJIT_INLINE void setUInt8(uint8_t val) noexcept { _imm.value.u64 = static_cast<uint64_t>(val); }
    1221             : 
    1222             :   //! Set immediate value to 16-bit signed integer `val`.
    1223             :   ASMJIT_INLINE void setInt16(int16_t val) noexcept { _imm.value.i64 = static_cast<int64_t>(val); }
    1224             :   //! Set immediate value to 16-bit unsigned integer `val`.
    1225             :   ASMJIT_INLINE void setUInt16(uint16_t val) noexcept { _imm.value.u64 = static_cast<uint64_t>(val); }
    1226             : 
    1227             :   //! Set immediate value to 32-bit signed integer `val`.
    1228             :   ASMJIT_INLINE void setInt32(int32_t val) noexcept { _imm.value.i64 = static_cast<int64_t>(val); }
    1229             :   //! Set immediate value to 32-bit unsigned integer `val`.
    1230           0 :   ASMJIT_INLINE void setUInt32(uint32_t val) noexcept { _imm.value.u64 = static_cast<uint64_t>(val); }
    1231             : 
    1232             :   //! Set immediate value to 64-bit signed integer `val`.
    1233             :   ASMJIT_INLINE void setInt64(int64_t val) noexcept { _imm.value.i64 = val; }
    1234             :   //! Set immediate value to 64-bit unsigned integer `val`.
    1235             :   ASMJIT_INLINE void setUInt64(uint64_t val) noexcept { _imm.value.u64 = val; }
    1236             :   //! Set immediate value to intptr_t `val`.
    1237             :   ASMJIT_INLINE void setIntPtr(intptr_t val) noexcept { _imm.value.i64 = static_cast<int64_t>(val); }
    1238             :   //! Set immediate value to uintptr_t `val`.
    1239             :   ASMJIT_INLINE void setUIntPtr(uintptr_t val) noexcept { _imm.value.u64 = static_cast<uint64_t>(val); }
    1240             : 
    1241             :   //! Set immediate value as unsigned type to `val`.
    1242             :   ASMJIT_INLINE void setPtr(void* p) noexcept { setIntPtr((uint64_t)p); }
    1243             :   //! Set immediate value to `val`.
    1244             :   template<typename T>
    1245             :   ASMJIT_INLINE void setValue(T val) noexcept { setIntPtr((int64_t)val); }
    1246             : 
    1247             :   // --------------------------------------------------------------------------
    1248             :   // [Float]
    1249             :   // --------------------------------------------------------------------------
    1250             : 
    1251             :   ASMJIT_INLINE void setFloat(float f) noexcept {
    1252             :     _imm.value.f32Lo = f;
    1253             :     _imm.value.u32Hi = 0;
    1254             :   }
    1255             : 
    1256             :   ASMJIT_INLINE void setDouble(double d) noexcept {
    1257             :     _imm.value.f64 = d;
    1258             :   }
    1259             : 
    1260             :   // --------------------------------------------------------------------------
    1261             :   // [Truncate]
    1262             :   // --------------------------------------------------------------------------
    1263             : 
    1264             :   ASMJIT_INLINE void truncateTo8Bits() noexcept {
    1265             :     if (ASMJIT_ARCH_64BIT) {
    1266           0 :       _imm.value.u64   &= static_cast<uint64_t>(0x000000FFU);
    1267             :     }
    1268             :     else {
    1269             :       _imm.value.u32Lo &= 0x000000FFU;
    1270             :       _imm.value.u32Hi  = 0;
    1271             :     }
    1272           0 :   }
    1273             : 
    1274             :   ASMJIT_INLINE void truncateTo16Bits() noexcept {
    1275             :     if (ASMJIT_ARCH_64BIT) {
    1276           0 :       _imm.value.u64   &= static_cast<uint64_t>(0x0000FFFFU);
    1277             :     }
    1278             :     else {
    1279             :       _imm.value.u32Lo &= 0x0000FFFFU;
    1280             :       _imm.value.u32Hi  = 0;
    1281             :     }
    1282           0 :   }
    1283             : 
    1284           0 :   ASMJIT_INLINE void truncateTo32Bits() noexcept { _imm.value.u32Hi = 0; }
    1285             : 
    1286             :   // --------------------------------------------------------------------------
    1287             :   // [Operator Overload]
    1288             :   // --------------------------------------------------------------------------
    1289             : 
    1290             :   //! Assign `other` to the immediate operand.
    1291             :   ASMJIT_INLINE Imm& operator=(const Imm& other) noexcept { copyFrom(other); return *this; }
    1292             : };
    1293             : 
    1294             : //! Create a signed immediate operand.
    1295             : static ASMJIT_INLINE Imm imm(int64_t val) noexcept { return Imm(val); }
    1296             : //! Create an unsigned immediate operand.
    1297             : static ASMJIT_INLINE Imm imm_u(uint64_t val) noexcept { return Imm(static_cast<int64_t>(val)); }
    1298             : //! Create an immediate operand from `p`.
    1299             : template<typename T>
    1300        7450 : static ASMJIT_INLINE Imm imm_ptr(T p) noexcept { return Imm(static_cast<int64_t>((intptr_t)p)); }
    1301             : 
    1302             : // ============================================================================
    1303             : // [asmjit::TypeId]
    1304             : // ============================================================================
    1305             : 
    1306             : //! Type-id.
    1307             : //!
    1308             : //! This is an additional information that can be used to describe a physical
    1309             : //! or virtual register. it's used mostly by CodeCompiler to describe register
    1310             : //! representation (the kind of data stored in the register and the width used)
    1311             : //! and it's also used by APIs that allow to describe and work with function
    1312             : //! signatures.
    1313             : struct TypeId {
    1314             :   // --------------------------------------------------------------------------
    1315             :   // [Id]
    1316             :   // --------------------------------------------------------------------------
    1317             : 
    1318             :   enum Id {
    1319             :     kVoid         = 0,
    1320             : 
    1321             :     _kIntStart    = 32,
    1322             :     _kIntEnd      = 41,
    1323             : 
    1324             :     kIntPtr       = 32,
    1325             :     kUIntPtr      = 33,
    1326             : 
    1327             :     kI8           = 34,
    1328             :     kU8           = 35,
    1329             :     kI16          = 36,
    1330             :     kU16          = 37,
    1331             :     kI32          = 38,
    1332             :     kU32          = 39,
    1333             :     kI64          = 40,
    1334             :     kU64          = 41,
    1335             : 
    1336             :     _kFloatStart  = 42,
    1337             :     _kFloatEnd    = 44,
    1338             : 
    1339             :     kF32          = 42,
    1340             :     kF64          = 43,
    1341             :     kF80          = 44,
    1342             : 
    1343             :     _kMaskStart   = 45,
    1344             :     _kMaskEnd     = 48,
    1345             : 
    1346             :     kMask8        = 45,
    1347             :     kMask16       = 46,
    1348             :     kMask32       = 47,
    1349             :     kMask64       = 48,
    1350             : 
    1351             :     _kMmxStart    = 49,
    1352             :     _kMmxEnd      = 50,
    1353             : 
    1354             :     kMmx32        = 49,
    1355             :     kMmx64        = 50,
    1356             : 
    1357             :     _kVec32Start  = 51,
    1358             :     _kVec32End    = 60,
    1359             : 
    1360             :     kI8x4         = 51,
    1361             :     kU8x4         = 52,
    1362             :     kI16x2        = 53,
    1363             :     kU16x2        = 54,
    1364             :     kI32x1        = 55,
    1365             :     kU32x1        = 56,
    1366             :     kF32x1        = 59,
    1367             : 
    1368             :     _kVec64Start  = 61,
    1369             :     _kVec64End    = 70,
    1370             : 
    1371             :     kI8x8         = 61,
    1372             :     kU8x8         = 62,
    1373             :     kI16x4        = 63,
    1374             :     kU16x4        = 64,
    1375             :     kI32x2        = 65,
    1376             :     kU32x2        = 66,
    1377             :     kI64x1        = 67,
    1378             :     kU64x1        = 68,
    1379             :     kF32x2        = 69,
    1380             :     kF64x1        = 70,
    1381             : 
    1382             :     _kVec128Start = 71,
    1383             :     _kVec128End   = 80,
    1384             : 
    1385             :     kI8x16        = 71,
    1386             :     kU8x16        = 72,
    1387             :     kI16x8        = 73,
    1388             :     kU16x8        = 74,
    1389             :     kI32x4        = 75,
    1390             :     kU32x4        = 76,
    1391             :     kI64x2        = 77,
    1392             :     kU64x2        = 78,
    1393             :     kF32x4        = 79,
    1394             :     kF64x2        = 80,
    1395             : 
    1396             :     _kVec256Start = 81,
    1397             :     _kVec256End   = 90,
    1398             : 
    1399             :     kI8x32        = 81,
    1400             :     kU8x32        = 82,
    1401             :     kI16x16       = 83,
    1402             :     kU16x16       = 84,
    1403             :     kI32x8        = 85,
    1404             :     kU32x8        = 86,
    1405             :     kI64x4        = 87,
    1406             :     kU64x4        = 88,
    1407             :     kF32x8        = 89,
    1408             :     kF64x4        = 90,
    1409             : 
    1410             :     _kVec512Start = 91,
    1411             :     _kVec512End   = 100,
    1412             : 
    1413             :     kI8x64        = 91,
    1414             :     kU8x64        = 92,
    1415             :     kI16x32       = 93,
    1416             :     kU16x32       = 94,
    1417             :     kI32x16       = 95,
    1418             :     kU32x16       = 96,
    1419             :     kI64x8        = 97,
    1420             :     kU64x8        = 98,
    1421             :     kF32x16       = 99,
    1422             :     kF64x8        = 100,
    1423             : 
    1424             :     kCount        = 101
    1425             :   };
    1426             : 
    1427             :   // --------------------------------------------------------------------------
    1428             :   // [TypeName - Used by Templates]
    1429             :   // --------------------------------------------------------------------------
    1430             : 
    1431             :   struct Int8    {};                     //!< int8_t as C++ type-name.
    1432             :   struct UInt8   {};                     //!< uint8_t as C++ type-name.
    1433             :   struct Int16   {};                     //!< int16_t as C++ type-name.
    1434             :   struct UInt16  {};                     //!< uint16_t as C++ type-name.
    1435             :   struct Int32   {};                     //!< int32_t as C++ type-name.
    1436             :   struct UInt32  {};                     //!< uint32_t as C++ type-name.
    1437             :   struct Int64   {};                     //!< int64_t as C++ type-name.
    1438             :   struct UInt64  {};                     //!< uint64_t as C++ type-name.
    1439             :   struct IntPtr  {};                     //!< intptr_t as C++ type-name.
    1440             :   struct UIntPtr {};                     //!< uintptr_t as C++ type-name.
    1441             :   struct Float   {};                     //!< float as C++ type-name.
    1442             :   struct Double  {};                     //!< double as C++ type-name.
    1443             :   struct MmxReg  {};                     //!< MMX register as C++ type-name.
    1444             :   struct Vec128  {};                     //!< SIMD128/XMM register as C++ type-name.
    1445             :   struct Vec256  {};                     //!< SIMD256/YMM register as C++ type-name.
    1446             :   struct Vec512  {};                     //!< SIMD512/ZMM register as C++ type-name.
    1447             : 
    1448             :   // --------------------------------------------------------------------------
    1449             :   // [Utilities]
    1450             :   // --------------------------------------------------------------------------
    1451             : 
    1452             :   struct Info {
    1453             :     uint8_t sizeOf[128];
    1454             :     uint8_t elementOf[128];
    1455             :   };
    1456             : 
    1457             :   ASMJIT_API static const Info _info;
    1458             : 
    1459             :   static ASMJIT_INLINE bool isVoid(uint32_t typeId) noexcept { return typeId == 0; }
    1460       23740 :   static ASMJIT_INLINE bool isValid(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kVec512End; }
    1461        5430 :   static ASMJIT_INLINE bool isAbstract(uint32_t typeId) noexcept { return typeId >= kIntPtr && typeId <= kUIntPtr; }
    1462        1850 :   static ASMJIT_INLINE bool isInt(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kIntEnd; }
    1463           0 :   static ASMJIT_INLINE bool isGpb(uint32_t typeId) noexcept { return typeId >= kI8 && typeId <= kU8; }
    1464           0 :   static ASMJIT_INLINE bool isGpw(uint32_t typeId) noexcept { return typeId >= kI16 && typeId <= kU16; }
    1465             :   static ASMJIT_INLINE bool isGpd(uint32_t typeId) noexcept { return typeId >= kI32 && typeId <= kU32; }
    1466             :   static ASMJIT_INLINE bool isGpq(uint32_t typeId) noexcept { return typeId >= kI64 && typeId <= kU64; }
    1467        1446 :   static ASMJIT_INLINE bool isFloat(uint32_t typeId) noexcept { return typeId >= _kFloatStart && typeId <= _kFloatEnd; }
    1468           0 :   static ASMJIT_INLINE bool isMask(uint32_t typeId) noexcept { return typeId >= _kMaskStart && typeId <= _kMaskEnd; }
    1469           0 :   static ASMJIT_INLINE bool isMmx(uint32_t typeId) noexcept { return typeId >= _kMmxStart && typeId <= _kMmxEnd; }
    1470             : 
    1471           0 :   static ASMJIT_INLINE bool isVec(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec512End; }
    1472        9084 :   static ASMJIT_INLINE bool isVec32(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec32End; }
    1473        9084 :   static ASMJIT_INLINE bool isVec64(uint32_t typeId) noexcept { return typeId >= _kVec64Start && typeId <= _kVec64End; }
    1474             :   static ASMJIT_INLINE bool isVec128(uint32_t typeId) noexcept { return typeId >= _kVec128Start && typeId <= _kVec128End; }
    1475             :   static ASMJIT_INLINE bool isVec256(uint32_t typeId) noexcept { return typeId >= _kVec256Start && typeId <= _kVec256End; }
    1476             :   static ASMJIT_INLINE bool isVec512(uint32_t typeId) noexcept { return typeId >= _kVec512Start && typeId <= _kVec512End; }
    1477             : 
    1478             :   static ASMJIT_INLINE uint32_t sizeOf(uint32_t typeId) noexcept {
    1479             :     ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.sizeOf));
    1480       47480 :     return _info.sizeOf[typeId];
    1481             :   }
    1482             : 
    1483             :   static ASMJIT_INLINE uint32_t elementOf(uint32_t typeId) noexcept {
    1484             :     ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.elementOf));
    1485        9084 :     return _info.elementOf[typeId];
    1486             :   }
    1487             : 
    1488             :   //! Get an offset to convert a `kIntPtr` and `kUIntPtr` TypeId into a
    1489             :   //! type that matches `gpSize` (general-purpose register size). If you
    1490             :   //! find such TypeId it's then only about adding the offset to it.
    1491             :   //!
    1492             :   //! For example:
    1493             :   //! ~~~
    1494             :   //! uint32_t gpSize = '4' or '8';
    1495             :   //! uint32_t deabstractDelta = TypeId::deabstractDeltaOfSize(gpSize);
    1496             :   //!
    1497             :   //! uint32_t typeId = 'some type-id';
    1498             :   //!
    1499             :   //! // Normalize some typeId into a non-abstract typeId.
    1500             :   //! if (TypeId::isAbstract(typeId)) typeId += deabstractDelta;
    1501             :   //!
    1502             :   //! // The same, but by using TypeId::deabstract() function.
    1503             :   //! typeId = TypeId::deabstract(typeId, deabstractDelta);
    1504             :   //! ~~~
    1505             :   static ASMJIT_INLINE uint32_t deabstractDeltaOfSize(uint32_t gpSize) noexcept {
    1506             :     return gpSize >= 8 ? kI64 - kIntPtr : kI32 - kIntPtr;
    1507             :   }
    1508             : 
    1509             :   static ASMJIT_INLINE uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept {
    1510        5430 :     return TypeId::isAbstract(typeId) ? typeId += deabstractDelta : typeId;
    1511             :   }
    1512             : };
    1513             : 
    1514             : //! TypeIdOf<> template allows to get a TypeId of a C++ type.
    1515             : template<typename T> struct TypeIdOf {
    1516             :   // Don't provide anything if not specialized.
    1517             : };
    1518             : template<typename T> struct TypeIdOf<T*> {
    1519             :   enum { kTypeId = TypeId::kUIntPtr };
    1520             : };
    1521             : 
    1522             : template<typename T>
    1523             : struct TypeIdOfInt {
    1524             :   enum {
    1525             :     kSigned = int(~T(0) < T(0)),
    1526             :     kTypeId = (sizeof(T) == 1) ? (int)(kSigned ? TypeId::kI8  : TypeId::kU8 ) :
    1527             :               (sizeof(T) == 2) ? (int)(kSigned ? TypeId::kI16 : TypeId::kU16) :
    1528             :               (sizeof(T) == 4) ? (int)(kSigned ? TypeId::kI32 : TypeId::kU32) :
    1529             :               (sizeof(T) == 8) ? (int)(kSigned ? TypeId::kI64 : TypeId::kU64) : (int)TypeId::kVoid
    1530             :   };
    1531             : };
    1532             : 
    1533             : #define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \
    1534             :   template<> \
    1535             :   struct TypeIdOf<T> { enum { kTypeId = TYPE_ID}; }
    1536             : 
    1537             : ASMJIT_DEFINE_TYPE_ID(signed char       , TypeIdOfInt< signed char        >::kTypeId);
    1538             : ASMJIT_DEFINE_TYPE_ID(unsigned char     , TypeIdOfInt< unsigned char      >::kTypeId);
    1539             : ASMJIT_DEFINE_TYPE_ID(short             , TypeIdOfInt< short              >::kTypeId);
    1540             : ASMJIT_DEFINE_TYPE_ID(unsigned short    , TypeIdOfInt< unsigned short     >::kTypeId);
    1541             : ASMJIT_DEFINE_TYPE_ID(int               , TypeIdOfInt< int                >::kTypeId);
    1542             : ASMJIT_DEFINE_TYPE_ID(unsigned int      , TypeIdOfInt< unsigned int       >::kTypeId);
    1543             : ASMJIT_DEFINE_TYPE_ID(long              , TypeIdOfInt< long               >::kTypeId);
    1544             : ASMJIT_DEFINE_TYPE_ID(unsigned long     , TypeIdOfInt< unsigned long      >::kTypeId);
    1545             : #if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(16, 0, 0)
    1546             : ASMJIT_DEFINE_TYPE_ID(__int64           , TypeIdOfInt< __int64            >::kTypeId);
    1547             : ASMJIT_DEFINE_TYPE_ID(unsigned __int64  , TypeIdOfInt< unsigned __int64   >::kTypeId);
    1548             : #else
    1549             : ASMJIT_DEFINE_TYPE_ID(long long         , TypeIdOfInt< long long          >::kTypeId);
    1550             : ASMJIT_DEFINE_TYPE_ID(unsigned long long, TypeIdOfInt< unsigned long long >::kTypeId);
    1551             : #endif
    1552             : #if ASMJIT_CC_HAS_NATIVE_CHAR
    1553             : ASMJIT_DEFINE_TYPE_ID(char              , TypeIdOfInt< char               >::kTypeId);
    1554             : #endif
    1555             : #if ASMJIT_CC_HAS_NATIVE_CHAR16_T
    1556             : ASMJIT_DEFINE_TYPE_ID(char16_t          , TypeIdOfInt< char16_t           >::kTypeId);
    1557             : #endif
    1558             : #if ASMJIT_CC_HAS_NATIVE_CHAR32_T
    1559             : ASMJIT_DEFINE_TYPE_ID(char32_t          , TypeIdOfInt< char32_t           >::kTypeId);
    1560             : #endif
    1561             : #if ASMJIT_CC_HAS_NATIVE_WCHAR_T
    1562             : ASMJIT_DEFINE_TYPE_ID(wchar_t           , TypeIdOfInt< wchar_t            >::kTypeId);
    1563             : #endif
    1564             : 
    1565             : ASMJIT_DEFINE_TYPE_ID(void              , TypeId::kVoid);
    1566             : ASMJIT_DEFINE_TYPE_ID(bool              , TypeId::kI8);
    1567             : ASMJIT_DEFINE_TYPE_ID(float             , TypeId::kF32);
    1568             : ASMJIT_DEFINE_TYPE_ID(double            , TypeId::kF64);
    1569             : 
    1570             : ASMJIT_DEFINE_TYPE_ID(TypeId::Int8      , TypeId::kI8);
    1571             : ASMJIT_DEFINE_TYPE_ID(TypeId::UInt8     , TypeId::kU8);
    1572             : ASMJIT_DEFINE_TYPE_ID(TypeId::Int16     , TypeId::kI16);
    1573             : ASMJIT_DEFINE_TYPE_ID(TypeId::UInt16    , TypeId::kU16);
    1574             : ASMJIT_DEFINE_TYPE_ID(TypeId::Int32     , TypeId::kI32);
    1575             : ASMJIT_DEFINE_TYPE_ID(TypeId::UInt32    , TypeId::kU32);
    1576             : ASMJIT_DEFINE_TYPE_ID(TypeId::Int64     , TypeId::kI64);
    1577             : ASMJIT_DEFINE_TYPE_ID(TypeId::UInt64    , TypeId::kU64);
    1578             : ASMJIT_DEFINE_TYPE_ID(TypeId::IntPtr    , TypeId::kIntPtr);
    1579             : ASMJIT_DEFINE_TYPE_ID(TypeId::UIntPtr   , TypeId::kUIntPtr);
    1580             : ASMJIT_DEFINE_TYPE_ID(TypeId::Float     , TypeId::kF32);
    1581             : ASMJIT_DEFINE_TYPE_ID(TypeId::Double    , TypeId::kF64);
    1582             : ASMJIT_DEFINE_TYPE_ID(TypeId::MmxReg    , TypeId::kMmx64);
    1583             : ASMJIT_DEFINE_TYPE_ID(TypeId::Vec128    , TypeId::kI32x4);
    1584             : ASMJIT_DEFINE_TYPE_ID(TypeId::Vec256    , TypeId::kI32x8);
    1585             : ASMJIT_DEFINE_TYPE_ID(TypeId::Vec512    , TypeId::kI32x16);
    1586             : 
    1587             : //! \}
    1588             : 
    1589             : } // asmjit namespace
    1590             : } // namespace PLMD
    1591             : 
    1592             : // [Api-End]
    1593             : #include "./asmjit_apiend.h"
    1594             : 
    1595             : // [Guard]
    1596             : #endif // _ASMJIT_BASE_OPERAND_H
    1597             : #pragma GCC diagnostic pop
    1598             : #endif // __PLUMED_HAS_ASMJIT
    1599             : #endif

Generated by: LCOV version 1.15