operand.h 34.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Guard]
#ifndef _ASMJIT_BASE_OPERAND_H
#define _ASMJIT_BASE_OPERAND_H

// [Dependencies - AsmJit]
#include "../base/intutil.h"

// [Api-Begin]
#include "../apibegin.h"

namespace asmjit {

// ============================================================================
// [Forward Declarations]
// ============================================================================

struct Assembler;
struct Compiler;

//! \addtogroup asmjit_base_general
//! \{

// ============================================================================
30
// [asmjit::OperandType]
31
32
33
// ============================================================================

//! Operand types that can be encoded in `Operand`.
34
ASMJIT_ENUM(OperandType) {
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  //! Invalid operand, used only internally (not initialized Operand).
  kOperandTypeNone = 0,
  //! Operand is a register.
  kOperandTypeReg = 1,
  //! Operand is a variable.
  kOperandTypeVar = 2,
  //! Operand is a memory.
  kOperandTypeMem = 3,
  //! Operand is an immediate value.
  kOperandTypeImm = 4,
  //! Operand is a label.
  kOperandTypeLabel = 5
};

// ============================================================================
50
// [asmjit::OperandId]
51
52
53
// ============================================================================

//! Operand id masks used to determine the operand type.
54
ASMJIT_ENUM(OperandId) {
55
56
57
58
59
60
61
  //! Operand id refers to `Var`.
  kOperandIdVar = 0x80000000U,
  //! Operand id to real index mask.
  kOperandIdNum = 0x7FFFFFFFU
};

// ============================================================================
62
// [asmjit::RegClass]
63
64
65
// ============================================================================

//! Register class.
66
ASMJIT_ENUM(RegClass) {
67
68
69
70
71
  //! Gp register class, compatible with all architectures.
  kRegClassGp = 0
};

// ============================================================================
72
// [asmjit::SizeDefs]
73
74
75
// ============================================================================

//! Common size of registers and pointers.
76
ASMJIT_ENUM(SizeDefs) {
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  //! 1 byte size (BYTE).
  kSizeByte = 1,
  //! 2 bytes size (WORD).
  kSizeWord = 2,
  //! 4 bytes size (DWORD).
  kSizeDWord = 4,
  //! 8 bytes size (QWORD).
  kSizeQWord = 8,
  //! 10 bytes size (TWORD).
  kSizeTWord = 10,
  //! 16 bytes size (OWORD / DQWORD).
  kSizeOWord = 16,
  //! 32 bytes size (YWORD / QQWORD).
  kSizeYWord = 32
};

// ============================================================================
94
// [asmjit::MemType]
95
96
97
// ============================================================================

//! Type of memory operand.
98
ASMJIT_ENUM(MemType) {
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  //! Memory operand is a combination of base register and optional index register
  //! and displacement.
  //!
  //! The `Assembler` interprets `kMemTypeBaseIndex` and `kMemTypeStackIndex`
  //! types the same way, but `Compiler` interprets  `kMemTypeBaseIndex` as
  //! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`.
  kMemTypeBaseIndex = 0,

  //! Memory operand is a combination of variable's memory location,
  //! optional index register and displacement.
  //!
  //! The `Assembler` interprets `kMemTypeBaseIndex` and  `kMemTypeStackIndex`
  //! types in the same way, but `Compiler` interprets `kMemTypeBaseIndex` as
  //! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`.
  kMemTypeStackIndex = 1,

  //! Memory operand refers to the memory location specified by a label.
  kMemTypeLabel = 2,
  //! Memory operand is an absolute memory location.
  //!
  //! Supported mostly by x86, truncated to a 32-bit value when running in
  //! 64-bit mode (x64).
  kMemTypeAbsolute = 3
};

// ============================================================================
// [asmjit::Operand]
// ============================================================================

//! Operand can contain register, memory location, immediate, or label.
struct Operand {
  // --------------------------------------------------------------------------
  // [Structs]
  // --------------------------------------------------------------------------

  //! \internal
  //!
  //! Base operand data.
  struct BaseOp {
138
    //! Type of operand, see \ref OperandType.
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
    uint8_t op;
    //! Size of operand (register, address, immediate, or variable).
    uint8_t size;
    //! \internal
    uint8_t reserved_2_1;
    //! \internal
    uint8_t reserved_3_1;

    //! Operand id, identifier used by `Assembler` and `Compiler`.
    //!
    //! \note Uninitialized operand has always set id to `kInvalidValue`.
    uint32_t id;

    //! \internal
    uint32_t reserved_8_4;
    //! \internal
    uint32_t reserved_12_4;
  };

