|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef ASMJIT_ARM_ARMOPERAND_H_INCLUDED
|
|
|
#define ASMJIT_ARM_ARMOPERAND_H_INCLUDED
|
|
|
|
|
|
#include "../core/archtraits.h"
|
|
|
#include "../core/operand.h"
|
|
|
#include "../core/type.h"
|
|
|
#include "../arm/armglobals.h"
|
|
|
|
|
|
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Reg;
|
|
|
class Mem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<RegType kRegType>
|
|
|
struct RegTraits : public BaseRegTraits {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_GpW , RegGroup::kGp , 4 , TypeId::kInt32 );
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_GpX , RegGroup::kGp , 8 , TypeId::kInt64 );
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecB , RegGroup::kVec , 1 , TypeId::kVoid );
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecH , RegGroup::kVec , 2 , TypeId::kVoid );
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecS , RegGroup::kVec , 4 , TypeId::kInt32x1 );
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecD , RegGroup::kVec , 8 , TypeId::kInt32x2 );
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecQ , RegGroup::kVec , 16, TypeId::kInt32x4 );
|
|
|
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_PC , RegGroup::kPC , 8 , TypeId::kInt64 );
|
|
|
|
|
|
|
|
|
|
|
|
class Reg : public BaseReg {
|
|
|
public:
|
|
|
ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg)
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isGpR() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isGpW() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isGpX() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpX>::kSignature; }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVecB() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVecH() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVecS() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVecD() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVecQ() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVecDOrQ() const noexcept { return uint32_t(type()) - uint32_t(RegType::kARM_VecD) <= 1u; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVec8() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVec16() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVec32() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVec64() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isVec128() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
|
|
|
|
|
template<RegType kRegType>
|
|
|
ASMJIT_INLINE_NODEBUG void setRegT(uint32_t id) noexcept {
|
|
|
setSignature(RegTraits<kRegType>::kSignature);
|
|
|
setId(id);
|
|
|
}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setTypeAndId(RegType type, uint32_t id) noexcept {
|
|
|
setSignature(signatureOf(type));
|
|
|
setId(id);
|
|
|
}
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG RegGroup groupOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToGroup(type); }
|
|
|
static ASMJIT_INLINE_NODEBUG TypeId typeIdOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToTypeId(type); }
|
|
|
static ASMJIT_INLINE_NODEBUG OperandSignature signatureOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToSignature(type); }
|
|
|
|
|
|
template<RegType kRegType>
|
|
|
static ASMJIT_INLINE_NODEBUG RegGroup groupOfT() noexcept { return RegTraits<kRegType>::kGroup; }
|
|
|
|
|
|
template<RegType kRegType>
|
|
|
static ASMJIT_INLINE_NODEBUG TypeId typeIdOfT() noexcept { return RegTraits<kRegType>::kTypeId; }
|
|
|
|
|
|
template<RegType kRegType>
|
|
|
static ASMJIT_INLINE_NODEBUG OperandSignature signatureOfT() noexcept { return OperandSignature{RegTraits<kRegType>::kSignature}; }
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG bool isGpW(const Operand_& op) noexcept { return op.as<Reg>().isGpW(); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isGpX(const Operand_& op) noexcept { return op.as<Reg>().isGpX(); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecB(const Operand_& op) noexcept { return op.as<Reg>().isVecB(); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecH(const Operand_& op) noexcept { return op.as<Reg>().isVecH(); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecS(const Operand_& op) noexcept { return op.as<Reg>().isVecS(); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecD(const Operand_& op) noexcept { return op.as<Reg>().isVecD(); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecQ(const Operand_& op) noexcept { return op.as<Reg>().isVecQ(); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecV(const Operand_& op) noexcept { return op.as<Reg>().isVecV(); }
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG bool isGpW(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isGpW(op)) & unsigned(op.id() == id)); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isGpX(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isGpX(op)) & unsigned(op.id() == id)); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecB(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecB(op)) & unsigned(op.id() == id)); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecH(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecH(op)) & unsigned(op.id() == id)); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecS(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecS(op)) & unsigned(op.id() == id)); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecD(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecD(op)) & unsigned(op.id() == id)); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecQ(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecQ(op)) & unsigned(op.id() == id)); }
|
|
|
static ASMJIT_INLINE_NODEBUG bool isVecV(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecV(op)) & unsigned(op.id() == id)); }
|
|
|
};
|
|
|
|
|
|
|
|
|
class BaseVec : public Reg {
|
|
|
public:
|
|
|
ASMJIT_DEFINE_ABSTRACT_REG(BaseVec, Reg)
|
|
|
|
|
|
|
|
|
enum AdditionalBits : uint32_t {
|
|
|
|
|
|
|
|
|
kSignatureRegElementTypeShift = 12,
|
|
|
kSignatureRegElementTypeMask = 0x07 << kSignatureRegElementTypeShift,
|
|
|
|
|
|
|
|
|
|
|
|
kSignatureRegElementFlagShift = 15,
|
|
|
kSignatureRegElementFlagMask = 0x01 << kSignatureRegElementFlagShift,
|
|
|
|
|
|
|
|
|
|
|
|
kSignatureRegElementIndexShift = 16,
|
|
|
kSignatureRegElementIndexMask = 0x0F << kSignatureRegElementIndexShift
|
|
|
};
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool hasElementIndex() const noexcept { return _signature.hasField<kSignatureRegElementFlagMask>(); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr uint32_t elementIndex() const noexcept { return _signature.getField<kSignatureRegElementIndexMask>(); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setElementIndex(uint32_t elementIndex) noexcept {
|
|
|
_signature |= kSignatureRegElementFlagMask;
|
|
|
_signature.setField<kSignatureRegElementIndexMask>(elementIndex);
|
|
|
}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void resetElementIndex() noexcept {
|
|
|
_signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
|
|
|
class Mem : public BaseMem {
|
|
|
public:
|
|
|
|
|
|
|
|
|
enum AdditionalBits : uint32_t {
|
|
|
|
|
|
|
|
|
kSignatureMemShiftValueShift = 14,
|
|
|
kSignatureMemShiftValueMask = 0x1Fu << kSignatureMemShiftValueShift,
|
|
|
|
|
|
|
|
|
|
|
|
kSignatureMemShiftOpShift = 20,
|
|
|
kSignatureMemShiftOpMask = 0x0Fu << kSignatureMemShiftOpShift,
|
|
|
|
|
|
|
|
|
|
|
|
kSignatureMemOffsetModeShift = 24,
|
|
|
kSignatureMemOffsetModeMask = 0x03u << kSignatureMemOffsetModeShift
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr Mem() noexcept
|
|
|
: BaseMem() {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr Mem(const Mem& other) noexcept
|
|
|
: BaseMem(other) {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG explicit Mem(Globals::NoInit_) noexcept
|
|
|
: BaseMem(Globals::NoInit) {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept
|
|
|
: BaseMem(signature, baseId, indexId, offset) {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr explicit Mem(const Label& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
|
|
|
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
|
Signature::fromMemBaseType(RegType::kLabelTag) |
|
|
|
signature, base.id(), 0, off) {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr explicit Mem(const BaseReg& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
|
|
|
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
|
Signature::fromMemBaseType(base.type()) |
|
|
|
signature, base.id(), 0, off) {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr Mem(const BaseReg& base, const BaseReg& index, Signature signature = Signature{0}) noexcept
|
|
|
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
|
Signature::fromMemBaseType(base.type()) |
|
|
|
Signature::fromMemIndexType(index.type()) |
|
|
|
signature, base.id(), index.id(), 0) {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr Mem(const BaseReg& base, const BaseReg& index, const Shift& shift, Signature signature = Signature{0}) noexcept
|
|
|
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
|
Signature::fromMemBaseType(base.type()) |
|
|
|
Signature::fromMemIndexType(index.type()) |
|
|
|
Signature::fromValue<kSignatureMemShiftOpMask>(uint32_t(shift.op())) |
|
|
|
Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) |
|
|
|
signature, base.id(), index.id(), 0) {}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr explicit Mem(uint64_t base, Signature signature = Signature{0}) noexcept
|
|
|
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
|
signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Mem& operator=(const Mem& other) noexcept = default;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr Mem clone() const noexcept { return Mem(*this); }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Mem cloneAdjusted(int64_t off) const noexcept {
|
|
|
Mem result(*this);
|
|
|
result.addOffset(off);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Mem pre() const noexcept {
|
|
|
Mem result(*this);
|
|
|
result.setOffsetMode(OffsetMode::kPreIndex);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Mem pre(int64_t off) const noexcept {
|
|
|
Mem result(*this);
|
|
|
result.setOffsetMode(OffsetMode::kPreIndex);
|
|
|
result.addOffset(off);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Mem post() const noexcept {
|
|
|
Mem result(*this);
|
|
|
result.setOffsetMode(OffsetMode::kPostIndex);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Mem post(int64_t off) const noexcept {
|
|
|
Mem result(*this);
|
|
|
result.setOffsetMode(OffsetMode::kPostIndex);
|
|
|
result.addOffset(off);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Reg baseReg() const noexcept { return Reg::fromTypeAndId(baseType(), baseId()); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); }
|
|
|
|
|
|
using BaseMem::setIndex;
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setIndex(const BaseReg& index, uint32_t shift) noexcept {
|
|
|
setIndex(index);
|
|
|
setShift(shift);
|
|
|
}
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setIndex(const BaseReg& index, Shift shift) noexcept {
|
|
|
setIndex(index);
|
|
|
setShift(shift);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr OffsetMode offsetMode() const noexcept { return OffsetMode(_signature.getField<kSignatureMemOffsetModeMask>()); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setOffsetMode(OffsetMode mode) noexcept { _signature.setField<kSignatureMemOffsetModeMask>(uint32_t(mode)); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void resetOffsetMode() noexcept { _signature.setField<kSignatureMemOffsetModeMask>(uint32_t(OffsetMode::kFixed)); }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isFixedOffset() const noexcept { return offsetMode() == OffsetMode::kFixed; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isPreOrPost() const noexcept { return offsetMode() != OffsetMode::kFixed; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isPreIndex() const noexcept { return offsetMode() == OffsetMode::kPreIndex; }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool isPostIndex() const noexcept { return offsetMode() == OffsetMode::kPostIndex; }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void makePreIndex() noexcept { setOffsetMode(OffsetMode::kPreIndex); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void makePostIndex() noexcept { setOffsetMode(OffsetMode::kPostIndex); }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr ShiftOp shiftOp() const noexcept { return ShiftOp(_signature.getField<kSignatureMemShiftOpMask>()); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setShiftOp(ShiftOp sop) noexcept { _signature.setField<kSignatureMemShiftOpMask>(uint32_t(sop)); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void resetShiftOp() noexcept { _signature.setField<kSignatureMemShiftOpMask>(uint32_t(ShiftOp::kLSL)); }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG constexpr uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); }
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); }
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void setShift(Shift shift) noexcept {
|
|
|
_signature.setField<kSignatureMemShiftOpMask>(uint32_t(shift.op()));
|
|
|
_signature.setField<kSignatureMemShiftValueMask>(shift.value());
|
|
|
}
|
|
|
|
|
|
|
|
|
ASMJIT_INLINE_NODEBUG void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); }
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG constexpr Shift lsl(uint32_t value) noexcept { return Shift(ShiftOp::kLSL, value); }
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG constexpr Shift lsr(uint32_t value) noexcept { return Shift(ShiftOp::kLSR, value); }
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG constexpr Shift asr(uint32_t value) noexcept { return Shift(ShiftOp::kASR, value); }
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG constexpr Shift ror(uint32_t value) noexcept { return Shift(ShiftOp::kROR, value); }
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG constexpr Shift rrx() noexcept { return Shift(ShiftOp::kRRX, 0); }
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG constexpr Shift msl(uint32_t value) noexcept { return Shift(ShiftOp::kMSL, value); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(uint64_t base) noexcept { return Mem(base); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASMJIT_END_SUB_NAMESPACE
|
|
|
|
|
|
#endif
|
|
|
|