diff --git a/src/asmjit/core/archcommons.h b/src/asmjit/core/archcommons.h index e9d2c84..ab2d725 100644 --- a/src/asmjit/core/archcommons.h +++ b/src/asmjit/core/archcommons.h @@ -17,6 +17,41 @@ ASMJIT_BEGIN_SUB_NAMESPACE(arm) //! \addtogroup asmjit_arm //! \{ +//! Data type that can be encoded with the instruction (AArch32 only). +enum class DataType : uint32_t { + //! No data type specified (default for all general purpose instructions). + kNone = 0, + //! 8-bit signed integer, specified as `.s8` in assembly. + kS8 = 1, + //! 16-bit signed integer, specified as `.s16` in assembly. + kS16 = 2, + //! 32-bit signed integer, specified as `.s32` in assembly. + kS32 = 3, + //! 64-bit signed integer, specified as `.s64` in assembly. + kS64 = 4, + //! 8-bit unsigned integer, specified as `.u8` in assembly. + kU8 = 5, + //! 16-bit unsigned integer, specified as `.u16` in assembly. + kU16 = 6, + //! 32-bit unsigned integer, specified as `.u32` in assembly. + kU32 = 7, + //! 64-bit unsigned integer, specified as `.u64` in assembly. + kU64 = 8, + //! 16-bit floating point (half precision), specified as `.f16` in assembly. + kF16 = 10, + //! 32-bit floating point (single precision), specified as `.f32` in assembly. + kF32 = 11, + //! 64-bit floating point (double precision), specified as `.f64` in assembly. + kF64 = 12, + //! 8-bit polynomial. + kP8 = 13, + //! 64-bit polynomial. + kP64 = 15, + + //! Maximum value of `DataType`. + kMaxValue = 15 +}; + //! Condition code (both AArch32 & AArch64). //! //! \note This enumeration doesn't match condition code that is used in AArch32/AArch64 opcodes. In general this @@ -75,41 +110,6 @@ enum class CondCode : uint8_t { //! Negates a condition code. static inline constexpr CondCode negateCond(CondCode cond) noexcept { return CondCode(uint8_t(cond) ^ uint8_t(1)); } -//! Data type that can be encoded with the instruction (AArch32 only). -enum class DataType : uint32_t { - //! No data type specified (default for all general purpose instructions). - kNone = 0, - //! 8-bit signed integer, specified as `.s8` in assembly. - kS8 = 1, - //! 16-bit signed integer, specified as `.s16` in assembly. - kS16 = 2, - //! 32-bit signed integer, specified as `.s32` in assembly. - kS32 = 3, - //! 64-bit signed integer, specified as `.s64` in assembly. - kS64 = 4, - //! 8-bit unsigned integer, specified as `.u8` in assembly. - kU8 = 5, - //! 16-bit unsigned integer, specified as `.u16` in assembly. - kU16 = 6, - //! 32-bit unsigned integer, specified as `.u32` in assembly. - kU32 = 7, - //! 64-bit unsigned integer, specified as `.u64` in assembly. - kU64 = 8, - //! 16-bit floating point (half precision), specified as `.f16` in assembly. - kF16 = 10, - //! 32-bit floating point (single precision), specified as `.f32` in assembly. - kF32 = 11, - //! 64-bit floating point (double precision), specified as `.f64` in assembly. - kF64 = 12, - //! 8-bit polynomial. - kP8 = 13, - //! 64-bit polynomial. - kP64 = 15, - - //! Maximum value of `DataType`. - kMaxValue = 15 -}; - //! Shift operation predicate (ARM) describes either SHIFT or EXTEND operation. //! //! \note The constants are AsmJit specific. The first 5 values describe real constants on ARM32 and AArch64 hardware, diff --git a/src/asmjit/core/operand.h b/src/asmjit/core/operand.h index 634acec..789b3ba 100644 --- a/src/asmjit/core/operand.h +++ b/src/asmjit/core/operand.h @@ -47,7 +47,7 @@ enum class RegType : uint8_t { //! No register - unused, invalid, multiple meanings. kNone = 0, - //! This is not a register type. This value is reserved for a \ref Label that used in \ref BaseMem as a base. + //! This is not a register type. This value is reserved for a \ref Label used in \ref BaseMem as a base. //! //! Label tag is used as a sub-type, forming a unique signature across all operand types as 0x1 is never associated //! with any register type. This means that a memory operand's BASE register can be constructed from virtually any @@ -217,6 +217,18 @@ ASMJIT_DEFINE_ENUM_COMPARE(RegGroup) typedef Support::EnumValues RegGroupVirtValues; +//! Label operation type. +//! +//! Operation type describes how a \ref Label should be used to calculate an instruction immediate value, typically +//! used in places that require relocations. +enum class LabelOp : uint32_t { + //! No operation specified, \ref Label encoding is determined by the instruction. + kNone = 0u, + + //! Low 12 bits of the Label's absolute address are used as an immediate value (AArch64). + kAArch64_Lo12 = 1u +}; + //! Operand signature is a 32-bit number describing \ref Operand and some of its payload. //! //! In AsmJit operand signature is used to store additional payload of register, memory, and immediate operands. @@ -273,6 +285,11 @@ struct OperandSignature { kPredicateShift = 20, kPredicateMask = 0x0Fu << kPredicateShift, + // Predicate used by either registers or immediate values (4 bits). + // |....XXXX|........|........|........| + kLabelOpShift = 24, + kLabelOpMask = 0x0Fu << kLabelOpShift, + // Operand size (8 most significant bits). // |XXXXXXXX|........|........|........| kSizeShift = 24, @@ -382,6 +399,8 @@ struct OperandSignature { inline constexpr uint32_t predicate() const noexcept { return getField(); } inline constexpr uint32_t size() const noexcept { return getField(); } + inline constexpr LabelOp labelOp() const noexcept { return LabelOp(getField()); } + inline void setOpType(OperandType opType) noexcept { setField(uint32_t(opType)); } inline void setRegType(RegType regType) noexcept { setField(uint32_t(regType)); } inline void setRegGroup(RegGroup regGroup) noexcept { setField(uint32_t(regGroup)); } @@ -392,6 +411,8 @@ struct OperandSignature { inline void setPredicate(uint32_t predicate) noexcept { setField(predicate); } inline void setSize(uint32_t size) noexcept { setField(size); } + inline void setLabelOp(LabelOp op) noexcept { setField(uint32_t(op)); } + //! \} //! \name Static Constructors @@ -438,6 +459,10 @@ struct OperandSignature { return OperandSignature{size << kSizeShift}; } + static inline constexpr OperandSignature fromLabelOp(LabelOp labelOp) noexcept { + return OperandSignature{uint32_t(labelOp) << kLabelOpShift}; + } + //! \} }; @@ -763,10 +788,18 @@ public: inline constexpr Label(const Label& other) noexcept : Operand(other) {} + //! Creates a cloned label operand of `other`, but with \ref LabelOp set to `op`. + inline constexpr Label(const Label& other, LabelOp op) noexcept + : Operand(Globals::Init, Signature::fromOpType(OperandType::kLabel) | Signature::fromLabelOp(op), other.id(), 0, 0) {} + //! Creates a label operand of the given `id`. inline constexpr explicit Label(uint32_t id) noexcept : Operand(Globals::Init, Signature::fromOpType(OperandType::kLabel), id, 0, 0) {} + //! Creates a label operand of the given `id`. + inline constexpr Label(uint32_t id, LabelOp op) noexcept + : Operand(Globals::Init, Signature::fromOpType(OperandType::kLabel) | Signature::fromLabelOp(op), id, 0, 0) {} + inline explicit Label(Globals::NoInit_) noexcept : Operand(Globals::NoInit) {} @@ -795,6 +828,16 @@ public: //! Sets the label `id`. inline void setId(uint32_t id) noexcept { _baseId = id; } + //! Returns \ref LabelOp associated with this label. + inline LabelOp op() const noexcept { return _signature.labelOp(); } + //! Tests whether the label has associated \ref LabelOp. + inline bool hasOp() const noexcept { return _signature.labelOp() != LabelOp::kNone; } + //! Sets \ref LabelOp to be associated with this label. + inline void setOp(LabelOp op) noexcept { _signature.setLabelOp(op); } + + //! Returns a new \ref Label with associated \ref LabelOp::kAArch64_Lo12. + inline Label lo12() const noexcept { return Label(*this, LabelOp::kAArch64_Lo12); } + //! \} }; @@ -1392,7 +1435,7 @@ public: //! \} }; -//! Type of the an immediate value. +//! Type of an immediate value. enum class ImmType : uint32_t { //! Immediate is integer. kInt = 0,