  //! \internal
  //!
  //! Register or Variable operand data.
  struct VRegOp {
    //! Type of operand, `kOperandTypeReg`.
    uint8_t op;
    //! Size of register or variable.
    uint8_t size;

    union {
      //! Register code = (type << 8) | index.
      uint16_t code;

      //! Register type and index access.
      struct {
173
#if defined(ASMJIT_ARCH_LE)
174
175
176
177
178
179
180
181
182
        //! Register index.
        uint8_t index;
        //! Register type.
        uint8_t type;
#else
        //! Register type.
        uint8_t type;
        //! Register index.
        uint8_t index;
183
#endif
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
      };
    };

    //! Variable id, used by `Compiler` to identify variables.
    uint32_t id;

    union {
      struct {
        //! Variable type.
        uint32_t vType;
        //! \internal
        uint32_t reserved_12_4;
      };

      //! \internal
      //!
      //! This is not needed or used, it's just to force compiler to always
      //! align this struct to 8-bytes (so the struct is compatible to others
      //! when it comes to alignment). It should fix VS linker warning as well.
      uint64_t reserved8_8;
    };
  };

  //! \internal
  //!
  //! Memory or Variable operand data.
  struct VMemOp {
    //! Type of operand, `kOperandTypeMem`.
    uint8_t op;
    //! Size of the pointer in bytes.
    uint8_t size;
215
    //! Type of the memory operand, see `MemType`.
216
217
    uint8_t type;
    //! X86/X64 layout:
218
    //!   - segment  [3 bits], see `X86Seg`.
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
    //!   - shift    [2 bits], index register shift (0 to 3).
    uint8_t flags;

    //! Base register, variable or label id.
    uint32_t base;
    //! Index register or variable.
    uint32_t index;
    //! 32-bit displacement or absolute address.
    int32_t displacement;
  };

  //! \internal
  //!
  //! Immediate operand data.
  struct ImmOp {
    //! Type of operand, `kOperandTypeImm`.
    uint8_t op;
    //! Size of immediate (or 0 to autodetect).
    uint8_t size;
    //! \internal
    uint8_t reserved_2_1;
    //! \internal
    uint8_t reserved_3_1;

    //! Operand id, always set to `kInvalidValue` (immediates don't have IDs).
    uint32_t id;

    union {
      //! 8x8-bit signed immediate values.
      int8_t _i8[8];
      //! 8x8-bit unsigned immediate values.
      uint8_t _u8[8];

      //! 4x16-bit signed immediate values.
      int16_t _i16[4];
      //! 4x16-bit unsigned immediate values.
      uint16_t _u16[4];

      //! 2x32-bit signed immediate values.
      int32_t _i32[2];
      //! 2x32-bit unsigned immediate values.
      uint32_t _u32[2];

      //! 1x64-bit signed immediate value.
      int64_t _i64[1];
      //! 1x64-bit unsigned immediate value.
      uint64_t _u64[1];

      //! 2x SP-FP values.
      float _f32[2];
      //! 1x DP-FP value.
      double _f64[1];
    } value;
  };

  //! \internal
  //!
  //! Label operand data.
  struct LabelOp {
    //! Type of operand, `kOperandTypeLabel`.
    uint8_t op;
    //! Always zero, labels don't have size.
    uint8_t size;
    //! \internal
    uint8_t reserved_2_1;
    //! \internal
    uint8_t reserved_3_1;

    //! Operand id (`kInvalidValue` if the label is not initialized by code
    //! generator).
    uint32_t id;

    //! \internal
    uint32_t reserved_8_4;
    //! \internal
    uint32_t reserved_12_4;
  };

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create an uninitialized operand.
  ASMJIT_INLINE Operand() {
    _init_packed_op_sz_b0_b1_id(kOperandTypeNone, 0, 0, 0, kInvalidValue);
    _init_packed_d2_d3(0, 0);
  }

  //! Create a reference to `other` operand.
  ASMJIT_INLINE Operand(const Operand& other) {
    _init(other);
  }

  explicit ASMJIT_INLINE Operand(const _NoInit&) {}

  // --------------------------------------------------------------------------
  // [Operand]
  // --------------------------------------------------------------------------

  //! Clone `Operand`.
  ASMJIT_INLINE Operand clone() const {
    return Operand(*this);
  }

  // --------------------------------------------------------------------------
  // [Init & Copy]
  // --------------------------------------------------------------------------

  //! \internal
  //!
  //! Initialize operand to `other` (used by constructors).
  ASMJIT_INLINE void _init(const Operand& other) {
    ::memcpy(this, &other, sizeof(Operand));
  }

  ASMJIT_INLINE void _init_packed_op_sz_b0_b1_id(uint32_t op, uint32_t sz, uint32_t r0, uint32_t r1, uint32_t id) {
    // This hack is not for performance, but to decrease the size of the binary
    // generated when constructing AsmJit operands (mostly for third parties).
    // Some compilers are not able to join four BYTE writes to a single DWORD
    // write. Because the 'a', 'b', 'c' and 'd' variables are usually compile
    // time constants the compiler can do a really nice job if they are joined
    // by using bitwise operations.
    _packed[0].setPacked_2x32(IntUtil::pack32_4x8(op, sz, r0, r1), id);
  }

  ASMJIT_INLINE void _init_packed_op_sz_w0_id(uint32_t op, uint32_t sz, uint32_t w0, uint32_t id) {
    _packed[0].setPacked_2x32(IntUtil::pack32_2x8_1x16(op, sz, w0), id);
  }

  ASMJIT_INLINE void _init_packed_d0_d1(uint32_t u0, uint32_t u1) {
    _packed[0].setPacked_2x32(u0, u1);
  }

  ASMJIT_INLINE void _init_packed_d2_d3(uint32_t u2, uint32_t u3) {
    _packed[1].setPacked_2x32(u2, u3);
  }

  //! \internal
  //!
  //! Initialize operand to `other` (used by assign operators).
  ASMJIT_INLINE void _copy(const Operand& other) {
    ::memcpy(this, &other, sizeof(Operand));
  }

  // --------------------------------------------------------------------------
  // [Data]
  // --------------------------------------------------------------------------

  template<typename T>
  ASMJIT_INLINE T& getData() {
    return reinterpret_cast<T&>(_base);
  }

  template<typename T>
  ASMJIT_INLINE const T& getData() const {
    return reinterpret_cast<const T&>(_base);
  }

  // --------------------------------------------------------------------------
  // [Type]
  // --------------------------------------------------------------------------

381
  //! Get type of the operand, see \ref OperandType.
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
  ASMJIT_INLINE uint32_t getOp() const { return _base.op; }

  //! Get whether the operand is none - `kOperandTypeNone`.
  ASMJIT_INLINE bool isNone() const { return (_base.op == kOperandTypeNone); }
  //! Get whether the operand is a register - `kOperandTypeReg`.
  ASMJIT_INLINE bool isReg() const { return (_base.op == kOperandTypeReg); }
  //! Get whether the operand is a variable - `kOperandTypeVar`.
  ASMJIT_INLINE bool isVar() const { return (_base.op == kOperandTypeVar); }
  //! Get whether the operand is a memory address - `kOperandTypeMem`.
  ASMJIT_INLINE bool isMem() const { return (_base.op == kOperandTypeMem); }
  //! Get whether the operand is an immediate value - `kOperandTypeImm`.
  ASMJIT_INLINE bool isImm() const { return (_base.op == kOperandTypeImm); }
  //! Get whether the operand is a label - `kOperandTypeLabel`.
  ASMJIT_INLINE bool isLabel() const { return (_base.op == kOperandTypeLabel); }

  // --------------------------------------------------------------------------
  // [Type - Combined]
  // --------------------------------------------------------------------------

  //! Get register type.
  ASMJIT_INLINE uint32_t getRegType() const {
    return _vreg.type;
  }

  //! Get register index.
  ASMJIT_INLINE uint32_t getRegIndex() const {
    return _vreg.index;
  }

  //! Get whether the operand is register of `type`.
  ASMJIT_INLINE bool isRegType(uint32_t type) const {
    return (_packed[0].u32[0] & IntUtil::pack32_2x8_1x16(0xFF, 0, 0xFF00)) == IntUtil::pack32_2x8_1x16(kOperandTypeReg, 0, (type << 8));
  }

  //! Get whether the operand is register and of `type` and `index`.
  ASMJIT_INLINE bool isRegCode(uint32_t type, uint32_t index) const {
    return (_packed[0].u32[0] & IntUtil::pack32_2x8_1x16(0xFF, 0, 0xFFFF)) == IntUtil::pack32_2x8_1x16(kOperandTypeReg, 0, (type << 8) + index);
  }

  //! Get whether the operand is a register or memory.
  ASMJIT_INLINE bool isRegOrMem() const {
    ASMJIT_ASSERT(kOperandTypeReg == 1);
    ASMJIT_ASSERT(kOperandTypeMem == 3);
    return (static_cast<uint32_t>(_base.op) | 0x2U) == 0x3U;
  }

  //! Get whether the operand is variable or memory.
  ASMJIT_INLINE bool isVarOrMem() const {
    ASMJIT_ASSERT(kOperandTypeVar == 2);
    ASMJIT_ASSERT(kOperandTypeMem == 3);
    return (static_cast<uint32_t>(_base.op) - 2U) <= 1;
  }

  // --------------------------------------------------------------------------
  // [Size]
  // --------------------------------------------------------------------------

  //! Get size of the operand in bytes.
  ASMJIT_INLINE uint32_t getSize() const {
    return _base.size;
  }

  // --------------------------------------------------------------------------
  // [Id]
  // --------------------------------------------------------------------------

  //! Get operand id.
  //!
  //! Operand id's are used internally by `Assembler` and `Compiler`.
  //!
  //! There is no way to change or remove operand id. Unneeded operands can be
  //! simply reassigned by `operator=`.
  ASMJIT_INLINE uint32_t getId() const {
    return _base.id;
  }

  // --------------------------------------------------------------------------
  // [Members]
  // --------------------------------------------------------------------------

  union {
    //! Base data.
    BaseOp _base;
    //! Register or variable data.
    VRegOp _vreg;
    //! Memory data.
    VMemOp _vmem;
    //! Immediate data.
    ImmOp _imm;
    //! Label data.
    LabelOp _label;

    //! Packed operand as two 64-bit integers.
    UInt64 _packed[2];
  };
};

// ============================================================================
// [asmjit::OperandUtil]
// ============================================================================

//! Operand utilities.
struct OperandUtil {
  //! Make variable id.
  static ASMJIT_INLINE uint32_t makeVarId(uint32_t id) {
    return id | kOperandIdVar;
  }

  //! Make label id.
  static ASMJIT_INLINE uint32_t makeLabelId(uint32_t id) {
    return id;
  }

  //! Strip variable id bit so it becomes a pure index to `VarData[]` array.
  static ASMJIT_INLINE uint32_t stripVarId(uint32_t id) {
    return id & 0x7FFFFFFFU;
  }

  //! Get whether the id refers to `Var`.
  //!
  //! \note The function will never return `true` if the id is `kInvalidValue`.
  //! The trick is to compare a given id to -1 (kInvalidValue) so we check both
  //! using only one comparison.
  static ASMJIT_INLINE bool isVarId(uint32_t id) {
    return static_cast<int32_t>(id) < -1;
  }

  //! Get whether the id refers to `Label`.
  //!
  //! \note The function will never return `true` if the id is `kInvalidValue`.
  static ASMJIT_INLINE bool isLabelId(uint32_t id) {
    return static_cast<int32_t>(id) >= 0;
  }
};

// ============================================================================
// [asmjit::Reg]
// ============================================================================

//! Base class for all register operands.
struct Reg : public Operand {
  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a dummy base register.
  ASMJIT_INLINE Reg() : Operand(NoInit) {
    _init_packed_op_sz_w0_id(kOperandTypeReg, 0, (kInvalidReg << 8) + kInvalidReg, kInvalidValue);
    _init_packed_d2_d3(kInvalidVar, 0);
  }

  //! Create a new base register.
  ASMJIT_INLINE Reg(uint32_t type, uint32_t index, uint32_t size) : Operand(NoInit) {
    _init_packed_op_sz_w0_id(kOperandTypeReg, size, (type << 8) + index, kInvalidValue);
    _init_packed_d2_d3(kInvalidVar, 0);
  }

  //! Create a new reference to `other`.
  ASMJIT_INLINE Reg(const Reg& other) : Operand(other) {}

  //! Create a new reference to `other` and change the index to `index`.
  ASMJIT_INLINE Reg(const Reg& other, uint32_t index) : Operand(other) {
    _vreg.index = static_cast<uint8_t>(index);
  }

  explicit ASMJIT_INLINE Reg(const _NoInit&) : Operand(NoInit) {}

  // --------------------------------------------------------------------------
  // [Reg Specific]
  // --------------------------------------------------------------------------

  //! Clone `Reg` operand.
  ASMJIT_INLINE Reg clone() const {
    return Reg(*this);
  }

  //! Get whether register code is equal to `type`.
  ASMJIT_INLINE bool isRegType(uint32_t type) const {
    return _vreg.type == type;
  }

  //! Get whether register code is equal to `type`.
  ASMJIT_INLINE bool isRegCode(uint32_t code) const {
    return _vreg.code == code;
  }

  //! Get whether register code is equal to `type`.
  ASMJIT_INLINE bool isRegCode(uint32_t type, uint32_t index) const {
    return _vreg.code == (type << 8) + index;
  }

  //! Get register code that equals to '(type << 8) + index'.
  ASMJIT_INLINE uint32_t getRegCode() const {
    return _vreg.code;
  }

  //! Get register type.
  ASMJIT_INLINE uint32_t getRegType() const {
    return _vreg.type;
  }

