Added more memory addressing types to Mem operand

This commit is contained in:
kobalicek
2017-02-27 17:12:28 +01:00
parent a808b44359
commit 90c26db709
3 changed files with 56 additions and 54 deletions

View File

@@ -90,20 +90,20 @@ struct Operand_ {
kSignatureMemBaseIndexMask = kSignatureMemBaseIndexBits << kSignatureMemBaseIndexShift, kSignatureMemBaseIndexMask = kSignatureMemBaseIndexBits << kSignatureMemBaseIndexShift,
// Memory should be encoded as absolute immediate (X86|X64). // Memory should be encoded as absolute immediate (X86|X64).
// |........|........|..X.....|........| // |........|........|.XX.....|........|
kSignatureMemAbsoluteShift = 13, kSignatureMemAddrTypeShift = 13,
kSignatureMemAbsoluteBits = 0x01U, kSignatureMemAddrTypeBits = 0x03U,
kSignatureMemAbsoluteFlag = kSignatureMemAbsoluteBits << kSignatureMemAbsoluteShift, kSignatureMemAddrTypeMask = kSignatureMemAddrTypeBits << kSignatureMemAddrTypeShift,
// This memory operand represents a function argument's stack location (CodeCompiler) // This memory operand represents a function argument's stack location (CodeCompiler)
// |........|........|.X......|........| // |........|........|.X......|........|
kSignatureMemArgHomeShift = 14, kSignatureMemArgHomeShift = 15,
kSignatureMemArgHomeBits = 0x01U, kSignatureMemArgHomeBits = 0x01U,
kSignatureMemArgHomeFlag = kSignatureMemArgHomeBits << kSignatureMemArgHomeShift, kSignatureMemArgHomeFlag = kSignatureMemArgHomeBits << kSignatureMemArgHomeShift,
// This memory operand represents a virtual register's home-slot (CodeCompiler). // This memory operand represents a virtual register's home-slot (CodeCompiler).
// |........|........|X.......|........| // |........|........|X.......|........|
kSignatureMemRegHomeShift = 15, kSignatureMemRegHomeShift = 16,
kSignatureMemRegHomeBits = 0x01U, kSignatureMemRegHomeBits = 0x01U,
kSignatureMemRegHomeFlag = kSignatureMemRegHomeBits << kSignatureMemRegHomeShift kSignatureMemRegHomeFlag = kSignatureMemRegHomeBits << kSignatureMemRegHomeShift
}; };
@@ -243,16 +243,12 @@ struct Operand_ {
//! Improper use of `setSignature()` can lead to hard-to-debug errors. //! Improper use of `setSignature()` can lead to hard-to-debug errors.
ASMJIT_INLINE void setSignature(uint32_t signature) noexcept { _signature = signature; } ASMJIT_INLINE void setSignature(uint32_t signature) noexcept { _signature = signature; }
ASMJIT_INLINE bool _hasSignatureData(uint32_t bits) const noexcept { ASMJIT_INLINE bool _hasSignatureData(uint32_t bits) const noexcept { return (_signature & bits) != 0; }
return (_signature & bits) != 0;
}
//! \internal //! \internal
//! //!
//! Unpacks information from operand's signature. //! Unpacks information from operand's signature.
ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { ASMJIT_INLINE uint32_t _getSignatureData(uint32_t bits, uint32_t shift) const noexcept { return (_signature >> shift) & bits; }
return (_signature >> shift) & bits;
}
//! \internal //! \internal
//! //!
@@ -264,6 +260,9 @@ struct Operand_ {
ASMJIT_INLINE void _addSignatureData(uint32_t data) noexcept { _signature |= data; } ASMJIT_INLINE void _addSignatureData(uint32_t data) noexcept { _signature |= data; }
//! Clears specified bits in operand's signature.
ASMJIT_INLINE void _clearSignatureData(uint32_t bits, uint32_t shift) noexcept { _signature &= ~(bits << shift); }
//! Get type of the operand, see \ref OpType. //! Get type of the operand, see \ref OpType.
ASMJIT_INLINE uint32_t getOp() const noexcept { return _getSignatureData(kSignatureOpBits, kSignatureOpShift); } ASMJIT_INLINE uint32_t getOp() const noexcept { return _getSignatureData(kSignatureOpBits, kSignatureOpShift); }
//! Get if the operand is none (\ref kOpNone). //! Get if the operand is none (\ref kOpNone).
@@ -818,6 +817,20 @@ public:
//! prefix and index shift (scale). //! prefix and index shift (scale).
class Mem : public Operand { class Mem : public Operand {
public: public:
enum AddrType {
kAddrTypeDefault = 0,
kAddrTypeAbs = 1,
kAddrTypeRel = 2,
kAddrTypeWrt = 3
};
// Shortcuts.
enum SignatureMem {
kSignatureMemAbs = kAddrTypeAbs << kSignatureMemAddrTypeShift,
kSignatureMemRel = kAddrTypeRel << kSignatureMemAddrTypeShift,
kSignatureMemWrt = kAddrTypeWrt << kSignatureMemAddrTypeShift
};
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -854,15 +867,25 @@ public:
_init_packed_d2_d3(0, 0); _init_packed_d2_d3(0, 0);
} }
ASMJIT_INLINE bool isAbs() const noexcept { return _hasSignatureData(kSignatureMemAbsoluteFlag); } ASMJIT_INLINE bool hasAddrType() const noexcept { return _hasSignatureData(kSignatureMemAddrTypeMask); }
ASMJIT_INLINE uint32_t getAddrType() const noexcept { return _getSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
ASMJIT_INLINE void setAddrType(uint32_t addrType) noexcept { return _setSignatureData(addrType, kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
ASMJIT_INLINE void resetAddrType() noexcept { return _clearSignatureData(kSignatureMemAddrTypeBits, kSignatureMemAddrTypeShift); }
ASMJIT_INLINE bool isAbs() const noexcept { return getAddrType() == kAddrTypeAbs; }
ASMJIT_INLINE bool isRel() const noexcept { return getAddrType() == kAddrTypeRel; }
ASMJIT_INLINE bool isWrt() const noexcept { return getAddrType() == kAddrTypeWrt; }
ASMJIT_INLINE void setAbs() noexcept { setAddrType(kAddrTypeAbs); }
ASMJIT_INLINE void setRel() noexcept { setAddrType(kAddrTypeRel); }
ASMJIT_INLINE void setWrt() noexcept { setAddrType(kAddrTypeWrt); }
ASMJIT_INLINE bool isArgHome() const noexcept { return _hasSignatureData(kSignatureMemArgHomeFlag); } ASMJIT_INLINE bool isArgHome() const noexcept { return _hasSignatureData(kSignatureMemArgHomeFlag); }
ASMJIT_INLINE bool isRegHome() const noexcept { return _hasSignatureData(kSignatureMemRegHomeFlag); } ASMJIT_INLINE bool isRegHome() const noexcept { return _hasSignatureData(kSignatureMemRegHomeFlag); }
ASMJIT_INLINE void setAbs() noexcept { _signature |= kSignatureMemAbsoluteFlag; }
ASMJIT_INLINE void setArgHome() noexcept { _signature |= kSignatureMemArgHomeFlag; } ASMJIT_INLINE void setArgHome() noexcept { _signature |= kSignatureMemArgHomeFlag; }
ASMJIT_INLINE void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; } ASMJIT_INLINE void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; }
ASMJIT_INLINE void clearAbs() noexcept { _signature &= ~kSignatureMemAbsoluteFlag; }
ASMJIT_INLINE void clearArgHome() noexcept { _signature &= ~kSignatureMemArgHomeFlag; } ASMJIT_INLINE void clearArgHome() noexcept { _signature &= ~kSignatureMemArgHomeFlag; }
ASMJIT_INLINE void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; } ASMJIT_INLINE void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; }
@@ -873,46 +896,28 @@ public:
//! Get whether the memory operand has BASE and INDEX register. //! Get whether the memory operand has BASE and INDEX register.
ASMJIT_INLINE bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; } ASMJIT_INLINE bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; }
//! Get whether the memory operand has BASE and INDEX register. //! Get whether the memory operand has BASE and INDEX register.
ASMJIT_INLINE bool hasBaseAndIndex() const noexcept { ASMJIT_INLINE bool hasBaseAndIndex() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0 && (_signature & kSignatureMemIndexTypeMask) != 0; }
return (_signature & kSignatureMemBaseTypeMask) != 0 &&
(_signature & kSignatureMemIndexTypeMask) != 0;
}
//! Get if the BASE operand is a register. //! Get if the BASE operand is a register (registers start after `kLabelTag`).
ASMJIT_INLINE bool hasBaseReg() const noexcept { ASMJIT_INLINE bool hasBaseReg() const noexcept { return (_signature & kSignatureMemBaseTypeMask) > (Label::kLabelTag << kSignatureMemBaseTypeShift); }
// Registers start after kLabelTag.
return (_signature & kSignatureMemBaseTypeMask) > (Label::kLabelTag << kSignatureMemBaseTypeShift);
}
//! Get if the BASE operand is a label. //! Get if the BASE operand is a label.
ASMJIT_INLINE bool hasBaseLabel() const noexcept { ASMJIT_INLINE bool hasBaseLabel() const noexcept { return (_signature & kSignatureMemBaseTypeMask) == (Label::kLabelTag << kSignatureMemBaseTypeShift); }
return (_signature & kSignatureMemBaseTypeMask) == (Label::kLabelTag << kSignatureMemBaseTypeShift); //! Get if the INDEX operand is a register (registers start after `kLabelTag`).
} ASMJIT_INLINE bool hasIndexReg() const noexcept { return (_signature & kSignatureMemIndexTypeMask) > (Label::kLabelTag << kSignatureMemIndexTypeShift); }
//! Get if the INDEX operand is a register.
ASMJIT_INLINE bool hasIndexReg() const noexcept {
// Registers start after kLabelTag.
return (_signature & kSignatureMemIndexTypeMask) > (Label::kLabelTag << kSignatureMemIndexTypeShift);
}
//! Get type of a BASE register (0 if this memory operand doesn't use the BASE register). //! Get type of a BASE register (0 if this memory operand doesn't use the BASE register).
//! //!
//! NOTE: If the returned type is one (a value never associated to a register //! NOTE: If the returned type is one (a value never associated to a register
//! type) the BASE is not register, but it's a label. One equals to `kLabelTag`. //! type) the BASE is not register, but it's a label. One equals to `kLabelTag`.
//! You should always check `hasBaseLabel()` before using `getBaseId()` result. //! You should always check `hasBaseLabel()` before using `getBaseId()` result.
ASMJIT_INLINE uint32_t getBaseType() const noexcept { ASMJIT_INLINE uint32_t getBaseType() const noexcept { return _getSignatureData(kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift); }
return _getSignatureData(kSignatureMemBaseTypeBits, kSignatureMemBaseTypeShift);
}
//! Get type of an INDEX register (0 if this memory operand doesn't use the INDEX register). //! Get type of an INDEX register (0 if this memory operand doesn't use the INDEX register).
ASMJIT_INLINE uint32_t getIndexType() const noexcept { ASMJIT_INLINE uint32_t getIndexType() const noexcept { return _getSignatureData(kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift); }
return _getSignatureData(kSignatureMemIndexTypeBits, kSignatureMemIndexTypeShift);
}
//! Get both BASE (4:0 bits) and INDEX (9:5 bits) types combined into a single integer. //! Get both BASE (4:0 bits) and INDEX (9:5 bits) types combined into a single integer.
//! //!
//! This is used internally for BASE+INDEX validation. //! This is used internally for BASE+INDEX validation.
ASMJIT_INLINE uint32_t getBaseIndexType() const noexcept { ASMJIT_INLINE uint32_t getBaseIndexType() const noexcept { return _getSignatureData(kSignatureMemBaseIndexBits, kSignatureMemBaseIndexShift); }
return _getSignatureData(kSignatureMemBaseIndexBits, kSignatureMemBaseIndexShift);
}
//! Get id of the BASE register or label (if the BASE was specified as label). //! Get id of the BASE register or label (if the BASE was specified as label).
ASMJIT_INLINE uint32_t getBaseId() const noexcept { return _mem.base; } ASMJIT_INLINE uint32_t getBaseId() const noexcept { return _mem.base; }

