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