  //! Get register index.
  ASMJIT_INLINE uint32_t getRegIndex() const {
    return _vreg.index;
  }

#define ASMJIT_REG_OP(_Type_) \
  ASMJIT_INLINE _Type_ clone() const { \
    return _Type_(*this); \
  } \
  \
  /*! Set register `size`. */ \
  ASMJIT_INLINE _Type_& setSize(uint32_t size) { \
    _vreg.size = static_cast<uint8_t>(size); \
    return *this; \
  } \
  \
  /*! Set register `code`. */ \
  ASMJIT_INLINE _Type_& setCode(uint32_t code) { \
    _vreg.code = static_cast<uint16_t>(code); \
    return *this; \
  } \
  \
  /*! Set register `type` and `index`. */ \
  ASMJIT_INLINE _Type_& setCode(uint32_t type, uint32_t index) { \
    _vreg.type = static_cast<uint8_t>(type); \
    _vreg.index = static_cast<uint8_t>(index); \
    return *this; \
  } \
  \
  /*! Set register `type`. */ \
  ASMJIT_INLINE _Type_& setType(uint32_t type) { \
    _vreg.type = static_cast<uint8_t>(type); \
    return *this; \
  } \
  \
  /*! Set register `index`. */ \
  ASMJIT_INLINE _Type_& setIndex(uint32_t index) { \
    _vreg.index = static_cast<uint8_t>(index); \
    return *this; \
  } \
  \
  ASMJIT_INLINE _Type_& operator=(const _Type_& other) { _copy(other); return *this; } \
  \
  ASMJIT_INLINE bool operator==(const _Type_& other) const { return _packed[0].u32[0] == other._packed[0].u32[0]; } \
  ASMJIT_INLINE bool operator!=(const _Type_& other) const { return !operator==(other); }
};

// ============================================================================
// [asmjit::BaseMem]
// ============================================================================

//! Base class for all memory operands.
struct BaseMem : public Operand {
  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  ASMJIT_INLINE BaseMem() : Operand(NoInit) {
    reset();
  }

  ASMJIT_INLINE BaseMem(const BaseMem& other) : Operand(other) {}
  explicit ASMJIT_INLINE BaseMem(const _NoInit&) : Operand(NoInit) {}

  // --------------------------------------------------------------------------
  // [BaseMem Specific]
  // --------------------------------------------------------------------------

  //! Clone `BaseMem` operand.
  ASMJIT_INLINE BaseMem clone() const {
    return BaseMem(*this);
  }

  //! Reset `BaseMem` operand.
  ASMJIT_INLINE void reset() {
    _init_packed_op_sz_b0_b1_id(kOperandTypeMem, 0, kMemTypeBaseIndex, 0, kInvalidValue);
    _init_packed_d2_d3(kInvalidValue, 0);
  }

662
  //! Get the type of the memory operand, see `MemType`.
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  ASMJIT_INLINE uint32_t getMemType() const {
    return _vmem.type;
  }

  //! Get whether the type of the memory operand is either `kMemTypeBaseIndex`
  //! or `kMemTypeStackIndex`.
  ASMJIT_INLINE bool isBaseIndexType() const {
    return _vmem.type <= kMemTypeStackIndex;
  }

  //! Get whether the memory operand has base register.
  ASMJIT_INLINE bool hasBase() const {
    return _vmem.base != kInvalidValue;
  }

  //! Get memory operand base id, or `kInvalidValue`.
  ASMJIT_INLINE uint32_t getBase() const {
    return _vmem.base;
  }

  //! Set memory operand size.
  ASMJIT_INLINE BaseMem& setSize(uint32_t size) {
    _vmem.size = static_cast<uint8_t>(size);
    return *this;
  }

  //! Get memory operand relative displacement.
  ASMJIT_INLINE int32_t getDisplacement() const {
    return _vmem.displacement;
  }

  //! Set memory operand relative displacement.
  ASMJIT_INLINE BaseMem& setDisplacement(int32_t disp) {
    _vmem.displacement = disp;
    return *this;
  }

  // --------------------------------------------------------------------------
  // [Operator Overload]
  // --------------------------------------------------------------------------

  ASMJIT_INLINE BaseMem& operator=(const BaseMem& other) {
    _copy(other);
    return *this;
  }

  ASMJIT_INLINE bool operator==(const BaseMem& other) const {
    return (_packed[0] == other._packed[0]) & (_packed[1] == other._packed[1]);
  }

