Commit 751ff079 authored by peastman's avatar peastman
Browse files

Merge pull request #630 from peastman/jit

JIT compilation for custom forces in CPU platform
parents 77ea3bb6 5a98c0a1
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../build.h"
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
// [Dependencies - AsmJit]
#include "../x86/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
namespace x86 {
// ============================================================================
// [asmjit::X86Mem - abs[]]
// ============================================================================
X86Mem ptr_abs(Ptr pAbs, int32_t disp, uint32_t size) {
X86Mem m(NoInit);
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, 0, kInvalidValue);
m._vmem.index = kInvalidValue;
m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp));
return m;
}
X86Mem ptr_abs(Ptr pAbs, const X86Reg& index, uint32_t shift, int32_t disp, uint32_t size) {
X86Mem m(NoInit);
uint32_t flags = shift << kX86MemShiftIndex;
if (index.isGp())
flags |= X86Mem::_getGpdFlags(index);
else if (index.isXmm())
flags |= kX86MemVSibXmm << kX86MemVSibIndex;
else if (index.isYmm())
flags |= kX86MemVSibYmm << kX86MemVSibIndex;
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue);
m._vmem.index = index.getRegIndex();
m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp));
return m;
}
#if !defined(ASMJIT_DISABLE_COMPILER)
X86Mem ptr_abs(Ptr pAbs, const X86Var& index, uint32_t shift, int32_t disp, uint32_t size) {
X86Mem m(NoInit);
uint32_t flags = shift << kX86MemShiftIndex;
const Var& index_ = reinterpret_cast<const Var&>(index);
uint32_t indexRegType = index_.getRegType();
if (indexRegType <= kX86RegTypeGpq)
flags |= X86Mem::_getGpdFlags(reinterpret_cast<const Var&>(index));
else if (indexRegType == kX86RegTypeXmm)
flags |= kX86MemVSibXmm << kX86MemVSibIndex;
else if (indexRegType == kX86RegTypeYmm)
flags |= kX86MemVSibYmm << kX86MemVSibIndex;
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue);
m._vmem.index = index_.getId();
m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp));
return m;
}
#endif // !ASMJIT_DISABLE_COMPILER
} // x86 namespace
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_X86OPERAND_H
#define _ASMJIT_X86_X86OPERAND_H
// [Dependencies - AsmJit]
#include "../base/assembler.h"
#include "../base/compiler.h"
#include "../base/globals.h"
#include "../base/intutil.h"
#include "../base/operand.h"
#include "../base/vectypes.h"
// [Api-Begin]
#include "../apibegin.h"
//! \internal
//!
//! Internal macro to get an operand ID casting it to `Operand`. Basically
//! allows to get an id of operand that has been just 'typedef'ed.
#define _OP_ID(_Op_) reinterpret_cast<const Operand&>(_Op_).getId()
namespace asmjit {
// ============================================================================
// [Forward Declarations]
// ============================================================================
struct X86Reg;
struct X86GpReg;
struct X86FpReg;
struct X86MmReg;
struct X86XmmReg;
struct X86YmmReg;
struct X86SegReg;
#if !defined(ASMJIT_DISABLE_COMPILER)
struct X86Var;
struct X86GpVar;
struct X86MmVar;
struct X86XmmVar;
struct X86YmmVar;
#endif // !ASMJIT_DISABLE_COMPILER
//! \addtogroup asmjit_x86_general
//! \{
// ============================================================================
// [asmjit::kX86RegClass]
// ============================================================================
//! X86/X64 variable class.
ASMJIT_ENUM(kX86RegClass) {
//! X86/X64 Gp register class (compatible with universal \ref kRegClassGp).
kX86RegClassGp = kRegClassGp,
//! X86/X64 Fp register class.
kX86RegClassFp = 1,
//! X86/X64 Mm register class.
kX86RegClassMm = 2,
//! X86/X64 Xmm/Ymm/Zmm register class.
kX86RegClassXyz = 3,
//! Count of X86/X64 register classes.
kX86RegClassCount = 4
};
// ============================================================================
// [asmjit::kX86RegType]
// ============================================================================
//! X86/X64 register type.
ASMJIT_ENUM(kX86RegType) {
//! Gpb-lo register (AL, BL, CL, DL, ...).
kX86RegTypeGpbLo = 0x01,
//! Gpb-hi register (AH, BH, CH, DH only).
kX86RegTypeGpbHi = 0x02,
//! \internal
//!
//! Gpb-hi register patched to native index (4-7).
_kX86RegTypePatchedGpbHi = kX86RegTypeGpbLo | kX86RegTypeGpbHi,
//! Gpw register.
kX86RegTypeGpw = 0x10,
//! Gpd register.
kX86RegTypeGpd = 0x20,
//! Gpq register.
kX86RegTypeGpq = 0x30,
//! Fp register.
kX86RegTypeFp = 0x50,
//! Mm register.
kX86RegTypeMm = 0x60,
//! Xmm register.
kX86RegTypeXmm = 0x70,
//! Ymm register.
kX86RegTypeYmm = 0x80,
//! Zmm register.
kX86RegTypeZmm = 0x90,
//! Segment register.
kX86RegTypeSeg = 0xF0
};
// ============================================================================
// [asmjit::kX86RegIndex]
// ============================================================================
//! X86/X64 register indexes.
//!
//! \note Register indexes have been reduced to only support general purpose
//! registers. There is no need to have enumerations with number suffix that
//! expands to the exactly same value as the suffix value itself.
ASMJIT_ENUM(kX86RegIndex) {
//! Index of Al/Ah/Ax/Eax/Rax registers.
kX86RegIndexAx = 0,
//! Index of Cl/Ch/Cx/Ecx/Rcx registers.
kX86RegIndexCx = 1,
//! Index of Dl/Dh/Dx/Edx/Rdx registers.
kX86RegIndexDx = 2,
//! Index of Bl/Bh/Bx/Ebx/Rbx registers.
kX86RegIndexBx = 3,
//! Index of Spl/Sp/Esp/Rsp registers.
kX86RegIndexSp = 4,
//! Index of Bpl/Bp/Ebp/Rbp registers.
kX86RegIndexBp = 5,
//! Index of Sil/Si/Esi/Rsi registers.
kX86RegIndexSi = 6,
//! Index of Dil/Di/Edi/Rdi registers.
kX86RegIndexDi = 7,
//! Index of R8b/R8w/R8d/R8 registers (64-bit only).
kX86RegIndexR8 = 8,
//! Index of R9B/R9w/R9d/R9 registers (64-bit only).
kX86RegIndexR9 = 9,
//! Index of R10B/R10w/R10D/R10 registers (64-bit only).
kX86RegIndexR10 = 10,
//! Index of R11B/R11w/R11d/R11 registers (64-bit only).
kX86RegIndexR11 = 11,
//! Index of R12B/R12w/R12d/R12 registers (64-bit only).
kX86RegIndexR12 = 12,
//! Index of R13B/R13w/R13d/R13 registers (64-bit only).
kX86RegIndexR13 = 13,
//! Index of R14B/R14w/R14d/R14 registers (64-bit only).
kX86RegIndexR14 = 14,
//! Index of R15B/R15w/R15d/R15 registers (64-bit only).
kX86RegIndexR15 = 15
};
// ============================================================================
// [asmjit::kX86Seg]
// ============================================================================
//! X86/X64 segment codes.
ASMJIT_ENUM(kX86Seg) {
//! No/Default segment.
kX86SegDefault = 0,
//! Es segment.
kX86SegEs = 1,
//! Cs segment.
kX86SegCs = 2,
//! Ss segment.
kX86SegSs = 3,
//! Ds segment.
kX86SegDs = 4,
//! Fs segment.
kX86SegFs = 5,
//! Gs segment.
kX86SegGs = 6,
//! Count of X86 segment registers supported by AsmJit.
//!
//! \note X86 architecture has 6 segment registers - ES, CS, SS, DS, FS, GS.
//! X64 architecture lowers them down to just FS and GS. AsmJit supports 7
//! segment registers - all addressable in both X86 and X64 modes and one
//! extra called `kX86SegDefault`, which is AsmJit specific and means that there
//! is no segment register specified so the segment prefix will not be emitted.
kX86SegCount = 7
};
// ============================================================================
// [asmjit::kX86MemVSib]
// ============================================================================
//! X86/X64 index register legacy and AVX2 (VSIB) support.
ASMJIT_ENUM(kX86MemVSib) {
//! Memory operand uses Gp or no index register.
kX86MemVSibGpz = 0,
//! Memory operand uses Xmm or no index register.
kX86MemVSibXmm = 1,
//! Memory operand uses Ymm or no index register.
kX86MemVSibYmm = 2
};
// ============================================================================
// [asmjit::kX86MemFlags]
// ============================================================================
//! \internal
//!
//! X86/X64 specific memory flags.
ASMJIT_ENUM(kX86MemFlags) {
kX86MemSegBits = 0x7,
kX86MemSegIndex = 0,
kX86MemSegMask = kX86MemSegBits << kX86MemSegIndex,
kX86MemGpdBits = 0x1,
kX86MemGpdIndex = 3,
kX86MemGpdMask = kX86MemGpdBits << kX86MemGpdIndex,
kX86MemVSibBits = 0x3,
kX86MemVSibIndex = 4,
kX86MemVSibMask = kX86MemVSibBits << kX86MemVSibIndex,
kX86MemShiftBits = 0x3,
kX86MemShiftIndex = 6,
kX86MemShiftMask = kX86MemShiftBits << kX86MemShiftIndex
};
// This is only defined by `x86operand_regs.cpp` when exporting registers.
#if !defined(ASMJIT_EXPORTS_X86OPERAND_REGS)
// ============================================================================
// [asmjit::X86RegCount]
// ============================================================================
//! \internal
//!
//! X86/X64 registers count (Gp, Fp, Mm, Xmm).
struct X86RegCount {
// --------------------------------------------------------------------------
// [Zero]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_packed = 0;
}
// --------------------------------------------------------------------------
// [Get]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t get(uint32_t c) const {
ASMJIT_ASSERT(c < kX86RegClassCount);
return _regs[c];
}
ASMJIT_INLINE uint32_t getGp() const { return _regs[kX86RegClassGp]; }
ASMJIT_INLINE uint32_t getFp() const { return _regs[kX86RegClassFp]; }
ASMJIT_INLINE uint32_t getMm() const { return _regs[kX86RegClassMm]; }
ASMJIT_INLINE uint32_t getXyz() const { return _regs[kX86RegClassXyz]; }
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
ASMJIT_INLINE void set(uint32_t c, uint32_t n) {
ASMJIT_ASSERT(c < kX86RegClassCount);
ASMJIT_ASSERT(n < 0x100);
_regs[c] = static_cast<uint8_t>(n);
}
ASMJIT_INLINE void setGp(uint32_t n) { set(kX86RegClassGp, n); }
ASMJIT_INLINE void setFp(uint32_t n) { set(kX86RegClassFp, n); }
ASMJIT_INLINE void setMm(uint32_t n) { set(kX86RegClassMm, n); }
ASMJIT_INLINE void setXyz(uint32_t n) { set(kX86RegClassXyz, n); }
// --------------------------------------------------------------------------
// [Add]
// --------------------------------------------------------------------------
ASMJIT_INLINE void add(uint32_t c, uint32_t n = 1) {
ASMJIT_ASSERT(c < kX86RegClassCount);
ASMJIT_ASSERT(n < 0x100);
_regs[c] += static_cast<uint8_t>(n);
}
ASMJIT_INLINE void addGp(uint32_t n) { add(kX86RegClassGp, n); }
ASMJIT_INLINE void addFp(uint32_t n) { add(kX86RegClassFp, n); }
ASMJIT_INLINE void addMm(uint32_t n) { add(kX86RegClassMm, n); }
ASMJIT_INLINE void addXyz(uint32_t n) { add(kX86RegClassXyz, n); }
// --------------------------------------------------------------------------
// [Misc]
// --------------------------------------------------------------------------
ASMJIT_INLINE void makeIndex(const X86RegCount& count) {
uint8_t a = count._regs[0];
uint8_t b = count._regs[1];
uint8_t c = count._regs[2];
_regs[0] = 0;
_regs[1] = a;
_regs[2] = a + b;
_regs[3] = a + b + c;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
uint8_t _gp;
uint8_t _fp;
uint8_t _mm;
uint8_t _xy;
};
uint8_t _regs[4];
uint32_t _packed;
};
};
// ============================================================================
// [asmjit::X86RegMask]
// ============================================================================
//! \internal
//!
//! X86/X64 registers mask (Gp, Fp, Mm, Xmm/Ymm/Zmm).
struct X86RegMask {
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_packed.reset();
}
// --------------------------------------------------------------------------
// [IsEmpty / Has]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const {
return _packed.isZero();
}
ASMJIT_INLINE bool has(uint32_t c, uint32_t mask = 0xFFFFFFFF) const {
switch (c) {
case kX86RegClassGp : return (static_cast<uint32_t>(_gp ) & mask) != 0;
case kX86RegClassFp : return (static_cast<uint32_t>(_fp ) & mask) != 0;
case kX86RegClassMm : return (static_cast<uint32_t>(_mm ) & mask) != 0;
case kX86RegClassXyz: return (static_cast<uint32_t>(_xyz) & mask) != 0;
}
ASMJIT_ASSERT(!"Reached");
return false;
}
// --------------------------------------------------------------------------
// [Zero]
// --------------------------------------------------------------------------
ASMJIT_INLINE void zero(uint32_t c) {
switch (c) {
case kX86RegClassGp : _gp = 0; break;
case kX86RegClassFp : _fp = 0; break;
case kX86RegClassMm : _mm = 0; break;
case kX86RegClassXyz: _xyz = 0; break;
}
}
// --------------------------------------------------------------------------
// [Get]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t get(uint32_t c) const {
switch (c) {
case kX86RegClassGp : return _gp;
case kX86RegClassFp : return _fp;
case kX86RegClassMm : return _mm;
case kX86RegClassXyz: return _xyz;
}
ASMJIT_ASSERT(!"Reached");
return 0;
}
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
ASMJIT_INLINE void set(uint32_t c, uint32_t mask) {
switch (c) {
case kX86RegClassGp : _gp = static_cast<uint16_t>(mask); break;
case kX86RegClassFp : _fp = static_cast<uint8_t >(mask); break;
case kX86RegClassMm : _mm = static_cast<uint8_t >(mask); break;
case kX86RegClassXyz: _xyz = static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void set(const X86RegMask& other) {
_packed.setUInt64(other._packed);
}
// --------------------------------------------------------------------------
// [Add]
// --------------------------------------------------------------------------
ASMJIT_INLINE void add(uint32_t c, uint32_t mask) {
switch (c) {
case kX86RegClassGp : _gp |= static_cast<uint16_t>(mask); break;
case kX86RegClassFp : _fp |= static_cast<uint8_t >(mask); break;
case kX86RegClassMm : _mm |= static_cast<uint8_t >(mask); break;
case kX86RegClassXyz: _xyz |= static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void add(const X86RegMask& other) {
_packed.or_(other._packed);
}
// --------------------------------------------------------------------------
// [Del]
// --------------------------------------------------------------------------
ASMJIT_INLINE void del(uint32_t c, uint32_t mask) {
switch (c) {
case kX86RegClassGp : _gp &= ~static_cast<uint16_t>(mask); break;
case kX86RegClassFp : _fp &= ~static_cast<uint8_t >(mask); break;
case kX86RegClassMm : _mm &= ~static_cast<uint8_t >(mask); break;
case kX86RegClassXyz: _xyz &= ~static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void del(const X86RegMask& other) {
_packed.del(other._packed);
}
// --------------------------------------------------------------------------
// [And]
// --------------------------------------------------------------------------
ASMJIT_INLINE void and_(uint32_t c, uint32_t mask) {
switch (c) {
case kX86RegClassGp : _gp &= static_cast<uint16_t>(mask); break;
case kX86RegClassFp : _fp &= static_cast<uint8_t >(mask); break;
case kX86RegClassMm : _mm &= static_cast<uint8_t >(mask); break;
case kX86RegClassXyz: _xyz &= static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void and_(const X86RegMask& other) {
_packed.and_(other._packed);
}
// --------------------------------------------------------------------------
// [Xor]
// --------------------------------------------------------------------------
ASMJIT_INLINE void xor_(uint32_t c, uint32_t mask) {
switch (c) {
case kX86RegClassGp : _gp ^= static_cast<uint16_t>(mask); break;
case kX86RegClassFp : _fp ^= static_cast<uint8_t >(mask); break;
case kX86RegClassMm : _mm ^= static_cast<uint8_t >(mask); break;
case kX86RegClassXyz: _xyz ^= static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void xor_(const X86RegMask& other) {
_packed.xor_(other._packed);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
//! Gp mask (16-bit).
uint16_t _gp;
//! Fp mask (8-bit).
uint8_t _fp;
//! Mm mask (8-bit).
uint8_t _mm;
//! Xmm/Ymm/Zmm mask (32-bit).
uint32_t _xyz;
};
//! All masks as 64-bit integer.
UInt64 _packed;
};
};
// ============================================================================
// [asmjit::X86Reg]
// ============================================================================
//! Base class for all X86 registers.
struct X86Reg : public Reg {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy X86 register.
ASMJIT_INLINE X86Reg() : Reg() {}
//! Create a reference to `other` X86 register.
ASMJIT_INLINE X86Reg(const X86Reg& other) : Reg(other) {}
//! Create a reference to `other` X86 register and change the index to `index`.
ASMJIT_INLINE X86Reg(const X86Reg& other, uint32_t index) : Reg(other, index) {}
//! Create a custom X86 register.
ASMJIT_INLINE X86Reg(uint32_t type, uint32_t index, uint32_t size) : Reg(type, index, size) {}
//! Create non-initialized X86 register.
explicit ASMJIT_INLINE X86Reg(const _NoInit&) : Reg(NoInit) {}
// --------------------------------------------------------------------------
// [X86Reg Specific]
// --------------------------------------------------------------------------
ASMJIT_REG_OP(X86Reg)
//! Get whether the register is Gp register.
ASMJIT_INLINE bool isGp() const { return _vreg.type <= kX86RegTypeGpq; }
//! Get whether the register is Gp byte (8-bit) register.
ASMJIT_INLINE bool isGpb() const { return _vreg.type <= kX86RegTypeGpbHi; }
//! Get whether the register is Gp lo-byte (8-bit) register.
ASMJIT_INLINE bool isGpbLo() const { return _vreg.type == kX86RegTypeGpbLo; }
//! Get whether the register is Gp hi-byte (8-bit) register.
ASMJIT_INLINE bool isGpbHi() const { return _vreg.type == kX86RegTypeGpbHi; }
//! Get whether the register is Gp word (16-bit) register.
ASMJIT_INLINE bool isGpw() const { return _vreg.type == kX86RegTypeGpw; }
//! Get whether the register is Gp dword (32-bit) register.
ASMJIT_INLINE bool isGpd() const { return _vreg.type == kX86RegTypeGpd; }
//! Get whether the register is Gp qword (64-bit) register.
ASMJIT_INLINE bool isGpq() const { return _vreg.type == kX86RegTypeGpq; }
//! Get whether the register is Fp register.
ASMJIT_INLINE bool isFp() const { return _vreg.type == kX86RegTypeFp; }
//! Get whether the register is Mm (64-bit) register.
ASMJIT_INLINE bool isMm() const { return _vreg.type == kX86RegTypeMm; }
//! Get whether the register is Xmm (128-bit) register.
ASMJIT_INLINE bool isXmm() const { return _vreg.type == kX86RegTypeXmm; }
//! Get whether the register is Ymm (256-bit) register.
ASMJIT_INLINE bool isYmm() const { return _vreg.type == kX86RegTypeYmm; }
//! Get whether the register is Zmm (512-bit) register.
ASMJIT_INLINE bool isZmm() const { return _vreg.type == kX86RegTypeZmm; }
//! Get whether the register is a segment.
ASMJIT_INLINE bool isSeg() const { return _vreg.type == kX86RegTypeSeg; }
// --------------------------------------------------------------------------
// [Statics]
// --------------------------------------------------------------------------
//! Get whether the `op` operand is Gpb-Lo or Gpb-Hi register.
static ASMJIT_INLINE bool isGpbReg(const Operand& op) {
const uint32_t mask = IntUtil::pack32_2x8_1x16(
0xFF, 0xFF, ~(_kX86RegTypePatchedGpbHi << 8) & 0xFF00);
return (op._packed[0].u32[0] & mask) == IntUtil::pack32_2x8_1x16(kOperandTypeReg, 1, 0x0000);
}
};
// ============================================================================
// [asmjit::X86GpReg]
// ============================================================================
//! X86/X64 Gpb/Gpw/Gpd/Gpq register.
struct X86GpReg : public X86Reg {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy Gp register.
ASMJIT_INLINE X86GpReg() : X86Reg() {}
//! Create a reference to `other` Gp register.
ASMJIT_INLINE X86GpReg(const X86GpReg& other) : X86Reg(other) {}
//! Create a reference to `other` Gp register and change the index to `index`.
ASMJIT_INLINE X86GpReg(const X86GpReg& other, uint32_t index) : X86Reg(other, index) {}
//! Create a custom Gp register.
ASMJIT_INLINE X86GpReg(uint32_t type, uint32_t index, uint32_t size) : X86Reg(type, index, size) {}
//! Create non-initialized Gp register.
explicit ASMJIT_INLINE X86GpReg(const _NoInit&) : X86Reg(NoInit) {}
// --------------------------------------------------------------------------
// [X86GpReg Specific]
// --------------------------------------------------------------------------
ASMJIT_REG_OP(X86GpReg)
};
// ============================================================================
// [asmjit::X86FpReg]
// ============================================================================
//! X86/X64 80-bit Fp register.
struct X86FpReg : public X86Reg {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy Fp register.
ASMJIT_INLINE X86FpReg() : X86Reg() {}
//! Create a reference to `other` Fp register.
ASMJIT_INLINE X86FpReg(const X86FpReg& other) : X86Reg(other) {}
//! Create a reference to `other` Fp register and change the index to `index`.
ASMJIT_INLINE X86FpReg(const X86FpReg& other, uint32_t index) : X86Reg(other, index) {}
//! Create a custom Fp register.
ASMJIT_INLINE X86FpReg(uint32_t type, uint32_t index, uint32_t size) : X86Reg(type, index, size) {}
//! Create non-initialized Fp register.
explicit ASMJIT_INLINE X86FpReg(const _NoInit&) : X86Reg(NoInit) {}
// --------------------------------------------------------------------------
// [X86FpReg Specific]
// --------------------------------------------------------------------------
ASMJIT_REG_OP(X86FpReg)
};
// ============================================================================
// [asmjit::X86MmReg]
// ============================================================================
//! X86/X64 64-bit Mm register.
struct X86MmReg : public X86Reg {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy Mm register.
ASMJIT_INLINE X86MmReg() : X86Reg() {}
//! Create a reference to `other` Mm register.
ASMJIT_INLINE X86MmReg(const X86MmReg& other) : X86Reg(other) {}
//! Create a reference to `other` Mm register and change the index to `index`.
ASMJIT_INLINE X86MmReg(const X86MmReg& other, uint32_t index) : X86Reg(other, index) {}
//! Create a custom Mm register.
ASMJIT_INLINE X86MmReg(uint32_t type, uint32_t index, uint32_t size) : X86Reg(type, index, size) {}
//! Create non-initialized Mm register.
explicit ASMJIT_INLINE X86MmReg(const _NoInit&) : X86Reg(NoInit) {}
// --------------------------------------------------------------------------
// [X86MmReg Specific]
// --------------------------------------------------------------------------
ASMJIT_REG_OP(X86MmReg)
};
// ============================================================================
// [asmjit::X86XmmReg]
// ============================================================================
//! X86/X64 128-bit Xmm register.
struct X86XmmReg : public X86Reg {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy Xmm register.
ASMJIT_INLINE X86XmmReg() : X86Reg() {}
//! Create a reference to `other` Xmm register.
ASMJIT_INLINE X86XmmReg(const X86XmmReg& other) : X86Reg(other) {}
//! Create a reference to `other` Xmm register and change the index to `index`.
ASMJIT_INLINE X86XmmReg(const X86XmmReg& other, uint32_t index) : X86Reg(other, index) {}
//! Create a custom Xmm register.
ASMJIT_INLINE X86XmmReg(uint32_t type, uint32_t index, uint32_t size) : X86Reg(type, index, size) {}
//! Create non-initialized Xmm register.
explicit ASMJIT_INLINE X86XmmReg(const _NoInit&) : X86Reg(NoInit) {}
// --------------------------------------------------------------------------
// [X86XmmReg Specific]
// --------------------------------------------------------------------------
ASMJIT_REG_OP(X86XmmReg)
};
// ============================================================================
// [asmjit::X86YmmReg]
// ============================================================================
//! X86/X64 256-bit Ymm register.
struct X86YmmReg : public X86Reg {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy Ymm register.
ASMJIT_INLINE X86YmmReg() : X86Reg() {}
//! Create a reference to `other` Xmm register.
ASMJIT_INLINE X86YmmReg(const X86YmmReg& other) : X86Reg(other) {}
//! Create a reference to `other` Ymm register and change the index to `index`.
ASMJIT_INLINE X86YmmReg(const X86YmmReg& other, uint32_t index) : X86Reg(other, index) {}
//! Create a custom Ymm register.
ASMJIT_INLINE X86YmmReg(uint32_t type, uint32_t index, uint32_t size) : X86Reg(type, index, size) {}
//! Create non-initialized Ymm register.
explicit ASMJIT_INLINE X86YmmReg(const _NoInit&) : X86Reg(NoInit) {}
// --------------------------------------------------------------------------
// [X86YmmReg Specific]
// --------------------------------------------------------------------------
ASMJIT_REG_OP(X86YmmReg)
};
// ============================================================================
// [asmjit::X86SegReg]
// ============================================================================
//! X86/X64 segment register.
struct X86SegReg : public X86Reg {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a dummy segment register.
ASMJIT_INLINE X86SegReg() : X86Reg() {}
//! Create a reference to `other` segment register.
ASMJIT_INLINE X86SegReg(const X86SegReg& other) : X86Reg(other) {}
//! Create a reference to `other` segment register and change the index to `index`.
ASMJIT_INLINE X86SegReg(const X86SegReg& other, uint32_t index) : X86Reg(other, index) {}
//! Create a custom segment register.
ASMJIT_INLINE X86SegReg(uint32_t type, uint32_t index, uint32_t size) : X86Reg(type, index, size) {}
//! Create non-initialized segment register.
explicit ASMJIT_INLINE X86SegReg(const _NoInit&) : X86Reg(NoInit) {}
// --------------------------------------------------------------------------
// [X86SegReg Specific]
// --------------------------------------------------------------------------
ASMJIT_REG_OP(X86SegReg)
};
// ============================================================================
// [asmjit::X86Mem]
// ============================================================================
//! X86 memory operand.
struct X86Mem : public BaseMem {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE X86Mem() : BaseMem(NoInit) {
reset();
}
ASMJIT_INLINE X86Mem(const Label& label, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeLabel, 0, label._base.id);
_init_packed_d2_d3(kInvalidValue, disp);
}
ASMJIT_INLINE X86Mem(const Label& label, const X86GpReg& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeLabel,
(kX86MemVSibGpz << kX86MemVSibIndex)
+ (shift << kX86MemShiftIndex),
label.getId());
_vmem.index = index.getRegIndex();
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const X86GpReg& base, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(base)
+ (kX86MemVSibGpz << kX86MemVSibIndex),
base.getRegIndex());
_init_packed_d2_d3(kInvalidValue, disp);
}
ASMJIT_INLINE X86Mem(const X86GpReg& base, const X86GpReg& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(base) + (shift << kX86MemShiftIndex),
base.getRegIndex());
_vmem.index = index.getRegIndex();
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const X86GpReg& base, const X86XmmReg& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(base)
+ (kX86MemVSibXmm << kX86MemVSibIndex)
+ (shift << kX86MemShiftIndex),
base.getRegIndex());
_vmem.index = index.getRegIndex();
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const X86GpReg& base, const X86YmmReg& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(base)
+ (kX86MemVSibYmm << kX86MemVSibIndex)
+ (shift << kX86MemShiftIndex),
base.getRegIndex());
_vmem.index = index.getRegIndex();
_vmem.displacement = disp;
}
#if !defined(ASMJIT_DISABLE_COMPILER)
ASMJIT_INLINE X86Mem(const Label& label, const X86GpVar& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeLabel,
(kX86MemVSibGpz << kX86MemVSibIndex)
+ (shift << kX86MemShiftIndex),
label.getId());
_vmem.index = _OP_ID(index);
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const X86GpVar& base, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(reinterpret_cast<const Var&>(base))
+ (kX86MemVSibGpz << kX86MemVSibIndex),
_OP_ID(base));
_init_packed_d2_d3(kInvalidValue, disp);
}
ASMJIT_INLINE X86Mem(const X86GpVar& base, const X86GpVar& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(reinterpret_cast<const Var&>(base))
+ (shift << kX86MemShiftIndex),
_OP_ID(base));
_vmem.index = _OP_ID(index);
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const X86GpVar& base, const X86XmmVar& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(reinterpret_cast<const Var&>(base))
+ (kX86MemVSibXmm << kX86MemVSibIndex)
+ (shift << kX86MemShiftIndex),
_OP_ID(base));
_vmem.index = _OP_ID(index);
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const X86GpVar& base, const X86YmmVar& index, uint32_t shift, int32_t disp, uint32_t size = 0) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeBaseIndex,
_getGpdFlags(reinterpret_cast<const Var&>(base))
+ (kX86MemVSibYmm << kX86MemVSibIndex)
+ (shift << kX86MemShiftIndex),
_OP_ID(base));
_vmem.index = _OP_ID(index);
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const _Init&, uint32_t memType, const X86Var& base, int32_t disp, uint32_t size) : BaseMem(NoInit) {
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, memType, 0, _OP_ID(base));
_vmem.index = kInvalidValue;
_vmem.displacement = disp;
}
ASMJIT_INLINE X86Mem(const _Init&, uint32_t memType, const X86Var& base, const X86GpVar& index, uint32_t shift, int32_t disp, uint32_t size) : BaseMem(NoInit) {
ASMJIT_ASSERT(shift <= 3);
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, memType, shift << kX86MemShiftIndex, _OP_ID(base));
_vmem.index = _OP_ID(index);
_vmem.displacement = disp;
}
#endif // !ASMJIT_DISABLE_COMPILER
ASMJIT_INLINE X86Mem(const X86Mem& other) : BaseMem(other) {}
explicit ASMJIT_INLINE X86Mem(const _NoInit&) : BaseMem(NoInit) {}
// --------------------------------------------------------------------------
// [X86Mem Specific]
// --------------------------------------------------------------------------
//! Clone X86Mem operand.
ASMJIT_INLINE X86Mem clone() const {
return X86Mem(*this);
}
//! Reset X86Mem operand.
ASMJIT_INLINE void reset() {
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, 0, kMemTypeBaseIndex, 0, kInvalidValue);
_init_packed_d2_d3(kInvalidValue, 0);
}
//! \internal
ASMJIT_INLINE void _init(uint32_t memType, uint32_t base, int32_t disp, uint32_t size) {
_init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, memType, 0, base);
_vmem.index = kInvalidValue;
_vmem.displacement = disp;
}
// --------------------------------------------------------------------------
// [Segment]
// --------------------------------------------------------------------------
//! Get whether the memory operand has segment override prefix.
ASMJIT_INLINE bool hasSegment() const {
return (_vmem.flags & kX86MemSegMask) != (kX86SegDefault << kX86MemSegIndex);
}
//! Get memory operand segment, see `kX86Seg`.
ASMJIT_INLINE uint32_t getSegment() const {
return (static_cast<uint32_t>(_vmem.flags) >> kX86MemSegIndex) & kX86MemSegBits;
}
//! Set memory operand segment, see `kX86Seg`.
ASMJIT_INLINE X86Mem& setSegment(uint32_t segIndex) {
_vmem.flags = static_cast<uint8_t>(
(static_cast<uint32_t>(_vmem.flags) & kX86MemSegMask) + (segIndex << kX86MemSegIndex));
return *this;
}
//! Set memory operand segment, see `kX86Seg`.
ASMJIT_INLINE X86Mem& setSegment(const X86SegReg& seg) {
return setSegment(seg.getRegIndex());
}
// --------------------------------------------------------------------------
// [Gpd]
// --------------------------------------------------------------------------
//! Get whether the memory operand has 32-bit GP base.
ASMJIT_INLINE bool hasGpdBase() const {
return (_packed[0].u32[0] & IntUtil::pack32_4x8(0x00, 0x00, 0x00, kX86MemGpdMask)) != 0;
}
//! Set whether the memory operand has 32-bit GP base.
ASMJIT_INLINE X86Mem& setGpdBase() {
_packed[0].u32[0] |= IntUtil::pack32_4x8(0x00, 0x00, 0x00, kX86MemGpdMask);
return *this;
}
//! Set whether the memory operand has 32-bit GP base to `b`.
ASMJIT_INLINE X86Mem& setGpdBase(uint32_t b) {
_packed[0].u32[0] &=~IntUtil::pack32_4x8(0x00, 0x00, 0x00, kX86MemGpdMask);
_packed[0].u32[0] |= IntUtil::pack32_4x8(0x00, 0x00, 0x00, b << kX86MemGpdIndex);
return *this;
}
// --------------------------------------------------------------------------
// [VSib]
// --------------------------------------------------------------------------
//! Get SIB type.
ASMJIT_INLINE uint32_t getVSib() const {
return (static_cast<uint32_t>(_vmem.flags) >> kX86MemVSibIndex) & kX86MemVSibBits;
}
//! Set SIB type.
ASMJIT_INLINE X86Mem& _setVSib(uint32_t vsib) {
_packed[0].u32[0] &=~IntUtil::pack32_4x8(0x00, 0x00, 0x00, kX86MemVSibMask);
_packed[0].u32[0] |= IntUtil::pack32_4x8(0x00, 0x00, 0x00, vsib << kX86MemVSibIndex);
return *this;
}
// --------------------------------------------------------------------------
// [Size]
// --------------------------------------------------------------------------
//! Set memory operand size.
ASMJIT_INLINE X86Mem& setSize(uint32_t size) {
_vmem.size = static_cast<uint8_t>(size);
return *this;
}
// --------------------------------------------------------------------------
// [Base]
// --------------------------------------------------------------------------
//! Get whether the memory operand has base register.
ASMJIT_INLINE bool hasBase() const {
return _vmem.base != kInvalidValue;
}
//! Get memory operand base register code, variable id, or `kInvalidValue`.
ASMJIT_INLINE uint32_t getBase() const {
return _vmem.base;
}
//! Set memory operand base register code, variable id, or `kInvalidValue`.
ASMJIT_INLINE X86Mem& setBase(uint32_t base) {
_vmem.base = base;
return *this;
}
// --------------------------------------------------------------------------
// [Index]
// --------------------------------------------------------------------------
//! Get whether the memory operand has index.
ASMJIT_INLINE bool hasIndex() const {
return _vmem.index != kInvalidValue;
}
//! Get memory operand index register code, variable id, or `kInvalidValue`.
ASMJIT_INLINE uint32_t getIndex() const {
return _vmem.index;
}
//! Set memory operand index register code, variable id, or `kInvalidValue`.
ASMJIT_INLINE X86Mem& setIndex(uint32_t index) {
_vmem.index = index;
return *this;
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86GpReg& index) {
_vmem.index = index.getRegIndex();
return _setVSib(kX86MemVSibGpz);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86GpReg& index, uint32_t shift) {
_vmem.index = index.getRegIndex();
return _setVSib(kX86MemVSibGpz).setShift(shift);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86XmmReg& index) {
_vmem.index = index.getRegIndex();
return _setVSib(kX86MemVSibXmm);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86XmmReg& index, uint32_t shift) {
_vmem.index = index.getRegIndex();
return _setVSib(kX86MemVSibXmm).setShift(shift);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86YmmReg& index) {
_vmem.index = index.getRegIndex();
return _setVSib(kX86MemVSibYmm);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86YmmReg& index, uint32_t shift) {
_vmem.index = index.getRegIndex();
return _setVSib(kX86MemVSibYmm).setShift(shift);
}
#if !defined(ASMJIT_DISABLE_COMPILER)
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86GpVar& index) {
_vmem.index = _OP_ID(index);
return _setVSib(kX86MemVSibGpz);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86GpVar& index, uint32_t shift) {
_vmem.index = _OP_ID(index);
return _setVSib(kX86MemVSibGpz).setShift(shift);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86XmmVar& index) {
_vmem.index = _OP_ID(index);
return _setVSib(kX86MemVSibXmm);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86XmmVar& index, uint32_t shift) {
_vmem.index = _OP_ID(index);
return _setVSib(kX86MemVSibXmm).setShift(shift);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86YmmVar& index) {
_vmem.index = _OP_ID(index);
return _setVSib(kX86MemVSibYmm);
}
//! Set memory index.
ASMJIT_INLINE X86Mem& setIndex(const X86YmmVar& index, uint32_t shift) {
_vmem.index = _OP_ID(index);
return _setVSib(kX86MemVSibYmm).setShift(shift);
}
#endif // !ASMJIT_DISABLE_COMPILER
//! Reset memory index.
ASMJIT_INLINE X86Mem& resetIndex() {
_vmem.index = kInvalidValue;
return _setVSib(kX86MemVSibGpz);
}
// --------------------------------------------------------------------------
// [Misc]
// --------------------------------------------------------------------------
//! Get whether the memory operand has base and index register.
ASMJIT_INLINE bool hasBaseOrIndex() const {
return _vmem.base != kInvalidValue || _vmem.index != kInvalidValue;
}
//! Get whether the memory operand has base and index register.
ASMJIT_INLINE bool hasBaseAndIndex() const {
return _vmem.base != kInvalidValue && _vmem.index != kInvalidValue;
}
// --------------------------------------------------------------------------
// [Shift]
// --------------------------------------------------------------------------
//! Get whether the memory operand has shift used.
ASMJIT_INLINE bool hasShift() const {
return (_vmem.flags & kX86MemShiftMask) != 0;
}
//! Get memory operand index scale (0, 1, 2 or 3).
ASMJIT_INLINE uint32_t getShift() const {
return _vmem.flags >> kX86MemShiftIndex;
}
//! Set memory operand index scale (0, 1, 2 or 3).
ASMJIT_INLINE X86Mem& setShift(uint32_t shift) {
_packed[0].u32[0] &=~IntUtil::pack32_4x8(0x00, 0x00, 0x00, kX86MemShiftMask);
_packed[0].u32[0] |= IntUtil::pack32_4x8(0x00, 0x00, 0x00, shift << kX86MemShiftIndex);
return *this;
}
// --------------------------------------------------------------------------
// [Displacement]
// --------------------------------------------------------------------------
//! Get memory operand relative displacement.
ASMJIT_INLINE int32_t getDisplacement() const {
return _vmem.displacement;
}
//! Set memory operand relative displacement.
ASMJIT_INLINE X86Mem& setDisplacement(int32_t disp) {
_vmem.displacement = disp;
return *this;
}
//! Reset memory operand relative displacement.
ASMJIT_INLINE X86Mem& resetDisplacement(int32_t disp) {
_vmem.displacement = 0;
return *this;
}
//! Adjust memory operand relative displacement by `disp`.
ASMJIT_INLINE X86Mem& adjust(int32_t disp) {
_vmem.displacement += disp;
return *this;
}
//! Get new memory operand adjusted by `disp`.
ASMJIT_INLINE X86Mem adjusted(int32_t disp) const {
X86Mem result(*this);
result.adjust(disp);
return result;
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE X86Mem& operator=(const X86Mem& other) {
_copy(other);
return *this;
}
ASMJIT_INLINE bool operator==(const X86Mem& other) const {
return (_packed[0] == other._packed[0]) & (_packed[1] == other._packed[1]) ;
}
ASMJIT_INLINE bool operator!=(const X86Mem& other) const {
return !(*this == other);
}
// --------------------------------------------------------------------------
// [Static]
// --------------------------------------------------------------------------
static ASMJIT_INLINE uint32_t _getGpdFlags(const Operand& base) {
return (base._vreg.size & 0x4) << (kX86MemGpdIndex - 2);
}
};
#endif // !ASMJIT_EXPORTS_X86OPERAND_REGS
// ============================================================================
// [asmjit::x86]
// ============================================================================
namespace x86 {
// ============================================================================
// [asmjit::x86 - Reg]
// ============================================================================
//! No Gp register, can be used only within `X86Mem` operand.
ASMJIT_VAR const X86GpReg noGpReg;
ASMJIT_VAR const X86GpReg al; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const X86GpReg cl; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const X86GpReg dl; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const X86GpReg bl; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const X86GpReg spl; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg bpl; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg sil; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg dil; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r8b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r9b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r10b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r11b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r12b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r13b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r14b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg r15b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const X86GpReg ah; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const X86GpReg ch; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const X86GpReg dh; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const X86GpReg bh; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const X86GpReg ax; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg cx; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg dx; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg bx; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg sp; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg bp; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg si; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg di; //!< 16-bit Gpw register.
ASMJIT_VAR const X86GpReg r8w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg r9w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg r10w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg r11w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg r12w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg r13w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg r14w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg r15w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const X86GpReg eax; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg ecx; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg edx; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg ebx; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg esp; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg ebp; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg esi; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg edi; //!< 32-bit Gpd register.
ASMJIT_VAR const X86GpReg r8d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg r9d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg r10d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg r11d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg r12d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg r13d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg r14d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg r15d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const X86GpReg rax; //!< 64-bit Gpq register (X64).
ASMJIT_VAR const X86GpReg rcx; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg rdx; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg rbx; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg rsp; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg rbp; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg rsi; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg rdi; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r8; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r9; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r10; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r11; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r12; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r13; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r14; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86GpReg r15; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const X86FpReg fp0; //!< 80-bit Fp register.
ASMJIT_VAR const X86FpReg fp1; //!< 80-bit Fp register.
ASMJIT_VAR const X86FpReg fp2; //!< 80-bit Fp register.
ASMJIT_VAR const X86FpReg fp3; //!< 80-bit Fp register.
ASMJIT_VAR const X86FpReg fp4; //!< 80-bit Fp register.
ASMJIT_VAR const X86FpReg fp5; //!< 80-bit Fp register.
ASMJIT_VAR const X86FpReg fp6; //!< 80-bit Fp register.
ASMJIT_VAR const X86FpReg fp7; //!< 80-bit Fp register.
ASMJIT_VAR const X86MmReg mm0; //!< 64-bit Mm register.
ASMJIT_VAR const X86MmReg mm1; //!< 64-bit Mm register.
ASMJIT_VAR const X86MmReg mm2; //!< 64-bit Mm register.
ASMJIT_VAR const X86MmReg mm3; //!< 64-bit Mm register.
ASMJIT_VAR const X86MmReg mm4; //!< 64-bit Mm register.
ASMJIT_VAR const X86MmReg mm5; //!< 64-bit Mm register.
ASMJIT_VAR const X86MmReg mm6; //!< 64-bit Mm register.
ASMJIT_VAR const X86MmReg mm7; //!< 64-bit Mm register.
ASMJIT_VAR const X86XmmReg xmm0; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm1; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm2; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm3; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm4; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm5; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm6; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm7; //!< 128-bit Xmm register.
ASMJIT_VAR const X86XmmReg xmm8; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86XmmReg xmm9; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86XmmReg xmm10; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86XmmReg xmm11; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86XmmReg xmm12; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86XmmReg xmm13; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86XmmReg xmm14; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86XmmReg xmm15; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const X86YmmReg ymm0; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm1; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm2; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm3; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm4; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm5; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm6; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm7; //!< 256-bit Ymm register.
ASMJIT_VAR const X86YmmReg ymm8; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86YmmReg ymm9; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86YmmReg ymm10; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86YmmReg ymm11; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86YmmReg ymm12; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86YmmReg ymm13; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86YmmReg ymm14; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86YmmReg ymm15; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const X86SegReg cs; //!< Cs segment register.
ASMJIT_VAR const X86SegReg ss; //!< Ss segment register.
ASMJIT_VAR const X86SegReg ds; //!< Ds segment register.
ASMJIT_VAR const X86SegReg es; //!< Es segment register.
ASMJIT_VAR const X86SegReg fs; //!< Fs segment register.
ASMJIT_VAR const X86SegReg gs; //!< Gs segment register.
// This is only defined by `x86operand_regs.cpp` when exporting registers.
#if !defined(ASMJIT_EXPORTS_X86OPERAND_REGS)
//! Create 8-bit Gpb-lo register operand.
static ASMJIT_INLINE X86GpReg gpb_lo(uint32_t index) { return X86GpReg(kX86RegTypeGpbLo, index, 1); }
//! Create 8-bit Gpb-hi register operand.
static ASMJIT_INLINE X86GpReg gpb_hi(uint32_t index) { return X86GpReg(kX86RegTypeGpbHi, index, 1); }
//! Create 16-bit Gpw register operand.
static ASMJIT_INLINE X86GpReg gpw(uint32_t index) { return X86GpReg(kX86RegTypeGpw, index, 2); }
//! Create 32-bit Gpd register operand.
static ASMJIT_INLINE X86GpReg gpd(uint32_t index) { return X86GpReg(kX86RegTypeGpd, index, 4); }
//! Create 64-bit Gpq register operand (X64).
static ASMJIT_INLINE X86GpReg gpq(uint32_t index) { return X86GpReg(kX86RegTypeGpq, index, 8); }
//! Create 80-bit Fp register operand.
static ASMJIT_INLINE X86FpReg fp(uint32_t index) { return X86FpReg(kX86RegTypeFp, index, 10); }
//! Create 64-bit Mm register operand.
static ASMJIT_INLINE X86MmReg mm(uint32_t index) { return X86MmReg(kX86RegTypeMm, index, 8); }
//! Create 128-bit Xmm register operand.
static ASMJIT_INLINE X86XmmReg xmm(uint32_t index) { return X86XmmReg(kX86RegTypeXmm, index, 16); }
//! Create 256-bit Ymm register operand.
static ASMJIT_INLINE X86YmmReg ymm(uint32_t index) { return X86YmmReg(kX86RegTypeYmm, index, 32); }
// ============================================================================
// [asmjit::x86 - Ptr (Reg)]
// ============================================================================
//! Create `[base.reg + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpReg& base, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, disp, size);
}
//! Create `[base.reg + (index.reg << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpReg& base, const X86GpReg& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, index, shift, disp, size);
}
//! Create `[base.reg + (xmm.reg << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpReg& base, const X86XmmReg& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, index, shift, disp, size);
}
//! Create `[base.reg + (ymm.reg << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpReg& base, const X86YmmReg& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, index, shift, disp, size);
}
//! Create `[label + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const Label& label, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(label, disp, size);
}
//! Create `[label + (index.reg << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const Label& label, const X86GpReg& index, uint32_t shift, int32_t disp = 0, uint32_t size = 0) { \
return X86Mem(label, index, shift, disp, size); \
}
//! Create `[pAbs + disp]` absolute memory operand with no/custom size information.
ASMJIT_API X86Mem ptr_abs(Ptr pAbs, int32_t disp = 0, uint32_t size = 0);
//! Create `[pAbs + (index.reg << shift) + disp]` absolute memory operand with no/custom size information.
ASMJIT_API X86Mem ptr_abs(Ptr pAbs, const X86Reg& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0);
//! \internal
#define ASMJIT_EXPAND_PTR_REG(_Prefix_, _Size_) \
/*! Create `[base.reg + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpReg& base, int32_t disp = 0) { \
return X86Mem(base, disp, _Size_); \
} \
/*! Create `[base.reg + (index.reg << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpReg& base, const X86GpReg& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr(base, index, shift, disp, _Size_); \
} \
/*! Create `[base.reg + (xmm.reg << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpReg& base, const X86XmmReg& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr(base, index, shift, disp, _Size_); \
} \
/*! Create `[base.reg + (ymm.reg << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpReg& base, const X86YmmReg& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr(base, index, shift, disp, _Size_); \
} \
/*! Create `[label + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const Label& label, int32_t disp = 0) { \
return ptr(label, disp, _Size_); \
} \
/*! Create `[label + (index.reg << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const Label& label, const X86GpReg& index, uint32_t shift, int32_t disp = 0) { \
return ptr(label, index, shift, disp, _Size_); \
} \
/*! Create `[pAbs + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr##_abs(Ptr pAbs, int32_t disp = 0) { \
return ptr_abs(pAbs, disp, _Size_); \
} \
/*! Create `[pAbs + (index.reg << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr##_abs(Ptr pAbs, const X86GpReg& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr_abs(pAbs, index, shift, disp, _Size_); \
} \
/*! Create `[pAbs + (xmm.reg << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr##_abs(Ptr pAbs, const X86XmmReg& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr_abs(pAbs, index, shift, disp, _Size_); \
} \
/*! Create `[pAbs + (ymm.reg << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr##_abs(Ptr pAbs, const X86YmmReg& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr_abs(pAbs, index, shift, disp, _Size_); \
}
ASMJIT_EXPAND_PTR_REG(byte, 1)
ASMJIT_EXPAND_PTR_REG(word, 2)
ASMJIT_EXPAND_PTR_REG(dword, 4)
ASMJIT_EXPAND_PTR_REG(qword, 8)
ASMJIT_EXPAND_PTR_REG(tword, 10)
ASMJIT_EXPAND_PTR_REG(oword, 16)
ASMJIT_EXPAND_PTR_REG(yword, 32)
ASMJIT_EXPAND_PTR_REG(zword, 64)
#undef ASMJIT_EXPAND_PTR_REG
// ============================================================================
// [asmjit::x86 - Ptr (Var)]
// ============================================================================
#if !defined(ASMJIT_DISABLE_COMPILER)
//! Create `[base.var + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpVar& base, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, disp, size);
}
//! Create `[base.var + (index.var << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpVar& base, const X86GpVar& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, index, shift, disp, size);
}
//! Create `[base.var + (xmm.var << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpVar& base, const X86XmmVar& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, index, shift, disp, size);
}
//! Create `[base.var + (ymm.var << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const X86GpVar& base, const X86YmmVar& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0) {
return X86Mem(base, index, shift, disp, size);
}
//! Create `[label + (index.var << shift) + disp]` memory operand with no/custom size information.
static ASMJIT_INLINE X86Mem ptr(const Label& label, const X86GpVar& index, uint32_t shift, int32_t disp = 0, uint32_t size = 0) { \
return X86Mem(label, index, shift, disp, size); \
}
//! Create `[pAbs + (index.var << shift) + disp]` absolute memory operand with no/custom size information.
ASMJIT_API X86Mem ptr_abs(Ptr pAbs, const X86Var& index, uint32_t shift = 0, int32_t disp = 0, uint32_t size = 0);
//! \internal
#define ASMJIT_EXPAND_PTR_VAR(_Prefix_, _Size_) \
/*! Create `[base.var + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpVar& base, int32_t disp = 0) { \
return X86Mem(base, disp, _Size_); \
} \
/*! Create `[base.var + (index.var << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpVar& base, const X86GpVar& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr(base, index, shift, disp, _Size_); \
} \
/*! Create `[base.var + (xmm.var << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpVar& base, const X86XmmVar& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr(base, index, shift, disp, _Size_); \
} \
/*! Create `[base.var + (ymm.var << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const X86GpVar& base, const X86YmmVar& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr(base, index, shift, disp, _Size_); \
} \
/*! Create `[label + (index.var << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr(const Label& label, const X86GpVar& index, uint32_t shift, int32_t disp = 0) { \
return ptr(label, index, shift, disp, _Size_); \
} \
/*! Create `[pAbs + (index.var << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr##_abs(Ptr pAbs, const X86GpVar& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr_abs(pAbs, reinterpret_cast<const X86Var&>(index), shift, disp, _Size_); \
} \
/*! Create `[pAbs + (xmm.var << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr##_abs(Ptr pAbs, const X86XmmVar& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr_abs(pAbs, reinterpret_cast<const X86Var&>(index), shift, disp, _Size_); \
} \
/*! Create `[pAbs + (ymm.var << shift) + disp]` memory operand. */ \
static ASMJIT_INLINE X86Mem _Prefix_##_ptr##_abs(Ptr pAbs, const X86YmmVar& index, uint32_t shift = 0, int32_t disp = 0) { \
return ptr_abs(pAbs, reinterpret_cast<const X86Var&>(index), shift, disp, _Size_); \
}
ASMJIT_EXPAND_PTR_VAR(byte, 1)
ASMJIT_EXPAND_PTR_VAR(word, 2)
ASMJIT_EXPAND_PTR_VAR(dword, 4)
ASMJIT_EXPAND_PTR_VAR(qword, 8)
ASMJIT_EXPAND_PTR_VAR(tword, 10)
ASMJIT_EXPAND_PTR_VAR(oword, 16)
ASMJIT_EXPAND_PTR_VAR(yword, 32)
ASMJIT_EXPAND_PTR_VAR(zword, 64)
#undef ASMJIT_EXPAND_PTR_VAR
#endif // !ASMJIT_DISABLE_COMPILER
#endif // !ASMJIT_EXPORTS_X86OPERAND_REGS
} // x86 namespace
//! \}
} // asmjit namespace
#undef _OP_ID
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_X86_X86OPERAND_H
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
#define ASMJIT_EXPORTS_X86OPERAND_REGS
// [Guard]
#include "../build.h"
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
// [Dependencies - AsmJit]
#include "../x86/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// Prevent static initialization.
//
// Remap all classes to POD structs so they can be statically initialized
// without calling a constructor. Compiler will store these in data section.
struct X86GpReg { Operand::VRegOp data; };
struct X86FpReg { Operand::VRegOp data; };
struct X86MmReg { Operand::VRegOp data; };
struct X86XmmReg { Operand::VRegOp data; };
struct X86YmmReg { Operand::VRegOp data; };
struct X86SegReg { Operand::VRegOp data; };
namespace x86 {
// ============================================================================
// [asmjit::x86::Registers]
// ============================================================================
#define REG(_Class_, _Name_, _Type_, _Index_, _Size_) \
const _Class_ _Name_ = {{ \
kOperandTypeReg, _Size_, { ((_Type_) << 8) + _Index_ }, kInvalidValue, {{ kInvalidVar, 0 }} \
}}
REG(X86GpReg, noGpReg, kInvalidReg, kInvalidReg, 0);
REG(X86GpReg, al, kX86RegTypeGpbLo, kX86RegIndexAx, 1);
REG(X86GpReg, cl, kX86RegTypeGpbLo, kX86RegIndexCx, 1);
REG(X86GpReg, dl, kX86RegTypeGpbLo, kX86RegIndexDx, 1);
REG(X86GpReg, bl, kX86RegTypeGpbLo, kX86RegIndexBx, 1);
REG(X86GpReg, spl, kX86RegTypeGpbLo, kX86RegIndexSp, 1);
REG(X86GpReg, bpl, kX86RegTypeGpbLo, kX86RegIndexBp, 1);
REG(X86GpReg, sil, kX86RegTypeGpbLo, kX86RegIndexSi, 1);
REG(X86GpReg, dil, kX86RegTypeGpbLo, kX86RegIndexDi, 1);
REG(X86GpReg, r8b, kX86RegTypeGpbLo, 8, 1);
REG(X86GpReg, r9b, kX86RegTypeGpbLo, 9, 1);
REG(X86GpReg, r10b, kX86RegTypeGpbLo, 10, 1);
REG(X86GpReg, r11b, kX86RegTypeGpbLo, 11, 1);
REG(X86GpReg, r12b, kX86RegTypeGpbLo, 12, 1);
REG(X86GpReg, r13b, kX86RegTypeGpbLo, 13, 1);
REG(X86GpReg, r14b, kX86RegTypeGpbLo, 14, 1);
REG(X86GpReg, r15b, kX86RegTypeGpbLo, 15, 1);
REG(X86GpReg, ah, kX86RegTypeGpbHi, kX86RegIndexAx, 1);
REG(X86GpReg, ch, kX86RegTypeGpbHi, kX86RegIndexCx, 1);
REG(X86GpReg, dh, kX86RegTypeGpbHi, kX86RegIndexDx, 1);
REG(X86GpReg, bh, kX86RegTypeGpbHi, kX86RegIndexBx, 1);
REG(X86GpReg, ax, kX86RegTypeGpw, kX86RegIndexAx, 2);
REG(X86GpReg, cx, kX86RegTypeGpw, kX86RegIndexCx, 2);
REG(X86GpReg, dx, kX86RegTypeGpw, kX86RegIndexDx, 2);
REG(X86GpReg, bx, kX86RegTypeGpw, kX86RegIndexBx, 2);
REG(X86GpReg, sp, kX86RegTypeGpw, kX86RegIndexSp, 2);
REG(X86GpReg, bp, kX86RegTypeGpw, kX86RegIndexBp, 2);
REG(X86GpReg, si, kX86RegTypeGpw, kX86RegIndexSi, 2);
REG(X86GpReg, di, kX86RegTypeGpw, kX86RegIndexDi, 2);
REG(X86GpReg, r8w, kX86RegTypeGpw, 8, 2);
REG(X86GpReg, r9w, kX86RegTypeGpw, 9, 2);
REG(X86GpReg, r10w, kX86RegTypeGpw, 10, 2);
REG(X86GpReg, r11w, kX86RegTypeGpw, 11, 2);
REG(X86GpReg, r12w, kX86RegTypeGpw, 12, 2);
REG(X86GpReg, r13w, kX86RegTypeGpw, 13, 2);
REG(X86GpReg, r14w, kX86RegTypeGpw, 14, 2);
REG(X86GpReg, r15w, kX86RegTypeGpw, 15, 2);
REG(X86GpReg, eax, kX86RegTypeGpd, kX86RegIndexAx, 4);
REG(X86GpReg, ecx, kX86RegTypeGpd, kX86RegIndexCx, 4);
REG(X86GpReg, edx, kX86RegTypeGpd, kX86RegIndexDx, 4);
REG(X86GpReg, ebx, kX86RegTypeGpd, kX86RegIndexBx, 4);
REG(X86GpReg, esp, kX86RegTypeGpd, kX86RegIndexSp, 4);
REG(X86GpReg, ebp, kX86RegTypeGpd, kX86RegIndexBp, 4);
REG(X86GpReg, esi, kX86RegTypeGpd, kX86RegIndexSi, 4);
REG(X86GpReg, edi, kX86RegTypeGpd, kX86RegIndexDi, 4);
REG(X86GpReg, r8d, kX86RegTypeGpd, 8, 4);
REG(X86GpReg, r9d, kX86RegTypeGpd, 9, 4);
REG(X86GpReg, r10d, kX86RegTypeGpd, 10, 4);
REG(X86GpReg, r11d, kX86RegTypeGpd, 11, 4);
REG(X86GpReg, r12d, kX86RegTypeGpd, 12, 4);
REG(X86GpReg, r13d, kX86RegTypeGpd, 13, 4);
REG(X86GpReg, r14d, kX86RegTypeGpd, 14, 4);
REG(X86GpReg, r15d, kX86RegTypeGpd, 15, 4);
REG(X86GpReg, rax, kX86RegTypeGpq, kX86RegIndexAx, 8);
REG(X86GpReg, rcx, kX86RegTypeGpq, kX86RegIndexCx, 8);
REG(X86GpReg, rdx, kX86RegTypeGpq, kX86RegIndexDx, 8);
REG(X86GpReg, rbx, kX86RegTypeGpq, kX86RegIndexBx, 8);
REG(X86GpReg, rsp, kX86RegTypeGpq, kX86RegIndexSp, 8);
REG(X86GpReg, rbp, kX86RegTypeGpq, kX86RegIndexBp, 8);
REG(X86GpReg, rsi, kX86RegTypeGpq, kX86RegIndexSi, 8);
REG(X86GpReg, rdi, kX86RegTypeGpq, kX86RegIndexDi, 8);
REG(X86GpReg, r8, kX86RegTypeGpq, 8, 8);
REG(X86GpReg, r9, kX86RegTypeGpq, 9, 8);
REG(X86GpReg, r10, kX86RegTypeGpq, 10, 8);
REG(X86GpReg, r11, kX86RegTypeGpq, 11, 8);
REG(X86GpReg, r12, kX86RegTypeGpq, 12, 8);
REG(X86GpReg, r13, kX86RegTypeGpq, 13, 8);
REG(X86GpReg, r14, kX86RegTypeGpq, 14, 8);
REG(X86GpReg, r15, kX86RegTypeGpq, 15, 8);
REG(X86FpReg, fp0, kX86RegTypeFp, 0, 10);
REG(X86FpReg, fp1, kX86RegTypeFp, 1, 10);
REG(X86FpReg, fp2, kX86RegTypeFp, 2, 10);
REG(X86FpReg, fp3, kX86RegTypeFp, 3, 10);
REG(X86FpReg, fp4, kX86RegTypeFp, 4, 10);
REG(X86FpReg, fp5, kX86RegTypeFp, 5, 10);
REG(X86FpReg, fp6, kX86RegTypeFp, 6, 10);
REG(X86FpReg, fp7, kX86RegTypeFp, 7, 10);
REG(X86MmReg, mm0, kX86RegTypeMm, 0, 8);
REG(X86MmReg, mm1, kX86RegTypeMm, 1, 8);
REG(X86MmReg, mm2, kX86RegTypeMm, 2, 8);
REG(X86MmReg, mm3, kX86RegTypeMm, 3, 8);
REG(X86MmReg, mm4, kX86RegTypeMm, 4, 8);
REG(X86MmReg, mm5, kX86RegTypeMm, 5, 8);
REG(X86MmReg, mm6, kX86RegTypeMm, 6, 8);
REG(X86MmReg, mm7, kX86RegTypeMm, 7, 8);
REG(X86XmmReg, xmm0, kX86RegTypeXmm, 0, 16);
REG(X86XmmReg, xmm1, kX86RegTypeXmm, 1, 16);
REG(X86XmmReg, xmm2, kX86RegTypeXmm, 2, 16);
REG(X86XmmReg, xmm3, kX86RegTypeXmm, 3, 16);
REG(X86XmmReg, xmm4, kX86RegTypeXmm, 4, 16);
REG(X86XmmReg, xmm5, kX86RegTypeXmm, 5, 16);
REG(X86XmmReg, xmm6, kX86RegTypeXmm, 6, 16);
REG(X86XmmReg, xmm7, kX86RegTypeXmm, 7, 16);
REG(X86XmmReg, xmm8, kX86RegTypeXmm, 8, 16);
REG(X86XmmReg, xmm9, kX86RegTypeXmm, 9, 16);
REG(X86XmmReg, xmm10, kX86RegTypeXmm, 10, 16);
REG(X86XmmReg, xmm11, kX86RegTypeXmm, 11, 16);
REG(X86XmmReg, xmm12, kX86RegTypeXmm, 12, 16);
REG(X86XmmReg, xmm13, kX86RegTypeXmm, 13, 16);
REG(X86XmmReg, xmm14, kX86RegTypeXmm, 14, 16);
REG(X86XmmReg, xmm15, kX86RegTypeXmm, 15, 16);
REG(X86YmmReg, ymm0, kX86RegTypeYmm, 0, 32);
REG(X86YmmReg, ymm1, kX86RegTypeYmm, 1, 32);
REG(X86YmmReg, ymm2, kX86RegTypeYmm, 2, 32);
REG(X86YmmReg, ymm3, kX86RegTypeYmm, 3, 32);
REG(X86YmmReg, ymm4, kX86RegTypeYmm, 4, 32);
REG(X86YmmReg, ymm5, kX86RegTypeYmm, 5, 32);
REG(X86YmmReg, ymm6, kX86RegTypeYmm, 6, 32);
REG(X86YmmReg, ymm7, kX86RegTypeYmm, 7, 32);
REG(X86YmmReg, ymm8, kX86RegTypeYmm, 8, 32);
REG(X86YmmReg, ymm9, kX86RegTypeYmm, 9, 32);
REG(X86YmmReg, ymm10, kX86RegTypeYmm, 10, 32);
REG(X86YmmReg, ymm11, kX86RegTypeYmm, 11, 32);
REG(X86YmmReg, ymm12, kX86RegTypeYmm, 12, 32);
REG(X86YmmReg, ymm13, kX86RegTypeYmm, 13, 32);
REG(X86YmmReg, ymm14, kX86RegTypeYmm, 14, 32);
REG(X86YmmReg, ymm15, kX86RegTypeYmm, 15, 32);
REG(X86SegReg, cs, kX86RegTypeSeg, kX86SegCs, 2);
REG(X86SegReg, ss, kX86RegTypeSeg, kX86SegSs, 2);
REG(X86SegReg, ds, kX86RegTypeSeg, kX86SegDs, 2);
REG(X86SegReg, es, kX86RegTypeSeg, kX86SegEs, 2);
REG(X86SegReg, fs, kX86RegTypeSeg, kX86SegFs, 2);
REG(X86SegReg, gs, kX86RegTypeSeg, kX86SegGs, 2);
#undef REG
} // x86 namespace
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER) && (defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64))
// [Dependencies - AsmJit]
#include "../base/containers.h"
#include "../x86/x86scheduler_p.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [Internals]
// ============================================================================
//! \internal
struct X86ScheduleData {
//! Registers read by the instruction.
X86RegMask regsIn;
//! Registers written by the instruction.
X86RegMask regsOut;
//! Flags read by the instruction.
uint8_t flagsIn;
//! Flags written by the instruction.
uint8_t flagsOut;
//! How many `uops` or `cycles` the instruction takes.
uint8_t ops;
//! Instruction latency.
uint8_t latency;
//! Which ports the instruction can run at.
uint16_t ports;
//! \internal
uint16_t reserved;
//! All instructions that this instruction depends on.
PodList<InstNode*>::Link* dependsOn;
//! All instructions that use the result of this instruction.
PodList<InstNode*>::Link* usedBy;
};
// ============================================================================
// [asmjit::X86Scheduler - Construction / Destruction]
// ============================================================================
X86Scheduler::X86Scheduler(X86Compiler* compiler, const X86CpuInfo* cpuInfo) :
_compiler(compiler),
_cpuInfo(cpuInfo) {}
X86Scheduler::~X86Scheduler() {}
// ============================================================================
// [asmjit::X86Scheduler - Run]
// ============================================================================
Error X86Scheduler::run(Node* start, Node* stop) {
/*
ASMJIT_TLOG("[Schedule] === Begin ===");
Zone zone(8096 - kZoneOverhead);
Node* node_ = start;
while (node_ != stop) {
Node* next = node_->getNext();
ASMJIT_ASSERT(node_->getType() == kNodeTypeInst);
printf(" %s\n", X86Util::getInstInfo(static_cast<InstNode*>(node_)->getCode()).getInstName());
node_ = next;
}
ASMJIT_TLOG("[Schedule] === End ===");
*/
return kErrorOk;
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER && (ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64)
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_X86SCHEDULER_P_H
#define _ASMJIT_X86_X86SCHEDULER_P_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../x86/x86compiler.h"
#include "../x86/x86context_p.h"
#include "../x86/x86cpuinfo.h"
#include "../x86/x86inst.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::X86Scheduler]
// ============================================================================
//! \internal
//!
//! X86 scheduler.
struct X86Scheduler {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
X86Scheduler(X86Compiler* compiler, const X86CpuInfo* cpuInfo);
~X86Scheduler();
// --------------------------------------------------------------------------
// [Run]
// --------------------------------------------------------------------------
Error run(Node* start, Node* stop);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Attached compiler.
X86Compiler* _compiler;
//! CPU information used for scheduling.
const X86CpuInfo* _cpuInfo;
};
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_X86_X86SCHEDULER_P_H
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#ifdef LEPTON_USE_JIT
#include "asmjit.h"
#endif
namespace Lepton { namespace Lepton {
...@@ -87,6 +90,13 @@ private: ...@@ -87,6 +90,13 @@ private:
mutable std::vector<double> workspace; mutable std::vector<double> workspace;
mutable std::vector<double> argValues; mutable std::vector<double> argValues;
std::map<std::string, double> dummyVariables; std::map<std::string, double> dummyVariables;
void* jitCode;
#ifdef LEPTON_USE_JIT
void generateJitCode();
void generateSingleArgCall(asmjit::X86Compiler& c, asmjit::X86XmmVar& dest, asmjit::X86XmmVar& arg, double (*function)(double));
std::vector<double> constants;
asmjit::JitRuntime runtime;
#endif
}; };
} // namespace Lepton } // namespace Lepton
......
/* -------------------------------------------------------------------------- * /* -------------------------------------------------------------------------- *
* Lepton * * Lepton *
* -------------------------------------------------------------------------- * * -------------------------------------------------------------------------- *
* This is part of the Lepton expression parser originating from * * This is part of the Lepton expression parser originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of * * Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2013 Stanford University and the Authors. * * Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
* Permission is hereby granted, free of charge, to any person obtaining a * * Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), * * copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation * * to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the * * and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: * * Software is furnished to do so, subject to the following conditions: *
* * * *
* The above copyright notice and this permission notice shall be included in * * The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. * * all copies or substantial portions of the Software. *
* * * *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "lepton/CompiledExpression.h" #include "lepton/CompiledExpression.h"
#include "lepton/Operation.h" #include "lepton/Operation.h"
#include "lepton/ParsedExpression.h" #include "lepton/ParsedExpression.h"
#include <utility> #include <utility>
using namespace Lepton; using namespace Lepton;
using namespace std; using namespace std;
#ifdef LEPTON_USE_JIT
CompiledExpression::CompiledExpression() { using namespace asmjit;
} #endif
CompiledExpression::CompiledExpression(const ParsedExpression& expression) { CompiledExpression::CompiledExpression() : jitCode(NULL) {
ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized. }
vector<pair<ExpressionTreeNode, int> > temps;
compileExpression(expr.getRootNode(), temps); CompiledExpression::CompiledExpression(const ParsedExpression& expression) : jitCode(NULL) {
} ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized.
vector<pair<ExpressionTreeNode, int> > temps;
CompiledExpression::~CompiledExpression() { compileExpression(expr.getRootNode(), temps);
for (int i = 0; i < (int) operation.size(); i++) int maxArguments = 1;
if (operation[i] != NULL) for (int i = 0; i < (int) operation.size(); i++)
delete operation[i]; if (operation[i]->getNumArguments() > maxArguments)
} maxArguments = operation[i]->getNumArguments();
argValues.resize(maxArguments);
CompiledExpression::CompiledExpression(const CompiledExpression& expression) { #ifdef LEPTON_USE_JIT
*this = expression; generateJitCode();
} #endif
}
CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression) {
arguments = expression.arguments; CompiledExpression::~CompiledExpression() {
target = expression.target; for (int i = 0; i < (int) operation.size(); i++)
variableIndices = expression.variableIndices; if (operation[i] != NULL)
variableNames = expression.variableNames; delete operation[i];
workspace.resize(expression.workspace.size()); }
argValues.resize(expression.argValues.size());
operation.resize(expression.operation.size()); CompiledExpression::CompiledExpression(const CompiledExpression& expression) : jitCode(NULL) {
for (int i = 0; i < (int) operation.size(); i++) *this = expression;
operation[i] = expression.operation[i]->clone(); }
return *this;
} CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression) {
arguments = expression.arguments;
void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) { target = expression.target;
if (findTempIndex(node, temps) != -1) variableIndices = expression.variableIndices;
return; // We have already processed a node identical to this one. variableNames = expression.variableNames;
workspace.resize(expression.workspace.size());
// Process the child nodes. argValues.resize(expression.argValues.size());
operation.resize(expression.operation.size());
vector<int> args; for (int i = 0; i < (int) operation.size(); i++)
for (int i = 0; i < node.getChildren().size(); i++) { operation[i] = expression.operation[i]->clone();
compileExpression(node.getChildren()[i], temps); #ifdef LEPTON_USE_JIT
args.push_back(findTempIndex(node.getChildren()[i], temps)); generateJitCode();
} #endif
return *this;
// Process this node. }
if (node.getOperation().getId() == Operation::VARIABLE) { void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
variableIndices[node.getOperation().getName()] = (int) workspace.size(); if (findTempIndex(node, temps) != -1)
variableNames.insert(node.getOperation().getName()); return; // We have already processed a node identical to this one.
}
else { // Process the child nodes.
int stepIndex = (int) arguments.size();
arguments.push_back(vector<int>()); vector<int> args;
target.push_back((int) workspace.size()); for (int i = 0; i < node.getChildren().size(); i++) {
operation.push_back(node.getOperation().clone()); compileExpression(node.getChildren()[i], temps);
if (args.size() == 0) args.push_back(findTempIndex(node.getChildren()[i], temps));
arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there. }
else {
// If the arguments are sequential, we can just pass a pointer to the first one. // Process this node.
bool sequential = true; if (node.getOperation().getId() == Operation::VARIABLE) {
for (int i = 1; i < args.size(); i++) variableIndices[node.getOperation().getName()] = (int) workspace.size();
if (args[i] != args[i-1]+1) variableNames.insert(node.getOperation().getName());
sequential = false; }
if (sequential) else {
arguments[stepIndex].push_back(args[0]); int stepIndex = (int) arguments.size();
else { arguments.push_back(vector<int>());
arguments[stepIndex] = args; target.push_back((int) workspace.size());
if (args.size() > argValues.size()) operation.push_back(node.getOperation().clone());
argValues.resize(args.size(), 0.0); if (args.size() == 0)
} arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there.
} else {
} // If the arguments are sequential, we can just pass a pointer to the first one.
temps.push_back(make_pair(node, workspace.size()));
workspace.push_back(0.0); bool sequential = true;
} for (int i = 1; i < args.size(); i++)
if (args[i] != args[i-1]+1)
int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) { sequential = false;
for (int i = 0; i < (int) temps.size(); i++) if (sequential)
if (temps[i].first == node) arguments[stepIndex].push_back(args[0]);
return i; else
return -1; arguments[stepIndex] = args;
} }
}
const set<string>& CompiledExpression::getVariables() const { temps.push_back(make_pair(node, workspace.size()));
return variableNames; workspace.push_back(0.0);
} }
double& CompiledExpression::getVariableReference(const string& name) { int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
map<string, int>::iterator index = variableIndices.find(name); for (int i = 0; i < (int) temps.size(); i++)
if (index == variableIndices.end()) if (temps[i].first == node)
throw Exception("getVariableReference: Unknown variable '"+name+"'"); return i;
return workspace[index->second]; return -1;
} }
double CompiledExpression::evaluate() const { const set<string>& CompiledExpression::getVariables() const {
// Loop over the operations and evaluate each one. return variableNames;
}
for (int step = 0; step < operation.size(); step++) {
const vector<int>& args = arguments[step]; double& CompiledExpression::getVariableReference(const string& name) {
if (args.size() == 1) map<string, int>::iterator index = variableIndices.find(name);
workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables); if (index == variableIndices.end())
else { throw Exception("getVariableReference: Unknown variable '"+name+"'");
for (int i = 0; i < args.size(); i++) return workspace[index->second];
argValues[i] = workspace[args[i]]; }
workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
} double CompiledExpression::evaluate() const {
} #ifdef LEPTON_USE_JIT
return workspace[workspace.size()-1]; return ((double (*)()) jitCode)();
} #else
// Loop over the operations and evaluate each one.
for (int step = 0; step < operation.size(); step++) {
const vector<int>& args = arguments[step];
if (args.size() == 1)
workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables);
else {
for (int i = 0; i < args.size(); i++)
argValues[i] = workspace[args[i]];
workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
}
}
return workspace[workspace.size()-1];
#endif
}
#ifdef LEPTON_USE_JIT
static double evaluateOperation(Operation* op, double* args) {
map<string, double>* dummyVariables = NULL;
return op->evaluate(args, *dummyVariables);
}
void CompiledExpression::generateJitCode() {
X86Compiler c(&runtime);
c.addFunc(kFuncConvHost, FuncBuilder0<double>());
vector<X86XmmVar> workspaceVar(workspace.size());
for (int i = 0; i < (int) workspaceVar.size(); i++)
workspaceVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
X86GpVar workspacePointer(c);
X86GpVar argsPointer(c);
c.mov(workspacePointer, imm_ptr(&workspace[0]));
c.mov(argsPointer, imm_ptr(&argValues[0]));
// Load the arguments into variables.
for (set<string>::const_iterator iter = variableNames.begin(); iter != variableNames.end(); ++iter) {
map<string, int>::iterator index = variableIndices.find(*iter);
c.movsd(workspaceVar[index->second], x86::ptr(workspacePointer, 8*index->second, 0));
}
// Make a list of all constants that will be needed for evaluation.
vector<int> operationConstantIndex(operation.size(), -1);
for (int step = 0; step < (int) operation.size(); step++) {
// Find the constant value (if any) used by this operation.
Operation& op = *operation[step];
double value;
if (op.getId() == Operation::CONSTANT)
value = dynamic_cast<Operation::Constant&>(op).getValue();
else if (op.getId() == Operation::ADD_CONSTANT)
value = dynamic_cast<Operation::AddConstant&>(op).getValue();
else if (op.getId() == Operation::MULTIPLY_CONSTANT)
value = dynamic_cast<Operation::MultiplyConstant&>(op).getValue();
else if (op.getId() == Operation::RECIPROCAL)
value = 1.0;
else if (op.getId() == Operation::STEP)
value = 1.0;
else if (op.getId() == Operation::DELTA)
value = 1.0;
else
continue;
// See if we already have a variable for this constant.
for (int i = 0; i < (int) constants.size(); i++)
if (value == constants[i]) {
operationConstantIndex[step] = i;
break;
}
if (operationConstantIndex[step] == -1) {
operationConstantIndex[step] = constants.size();
constants.push_back(value);
}
}
// Load constants into variables.
vector<X86XmmVar> constantVar(constants.size());
if (constants.size() > 0) {
X86GpVar constantsPointer(c);
c.mov(constantsPointer, imm_ptr(&constants[0]));
for (int i = 0; i < (int) constants.size(); i++) {
constantVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
c.movsd(constantVar[i], x86::ptr(constantsPointer, 8*i, 0));
}
}
// Evaluate the operations.
for (int step = 0; step < (int) operation.size(); step++) {
Operation& op = *operation[step];
vector<int> args = arguments[step];
if (args.size() == 1) {
// One or more sequential arguments. Fill out the list.
for (int i = 1; i < op.getNumArguments(); i++)
args.push_back(args[0]+i);
}
// Generate instructions to execute this operation.
switch (op.getId()) {
case Operation::CONSTANT:
c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::ADD:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.addsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::SUBTRACT:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.subsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::MULTIPLY:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::DIVIDE:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.divsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::NEGATE:
c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
c.subsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::SQRT:
c.sqrtsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::EXP:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], exp);
break;
case Operation::LOG:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], log);
break;
case Operation::SIN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sin);
break;
case Operation::COS:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cos);
break;
case Operation::TAN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tan);
break;
case Operation::ASIN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], asin);
break;
case Operation::ACOS:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], acos);
break;
case Operation::ATAN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], atan);
break;
case Operation::SINH:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sinh);
break;
case Operation::COSH:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cosh);
break;
case Operation::TANH:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tanh);
break;
case Operation::STEP:
c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(18)); // Comparison mode is _CMP_LE_OQ = 18
c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::DELTA:
c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(16)); // Comparison mode is _CMP_EQ_OS = 16
c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::SQUARE:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::CUBE:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::RECIPROCAL:
c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
c.divsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::ADD_CONSTANT:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.addsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::MULTIPLY_CONSTANT:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::ABS:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], fabs);
break;
default:
// Just invoke evaluateOperation().
for (int i = 0; i < (int) args.size(); i++)
c.movsd(x86::ptr(argsPointer, 8*i, 0), workspaceVar[args[i]]);
X86GpVar fn(c, kVarTypeIntPtr);
c.mov(fn, imm_ptr((void*) evaluateOperation));
X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder2<double, Operation*, double*>());
call->setArg(0, imm_ptr(&op));
call->setArg(1, imm_ptr(&argValues[0]));
call->setRet(0, workspaceVar[target[step]]);
}
}
c.ret(workspaceVar[workspace.size()-1]);
c.endFunc();
jitCode = c.make();
}
void CompiledExpression::generateSingleArgCall(X86Compiler& c, X86XmmVar& dest, X86XmmVar& arg, double (*function)(double)) {
X86GpVar fn(c, kVarTypeIntPtr);
c.mov(fn, imm_ptr((void*) function));
X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder1<double, double>());
call->setArg(0, arg);
call->setRet(0, dest);
}
#endif
\ No newline at end of file
...@@ -127,6 +127,18 @@ void verifyInvalidExpression(const string& expression) { ...@@ -127,6 +127,18 @@ void verifyInvalidExpression(const string& expression) {
throw exception(); throw exception();
} }
/**
* Verify that two numbers have the same value.
*/
void assertNumbersEqual(double val1, double val2) {
const double inf = numeric_limits<double>::infinity();
if (val1 == val1 || val2 == val2) // If both are NaN, that's fine.
if (val1 != inf || val2 != inf) // Both infinity is also fine.
if (val1 != -inf || val2 != -inf) // Same for -infinity.
ASSERT_EQUAL_TOL(val1, val2, 1e-10);
}
/** /**
* Verify that two expressions give the same value. * Verify that two expressions give the same value.
*/ */
...@@ -137,11 +149,22 @@ void verifySameValue(const ParsedExpression& exp1, const ParsedExpression& exp2, ...@@ -137,11 +149,22 @@ void verifySameValue(const ParsedExpression& exp1, const ParsedExpression& exp2,
variables["y"] = y; variables["y"] = y;
double val1 = exp1.evaluate(variables); double val1 = exp1.evaluate(variables);
double val2 = exp2.evaluate(variables); double val2 = exp2.evaluate(variables);
const double inf = numeric_limits<double>::infinity(); assertNumbersEqual(val1, val2);
if (val1 == val1 || val2 == val2) // If both are NaN, that's fine.
if (val1 != inf || val2 != inf) // Both infinity is also fine. // Now create CompiledExpressions from them and see if those also match.
if (val1 != -inf || val2 != -inf) // Same for -infinity.
ASSERT_EQUAL_TOL(val1, val2, 1e-10); CompiledExpression compiled1 = exp1.createCompiledExpression();
CompiledExpression compiled2 = exp2.createCompiledExpression();
if (compiled1.getVariables().find("x") != compiled1.getVariables().end())
compiled1.getVariableReference("x") = x;
if (compiled1.getVariables().find("y") != compiled1.getVariables().end())
compiled1.getVariableReference("y") = y;
if (compiled2.getVariables().find("x") != compiled2.getVariables().end())
compiled2.getVariableReference("x") = x;
if (compiled2.getVariables().find("y") != compiled2.getVariables().end())
compiled2.getVariableReference("y") = y;
assertNumbersEqual(val1, compiled1.evaluate());
assertNumbersEqual(val2, compiled2.evaluate());
} }
/** /**
...@@ -171,14 +194,14 @@ void testCustomFunction(const string& expression, const string& equivalent) { ...@@ -171,14 +194,14 @@ void testCustomFunction(const string& expression, const string& equivalent) {
verifySameValue(exp1, exp2, 2.0, 3.0); verifySameValue(exp1, exp2, 2.0, 3.0);
verifySameValue(exp1, exp2, -2.0, 3.0); verifySameValue(exp1, exp2, -2.0, 3.0);
verifySameValue(exp1, exp2, 2.0, -3.0); verifySameValue(exp1, exp2, 2.0, -3.0);
ParsedExpression deriv1 = exp1.differentiate("x"); ParsedExpression deriv1 = exp1.differentiate("x").optimize();
ParsedExpression deriv2 = exp2.differentiate("x"); ParsedExpression deriv2 = exp2.differentiate("x").optimize();
verifySameValue(deriv1, deriv2, 1.0, 2.0); verifySameValue(deriv1, deriv2, 1.0, 2.0);
verifySameValue(deriv1, deriv2, 2.0, 3.0); verifySameValue(deriv1, deriv2, 2.0, 3.0);
verifySameValue(deriv1, deriv2, -2.0, 3.0); verifySameValue(deriv1, deriv2, -2.0, 3.0);
verifySameValue(deriv1, deriv2, 2.0, -3.0); verifySameValue(deriv1, deriv2, 2.0, -3.0);
ParsedExpression deriv3 = deriv1.differentiate("y"); ParsedExpression deriv3 = deriv1.differentiate("y").optimize();
ParsedExpression deriv4 = deriv2.differentiate("y"); ParsedExpression deriv4 = deriv2.differentiate("y").optimize();
verifySameValue(deriv3, deriv4, 1.0, 2.0); verifySameValue(deriv3, deriv4, 1.0, 2.0);
verifySameValue(deriv3, deriv4, 2.0, 3.0); verifySameValue(deriv3, deriv4, 2.0, 3.0);
verifySameValue(deriv3, deriv4, -2.0, 3.0); verifySameValue(deriv3, deriv4, -2.0, 3.0);
...@@ -223,6 +246,7 @@ int main() { ...@@ -223,6 +246,7 @@ int main() {
verifyEvaluation("max(x, -1)", 2.0, 3.0, 2.0); verifyEvaluation("max(x, -1)", 2.0, 3.0, 2.0);
verifyEvaluation("abs(x-y)", 2.0, 3.0, 1.0); verifyEvaluation("abs(x-y)", 2.0, 3.0, 1.0);
verifyEvaluation("delta(x)+3*delta(y-1.5)", 2.0, 1.5, 3.0); verifyEvaluation("delta(x)+3*delta(y-1.5)", 2.0, 1.5, 3.0);
verifyEvaluation("step(x-3)+y*step(x)", 2.0, 3.0, 3.0);
verifyInvalidExpression("1..2"); verifyInvalidExpression("1..2");
verifyInvalidExpression("1*(2+3"); verifyInvalidExpression("1*(2+3");
verifyInvalidExpression("5++4"); verifyInvalidExpression("5++4");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment