diff options
Diffstat (limited to 'erts/emulator/asmjit/arm/armoperand.h')
-rw-r--r-- | erts/emulator/asmjit/arm/armoperand.h | 416 |
1 files changed, 182 insertions, 234 deletions
diff --git a/erts/emulator/asmjit/arm/armoperand.h b/erts/emulator/asmjit/arm/armoperand.h index 532e9eb6ee..e7803e952b 100644 --- a/erts/emulator/asmjit/arm/armoperand.h +++ b/erts/emulator/asmjit/arm/armoperand.h @@ -1,25 +1,7 @@ -// AsmJit - Machine code generation for C++ +// This file is part of AsmJit project <https://asmjit.com> // -// * Official AsmJit Home Page: https://asmjit.com -// * Official Github Repository: https://github.com/asmjit/asmjit -// -// Copyright (c) 2008-2020 The AsmJit Authors -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib #ifndef ASMJIT_ARM_ARMOPERAND_H_INCLUDED #define ASMJIT_ARM_ARMOPERAND_H_INCLUDED @@ -34,10 +16,6 @@ ASMJIT_BEGIN_SUB_NAMESPACE(arm) //! \addtogroup asmjit_arm //! \{ -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - class Reg; class Mem; @@ -52,120 +30,76 @@ class VecS; class VecD; class VecV; -// ============================================================================ -// [asmjit::arm::RegTraits] -// ============================================================================ - //! Register traits (ARM/AArch64). //! -//! Register traits contains information about a particular register type. It's -//! used by asmjit to setup register information on-the-fly and to populate -//! tables that contain register information (this way it's possible to change -//! register types and groups without having to reorder these tables). -template<uint32_t REG_TYPE> +//! Register traits contains information about a particular register type. It's used by asmjit to setup register +//! information on-the-fly and to populate tables that contain register information (this way it's possible to +//! change register types and groups without having to reorder these tables). +template<RegType kRegType> struct RegTraits : public BaseRegTraits {}; //! \cond -// <--------------------+-----+----------------------+---------------------+---+---+----------------+ -// | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId | -// <--------------------+-----+----------------------+---------------------+---+---+----------------+ -ASMJIT_DEFINE_REG_TRAITS(GpW , BaseReg::kTypeGp32 , BaseReg::kGroupGp , 4 , 32, Type::kIdI32 ); -ASMJIT_DEFINE_REG_TRAITS(GpX , BaseReg::kTypeGp64 , BaseReg::kGroupGp , 8 , 32, Type::kIdI64 ); -ASMJIT_DEFINE_REG_TRAITS(VecB , BaseReg::kTypeVec8 , BaseReg::kGroupVec , 1 , 32, Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(VecH , BaseReg::kTypeVec16 , BaseReg::kGroupVec , 2 , 32, Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(VecS , BaseReg::kTypeVec32 , BaseReg::kGroupVec , 4 , 32, Type::kIdI32x1 ); -ASMJIT_DEFINE_REG_TRAITS(VecD , BaseReg::kTypeVec64 , BaseReg::kGroupVec , 8 , 32, Type::kIdI32x2 ); -ASMJIT_DEFINE_REG_TRAITS(VecV , BaseReg::kTypeVec128 , BaseReg::kGroupVec , 16, 32, Type::kIdI32x4 ); +// <--------------------+-----+-------------------------+------------------------+---+---+------------------+ +// | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId | +// <--------------------+-----+-------------------------+------------------------+---+---+------------------+ +ASMJIT_DEFINE_REG_TRAITS(GpW , RegType::kARM_GpW , RegGroup::kGp , 4 , 32, TypeId::kInt32 ); +ASMJIT_DEFINE_REG_TRAITS(GpX , RegType::kARM_GpX , RegGroup::kGp , 8 , 32, TypeId::kInt64 ); +ASMJIT_DEFINE_REG_TRAITS(VecB , RegType::kARM_VecB , RegGroup::kVec , 1 , 32, TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(VecH , RegType::kARM_VecH , RegGroup::kVec , 2 , 32, TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(VecS , RegType::kARM_VecS , RegGroup::kVec , 4 , 32, TypeId::kInt32x1 ); +ASMJIT_DEFINE_REG_TRAITS(VecD , RegType::kARM_VecD , RegGroup::kVec , 8 , 32, TypeId::kInt32x2 ); +ASMJIT_DEFINE_REG_TRAITS(VecV , RegType::kARM_VecV , RegGroup::kVec , 16, 32, TypeId::kInt32x4 ); //! \endcond -// ============================================================================ -// [asmjit::arm::Reg] -// ============================================================================ - //! Register (ARM). class Reg : public BaseReg { public: ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg) - //! Register type. - enum RegType : uint32_t { - //! No register type or invalid register. - kTypeNone = BaseReg::kTypeNone, - //! 32-bit general purpose register (R or W). - kTypeGpW = BaseReg::kTypeGp32, - //! 64-bit general purpose register (X). - kTypeGpX = BaseReg::kTypeGp64, - //! 8-bit view of VFP/ASIMD register (B). - kTypeVecB = BaseReg::kTypeVec8, - //! 16-bit view of VFP/ASIMD register (H). - kTypeVecH = BaseReg::kTypeVec16, - //! 32-bit view of VFP/ASIMD register (S). - kTypeVecS = BaseReg::kTypeVec32, - //! 64-bit view of VFP/ASIMD register (D). - kTypeVecD = BaseReg::kTypeVec64, - //! 128-bit view of VFP/ASIMD register (Q|V). - kTypeVecV = BaseReg::kTypeVec128, - //! Program pointer (PC) (AArch64). - kTypePC = BaseReg::kTypeIP, - //! Count of register types. - kTypeCount - }; - - //! Register group. - enum RegGroup : uint32_t { - //! General purpose register group. - kGroupGp = BaseReg::kGroupGp, - //! Vector (VFP/ASIMD) register group. - kGroupVec = BaseReg::kGroupVec, - //! Count of all ARM register groups. - kGroupCount - }; - //! Gets whether the register is a `R|W` register (32-bit). - constexpr bool isGpW() const noexcept { return hasBaseSignature(RegTraits<kTypeGpW>::kSignature); } + inline constexpr bool isGpW() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; } //! Gets whether the register is an `X` register (64-bit). - constexpr bool isGpX() const noexcept { return hasBaseSignature(RegTraits<kTypeGpX>::kSignature); } + inline constexpr bool isGpX() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpX>::kSignature; } //! Gets whether the register is a VEC-B register (8-bit). - constexpr bool isVecB() const noexcept { return hasBaseSignature(RegTraits<kTypeVecB>::kSignature); } + inline constexpr bool isVecB() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; } //! Gets whether the register is a VEC-H register (16-bit). - constexpr bool isVecH() const noexcept { return hasBaseSignature(RegTraits<kTypeVecH>::kSignature); } + inline constexpr bool isVecH() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; } //! Gets whether the register is a VEC-S register (32-bit). - constexpr bool isVecS() const noexcept { return hasBaseSignature(RegTraits<kTypeVecS>::kSignature); } + inline constexpr bool isVecS() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; } //! Gets whether the register is a VEC-D register (64-bit). - constexpr bool isVecD() const noexcept { return hasBaseSignature(RegTraits<kTypeVecD>::kSignature); } + inline constexpr bool isVecD() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; } //! Gets whether the register is a VEC-Q register (128-bit). - constexpr bool isVecQ() const noexcept { return hasBaseSignature(RegTraits<kTypeVecV>::kSignature); } + inline constexpr bool isVecQ() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; } //! Gets whether the register is either VEC-D (64-bit) or VEC-Q (128-bit). - constexpr bool isVecDOrQ() const noexcept { return type() - Reg::kTypeVecD <= 1u; } + inline constexpr bool isVecDOrQ() const noexcept { return uint32_t(type()) - uint32_t(RegType::kARM_VecD) <= 1u; } //! Gets whether the register is a VEC-V register (128-bit). - constexpr bool isVecV() const noexcept { return hasBaseSignature(RegTraits<kTypeVecV>::kSignature); } + inline constexpr bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; } - template<uint32_t REG_TYPE> + template<RegType kRegType> inline void setRegT(uint32_t id) noexcept { - setSignature(RegTraits<REG_TYPE>::kSignature); + setSignature(RegTraits<kRegType>::kSignature); setId(id); } - inline void setTypeAndId(uint32_t rType, uint32_t id) noexcept { - ASMJIT_ASSERT(rType < kTypeCount); - setSignature(signatureOf(rType)); + inline void setTypeAndId(RegType type, uint32_t id) noexcept { + setSignature(signatureOf(type)); setId(id); } - static inline uint32_t groupOf(uint32_t rType) noexcept { return _archTraits[Environment::kArchAArch64].regTypeToGroup(rType); } - static inline uint32_t typeIdOf(uint32_t rType) noexcept { return _archTraits[Environment::kArchAArch64].regTypeToTypeId(rType); } - static inline uint32_t signatureOf(uint32_t rType) noexcept { return _archTraits[Environment::kArchAArch64].regTypeToSignature(rType); } + static inline RegGroup groupOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToGroup(type); } + static inline TypeId typeIdOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToTypeId(type); } + static inline OperandSignature signatureOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToSignature(type); } - template<uint32_t REG_TYPE> - static inline uint32_t groupOfT() noexcept { return RegTraits<REG_TYPE>::kGroup; } + template<RegType kRegType> + static inline RegGroup groupOfT() noexcept { return RegTraits<kRegType>::kGroup; } - template<uint32_t REG_TYPE> - static inline uint32_t typeIdOfT() noexcept { return RegTraits<REG_TYPE>::kTypeId; } + template<RegType kRegType> + static inline TypeId typeIdOfT() noexcept { return RegTraits<kRegType>::kTypeId; } - template<uint32_t REG_TYPE> - static inline uint32_t signatureOfT() noexcept { return RegTraits<REG_TYPE>::kSignature; } + template<RegType kRegType> + static inline OperandSignature signatureOfT() noexcept { return RegTraits<kRegType>::kSignature; } static inline bool isGpW(const Operand_& op) noexcept { return op.as<Reg>().isGpW(); } static inline bool isGpX(const Operand_& op) noexcept { return op.as<Reg>().isGpX(); } @@ -203,15 +137,17 @@ public: kIdSp = 31, //! Zero register id. //! - //! Although zero register has the same id as stack register we treat it - //! special. The reason is that we may still want to map stack register - //! to a virtual register in some case, but we would never need to do that - //! mapping with zero register. + //! Although zero register has the same id as stack register it has a special treatment, because we need to be + //! able to distinguish between these two at API level. Some intructions were designed to be used with SP and + //! some other with ZR - so we need a way to distinguish these two to make sure we emit the right thing. + //! + //! The number 63 is not random, when you perform `id & 31` you would always get 31 for both SP and ZR inputs, + //! which is the identifier used by AArch64 ISA to encode either SP or ZR depending on the instruction. kIdZr = 63 }; - constexpr bool isZR() const noexcept { return id() == kIdZr; } - constexpr bool isSP() const noexcept { return id() == kIdSp; } + inline constexpr bool isZR() const noexcept { return id() == kIdZr; } + inline constexpr bool isSP() const noexcept { return id() == kIdSp; } //! Cast this register to a 32-bit R|W. inline GpW w() const noexcept; @@ -254,11 +190,11 @@ public: kElementTypeS, //! Doubleword elements (D2). kElementTypeD, - //! Byte elements groped by 4 bytes (B4). + //! Byte elements grouped by 4 bytes (B4). //! //! \note This element-type is only used by few instructions. kElementTypeB4, - //! Halfword elements groped by 2 halfwords (H2). + //! Halfword elements grouped by 2 halfwords (H2). //! //! \note This element-type is only used by few instructions. kElementTypeH2, @@ -280,46 +216,46 @@ public: //! \endcond //! Returns whether the register has associated an element type. - constexpr bool hasElementType() const noexcept { return elementType() != 0; } + inline constexpr bool hasElementType() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask>(); } //! Returns whether the register has element index (it's an element index access). - constexpr bool hasElementIndex() const noexcept { return (_signature & kSignatureRegElementFlagMask) != 0; } + inline constexpr bool hasElementIndex() const noexcept { return _signature.hasField<kSignatureRegElementFlagMask>(); } //! Returns whether the reggister has element type or element index (or both). - constexpr bool hasElementTypeOrIndex() const noexcept { return (_signature & (kSignatureRegElementFlagMask | kSignatureRegElementTypeMask)) != 0; } + inline constexpr bool hasElementTypeOrIndex() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask | kSignatureRegElementFlagMask>(); } //! Returns element type of the register. - constexpr uint32_t elementType() const noexcept { return _getSignaturePart<kSignatureRegElementTypeMask>(); } + inline constexpr uint32_t elementType() const noexcept { return _signature.getField<kSignatureRegElementTypeMask>(); } //! Sets element type of the register to `elementType`. - inline void setElementType(uint32_t elementType) noexcept { _setSignaturePart<kSignatureRegElementTypeMask>(elementType); } + inline void setElementType(uint32_t elementType) noexcept { _signature.setField<kSignatureRegElementTypeMask>(elementType); } //! Resets element type to none. - inline void resetElementType() noexcept { _setSignaturePart<kSignatureRegElementTypeMask>(0); } + inline void resetElementType() noexcept { _signature.setField<kSignatureRegElementTypeMask>(0); } //! Returns element index of the register. - constexpr uint32_t elementIndex() const noexcept { return _getSignaturePart<kSignatureRegElementIndexMask>(); } + inline constexpr uint32_t elementIndex() const noexcept { return _signature.getField<kSignatureRegElementIndexMask>(); } //! Sets element index of the register to `elementType`. inline void setElementIndex(uint32_t elementIndex) noexcept { _signature |= kSignatureRegElementFlagMask; - _setSignaturePart<kSignatureRegElementIndexMask>(elementIndex); + _signature.setField<kSignatureRegElementIndexMask>(elementIndex); } //! Resets element index of the register. inline void resetElementIndex() noexcept { _signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask); } - constexpr bool isVecB8() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecD>::kSignature | kSignatureElementB); } - constexpr bool isVecH4() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecD>::kSignature | kSignatureElementH); } - constexpr bool isVecS2() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecD>::kSignature | kSignatureElementS); } - constexpr bool isVecD1() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecD>::kSignature); } + inline constexpr bool isVecB8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementB); } + inline constexpr bool isVecH4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementH); } + inline constexpr bool isVecS2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature | kSignatureElementS); } + inline constexpr bool isVecD1() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecD>::kSignature); } - constexpr bool isVecB16() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecV>::kSignature | kSignatureElementB); } - constexpr bool isVecH8() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecV>::kSignature | kSignatureElementH); } - constexpr bool isVecS4() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecV>::kSignature | kSignatureElementS); } - constexpr bool isVecD2() const noexcept { return _hasSignaturePart<kBaseSignature | kSignatureRegElementTypeMask>(RegTraits<kTypeVecV>::kSignature | kSignatureElementD); } + inline constexpr bool isVecB16() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB); } + inline constexpr bool isVecH8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH); } + inline constexpr bool isVecS4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementS); } + inline constexpr bool isVecD2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementD); } + inline constexpr bool isVecB4x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementB4); } + inline constexpr bool isVecH2x4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits<RegType::kARM_VecV>::kSignature | kSignatureElementH2); } //! Creates a cloned register with element access. inline Vec at(uint32_t elementIndex) const noexcept { - return fromSignatureAndId( - (signature() & ~kSignatureRegElementIndexMask) | (elementIndex << kSignatureRegElementIndexShift) | kSignatureRegElementFlagMask, - id()); + return Vec((signature() & ~kSignatureRegElementIndexMask) | (elementIndex << kSignatureRegElementIndexShift) | kSignatureRegElementFlagMask, id()); } //! Cast this register to an 8-bit B register (scalar). @@ -343,7 +279,7 @@ public: inline VecV s(uint32_t elementIndex) const noexcept; //! Cast this register to a 128-bit V.D[elementIndex] register. inline VecV d(uint32_t elementIndex) const noexcept; - //! Cast this register to a 128-bit V.B4[elementIndex] register. + //! Cast this register to a 128-bit V.H2[elementIndex] register. inline VecV h2(uint32_t elementIndex) const noexcept; //! Cast this register to a 128-bit V.B4[elementIndex] register. inline VecV b4(uint32_t elementIndex) const noexcept; @@ -365,29 +301,30 @@ public: //! Cast this register to V.2D. inline VecV d2() const noexcept; - static constexpr uint32_t _makeElementAccessSignature(uint32_t elementType, uint32_t elementIndex) noexcept { - return uint32_t(RegTraits<kTypeVecV>::kSignature) | - uint32_t(kSignatureRegElementFlagMask) | - uint32_t(elementType << kSignatureRegElementTypeShift) | - uint32_t(elementIndex << kSignatureRegElementIndexShift) ; + static inline constexpr OperandSignature _makeElementAccessSignature(uint32_t elementType, uint32_t elementIndex) noexcept { + return OperandSignature{ + uint32_t(RegTraits<RegType::kARM_VecV>::kSignature) | + uint32_t(kSignatureRegElementFlagMask) | + uint32_t(elementType << kSignatureRegElementTypeShift) | + uint32_t(elementIndex << kSignatureRegElementIndexShift)}; } }; //! 32-bit GPW (AArch64) and/or GPR (ARM/AArch32) register. -class GpW : public Gp { ASMJIT_DEFINE_FINAL_REG(GpW, Gp, RegTraits<kTypeGpW>) }; +class GpW : public Gp { ASMJIT_DEFINE_FINAL_REG(GpW, Gp, RegTraits<RegType::kARM_GpW>) }; //! 64-bit GPX (AArch64) register. -class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<kTypeGpX>) }; +class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<RegType::kARM_GpX>) }; //! 8-bit view (S) of VFP/SIMD register. -class VecB : public Vec { ASMJIT_DEFINE_FINAL_REG(VecB, Vec, RegTraits<kTypeVecB>) }; +class VecB : public Vec { ASMJIT_DEFINE_FINAL_REG(VecB, Vec, RegTraits<RegType::kARM_VecB>) }; //! 16-bit view (S) of VFP/SIMD register. -class VecH : public Vec { ASMJIT_DEFINE_FINAL_REG(VecH, Vec, RegTraits<kTypeVecH>) }; +class VecH : public Vec { ASMJIT_DEFINE_FINAL_REG(VecH, Vec, RegTraits<RegType::kARM_VecH>) }; //! 32-bit view (S) of VFP/SIMD register. -class VecS : public Vec { ASMJIT_DEFINE_FINAL_REG(VecS, Vec, RegTraits<kTypeVecS>) }; +class VecS : public Vec { ASMJIT_DEFINE_FINAL_REG(VecS, Vec, RegTraits<RegType::kARM_VecS>) }; //! 64-bit view (D) of VFP/SIMD register. -class VecD : public Vec { ASMJIT_DEFINE_FINAL_REG(VecD, Vec, RegTraits<kTypeVecD>) }; +class VecD : public Vec { ASMJIT_DEFINE_FINAL_REG(VecD, Vec, RegTraits<RegType::kARM_VecD>) }; //! 128-bit vector register (Q or V). -class VecV : public Vec { ASMJIT_DEFINE_FINAL_REG(VecV, Vec, RegTraits<kTypeVecV>) }; +class VecV : public Vec { ASMJIT_DEFINE_FINAL_REG(VecV, Vec, RegTraits<RegType::kARM_VecV>) }; inline GpW Gp::w() const noexcept { return GpW(id()); } inline GpX Gp::x() const noexcept { return GpX(id()); } @@ -399,36 +336,36 @@ inline VecD Vec::d() const noexcept { return VecD(id()); } inline VecV Vec::q() const noexcept { return VecV(id()); } inline VecV Vec::v() const noexcept { return VecV(id()); } -inline VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV::fromSignatureAndId(_makeElementAccessSignature(kElementTypeB, elementIndex), id()); } -inline VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV::fromSignatureAndId(_makeElementAccessSignature(kElementTypeH, elementIndex), id()); } -inline VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV::fromSignatureAndId(_makeElementAccessSignature(kElementTypeS, elementIndex), id()); } -inline VecV Vec::d(uint32_t elementIndex) const noexcept { return VecV::fromSignatureAndId(_makeElementAccessSignature(kElementTypeD, elementIndex), id()); } -inline VecV Vec::h2(uint32_t elementIndex) const noexcept { return VecV::fromSignatureAndId(_makeElementAccessSignature(kElementTypeH2, elementIndex), id()); } -inline VecV Vec::b4(uint32_t elementIndex) const noexcept { return VecV::fromSignatureAndId(_makeElementAccessSignature(kElementTypeB4, elementIndex), id()); } - -inline VecD Vec::b8() const noexcept { return VecD::fromSignatureAndId(VecD::kSignature | kSignatureElementB, id()); } -inline VecS Vec::h2() const noexcept { return VecS::fromSignatureAndId(VecS::kSignature | kSignatureElementH, id()); } -inline VecD Vec::h4() const noexcept { return VecD::fromSignatureAndId(VecD::kSignature | kSignatureElementH, id()); } -inline VecD Vec::s2() const noexcept { return VecD::fromSignatureAndId(VecD::kSignature | kSignatureElementS, id()); } -inline VecV Vec::b16() const noexcept { return VecV::fromSignatureAndId(VecV::kSignature | kSignatureElementB, id()); } -inline VecV Vec::h8() const noexcept { return VecV::fromSignatureAndId(VecV::kSignature | kSignatureElementH, id()); } -inline VecV Vec::s4() const noexcept { return VecV::fromSignatureAndId(VecV::kSignature | kSignatureElementS, id()); } -inline VecV Vec::d2() const noexcept { return VecV::fromSignatureAndId(VecV::kSignature | kSignatureElementD, id()); } +inline VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB, elementIndex), id()); } +inline VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH, elementIndex), id()); } +inline VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeS, elementIndex), id()); } +inline VecV Vec::d(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeD, elementIndex), id()); } +inline VecV Vec::h2(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH2, elementIndex), id()); } +inline VecV Vec::b4(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB4, elementIndex), id()); } + +inline VecD Vec::b8() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementB}, id()); } +inline VecS Vec::h2() const noexcept { return VecS(OperandSignature{VecS::kSignature | kSignatureElementH}, id()); } +inline VecD Vec::h4() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementH}, id()); } +inline VecD Vec::s2() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementS}, id()); } +inline VecV Vec::b16() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementB}, id()); } +inline VecV Vec::h8() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementH}, id()); } +inline VecV Vec::s4() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementS}, id()); } +inline VecV Vec::d2() const noexcept { return VecV(OperandSignature{VecV::kSignature | kSignatureElementD}, id()); } #ifndef _DOXYGEN namespace regs { #endif //! Creates a 32-bit W register operand (ARM/AArch64). -static constexpr GpW w(uint32_t id) noexcept { return GpW(id); } +static inline constexpr GpW w(uint32_t id) noexcept { return GpW(id); } //! Creates a 64-bit X register operand (AArch64). -static constexpr GpX x(uint32_t id) noexcept { return GpX(id); } +static inline constexpr GpX x(uint32_t id) noexcept { return GpX(id); } //! Creates a 32-bit S register operand (ARM/AArch64). -static constexpr VecS s(uint32_t id) noexcept { return VecS(id); } +static inline constexpr VecS s(uint32_t id) noexcept { return VecS(id); } //! Creates a 64-bit D register operand (ARM/AArch64). -static constexpr VecD d(uint32_t id) noexcept { return VecD(id); } +static inline constexpr VecD d(uint32_t id) noexcept { return VecD(id); } //! Creates a 1282-bit V register operand (ARM/AArch64). -static constexpr VecV v(uint32_t id) noexcept { return VecV(id); } +static inline constexpr VecV v(uint32_t id) noexcept { return VecV(id); } #ifndef _DOXYGEN } // {regs} @@ -437,10 +374,6 @@ static constexpr VecV v(uint32_t id) noexcept { return VecV(id); } using namespace regs; #endif -// ============================================================================ -// [asmjit::arm::Mem] -// ============================================================================ - //! Memory operand (ARM). class Mem : public BaseMem { public: @@ -469,40 +402,64 @@ public: kOffsetPostIndex = 0xF }; - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- + //! \name Construction & Destruction + //! \{ //! Construct a default `Mem` operand, that points to [0]. - constexpr Mem() noexcept : BaseMem() {} - constexpr Mem(const Mem& other) noexcept : BaseMem(other) {} + inline constexpr Mem() noexcept + : BaseMem() {} + + inline constexpr Mem(const Mem& other) noexcept + : BaseMem(other) {} - constexpr explicit Mem(const Label& base, int32_t off = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { Label::kLabelTag, base.id(), 0, 0, off, 0, flags }) {} + inline explicit Mem(Globals::NoInit_) noexcept + : BaseMem(Globals::NoInit) {} - constexpr explicit Mem(const BaseReg& base, int32_t off = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { base.type(), base.id(), 0, 0, off, 0, flags }) {} + inline constexpr Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept + : BaseMem(signature, baseId, indexId, offset) {} - constexpr Mem(const BaseReg& base, const BaseReg& index) noexcept - : BaseMem(Decomposed { base.type(), base.id(), index.type(), index.id(), 0, 0, 0 }) {} + inline 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) {} - constexpr Mem(const BaseReg& base, const BaseReg& index, const Shift& shift, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { base.type(), base.id(), index.type(), index.id(), 0, 0, flags | (shift.op() << kSignatureMemPredicateShift) | (shift.value() << kSignatureMemShiftValueShift) }) {} + inline 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) {} - constexpr Mem(uint64_t base, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { 0, uint32_t(base >> 32), 0, 0, int32_t(uint32_t(base & 0xFFFFFFFFu)), 0, flags }) {} + inline 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) {} - constexpr Mem(Globals::Init_, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) noexcept - : BaseMem(Globals::Init, u0, u1, u2, u3) {} + inline 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<kSignatureMemPredicateMask>(uint32_t(shift.op())) | + Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) | + signature, base.id(), index.id(), 0) {} - inline explicit Mem(Globals::NoInit_) noexcept : BaseMem(Globals::NoInit) {} + inline constexpr 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))) {} - // -------------------------------------------------------------------------- - // [Arm Specific] - // -------------------------------------------------------------------------- + //! \} + + //! \name Overloaded Operators + //! \{ + + inline Mem& operator=(const Mem& other) noexcept = default; + + //! \} + + //! \name ARM Specific Features + //! \{ //! Clones the memory operand. - constexpr Mem clone() const noexcept { return Mem(*this); } + inline constexpr Mem clone() const noexcept { return Mem(*this); } //! Gets new memory operand adjusted by `off`. inline Mem cloneAdjusted(int64_t off) const noexcept { Mem result(*this); @@ -518,25 +475,25 @@ public: } //! Gets whether the memory operand has shift (aka scale) constant. - constexpr bool hasShift() const noexcept { return _hasSignaturePart<kSignatureMemShiftValueMask>(); } + inline constexpr bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); } //! Gets the memory operand's shift (aka scale) constant. - constexpr uint32_t shift() const noexcept { return _getSignaturePart<kSignatureMemShiftValueMask>(); } + inline constexpr uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); } //! Sets the memory operand's shift (aka scale) constant. - inline void setShift(uint32_t shift) noexcept { _setSignaturePart<kSignatureMemShiftValueMask>(shift); } + inline void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); } //! Resets the memory operand's shift (aka scale) constant to zero. - inline void resetShift() noexcept { _setSignaturePart<kSignatureMemShiftValueMask>(0); } + inline void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); } - //! Gets memory predicate (shift mode or offset mode), see \ref Predicate::ShiftOp and \ref OffsetMode. - constexpr uint32_t predicate() const noexcept { return _getSignaturePart<kSignatureMemPredicateMask>(); } + //! Gets memory predicate (shift mode or offset mode), see \ref ShiftOp and \ref OffsetMode. + inline constexpr uint32_t predicate() const noexcept { return _signature.getField<kSignatureMemPredicateMask>(); } //! Sets memory predicate to `predicate`, see `Mem::ShiftOp`. - inline void setPredicate(uint32_t predicate) noexcept { _setSignaturePart<kSignatureMemPredicateMask>(predicate); } + inline void setPredicate(uint32_t predicate) noexcept { _signature.setField<kSignatureMemPredicateMask>(predicate); } //! Resets shift mode to LSL (default). - inline void resetPredicate() noexcept { _setSignaturePart<kSignatureMemPredicateMask>(0); } + inline void resetPredicate() noexcept { _signature.setField<kSignatureMemPredicateMask>(0); } - constexpr bool isFixedOffset() const noexcept { return predicate() < kOffsetPreIndex; } - constexpr bool isPreOrPost() const noexcept { return predicate() >= kOffsetPreIndex; } - constexpr bool isPreIndex() const noexcept { return predicate() == kOffsetPreIndex; } - constexpr bool isPostIndex() const noexcept { return predicate() == kOffsetPostIndex; } + inline constexpr bool isFixedOffset() const noexcept { return predicate() < kOffsetPreIndex; } + inline constexpr bool isPreOrPost() const noexcept { return predicate() >= kOffsetPreIndex; } + inline constexpr bool isPreIndex() const noexcept { return predicate() == kOffsetPreIndex; } + inline constexpr bool isPostIndex() const noexcept { return predicate() == kOffsetPostIndex; } inline void resetToFixedOffset() noexcept { resetPredicate(); } inline void makePreIndex() noexcept { setPredicate(kOffsetPreIndex); } @@ -568,80 +525,71 @@ public: return result; } - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - inline Mem& operator=(const Mem& other) noexcept = default; + //! \} }; //! Creates `[base.reg, offset]` memory operand (offset mode). -static constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept { +static inline constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept { return Mem(base, offset); } //! Creates `[base.reg, offset]!` memory operand (pre-index mode). -static constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept { - return Mem(base, offset, Mem::kOffsetPreIndex << Mem::kSignatureMemPredicateShift); +static inline constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept { + return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPreIndex)); } //! Creates `[base.reg], offset` memory operand (post-index mode). -static constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept { - return Mem(base, offset, Mem::kOffsetPostIndex << Mem::kSignatureMemPredicateShift); +static inline constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept { + return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex)); } //! Creates `[base.reg, index]` memory operand. -static constexpr Mem ptr(const Gp& base, const Gp& index) noexcept { +static inline constexpr Mem ptr(const Gp& base, const Gp& index) noexcept { return Mem(base, index); } //! Creates `[base.reg], index` memory operand (post-index mode). -static constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept { - return Mem(base, index, Shift(Shift::kOpLSL, 0), Mem::kOffsetPostIndex << Mem::kSignatureMemPredicateShift); +static inline constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept { + return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex)); } //! Creates `[base.reg, index, SHIFT_OP #shift]` memory operand. -static constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept { +static inline constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept { return Mem(base, index, shift); } //! Creates `[base + offset]` memory operand. -static constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept { +static inline constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept { return Mem(base, offset); } // TODO: [ARM] PC + offset address. #if 0 //! Creates `[PC + offset]` (relative) memory operand. -static constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept { +static inline constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept { return Mem(pc, offset); } #endif //! Creates `[base]` absolute memory operand. //! -//! \note The concept of absolute memory operands doesn't exist on ARM, the ISA -//! only provides PC relative addressing. Absolute memory operands can only be -//! used if it's known that the PC relative offset is encodable and that it -//! would be within the limits. Absolute address is also often output from -//! disassemblers, so AsmJit support it so it can assemble it back. -static constexpr Mem ptr(uint64_t base) noexcept { return Mem(base); } +//! \note The concept of absolute memory operands doesn't exist on ARM, the ISA only provides PC relative addressing. +//! Absolute memory operands can only be used if it's known that the PC relative offset is encodable and that it +//! would be within the limits. Absolute address is also often output from disassemblers, so AsmJit support it so it +//! can assemble it back. +static inline constexpr Mem ptr(uint64_t base) noexcept { return Mem(base); } //! \} ASMJIT_END_SUB_NAMESPACE -// ============================================================================ -// [asmjit::Type::IdOfT<arm::Reg>] -// ============================================================================ - //! \cond INTERNAL ASMJIT_BEGIN_NAMESPACE -ASMJIT_DEFINE_TYPE_ID(arm::GpW, kIdI32); -ASMJIT_DEFINE_TYPE_ID(arm::GpX, kIdI64); -ASMJIT_DEFINE_TYPE_ID(arm::VecS, kIdF32x1); -ASMJIT_DEFINE_TYPE_ID(arm::VecD, kIdF64x1); -ASMJIT_DEFINE_TYPE_ID(arm::VecV, kIdI32x4); +ASMJIT_DEFINE_TYPE_ID(arm::GpW, TypeId::kInt32); +ASMJIT_DEFINE_TYPE_ID(arm::GpX, TypeId::kInt64); +ASMJIT_DEFINE_TYPE_ID(arm::VecS, TypeId::kFloat32x1); +ASMJIT_DEFINE_TYPE_ID(arm::VecD, TypeId::kFloat64x1); +ASMJIT_DEFINE_TYPE_ID(arm::VecV, TypeId::kInt32x4); ASMJIT_END_NAMESPACE //! \endcond |