  ASMJIT_INLINE bool operator!=(const BaseMem& other) const {
    return !(*this == other);
  }
};

// ============================================================================
// [asmjit::Imm]
// ============================================================================

//! Immediate operand.
//!
//! Immediate operand is usually part of instruction itself. It's inlined after
//! or before the instruction opcode. Immediates can be only signed or unsigned
//! integers.
//!
//! To create immediate operand use `imm()` or `imm_u()` non-members or `Imm`
//! constructors.
struct Imm : public Operand {
  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a new immediate value (initial value is 0).
  Imm() : Operand(NoInit) {
    _init_packed_op_sz_b0_b1_id(kOperandTypeImm, 0, 0, 0, kInvalidValue);
    _imm.value._i64[0] = 0;
  }

  //! Create a new signed immediate value, assigning the value to `val`.
  explicit Imm(int64_t val) : Operand(NoInit) {
    _init_packed_op_sz_b0_b1_id(kOperandTypeImm, 0, 0, 0, kInvalidValue);
    _imm.value._i64[0] = val;
  }

  //! Create a new immediate value from `other`.
  ASMJIT_INLINE Imm(const Imm& other) : Operand(other) {}

  explicit ASMJIT_INLINE Imm(const _NoInit&) : Operand(NoInit) {}

  // --------------------------------------------------------------------------
  // [Immediate Specific]
  // --------------------------------------------------------------------------

  //! Clone `Imm` operand.
  ASMJIT_INLINE Imm clone() const {
    return Imm(*this);
  }

  //! Get whether the immediate can be casted to 8-bit signed integer.
  ASMJIT_INLINE bool isInt8() const { return IntUtil::isInt8(_imm.value._i64[0]); }
  //! Get whether the immediate can be casted to 8-bit unsigned integer.
  ASMJIT_INLINE bool isUInt8() const { return IntUtil::isUInt8(_imm.value._i64[0]); }

  //! Get whether the immediate can be casted to 16-bit signed integer.
  ASMJIT_INLINE bool isInt16() const { return IntUtil::isInt16(_imm.value._i64[0]); }
  //! Get whether the immediate can be casted to 16-bit unsigned integer.
  ASMJIT_INLINE bool isUInt16() const { return IntUtil::isUInt16(_imm.value._i64[0]); }

  //! Get whether the immediate can be casted to 32-bit signed integer.
  ASMJIT_INLINE bool isInt32() const { return IntUtil::isInt32(_imm.value._i64[0]); }
  //! Get whether the immediate can be casted to 32-bit unsigned integer.
  ASMJIT_INLINE bool isUInt32() const { return IntUtil::isUInt32(_imm.value._i64[0]); }

  //! Get immediate value as 8-bit signed integer.
777
  ASMJIT_INLINE int8_t getInt8() const { return _imm.value._i8[_ASMJIT_ARCH_INDEX(8, 0)]; }
778
  //! Get immediate value as 8-bit unsigned integer.
779
  ASMJIT_INLINE uint8_t getUInt8() const { return _imm.value._u8[_ASMJIT_ARCH_INDEX(8, 0)]; }
780
  //! Get immediate value as 16-bit signed integer.
781
  ASMJIT_INLINE int16_t getInt16() const { return _imm.value._i16[_ASMJIT_ARCH_INDEX(4, 0)]; }
782
  //! Get immediate value as 16-bit unsigned integer.
783
  ASMJIT_INLINE uint16_t getUInt16() const { return _imm.value._u16[_ASMJIT_ARCH_INDEX(4, 0)]; }
784
  //! Get immediate value as 32-bit signed integer.
785
  ASMJIT_INLINE int32_t getInt32() const { return _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 0)]; }
786
  //! Get immediate value as 32-bit unsigned integer.
787
  ASMJIT_INLINE uint32_t getUInt32() const { return _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 0)]; }
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  //! Get immediate value as 64-bit signed integer.
  ASMJIT_INLINE int64_t getInt64() const { return _imm.value._i64[0]; }
  //! Get immediate value as 64-bit unsigned integer.
  ASMJIT_INLINE uint64_t getUInt64() const { return _imm.value._u64[0]; }

  //! Get immediate value as `intptr_t`.
  ASMJIT_INLINE intptr_t getIntPtr() const {
    if (sizeof(intptr_t) == sizeof(int64_t))
      return static_cast<intptr_t>(getInt64());
    else
      return static_cast<intptr_t>(getInt32());
  }

  //! Get immediate value as `uintptr_t`.
  ASMJIT_INLINE uintptr_t getUIntPtr() const {
    if (sizeof(uintptr_t) == sizeof(uint64_t))
      return static_cast<uintptr_t>(getUInt64());
    else
      return static_cast<uintptr_t>(getUInt32());
  }

  //! Get low 32-bit signed integer.
810
  ASMJIT_INLINE int32_t getInt32Lo() const { return _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 0)]; }
811
  //! Get low 32-bit signed integer.
