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.
ASMJIT_ENUMOperand_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 
ASMJIT_ENUMOperand_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.
ASMJIT_ENUMOperand_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.
isPackedIdOperand_161   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.
packIdOperand_163   static ASMJIT_INLINE uint32_t packId(uint32_t id) noexcept { return id + kPackedIdMin; }
164   //! Convert a packed-id back to real-id.
unpackIdOperand_165   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).
_initOperand_229   ASMJIT_INLINE void _init(const Operand_& other) noexcept { ::memcpy(this, &other, sizeof(Operand_)); }
230 
231   //! \internal
_initRegOperand_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
_init_packed_d0_d1Operand_238   ASMJIT_INLINE void _init_packed_d0_d1(uint32_t d0, uint32_t d1) noexcept { _packed[0].setPacked_2x32(d0, d1); }
239   //! \internal
_init_packed_d2_d3Operand_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).
copyFromOperand_245   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`.
hasSignatureOperand_252   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.
hasSignatureOperand_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.
getSignatureOperand_264   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.
setSignatureOperand_269   ASMJIT_INLINE void setSignature(uint32_t signature) noexcept { _signature = signature; }
270 
_hasSignatureDataOperand_271   ASMJIT_INLINE bool _hasSignatureData(uint32_t bits) const noexcept { return (_signature & bits) != 0; }
272 
273   //! \internal
274   //!
275   //! Unpacks information from operand's signature.
_getSignatureDataOperand_276   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.
_setSignatureDataOperand_281   ASMJIT_INLINE void _setSignatureData(uint32_t value, uint32_t bits, uint32_t shift) noexcept {
282     ASMJIT_ASSERT(value <= bits);
283     _signature = (_signature & ~(bits << shift)) | (value << shift);
284   }
285 
_addSignatureDataOperand_286   ASMJIT_INLINE void _addSignatureData(uint32_t data) noexcept { _signature |= data; }
287 
288   //! Clears specified bits in operand's signature.
_clearSignatureDataOperand_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.
getOpOperand_292   ASMJIT_INLINE uint32_t getOp() const noexcept { return _getSignatureData(kSignatureOpBits, kSignatureOpShift); }
293   //! Get if the operand is none (\ref kOpNone).
isNoneOperand_294   ASMJIT_INLINE bool isNone() const noexcept { return getOp() == 0; }
295   //! Get if the operand is a register (\ref kOpReg).
isRegOperand_296   ASMJIT_INLINE bool isReg() const noexcept { return getOp() == kOpReg; }
297   //! Get if the operand is a memory location (\ref kOpMem).
isMemOperand_298   ASMJIT_INLINE bool isMem() const noexcept { return getOp() == kOpMem; }
299   //! Get if the operand is an immediate (\ref kOpImm).
isImmOperand_300   ASMJIT_INLINE bool isImm() const noexcept { return getOp() == kOpImm; }
301   //! Get if the operand is a label (\ref kOpLabel).
isLabelOperand_302   ASMJIT_INLINE bool isLabel() const noexcept { return getOp() == kOpLabel; }
303 
304   //! Get if the operand is a physical register.
isPhysRegOperand_305   ASMJIT_INLINE bool isPhysReg() const noexcept { return isReg() && _reg.id < Globals::kInvalidRegId; }
306   //! Get if the operand is a virtual register.
isVirtRegOperand_307   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).
hasSizeOperand_310   ASMJIT_INLINE bool hasSize() const noexcept { return _hasSignatureData(kSignatureSizeMask); }
311   //! Get if the size of the operand matches `size`.
hasSizeOperand_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.
getSizeOperand_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.
getIdOperand_337   ASMJIT_INLINE uint32_t getId() const noexcept { return _any.id; }
338 
339   //! Get if the operand is 100% equal to `other`.
isEqualOperand_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`.
isRegOperand_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`.
isRegOperand_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.
isRegOrMemOperand_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>
asOperand_365   ASMJIT_INLINE T& as() noexcept { return static_cast<T&>(*this); }
366   //! Cast this operand to `T` type (const).
367   template<typename T>
asOperand_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   //! ```
resetOperand_402   ASMJIT_INLINE void reset() noexcept {
403     _init_packed_d0_d1(kOpNone, 0);
404     _init_packed_d2_d3(0, 0);
405   }
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.
Operand()444   ASMJIT_INLINE Operand() noexcept { reset(); }
445   //! Create a reference to `other` operand.
Operand(const Operand & other)446   ASMJIT_INLINE Operand(const Operand& other) noexcept { _init(other); }
447   //! Create a reference to `other` operand.
Operand(const Operand_ & other)448   explicit ASMJIT_INLINE Operand(const Operand_& other) noexcept { _init(other); }
449   //! Create a completely uninitialized operand (dangerous).
Operand(const _NoInit &)450   explicit ASMJIT_INLINE Operand(const _NoInit&) noexcept {}
451 
452   // --------------------------------------------------------------------------
453   // [Clone]
454   // --------------------------------------------------------------------------
455 
456   //! Clone the `Operand`.
clone()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.
Label()516   ASMJIT_INLINE Label() noexcept : Operand(NoInit) { reset(); }
517   //! Create a reference to another label.
Label(const Label & other)518   ASMJIT_INLINE Label(const Label& other) noexcept : Operand(other) {}
519 
Label(uint32_t id)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 
Label(const _NoInit &)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.
reset()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.
isValid()543   ASMJIT_INLINE bool isValid() const noexcept { return _label.id != 0; }
544   //! Set label id.
setId(uint32_t 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 {
getSignatureRegInfo636   ASMJIT_INLINE uint32_t getSignature() const noexcept {
637     return _signature;
638   }
639 
getOpRegInfo640   ASMJIT_INLINE uint32_t getOp() const noexcept {
641     return (_signature >> Operand::kSignatureOpShift) & Operand::kSignatureOpBits;
642   }
643 
getTypeRegInfo644   ASMJIT_INLINE uint32_t getType() const noexcept {
645     return (_signature >> Operand::kSignatureRegTypeShift) & Operand::kSignatureRegTypeBits;
646   }
647 
getKindRegInfo648   ASMJIT_INLINE uint32_t getKind() const noexcept {
649     return (_signature >> Operand::kSignatureRegKindShift) & Operand::kSignatureRegKindBits;
650   }
651 
getSizeRegInfo652   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.
ASMJIT_ENUM(RegType)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.
ASMJIT_ENUM(Kind)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.
Reg()699   ASMJIT_INLINE Reg() noexcept : Operand() {}
700   //! Create a new register operand which is the same as `other` .
Reg(const Reg & 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`.
Reg(const Reg & other,uint32_t 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`.
Reg(const _Init &,uint32_t signature,uint32_t rId)709   ASMJIT_INLINE Reg(const _Init&, uint32_t signature, uint32_t rId) noexcept : Operand(NoInit) {
710     _initReg(signature, rId);
711   }
Reg(const _NoInit &)712   explicit ASMJIT_INLINE Reg(const _NoInit&) noexcept : Operand(NoInit) {}
713 
714   //! Create a new register based on `signature` and `rId`.
fromSignature(uint32_t signature,uint32_t 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).
isValid()722   ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; }
723   //! Get if this is a physical register.
isPhysReg()724   ASMJIT_INLINE bool isPhysReg() const noexcept { return _reg.id < Globals::kInvalidRegId; }
725   //! Get if this is a virtual register (used by \ref CodeCompiler).
isVirtReg()726   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.
isSame(const Reg & other)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.
isType(uint32_t rType)740   ASMJIT_INLINE bool isType(uint32_t rType) const noexcept { return (_signature & kSignatureRegTypeMask) == (rType << kSignatureRegTypeShift); }
741   //! Get if the register kind matches `rKind`.
isKind(uint32_t rKind)742   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).
isGp()745   ASMJIT_INLINE bool isGp() const noexcept { return isKind(kKindGp); }
746   //! Get if the register is a vector register.
isVec()747   ASMJIT_INLINE bool isVec() const noexcept { return isKind(kKindVec); }
748 
749   using Operand_::isReg;
750 
751   //! Same as `isType()`, provided for convenience.
isReg(uint32_t rType)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`.
isReg(uint32_t rType,uint32_t 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.
getType()757   ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(kSignatureRegTypeBits, kSignatureRegTypeShift); }
758   //! Get the register kind.
getKind()759   ASMJIT_INLINE uint32_t getKind() const noexcept { return _getSignatureData(kSignatureRegKindBits, kSignatureRegKindShift); }
760 
761   //! Clone the register operand.
clone()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>
cloneAs()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>
cloneAs(const RegT & other)774   ASMJIT_INLINE RegT cloneAs(const RegT& other) const noexcept { return RegT(Init, other.getSignature(), getId()); }
775 
776   //! Set the register id to `id`.
setId(uint32_t rId)777   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>
setSignatureT()781   ASMJIT_INLINE void setSignatureT() noexcept { _signature = RegT::kSignature; }
782 
783   //! Set register's `signature` and `rId`.
setSignatureAndId(uint32_t signature,uint32_t 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 
isGp(const Operand_ & op)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     return (op.getSignature() & (kSignatureOpMask | kSignatureRegKindMask)) == kSgn;
798   }
799 
800   //! Get if the `op` operand is either a low or high 8-bit GPB register.
isVec(const Operand_ & op)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 
isGp(const Operand_ & op,uint32_t rId)808   static ASMJIT_INLINE bool isGp(const Operand_& op, uint32_t rId) noexcept { return isGp(op) & (op.getId() == rId); }
isVec(const Operand_ & op,uint32_t 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`.
initRegOnly825   ASMJIT_INLINE void init(uint32_t signature, uint32_t id) noexcept {
826     _signature = signature;
827     _id = id;
828   }
829 
initRegOnly830   ASMJIT_INLINE void init(const Reg& reg) noexcept { init(reg.getSignature(), reg.getId()); }
initRegOnly831   ASMJIT_INLINE void init(const RegOnly& reg) noexcept { init(reg.getSignature(), reg.getId()); }
832 
833   //! Reset the `RegOnly` to none.
resetRegOnly834   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()`).
isNoneRegOnly841   ASMJIT_INLINE bool isNone() const noexcept { return _signature == 0; }
842   //! Get if the register is valid (either virtual or physical).
isValidRegOnly843   ASMJIT_INLINE bool isValid() const noexcept { return _signature != 0; }
844 
845   //! Get if this is a physical register.
isPhysRegRegOnly846   ASMJIT_INLINE bool isPhysReg() const noexcept { return _id < Globals::kInvalidRegId; }
847   //! Get if this is a virtual register (used by \ref CodeCompiler).
isVirtRegRegOnly848   ASMJIT_INLINE bool isVirtReg() const noexcept { return Operand::isPackedId(_id); }
849 
850   //! Get register signature or 0.
getSignatureRegOnly851   ASMJIT_INLINE uint32_t getSignature() const noexcept { return _signature; }
852   //! Get register id or 0.
getIdRegOnly853   ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
854 
855   //! \internal
856   //!
857   //! Unpacks information from operand's signature.
_getSignatureDataRegOnly858   ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; }
859 
860   //! Get the register type.
getTypeRegOnly861   ASMJIT_INLINE uint32_t getType() const noexcept { return _getSignatureData(Operand::kSignatureRegTypeBits, Operand::kSignatureRegTypeShift); }
862   //! Get the register kind.
getKindRegOnly863   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>
toRegRegOnly871   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].
Mem()934   ASMJIT_INLINE Mem() noexcept : Operand(NoInit) { reset(); }
Mem(const Mem & other)935   ASMJIT_INLINE Mem(const Mem& other) noexcept : Operand(other) {}
936 
Mem(const _Init &,uint32_t baseType,uint32_t baseId,uint32_t indexType,uint32_t indexId,int32_t off,uint32_t size,uint32_t flags)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     uint32_t signature = (baseType  << kSignatureMemBaseTypeShift ) |
943                          (indexType << kSignatureMemIndexTypeShift) |
944                          (size      << kSignatureSizeShift        ) ;
945 
946     _init_packed_d0_d1(kOpMem | signature | flags, indexId);
947     _mem.base = baseId;
948     _mem.offsetLo32 = static_cast<uint32_t>(off);
949   }
Mem(const _NoInit &)950   explicit ASMJIT_INLINE Mem(const _NoInit&) noexcept : Operand(NoInit) {}
951 
952   // --------------------------------------------------------------------------
953   // [Mem Specific]
954   // --------------------------------------------------------------------------
955 
956   //! Clone `Mem` operand.
clone()957   ASMJIT_INLINE Mem clone() const noexcept { return Mem(*this); }
958 
959   //! Reset the memory operand - after reset the memory points to [0].
reset()960   ASMJIT_INLINE void reset() noexcept {
961     _init_packed_d0_d1(kOpMem, 0);
962     _init_packed_d2_d3(0, 0);
963   }
964 
hasAddrType()965   ASMJIT_INLINE bool hasAddrType() const noexcept { return _hasSignatureData(kSignatureMemAddrTypeMask); }
getAddrType()966   ASMJIT_INLINE uint32_t getAddrType() const noexcept { return _getSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
setAddrType(uint32_t addrType)967   ASMJIT_INLINE void setAddrType(uint32_t addrType) noexcept { return _setSignatureData(addrType, kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
resetAddrType()968   ASMJIT_INLINE void resetAddrType() noexcept { return _clearSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
969 
isAbs()970   ASMJIT_INLINE bool isAbs() const noexcept { return getAddrType() == kAddrTypeAbs; }
isRel()971   ASMJIT_INLINE bool isRel() const noexcept { return getAddrType() == kAddrTypeRel; }
isWrt()972   ASMJIT_INLINE bool isWrt() const noexcept { return getAddrType() == kAddrTypeWrt; }
973 
setAbs()974   ASMJIT_INLINE void setAbs() noexcept { setAddrType(kAddrTypeAbs); }
setRel()975   ASMJIT_INLINE void setRel() noexcept { setAddrType(kAddrTypeRel); }
setWrt()976   ASMJIT_INLINE void setWrt() noexcept { setAddrType(kAddrTypeWrt); }
977 
isArgHome()978   ASMJIT_INLINE bool isArgHome() const noexcept { return _hasSignatureData(kSignatureMemArgHomeFlag); }
isRegHome()979   ASMJIT_INLINE bool isRegHome() const noexcept { return _hasSignatureData(kSignatureMemRegHomeFlag); }
980 
setArgHome()981   ASMJIT_INLINE void setArgHome() noexcept { _signature |= kSignatureMemArgHomeFlag; }
setRegHome()982   ASMJIT_INLINE void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; }
983 
clearArgHome()984   ASMJIT_INLINE void clearArgHome() noexcept { _signature &= ~kSignatureMemArgHomeFlag; }
clearRegHome()985   ASMJIT_INLINE void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; }
986 
987   //! Get if the memory operand has a BASE register or label specified.
hasBase()988   ASMJIT_INLINE bool hasBase() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0; }
989   //! Get if the memory operand has an INDEX register specified.
hasIndex()990   ASMJIT_INLINE bool hasIndex() const noexcept { return (_signature & kSignatureMemIndexTypeMask) != 0; }
991   //! Get whether the memory operand has BASE and INDEX register.
hasBaseOrIndex()992   ASMJIT_INLINE bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; }
993   //! Get whether the memory operand has BASE and INDEX register.
hasBaseAndIndex()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`).
hasBaseReg()997   ASMJIT_INLINE bool hasBaseReg() const noexcept { return (_signature & kSignatureMemBaseTypeMask) > (Label::kLabelTag << kSignatureMemBaseTypeShift); }
998   //! Get if the BASE operand is a label.
hasBaseLabel()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`).
hasIndexReg()1001   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.
getBaseType()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).
getIndexType()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.
getBaseIndexType()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).
getBaseId()1018   ASMJIT_INLINE uint32_t getBaseId() const noexcept { return _mem.base; }
1019   //! Get id of the INDEX register.
getIndexId()1020   ASMJIT_INLINE uint32_t getIndexId() const noexcept { return _mem.index; }
1021 
_setBase(uint32_t rType,uint32_t rId)1022   ASMJIT_INLINE void _setBase(uint32_t rType, uint32_t rId) noexcept {
1023     _setSignatureData(rType, kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift);
1024     _mem.base = rId;
1025   }
1026 
_setIndex(uint32_t rType,uint32_t rId)1027   ASMJIT_INLINE void _setIndex(uint32_t rType, uint32_t rId) noexcept {
1028     _setSignatureData(rType, kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift);
1029     _mem.index = rId;
1030   }
1031 
setBase(const Reg & base)1032   ASMJIT_INLINE void setBase(const Reg& base) noexcept { return _setBase(base.getType(), base.getId()); }
setIndex(const Reg & index)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.
resetBase()1036   ASMJIT_INLINE void resetBase() noexcept { _setBase(0, 0); }
1037   //! Reset the memory operand's INDEX register.
resetIndex()1038   ASMJIT_INLINE void resetIndex() noexcept { _setIndex(0, 0); }
1039 
1040   //! Set memory operand size.
setSize(uint32_t size)1041   ASMJIT_INLINE void setSize(uint32_t size) noexcept {
1042     _setSignatureData(size, kSignatureSizeBits, kSignatureSizeShift);
1043   }
1044 
hasOffset()1045   ASMJIT_INLINE bool hasOffset() const noexcept {
1046     int32_t lo = static_cast<int32_t>(_mem.offsetLo32);
1047     int32_t hi = static_cast<int32_t>(_mem.base) & -static_cast<int32_t>(getBaseType() == 0);
1048     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.
has64BitOffset()1054   ASMJIT_INLINE bool has64BitOffset() const noexcept { return getBaseType() == 0; }
1055 
1056   //! Get a 64-bit offset or absolute address.
getOffset()1057   ASMJIT_INLINE int64_t getOffset() const noexcept {
1058     return has64BitOffset()
1059       ? static_cast<int64_t>(_mem.offset64)
1060       : 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.
getOffsetLo32()1064   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.
getOffsetHi32()1069   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.
setOffset(int64_t offset)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`.
addOffset(int64_t off)1085   ASMJIT_INLINE void addOffset(int64_t off) noexcept {
1086     if (has64BitOffset())
1087       _mem.offset64 += static_cast<uint64_t>(off);
1088     else
1089       _mem.offsetLo32 += static_cast<uint32_t>(off & 0xFFFFFFFF);
1090   }
1091   //! Reset the memory offset to zero.
resetOffset()1092   ASMJIT_INLINE void resetOffset() noexcept { setOffset(0); }
1093 
1094   //! Set a low 32-bit offset to `off`.
setOffsetLo32(int32_t 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.
addOffsetLo32(int32_t off)1103   ASMJIT_INLINE void addOffsetLo32(int32_t off) noexcept {
1104     _mem.offsetLo32 += static_cast<uint32_t>(off);
1105   }
1106   //! Reset the memory offset to zero.
resetOffsetLo32()1107   ASMJIT_INLINE void resetOffsetLo32() noexcept { setOffsetLo32(0); }
1108 
1109   // --------------------------------------------------------------------------
1110   // [Operator Overload]
1111   // --------------------------------------------------------------------------
1112 
1113   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).
Imm()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`.
Imm(int64_t val)1141   explicit Imm(int64_t val) noexcept : Operand(NoInit) {
1142     _init_packed_d0_d1(kOpImm, 0);
1143     _imm.value.i64 = val;
1144   }
1145 
1146   //! Create a new immediate value from `other`.
Imm(const Imm & other)1147   ASMJIT_INLINE Imm(const Imm& other) noexcept : Operand(other) {}
1148 
Imm(const _NoInit &)1149   explicit ASMJIT_INLINE Imm(const _NoInit&) noexcept : Operand(NoInit) {}
1150 
1151   // --------------------------------------------------------------------------
1152   // [Immediate Specific]
1153   // --------------------------------------------------------------------------
1154 
1155   //! Clone `Imm` operand.
clone()1156   ASMJIT_INLINE Imm clone() const noexcept { return Imm(*this); }
1157 
1158   //! Get whether the immediate can be casted to 8-bit signed integer.
isInt8()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.
isUInt8()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.
isInt16()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.
isUInt16()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.
isInt32()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.
isUInt32()1171   ASMJIT_INLINE bool isUInt32() const noexcept { return Utils::isUInt32(_imm.value.i64); }
1172 
1173   //! Get immediate value as 8-bit signed integer.
getInt8()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.
getUInt8()1176   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.
getInt16()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.
getUInt16()1180   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.
getInt32()1183   ASMJIT_INLINE int32_t getInt32() const noexcept { return _imm.value.i32Lo; }
1184   //! Get low 32-bit signed integer.
getInt32Lo()1185   ASMJIT_INLINE int32_t getInt32Lo() const noexcept { return _imm.value.i32Lo; }
1186   //! Get high 32-bit signed integer.
getInt32Hi()1187   ASMJIT_INLINE int32_t getInt32Hi() const noexcept { return _imm.value.i32Hi; }
1188 
1189   //! Get immediate value as 32-bit unsigned integer.
getUInt32()1190   ASMJIT_INLINE uint32_t getUInt32() const noexcept { return _imm.value.u32Lo; }
1191   //! Get low 32-bit signed integer.
getUInt32Lo()1192   ASMJIT_INLINE uint32_t getUInt32Lo() const noexcept { return _imm.value.u32Lo; }
1193   //! Get high 32-bit signed integer.
getUInt32Hi()1194   ASMJIT_INLINE uint32_t getUInt32Hi() const noexcept { return _imm.value.u32Hi; }
1195 
1196   //! Get immediate value as 64-bit signed integer.
getInt64()1197   ASMJIT_INLINE int64_t getInt64() const noexcept { return _imm.value.i64; }
1198   //! Get immediate value as 64-bit unsigned integer.
getUInt64()1199   ASMJIT_INLINE uint64_t getUInt64() const noexcept { return _imm.value.u64; }
1200 
1201   //! Get immediate value as `intptr_t`.
getIntPtr()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`.
getUIntPtr()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`.
setInt8(int8_t 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`.
setUInt8(uint8_t 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`.
setInt16(int16_t 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`.
setUInt16(uint16_t 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`.
setInt32(int32_t 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`.
setUInt32(uint32_t val)1230   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`.
setInt64(int64_t val)1233   ASMJIT_INLINE void setInt64(int64_t val) noexcept { _imm.value.i64 = val; }
1234   //! Set immediate value to 64-bit unsigned integer `val`.
setUInt64(uint64_t val)1235   ASMJIT_INLINE void setUInt64(uint64_t val) noexcept { _imm.value.u64 = val; }
1236   //! Set immediate value to intptr_t `val`.
setIntPtr(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`.
setUIntPtr(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`.
setPtr(void * p)1242   ASMJIT_INLINE void setPtr(void* p) noexcept { setIntPtr((uint64_t)p); }
1243   //! Set immediate value to `val`.
1244   template<typename T>
setValue(T val)1245   ASMJIT_INLINE void setValue(T val) noexcept { setIntPtr((int64_t)val); }
1246 
1247   // --------------------------------------------------------------------------
1248   // [Float]
1249   // --------------------------------------------------------------------------
1250 
setFloat(float f)1251   ASMJIT_INLINE void setFloat(float f) noexcept {
1252     _imm.value.f32Lo = f;
1253     _imm.value.u32Hi = 0;
1254   }
1255 
setDouble(double d)1256   ASMJIT_INLINE void setDouble(double d) noexcept {
1257     _imm.value.f64 = d;
1258   }
1259 
1260   // --------------------------------------------------------------------------
1261   // [Truncate]
1262   // --------------------------------------------------------------------------
1263 
truncateTo8Bits()1264   ASMJIT_INLINE void truncateTo8Bits() noexcept {
1265     if (ASMJIT_ARCH_64BIT) {
1266       _imm.value.u64   &= static_cast<uint64_t>(0x000000FFU);
1267     }
1268     else {
1269       _imm.value.u32Lo &= 0x000000FFU;
1270       _imm.value.u32Hi  = 0;
1271     }
1272   }
1273 
truncateTo16Bits()1274   ASMJIT_INLINE void truncateTo16Bits() noexcept {
1275     if (ASMJIT_ARCH_64BIT) {
1276       _imm.value.u64   &= static_cast<uint64_t>(0x0000FFFFU);
1277     }
1278     else {
1279       _imm.value.u32Lo &= 0x0000FFFFU;
1280       _imm.value.u32Hi  = 0;
1281     }
1282   }
1283 
truncateTo32Bits()1284   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.
imm(int64_t val)1295 static ASMJIT_INLINE Imm imm(int64_t val) noexcept { return Imm(val); }
1296 //! Create an unsigned immediate operand.
imm_u(uint64_t val)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>
imm_ptr(T p)1300 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 
isVoidTypeId1459   static ASMJIT_INLINE bool isVoid(uint32_t typeId) noexcept { return typeId == 0; }
isValidTypeId1460   static ASMJIT_INLINE bool isValid(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kVec512End; }
isAbstractTypeId1461   static ASMJIT_INLINE bool isAbstract(uint32_t typeId) noexcept { return typeId >= kIntPtr && typeId <= kUIntPtr; }
isIntTypeId1462   static ASMJIT_INLINE bool isInt(uint32_t typeId) noexcept { return typeId >= _kIntStart && typeId <= _kIntEnd; }
isGpbTypeId1463   static ASMJIT_INLINE bool isGpb(uint32_t typeId) noexcept { return typeId >= kI8 && typeId <= kU8; }
isGpwTypeId1464   static ASMJIT_INLINE bool isGpw(uint32_t typeId) noexcept { return typeId >= kI16 && typeId <= kU16; }
isGpdTypeId1465   static ASMJIT_INLINE bool isGpd(uint32_t typeId) noexcept { return typeId >= kI32 && typeId <= kU32; }
isGpqTypeId1466   static ASMJIT_INLINE bool isGpq(uint32_t typeId) noexcept { return typeId >= kI64 && typeId <= kU64; }
isFloatTypeId1467   static ASMJIT_INLINE bool isFloat(uint32_t typeId) noexcept { return typeId >= _kFloatStart && typeId <= _kFloatEnd; }
isMaskTypeId1468   static ASMJIT_INLINE bool isMask(uint32_t typeId) noexcept { return typeId >= _kMaskStart && typeId <= _kMaskEnd; }
isMmxTypeId1469   static ASMJIT_INLINE bool isMmx(uint32_t typeId) noexcept { return typeId >= _kMmxStart && typeId <= _kMmxEnd; }
1470 
isVecTypeId1471   static ASMJIT_INLINE bool isVec(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec512End; }
isVec32TypeId1472   static ASMJIT_INLINE bool isVec32(uint32_t typeId) noexcept { return typeId >= _kVec32Start && typeId <= _kVec32End; }
isVec64TypeId1473   static ASMJIT_INLINE bool isVec64(uint32_t typeId) noexcept { return typeId >= _kVec64Start && typeId <= _kVec64End; }
isVec128TypeId1474   static ASMJIT_INLINE bool isVec128(uint32_t typeId) noexcept { return typeId >= _kVec128Start && typeId <= _kVec128End; }
isVec256TypeId1475   static ASMJIT_INLINE bool isVec256(uint32_t typeId) noexcept { return typeId >= _kVec256Start && typeId <= _kVec256End; }
isVec512TypeId1476   static ASMJIT_INLINE bool isVec512(uint32_t typeId) noexcept { return typeId >= _kVec512Start && typeId <= _kVec512End; }
1477 
sizeOfTypeId1478   static ASMJIT_INLINE uint32_t sizeOf(uint32_t typeId) noexcept {
1479     ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.sizeOf));
1480     return _info.sizeOf[typeId];
1481   }
1482 
elementOfTypeId1483   static ASMJIT_INLINE uint32_t elementOf(uint32_t typeId) noexcept {
1484     ASMJIT_ASSERT(typeId < ASMJIT_ARRAY_SIZE(_info.elementOf));
1485     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   //! ~~~
deabstractDeltaOfSizeTypeId1505   static ASMJIT_INLINE uint32_t deabstractDeltaOfSize(uint32_t gpSize) noexcept {
1506     return gpSize >= 8 ? kI64 - kIntPtr : kI32 - kIntPtr;
1507   }
1508 
deabstractTypeId1509   static ASMJIT_INLINE uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept {
1510     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
1600