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