812
  ASMJIT_INLINE uint32_t getUInt32Lo() const { return _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 0)]; }
813
  //! Get high 32-bit signed integer.
814
  ASMJIT_INLINE int32_t getInt32Hi() const { return _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 1)]; }
815
  //! Get high 32-bit signed integer.
816
  ASMJIT_INLINE uint32_t getUInt32Hi() const { return _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)]; }
817
818
819
820
821
822
823
824

  //! Set immediate value to 8-bit signed integer `val`.
  ASMJIT_INLINE Imm& setInt8(int8_t val) {
    if (kArchHost64Bit) {
      _imm.value._i64[0] = static_cast<int64_t>(val);
    }
    else {
      int32_t val32 = static_cast<int32_t>(val);
825
826
      _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 0)] = val32;
      _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 1)] = val32 >> 31;
827
828
829
830
831
832
833
834
835
836
    }
    return *this;
  }

  //! Set immediate value to 8-bit unsigned integer `val`.
  ASMJIT_INLINE Imm& setUInt8(uint8_t val) {
    if (kArchHost64Bit) {
      _imm.value._u64[0] = static_cast<uint64_t>(val);
    }
    else {
837
838
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 0)] = static_cast<uint32_t>(val);
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)] = 0;
839
840
841
842
843
844
845
846
847
848
849
    }
    return *this;
  }

  //! Set immediate value to 16-bit signed integer `val`.
  ASMJIT_INLINE Imm& setInt16(int16_t val) {
    if (kArchHost64Bit) {
      _imm.value._i64[0] = static_cast<int64_t>(val);
    }
    else {
      int32_t val32 = static_cast<int32_t>(val);
850
851
      _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 0)] = val32;
      _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 1)] = val32 >> 31;
852
853
854
855
856
857
858
859
860
861
    }
    return *this;
  }

  //! Set immediate value to 16-bit unsigned integer `val`.
  ASMJIT_INLINE Imm& setUInt16(uint16_t val) {
    if (kArchHost64Bit) {
      _imm.value._u64[0] = static_cast<uint64_t>(val);
    }
    else {
862
863
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 0)] = static_cast<uint32_t>(val);
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)] = 0;
864
865
866
867
868
869
870
871
872
873
    }
    return *this;
  }

  //! Set immediate value to 32-bit signed integer `val`.
  ASMJIT_INLINE Imm& setInt32(int32_t val) {
    if (kArchHost64Bit) {
      _imm.value._i64[0] = static_cast<int64_t>(val);
    }
    else {
874
875
      _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 0)] = val;
      _imm.value._i32[_ASMJIT_ARCH_INDEX(2, 1)] = val >> 31;
876
877
878
879
880
881
882
883
884
885
    }
    return *this;
  }

  //! Set immediate value to 32-bit unsigned integer `val`.
  ASMJIT_INLINE Imm& setUInt32(uint32_t val) {
    if (kArchHost64Bit) {
      _imm.value._u64[0] = static_cast<uint64_t>(val);
    }
    else {
886
887
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 0)] = val;
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)] = 0;
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
    }
    return *this;
  }

  //! Set immediate value to 64-bit signed integer `val`.
  ASMJIT_INLINE Imm& setInt64(int64_t val) {
    _imm.value._i64[0] = val;
    return *this;
  }

  //! Set immediate value to 64-bit unsigned integer `val`.
  ASMJIT_INLINE Imm& setUInt64(uint64_t val) {
    _imm.value._u64[0] = val;
    return *this;
  }

  //! Set immediate value to intptr_t `val`.
  ASMJIT_INLINE Imm& setIntPtr(intptr_t val) {
    _imm.value._i64[0] = static_cast<int64_t>(val);
    return *this;
  }

  //! Set immediate value to uintptr_t `val`.
  ASMJIT_INLINE Imm& setUIntPtr(uintptr_t val) {
    _imm.value._u64[0] = static_cast<uint64_t>(val);
    return *this;
  }

  //! Set immediate value as unsigned type to `val`.
  ASMJIT_INLINE Imm& setPtr(void* p) { return setIntPtr((intptr_t)p); }

  // --------------------------------------------------------------------------
  // [Float]
  // --------------------------------------------------------------------------

  ASMJIT_INLINE Imm& setFloat(float f) {
924
925
    _imm.value._f32[_ASMJIT_ARCH_INDEX(2, 0)] = f;
    _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)] = 0;
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
    return *this;
  }

  ASMJIT_INLINE Imm& setDouble(double d) {
    _imm.value._f64[0] = d;
    return *this;
  }

  // --------------------------------------------------------------------------
  // [Truncate]
  // --------------------------------------------------------------------------

  ASMJIT_INLINE Imm& truncateTo8Bits() {
    if (kArchHost64Bit) {
      _imm.value._u64[0] &= static_cast<uint64_t>(0x000000FFU);
    }
    else {
943
944
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 0)] &= 0x000000FFU;
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)] = 0;
945
946
947
948
949
950
951
952
953
    }
    return *this;
  }

  ASMJIT_INLINE Imm& truncateTo16Bits() {
    if (kArchHost64Bit) {
      _imm.value._u64[0] &= static_cast<uint64_t>(0x0000FFFFU);
    }
    else {
954
955
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 0)] &= 0x0000FFFFU;
      _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)] = 0;