View File

@@ -161,8 +161,6 @@ namespace asmjit {
template<typename This> template<typename This>
struct X86EmitterExplicitT { struct X86EmitterExplicitT {
ASMJIT_INLINE X86EmitterExplicitT() noexcept {}
// These typedefs are used to describe implicit operands passed explicitly. // These typedefs are used to describe implicit operands passed explicitly.
typedef X86Gp AL; typedef X86Gp AL;
typedef X86Gp AH; typedef X86Gp AH;
@@ -279,12 +277,12 @@ struct X86EmitterExplicitT {
//! \overload //! \overload
ASMJIT_INLINE X86Mem intptr_ptr_abs(uint64_t base) const noexcept { ASMJIT_INLINE X86Mem intptr_ptr_abs(uint64_t base) const noexcept {
uint32_t nativeGpSize = static_cast<const This*>(this)->getGpSize(); uint32_t nativeGpSize = static_cast<const This*>(this)->getGpSize();
return X86Mem(base, nativeGpSize, Mem::kSignatureMemAbsoluteFlag); return X86Mem(base, nativeGpSize, Mem::kSignatureMemAbs);
} }
//! \overload //! \overload
ASMJIT_INLINE X86Mem intptr_ptr_abs(uint64_t base, const X86Gp& index, uint32_t shift = 0) const noexcept { ASMJIT_INLINE X86Mem intptr_ptr_abs(uint64_t base, const X86Gp& index, uint32_t shift = 0) const noexcept {
uint32_t nativeGpSize = static_cast<const This*>(this)->getGpSize(); uint32_t nativeGpSize = static_cast<const This*>(this)->getGpSize();
return X86Mem(base, index, shift, nativeGpSize, Mem::kSignatureMemAbsoluteFlag); return X86Mem(base, index, shift, nativeGpSize, Mem::kSignatureMemAbs);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -5097,9 +5095,7 @@ struct X86EmitterImplicitT : public X86EmitterExplicitT<This> {
//! NOTE: This class cannot be created, you can only cast to it and use it as //! NOTE: This class cannot be created, you can only cast to it and use it as
//! emitter that emits to either X86Assembler, X86Builder, or X86Compiler (use //! emitter that emits to either X86Assembler, X86Builder, or X86Compiler (use
//! with caution with X86Compiler as it expects virtual registers to be used). //! with caution with X86Compiler as it expects virtual registers to be used).
class X86Emitter class X86Emitter : public CodeEmitter, public X86EmitterImplicitT<X86Emitter> {
: public CodeEmitter,
public X86EmitterImplicitT<X86Emitter> {
ASMJIT_NONCONSTRUCTIBLE(X86Emitter) ASMJIT_NONCONSTRUCTIBLE(X86Emitter)
}; };

View File

@@ -58,11 +58,11 @@ class X86Mem : public Mem {
public: public:
//! Additional bits of operand's signature used by `X86Mem`. //! Additional bits of operand's signature used by `X86Mem`.
ASMJIT_ENUM(AdditionalBits) { ASMJIT_ENUM(AdditionalBits) {
kSignatureMemShiftShift = 16, kSignatureMemShiftShift = 19,
kSignatureMemShiftBits = 0x03U, kSignatureMemShiftBits = 0x03U,
kSignatureMemShiftMask = kSignatureMemShiftBits << kSignatureMemShiftShift, kSignatureMemShiftMask = kSignatureMemShiftBits << kSignatureMemShiftShift,
kSignatureMemSegmentShift = 18, kSignatureMemSegmentShift = 21,
kSignatureMemSegmentBits = 0x07U, kSignatureMemSegmentBits = 0x07U,
kSignatureMemSegmentMask = kSignatureMemSegmentBits << kSignatureMemSegmentShift kSignatureMemSegmentMask = kSignatureMemSegmentBits << kSignatureMemSegmentShift
}; };
@@ -1052,7 +1052,7 @@ static ASMJIT_INLINE X86Mem ptr(uint64_t base, const X86Vec& index, uint32_t shi
} \ } \
/*! Create a `[base + (vec_index << shift) + offset]` memory operand. */ \ /*! Create a `[base + (vec_index << shift) + offset]` memory operand. */ \
static ASMJIT_INLINE X86Mem FUNC(uint64_t base, const X86Vec& index, uint32_t shift = 0) noexcept { \ static ASMJIT_INLINE X86Mem FUNC(uint64_t base, const X86Vec& index, uint32_t shift = 0) noexcept { \
return X86Mem(base, index, shift, SIZE, Mem::kSignatureMemAbsoluteFlag); \ return X86Mem(base, index, shift, SIZE, Mem::kSignatureMemAbs); \
} \ } \
/*! Create a `[base + offset]` memory operand. */ \ /*! Create a `[base + offset]` memory operand. */ \
static ASMJIT_INLINE X86Mem FUNC##_abs(uint64_t base) noexcept { \ static ASMJIT_INLINE X86Mem FUNC##_abs(uint64_t base) noexcept { \
@@ -1060,17 +1060,18 @@ static ASMJIT_INLINE X86Mem ptr(uint64_t base, const X86Vec& index, uint32_t shi
} \ } \
/*! Create a `[base + (index << shift) + offset]` memory operand. */ \ /*! Create a `[base + (index << shift) + offset]` memory operand. */ \
static ASMJIT_INLINE X86Mem FUNC##_abs(uint64_t base, const X86Gp& index, uint32_t shift = 0) noexcept { \ static ASMJIT_INLINE X86Mem FUNC##_abs(uint64_t base, const X86Gp& index, uint32_t shift = 0) noexcept { \
return X86Mem(base, index, shift, SIZE, Mem::kSignatureMemAbsoluteFlag); \ return X86Mem(base, index, shift, SIZE, Mem::kSignatureMemAbs); \
} \ } \
/*! Create a `[base + (vec_index << shift) + offset]` memory operand. */ \ /*! Create a `[base + (vec_index << shift) + offset]` memory operand. */ \
static ASMJIT_INLINE X86Mem FUNC##_abs(uint64_t base, const X86Vec& index, uint32_t shift = 0) noexcept { \ static ASMJIT_INLINE X86Mem FUNC##_abs(uint64_t base, const X86Vec& index, uint32_t shift = 0) noexcept { \
return X86Mem(base, index, shift, SIZE, Mem::kSignatureMemAbsoluteFlag); \ return X86Mem(base, index, shift, SIZE, Mem::kSignatureMemAbs); \
} }
// Define memory operand constructors that use platform independent naming. // Define memory operand constructors that use platform independent naming.
ASMJIT_X86_PTR_FN(ptr_8, 1) ASMJIT_X86_PTR_FN(ptr_8, 1)
ASMJIT_X86_PTR_FN(ptr_16, 2) ASMJIT_X86_PTR_FN(ptr_16, 2)
ASMJIT_X86_PTR_FN(ptr_32, 4) ASMJIT_X86_PTR_FN(ptr_32, 4)
ASMJIT_X86_PTR_FN(ptr_48, 6)
ASMJIT_X86_PTR_FN(ptr_64, 8) ASMJIT_X86_PTR_FN(ptr_64, 8)
ASMJIT_X86_PTR_FN(ptr_80, 10) ASMJIT_X86_PTR_FN(ptr_80, 10)
ASMJIT_X86_PTR_FN(ptr_128, 16) ASMJIT_X86_PTR_FN(ptr_128, 16)