956
957
958
959
960
    }
    return *this;
  }

  ASMJIT_INLINE Imm& truncateTo32Bits() {
961
    _imm.value._u32[_ASMJIT_ARCH_INDEX(2, 1)] = 0;
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
    return *this;
  }

  // --------------------------------------------------------------------------
  // [Operator Overload]
  // --------------------------------------------------------------------------

  //! Assign `other` to the immediate operand.
  ASMJIT_INLINE Imm& operator=(const Imm& other) {
    _copy(other);
    return *this;
  }
};

// ============================================================================
// [asmjit::Label]
// ============================================================================

//! Label (jump target or data location).
//!
//! Label represents a location in code typically used as jump targets, but may
//! be also reference data or static variables. Label has to be explicitly
//! created by a code-generator by calling `CodeGen::newLabel()` where `CodeGen`
//! is your code generator, which derives from `Assembler` or `Compiler`.
//!
//! Example of using labels:
//!
//! ~~~
//! // Create Assembler/Compiler.
//! host::Assembler a;
//!
//! // Create Label instance.
//! Label L_1(a);
//!
//! // ... your code ...
//!
//! // Using label.
//! a.jump(L_1);
//!
//! // ... your code ...
//!
//! // Bind label to the current position, see `CodeGen::bind()`.
//! a.bind(L_1);
//! ~~~
struct Label : public Operand {
  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create new, unassociated label.
  ASMJIT_INLINE Label() : Operand(NoInit) {
    reset();
  }

  explicit ASMJIT_INLINE Label(uint32_t id) : Operand(NoInit) {
    _init_packed_op_sz_b0_b1_id(kOperandTypeLabel, 0, 0, 0, id);
    _init_packed_d2_d3(0, 0);
  }

  //! Create new initialized label.
  explicit ASMJIT_INLINE Label(Assembler& a);
  //! Create new initialized label.
  explicit ASMJIT_INLINE Label(Compiler& c);

  //! Create reference to another label.
  ASMJIT_INLINE Label(const Label& other) : Operand(other) {}

  explicit ASMJIT_INLINE Label(const _NoInit&) : Operand(NoInit) {}

  // --------------------------------------------------------------------------
  // [Reset]
  // --------------------------------------------------------------------------

  ASMJIT_INLINE void reset() {
    _init_packed_op_sz_b0_b1_id(kOperandTypeLabel, 0, 0, 0, kInvalidValue);
    _init_packed_d2_d3(0, 0);
  }

  // --------------------------------------------------------------------------
  // [Label Specific]
  // --------------------------------------------------------------------------

  //! Get whether the label has been initialized by `Assembler` or `Compiler`.
  ASMJIT_INLINE bool isInitialized() const {
    return _label.id != kInvalidValue;
  }

  // --------------------------------------------------------------------------
  // [Operator Overload]
  // --------------------------------------------------------------------------

  ASMJIT_INLINE Label& operator=(const Label& other) { _copy(other); return *this; }

  ASMJIT_INLINE bool operator==(const Label& other) const { return _base.id == other._base.id; }
  ASMJIT_INLINE bool operator!=(const Label& other) const { return _base.id != other._base.id; }
};

// ============================================================================
// [asmjit::Operand - Globals]
// ============================================================================

//! No operand, can be used to reset an operand by assignment or to refer to an
//! operand that doesn't exist.
ASMJIT_VAR const Operand noOperand;

//! Create signed immediate value operand.
static ASMJIT_INLINE Imm imm(int64_t val) {
  return Imm(val);
}

//! Create unsigned immediate value operand.
static ASMJIT_INLINE Imm imm_u(uint64_t val) {
  return Imm(static_cast<int64_t>(val));
}

//! Create void* pointer immediate value operand.
static ASMJIT_INLINE Imm imm_ptr(void* p) {
  return Imm(static_cast<int64_t>((intptr_t)p));
}

//! \}

} // asmjit namespace

// [Api-End]
#include "../apiend.h"

// [Guard]
#endif // _ASMJIT_BASE_OPERAND_H