diff --git a/README.md b/README.md index 7bf0893..aac8f3a 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,6 @@ TODO * [ ] Ports: * [ ] 32-bit ARM/Thumb port. - * [ ] 64-bit ARM (AArch64) port. * [ ] RISC-V port. Support diff --git a/src/asmjit/arm/a64assembler.cpp b/src/asmjit/arm/a64assembler.cpp index e80f9c1..87c09a8 100644 --- a/src/asmjit/arm/a64assembler.cpp +++ b/src/asmjit/arm/a64assembler.cpp @@ -21,12 +21,16 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64) +// a64::Assembler - Utils +// ====================== + +static ASMJIT_FORCE_INLINE constexpr uint32_t diff(RegType a, RegType b) noexcept { return uint32_t(a) - uint32_t(b); } +static ASMJIT_FORCE_INLINE constexpr uint32_t diff(VecElementType elementType, VecElementType baseType) noexcept { return uint32_t(elementType) - uint32_t(baseType); } + // a64::Assembler - Cond // ===================== -static inline uint32_t condCodeToOpcodeCond(uint32_t cond) noexcept { - return (uint32_t(cond) - 2u) & 0xFu; -} +static inline uint32_t condCodeToOpcodeCond(uint32_t cond) noexcept { return (uint32_t(cond) - 2u) & 0xFu; } // a64::Assembler - Bits // ===================== @@ -49,10 +53,6 @@ static constexpr uint32_t kWX = InstDB::kWX; static const uint8_t armShiftOpToLdStOptMap[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) }; #undef VALUE -static inline constexpr uint32_t diff(RegType a, RegType b) noexcept { - return uint32_t(a) - uint32_t(b); -} - // asmjit::a64::Assembler - SizeOp // =============================== @@ -118,25 +118,25 @@ struct SizeOpTable { }; #define VALUE_BIN(x) { \ - x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k00 : \ - x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k00Q : \ - x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00 : \ - x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00Q : SizeOp::kInvalid \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kNone)) ? SizeOp::k00 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kNone)) ? SizeOp::k00Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kB )) ? SizeOp::k00 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kB )) ? SizeOp::k00Q : SizeOp::kInvalid \ } #define VALUE_ANY(x) { \ - x == (((uint32_t(RegType::kARM_VecB) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k00S : \ - x == (((uint32_t(RegType::kARM_VecH) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k01S : \ - x == (((uint32_t(RegType::kARM_VecS) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k10S : \ - x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeNone)) ? SizeOp::k11S : \ - x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00 : \ - x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeB )) ? SizeOp::k00Q : \ - x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeH )) ? SizeOp::k01 : \ - x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeH )) ? SizeOp::k01Q : \ - x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeS )) ? SizeOp::k10 : \ - x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeS )) ? SizeOp::k10Q : \ - x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeD )) ? SizeOp::k11S : \ - x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | (Vec::kElementTypeD )) ? SizeOp::k11Q : SizeOp::kInvalid \ + x == (((uint32_t(RegType::kARM_VecB) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kNone)) ? SizeOp::k00S : \ + x == (((uint32_t(RegType::kARM_VecH) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kNone)) ? SizeOp::k01S : \ + x == (((uint32_t(RegType::kARM_VecS) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kNone)) ? SizeOp::k10S : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kNone)) ? SizeOp::k11S : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kB )) ? SizeOp::k00 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kB )) ? SizeOp::k00Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kH )) ? SizeOp::k01 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kH )) ? SizeOp::k01Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kS )) ? SizeOp::k10 : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kS )) ? SizeOp::k10Q : \ + x == (((uint32_t(RegType::kARM_VecD) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kD )) ? SizeOp::k11S : \ + x == (((uint32_t(RegType::kARM_VecV) - uint32_t(RegType::kARM_VecB)) << 3) | uint32_t(VecElementType::kD )) ? SizeOp::k11Q : SizeOp::kInvalid \ } static const SizeOpTable sizeOpTable[SizeOpTable::kCount] = { @@ -254,16 +254,16 @@ static const Operand_& significantSimdOp(const Operand_& o0, const Operand_& o1, return !(instFlags & InstDB::kInstFlagLong) ? o0 : o1; } -static inline SizeOp armElementTypeToSizeOp(uint32_t vecOpType, RegType regType, uint32_t elementType) noexcept { +static inline SizeOp armElementTypeToSizeOp(uint32_t vecOpType, RegType regType, VecElementType elementType) noexcept { // Instruction data or Assembler is wrong if this triggers an assertion failure. ASMJIT_ASSERT(vecOpType < InstDB::kVO_Count); // ElementType uses 3 bits in the operand signature, it should never overflow. - ASMJIT_ASSERT(elementType <= 0x7u); + ASMJIT_ASSERT(uint32_t(elementType) <= 0x7u); const SizeOpMap& map = sizeOpMap[vecOpType]; const SizeOpTable& table = sizeOpTable[map.tableId]; - size_t index = (Support::min(diff(regType, RegType::kARM_VecB), diff(RegType::kARM_VecV, RegType::kARM_VecB) + 1) << 3) | elementType; + size_t index = (Support::min(diff(regType, RegType::kARM_VecB), diff(RegType::kARM_VecV, RegType::kARM_VecB) + 1) << 3) | uint32_t(elementType); SizeOp op = table.array[index]; SizeOp modifiedOp { uint8_t(op.value & map.sizeOpMask) }; @@ -537,7 +537,7 @@ static inline bool pickFpOpcode(const Vec& reg, uint32_t sOp, uint32_t sHf, uint else { // Vector operation [HSD]. uint32_t q = diff(reg.type(), RegType::kARM_VecD); - uint32_t sz = reg.elementType() - Vec::kElementTypeH; + uint32_t sz = diff(reg.elementType(), VecElementType::kH); if (q > 1u || sz > 2u || !Support::bitTest(szBits[vHf].sizeMask, sz)) return false; @@ -2768,7 +2768,7 @@ Case_BaseLdurStur: // hD, vS.{4|8}h (16-bit) // sD, vS.4s (32-bit) uint32_t sz = diff(o0.as().type(), RegType::kARM_VecH); - uint32_t elementSz = o1.as().elementType() - Vec::kElementTypeH; + uint32_t elementSz = diff(o1.as().elementType(), VecElementType::kH); // Size greater than 1 means 64-bit elements, not supported. if ((sz | elementSz) > 1 || sz != elementSz) @@ -2890,7 +2890,7 @@ Case_BaseLdurStur: if (q > 1) goto InvalidInstruction; - uint32_t sz = o0.as().elementType() - Vec::kElementTypeB; + uint32_t sz = diff(o0.as().elementType(), VecElementType::kB); if (sz == 0 || sz > 3) goto InvalidInstruction; @@ -2982,7 +2982,7 @@ Case_BaseLdurStur: if (q > 1) goto InvalidInstruction; - uint32_t sz = o0.as().elementType() - Vec::kElementTypeB; + uint32_t sz = diff(o0.as().elementType(), VecElementType::kB); if (sz == 0 || sz > 3) goto InvalidInstruction; @@ -3164,11 +3164,11 @@ Case_BaseLdurStur: if (uint32_t(opcode.hasQ()) != q) goto InvalidInstruction; - if (rL.isVecS4() && rN.elementType() == Vec::kElementTypeH && !opData.isCvtxn()) { + if (rL.isVecS4() && rN.elementType() == VecElementType::kH && !opData.isCvtxn()) { goto EmitOp_Rd0_Rn5; } - if (rL.isVecD2() && rN.elementType() == Vec::kElementTypeS) { + if (rL.isVecD2() && rN.elementType() == VecElementType::kS) { opcode |= B(22); goto EmitOp_Rd0_Rn5; } @@ -3279,8 +3279,8 @@ Case_BaseLdurStur: } if (uint32_t(o0.as().type()) != uint32_t(o1.as().type()) + qIsOptional || - o0.as().elementType() != opData.tA || - o1.as().elementType() != opData.tB) + uint32_t(o0.as().elementType()) != opData.tA || + uint32_t(o1.as().elementType()) != opData.tB) goto InvalidInstruction; if (!o2.as().hasElementIndex()) { @@ -3292,7 +3292,7 @@ Case_BaseLdurStur: goto EmitOp_Rd0_Rn5_Rm16; } else { - if (o2.as().elementType() != opData.tElement) + if (uint32_t(o2.as().elementType()) != opData.tElement) goto InvalidInstruction; if (o2.as().id() > 15) @@ -3442,7 +3442,7 @@ Case_BaseLdurStur: } else { uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); - uint32_t sz = o0.as().elementType() - Vec::kElementTypeH; + uint32_t sz = diff(o0.as().elementType(), VecElementType::kH); if (q > 1 || sz > 2) goto InvalidInstruction; @@ -3496,7 +3496,7 @@ Case_BaseLdurStur: if (q > 1) goto InvalidInstruction; - uint32_t sz = o0.as().elementType() - Vec::kElementTypeH; + uint32_t sz = diff(o0.as().elementType(), VecElementType::kH); if (sz > 2) goto InvalidInstruction; @@ -3520,7 +3520,7 @@ Case_BaseLdurStur: if (isign4 == ENC_OPS2(Reg, Reg)) { // The first destination operand is scalar, which matches element-type of source vectors. uint32_t L = (instFlags & InstDB::kInstFlagLong) != 0; - if (diff(o0.as().type(), RegType::kARM_VecB) != o1.as().elementType() - Vec::kElementTypeB + L) + if (diff(o0.as().type(), RegType::kARM_VecB) != diff(o1.as().elementType(), VecElementType::kB) + L) goto InvalidInstruction; SizeOp sizeOp = armElementTypeToSizeOp(opData.vecOpType, o1.as().type(), o1.as().elementType()); @@ -3620,7 +3620,7 @@ Case_BaseLdurStur: if (!sizeOp.isValid()) goto InvalidInstruction; - if (!checkSignature(o0, o1) || !o0.as().isVecV() || o0.as().elementType() != o2.as().elementType() + 1) + if (!checkSignature(o0, o1) || !o0.as().isVecV() || uint32_t(o0.as().elementType()) != uint32_t(o2.as().elementType()) + 1u) goto InvalidInstruction; opcode.reset(opData.opcode()); @@ -3905,9 +3905,9 @@ Case_BaseLdurStur: if (o0.as().type() != o1.as().type() || o1.as().type() != o2.as().type()) goto InvalidInstruction; - if (o0.as().elementType() != opData.tA || - o1.as().elementType() != opData.tB || - o2.as().elementType() != opData.tB) + if (uint32_t(o0.as().elementType()) != opData.tA || + uint32_t(o1.as().elementType()) != opData.tB || + uint32_t(o2.as().elementType()) != opData.tB) goto InvalidInstruction; opcode.reset(uint32_t(opData.vectorOp) << 10); @@ -3921,9 +3921,9 @@ Case_BaseLdurStur: if (o0.as().type() != o1.as().type() || !o2.as().isVecV()) goto InvalidInstruction; - if (o0.as().elementType() != opData.tA || - o1.as().elementType() != opData.tB || - o2.as().elementType() != opData.tElement) + if (uint32_t(o0.as().elementType()) != opData.tA || + uint32_t(o1.as().elementType()) != opData.tB || + uint32_t(o2.as().elementType()) != opData.tElement) goto InvalidInstruction; uint32_t elementIndex = o2.as().elementIndex(); @@ -3949,13 +3949,13 @@ Case_BaseLdurStur: case InstDB::kEncodingSimdDup: SimdDup: { if (isign4 == ENC_OPS2(Reg, Reg)) { // Truth table of valid encodings of `Q:1|ElementType:3` - uint32_t kValidEncodings = B(Vec::kElementTypeB + 0) | - B(Vec::kElementTypeH + 0) | - B(Vec::kElementTypeS + 0) | - B(Vec::kElementTypeB + 8) | - B(Vec::kElementTypeH + 8) | - B(Vec::kElementTypeS + 8) | - B(Vec::kElementTypeD + 8) ; + uint32_t kValidEncodings = B(uint32_t(VecElementType::kB) + 0) | + B(uint32_t(VecElementType::kH) + 0) | + B(uint32_t(VecElementType::kS) + 0) | + B(uint32_t(VecElementType::kB) + 8) | + B(uint32_t(VecElementType::kH) + 8) | + B(uint32_t(VecElementType::kS) + 8) | + B(uint32_t(VecElementType::kD) + 8) ; uint32_t q = diff(o0.as().type(), RegType::kARM_VecD); @@ -3964,7 +3964,7 @@ Case_BaseLdurStur: // // NOTE: This is only scalar for `dup d, x` case, otherwise the value // would be duplicated across all vector elements (1, 2, 4, 8, or 16). - uint32_t elementType = o0.as().elementType(); + uint32_t elementType = uint32_t(o0.as().elementType()); if (q > 1 || !Support::bitTest(kValidEncodings, (q << 3) | elementType)) goto InvalidInstruction; @@ -3985,7 +3985,7 @@ Case_BaseLdurStur: // DUP - Vec (scalar) <- Vec[N]. uint32_t lsbIndex = diff(o0.as().type(), RegType::kARM_VecB); - if (lsbIndex != o1.as().elementType() - Vec::kElementTypeB || lsbIndex > 3) + if (lsbIndex != diff(o1.as().elementType(), VecElementType::kB) || lsbIndex > 3) goto InvalidInstruction; uint32_t imm5 = ((dstIndex << 1) | 1u) << lsbIndex; @@ -3998,7 +3998,7 @@ Case_BaseLdurStur: } else { // DUP - Vec (all) <- Vec[N]. - uint32_t elementType = o0.as().elementType(); + uint32_t elementType = uint32_t(o0.as().elementType()); if (q > 1 || !Support::bitTest(kValidEncodings, (q << 3) | elementType)) goto InvalidInstruction; @@ -4023,7 +4023,7 @@ Case_BaseLdurStur: if (!o0.as().hasElementIndex()) goto InvalidInstruction; - uint32_t elementType = o0.as().elementType(); + uint32_t elementType = uint32_t(o0.as().elementType()); uint32_t dstIndex = o0.as().elementIndex(); uint32_t lsbIndex = elementType - 1u; @@ -4735,7 +4735,7 @@ Case_SimdLdurStur: uint32_t q = 0; uint32_t rm = 0; uint32_t rn = m.baseId(); - uint32_t sz = v.elementType() - Vec::kElementTypeB; + uint32_t sz = diff(v.elementType(), VecElementType::kB); uint32_t opcSsize = sz; uint32_t offsetPossibility = 0; diff --git a/src/asmjit/arm/a64assembler.h b/src/asmjit/arm/a64assembler.h index 7006c8c..3193215 100644 --- a/src/asmjit/arm/a64assembler.h +++ b/src/asmjit/arm/a64assembler.h @@ -31,14 +31,6 @@ public: //! \} - //! \name Accessors - //! \{ - - //! Gets whether the current ARM mode is THUMB (alternative to 32-bit ARM encoding). - ASMJIT_INLINE_NODEBUG bool isInThumbMode() const noexcept { return _environment.isArchThumb(); } - - //! \} - //! \name Emit //! \{ diff --git a/src/asmjit/arm/a64instapi.cpp b/src/asmjit/arm/a64instapi.cpp index 964bac1..97e23fd 100644 --- a/src/asmjit/arm/a64instapi.cpp +++ b/src/asmjit/arm/a64instapi.cpp @@ -174,10 +174,10 @@ Error queryRWInfo(const BaseInst& inst, const Operand_* operands, size_t opCount if (srcOp.isReg()) { if (srcOp.as().hasElementIndex()) { // Only part of the vector is accessed if element index [] is used. - uint32_t elementType = srcOp.as().elementType(); + VecElementType elementType = srcOp.as().elementType(); uint32_t elementIndex = srcOp.as().elementIndex(); - uint32_t elementSize = elementTypeSize[elementType]; + uint32_t elementSize = elementTypeSize[size_t(elementType)]; uint64_t accessMask = uint64_t(Support::lsbMask(elementSize)) << (elementIndex * elementSize); op._readByteMask &= accessMask; diff --git a/src/asmjit/arm/a64instdb_p.h b/src/asmjit/arm/a64instdb_p.h index 0256f9f..5c3da7e 100644 --- a/src/asmjit/arm/a64instdb_p.h +++ b/src/asmjit/arm/a64instdb_p.h @@ -59,14 +59,14 @@ enum RWInfoType : uint32_t { // a64::InstDB - ElementType // ========================= -enum ElementType : uint8_t { - kET_None = Vec::kElementTypeNone, - kET_B = Vec::kElementTypeB, - kET_H = Vec::kElementTypeH, - kET_S = Vec::kElementTypeS, - kET_D = Vec::kElementTypeD, - kET_2H = Vec::kElementTypeH2, - kET_4B = Vec::kElementTypeB4 +enum InstElementType : uint8_t { + kET_None = uint8_t(VecElementType::kNone), + kET_B = uint8_t(VecElementType::kB), + kET_H = uint8_t(VecElementType::kH), + kET_S = uint8_t(VecElementType::kS), + kET_D = uint8_t(VecElementType::kD), + kET_2H = uint8_t(VecElementType::kH2), + kET_4B = uint8_t(VecElementType::kB4) }; // a64::InstDB - GpType diff --git a/src/asmjit/arm/a64operand.cpp b/src/asmjit/arm/a64operand.cpp index 3dba96d..e8c6100 100644 --- a/src/asmjit/arm/a64operand.cpp +++ b/src/asmjit/arm/a64operand.cpp @@ -56,7 +56,7 @@ UNIT(a64_operand) { EXPECT_EQ(vd_1.group(), RegGroup::kVec); EXPECT_EQ(vd_1.id(), 15u); EXPECT_TRUE(vd_1.isVecD2()); - EXPECT_EQ(vd_1.elementType(), Vec::kElementTypeD); + EXPECT_EQ(vd_1.elementType(), VecElementType::kD); EXPECT_TRUE(vd_1.hasElementIndex()); EXPECT_EQ(vd_1.elementIndex(), 1u); @@ -65,7 +65,7 @@ UNIT(a64_operand) { EXPECT_EQ(vs_3.group(), RegGroup::kVec); EXPECT_EQ(vs_3.id(), 15u); EXPECT_TRUE(vs_3.isVecS4()); - EXPECT_EQ(vs_3.elementType(), Vec::kElementTypeS); + EXPECT_EQ(vs_3.elementType(), VecElementType::kS); EXPECT_TRUE(vs_3.hasElementIndex()); EXPECT_EQ(vs_3.elementIndex(), 3u); @@ -74,7 +74,7 @@ UNIT(a64_operand) { EXPECT_EQ(vb_4.group(), RegGroup::kVec); EXPECT_EQ(vb_4.id(), 15u); EXPECT_TRUE(vb_4.isVecB4x4()); - EXPECT_EQ(vb_4.elementType(), Vec::kElementTypeB4); + EXPECT_EQ(vb_4.elementType(), VecElementType::kB4); EXPECT_TRUE(vb_4.hasElementIndex()); EXPECT_EQ(vb_4.elementIndex(), 3u); } diff --git a/src/asmjit/arm/a64operand.h b/src/asmjit/arm/a64operand.h index 0d1cdd2..31b0beb 100644 --- a/src/asmjit/arm/a64operand.h +++ b/src/asmjit/arm/a64operand.h @@ -69,74 +69,60 @@ ASMJIT_INLINE_NODEBUG GpW Gp::w() const noexcept { return GpW(id()); } ASMJIT_INLINE_NODEBUG GpX Gp::x() const noexcept { return GpX(id()); } #endif +//! Vector element type (AArch64). +enum class VecElementType : uint32_t { + //! No element type specified. + kNone = 0, + //! Byte elements (B8 or B16). + kB, + //! Halfword elements (H4 or H8). + kH, + //! Singleword elements (S2 or S4). + kS, + //! Doubleword elements (D2). + kD, + //! Byte elements grouped by 4 bytes (B4). + //! + //! \note This element-type is only used by few instructions. + kB4, + //! Halfword elements grouped by 2 halfwords (H2). + //! + //! \note This element-type is only used by few instructions. + kH2, + + //! Maximum value of \ref VecElementType + kMaxValue = kH2 +}; + //! Vector register (AArch64). class Vec : public BaseVec { public: ASMJIT_DEFINE_ABSTRACT_REG(Vec, BaseVec) - //! Element type (AArch64 only). - enum ElementType : uint32_t { - //! No element type specified. - kElementTypeNone = 0, - //! Byte elements (B8 or B16). - kElementTypeB, - //! Halfword elements (H4 or H8). - kElementTypeH, - //! Singleword elements (S2 or S4). - kElementTypeS, - //! Doubleword elements (D2). - kElementTypeD, - //! Byte elements grouped by 4 bytes (B4). - //! - //! \note This element-type is only used by few instructions. - kElementTypeB4, - //! Halfword elements grouped by 2 halfwords (H2). - //! - //! \note This element-type is only used by few instructions. - kElementTypeH2, - - //! Count of element types. - kElementTypeCount - }; - //! \cond //! Shortcuts. enum SignatureReg : uint32_t { - kSignatureElementB = kElementTypeB << kSignatureRegElementTypeShift, - kSignatureElementH = kElementTypeH << kSignatureRegElementTypeShift, - kSignatureElementS = kElementTypeS << kSignatureRegElementTypeShift, - kSignatureElementD = kElementTypeD << kSignatureRegElementTypeShift, - kSignatureElementB4 = kElementTypeB4 << kSignatureRegElementTypeShift, - kSignatureElementH2 = kElementTypeH2 << kSignatureRegElementTypeShift + kSignatureElementB = uint32_t(VecElementType::kB) << kSignatureRegElementTypeShift, + kSignatureElementH = uint32_t(VecElementType::kH) << kSignatureRegElementTypeShift, + kSignatureElementS = uint32_t(VecElementType::kS) << kSignatureRegElementTypeShift, + kSignatureElementD = uint32_t(VecElementType::kD) << kSignatureRegElementTypeShift, + kSignatureElementB4 = uint32_t(VecElementType::kB4) << kSignatureRegElementTypeShift, + kSignatureElementH2 = uint32_t(VecElementType::kH2) << kSignatureRegElementTypeShift }; //! \endcond - //! Returns whether the register has associated an element type. - ASMJIT_INLINE_NODEBUG constexpr bool hasElementType() const noexcept { return _signature.hasField(); } - //! Returns whether the register has element index (it's an element index access). - ASMJIT_INLINE_NODEBUG constexpr bool hasElementIndex() const noexcept { return _signature.hasField(); } //! Returns whether the register has element type or element index (or both). ASMJIT_INLINE_NODEBUG constexpr bool hasElementTypeOrIndex() const noexcept { return _signature.hasField(); } - //! Returns element type of the register. - ASMJIT_INLINE_NODEBUG constexpr uint32_t elementType() const noexcept { return _signature.getField(); } - //! Sets element type of the register to `elementType`. - ASMJIT_INLINE_NODEBUG void setElementType(uint32_t elementType) noexcept { _signature.setField(elementType); } - //! Resets element type to none. + //! Returns whether the vector register has associated a vector element type. + ASMJIT_INLINE_NODEBUG constexpr bool hasElementType() const noexcept { return _signature.hasField(); } + //! Returns vector element type of the register. + ASMJIT_INLINE_NODEBUG constexpr VecElementType elementType() const noexcept { return VecElementType(_signature.getField()); } + //! Sets vector element type of the register to `elementType`. + ASMJIT_INLINE_NODEBUG void setElementType(VecElementType elementType) noexcept { _signature.setField(uint32_t(elementType)); } + //! Resets vector element type to none. ASMJIT_INLINE_NODEBUG void resetElementType() noexcept { _signature.setField(0); } - //! Returns element index of the register. - ASMJIT_INLINE_NODEBUG constexpr uint32_t elementIndex() const noexcept { return _signature.getField(); } - //! Sets element index of the register to `elementType`. - ASMJIT_INLINE_NODEBUG void setElementIndex(uint32_t elementIndex) noexcept { - _signature |= kSignatureRegElementFlagMask; - _signature.setField(elementIndex); - } - //! Resets element index of the register. - ASMJIT_INLINE_NODEBUG void resetElementIndex() noexcept { - _signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask); - } - ASMJIT_INLINE_NODEBUG constexpr bool isVecB8() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits::kSignature | kSignatureElementB); } ASMJIT_INLINE_NODEBUG constexpr bool isVecH4() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits::kSignature | kSignatureElementH); } ASMJIT_INLINE_NODEBUG constexpr bool isVecS2() const noexcept { return _signature.subset(kBaseSignatureMask | kSignatureRegElementTypeMask) == (RegTraits::kSignature | kSignatureElementS); } @@ -197,12 +183,12 @@ public: //! Cast this register to V.2D. ASMJIT_INLINE_NODEBUG VecV d2() const noexcept; - static ASMJIT_INLINE_NODEBUG constexpr OperandSignature _makeElementAccessSignature(uint32_t elementType, uint32_t elementIndex) noexcept { + static ASMJIT_INLINE_NODEBUG constexpr OperandSignature _makeElementAccessSignature(VecElementType elementType, uint32_t elementIndex) noexcept { return OperandSignature{ - uint32_t(RegTraits::kSignature) | - uint32_t(kSignatureRegElementFlagMask) | - uint32_t(elementType << kSignatureRegElementTypeShift) | - uint32_t(elementIndex << kSignatureRegElementIndexShift)}; + uint32_t(RegTraits::kSignature) | + uint32_t(kSignatureRegElementFlagMask) | + (uint32_t(elementType) << kSignatureRegElementTypeShift) | + (uint32_t(elementIndex << kSignatureRegElementIndexShift))}; } }; @@ -243,12 +229,12 @@ ASMJIT_INLINE_NODEBUG VecD Vec::d() const noexcept { return VecD(id()); } ASMJIT_INLINE_NODEBUG VecV Vec::q() const noexcept { return VecV(id()); } ASMJIT_INLINE_NODEBUG VecV Vec::v() const noexcept { return VecV(id()); } -ASMJIT_INLINE_NODEBUG VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB, elementIndex), id()); } -ASMJIT_INLINE_NODEBUG VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH, elementIndex), id()); } -ASMJIT_INLINE_NODEBUG VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeS, elementIndex), id()); } -ASMJIT_INLINE_NODEBUG VecV Vec::d(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeD, elementIndex), id()); } -ASMJIT_INLINE_NODEBUG VecV Vec::h2(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeH2, elementIndex), id()); } -ASMJIT_INLINE_NODEBUG VecV Vec::b4(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(kElementTypeB4, elementIndex), id()); } +ASMJIT_INLINE_NODEBUG VecV Vec::b(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kB, elementIndex), id()); } +ASMJIT_INLINE_NODEBUG VecV Vec::h(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kH, elementIndex), id()); } +ASMJIT_INLINE_NODEBUG VecV Vec::s(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kS, elementIndex), id()); } +ASMJIT_INLINE_NODEBUG VecV Vec::d(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kD, elementIndex), id()); } +ASMJIT_INLINE_NODEBUG VecV Vec::h2(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kH2, elementIndex), id()); } +ASMJIT_INLINE_NODEBUG VecV Vec::b4(uint32_t elementIndex) const noexcept { return VecV(_makeElementAccessSignature(VecElementType::kB4, elementIndex), id()); } ASMJIT_INLINE_NODEBUG VecD Vec::b8() const noexcept { return VecD(OperandSignature{VecD::kSignature | kSignatureElementB}, id()); } ASMJIT_INLINE_NODEBUG VecS Vec::h2() const noexcept { return VecS(OperandSignature{VecS::kSignature | kSignatureElementH}, id()); } diff --git a/src/asmjit/arm/a64rapass.cpp b/src/asmjit/arm/a64rapass.cpp index 4b58e7f..5606586 100644 --- a/src/asmjit/arm/a64rapass.cpp +++ b/src/asmjit/arm/a64rapass.cpp @@ -230,7 +230,7 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB if (reg.as().hasElementIndex()) { // Only the first 0..15 registers can be used if the register uses // element accessor that accesses half-words (h[0..7] elements). - if (instInfo.hasFlag(InstDB::kInstFlagVH0_15) && reg.as().elementType() == Vec::kElementTypeH) { + if (instInfo.hasFlag(InstDB::kInstFlagVH0_15) && reg.as().elementType() == VecElementType::kH) { if (Support::test(flags, RATiedFlags::kUse)) useId &= 0x0000FFFFu; else diff --git a/src/asmjit/arm/armformatter.cpp b/src/asmjit/arm/armformatter.cpp index f6b2dcb..601d976 100644 --- a/src/asmjit/arm/armformatter.cpp +++ b/src/asmjit/arm/armformatter.cpp @@ -318,9 +318,9 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister( ASMJIT_PROPAGATE(sb.appendFormat("%c%u", letter, rId)); } + constexpr uint32_t kElementTypeCount = uint32_t(a64::VecElementType::kMaxValue) + 1; if (elementType) { - if (elementType > a64::Vec::kElementTypeCount) - elementType = a64::Vec::kElementTypeCount; + elementType = Support::min(elementType, kElementTypeCount); FormatElementData elementData = formatElementDataTable[elementType]; uint32_t elementCount = elementData.elementCount; diff --git a/src/asmjit/core.h b/src/asmjit/core.h index b8c3636..21e2157 100644 --- a/src/asmjit/core.h +++ b/src/asmjit/core.h @@ -239,6 +239,13 @@ namespace asmjit { //! because some compilers would warn about that. If your project compiles fine with `ASMJIT_NO_DEPRECATED` //! it's not using anything, which was deprecated. //! +//! ### Changes committed at 2023-12-27 +//! +//! Core changes: +//! +//! - Renamed `a64::Vec::ElementType` to `a64::VecElementType` and made it a typed enum. This enum was used mostly +//! internally, but there is a public API using it, so it's a breaking change. +//! //! ### Changes committed at 2023-12-26 //! //! Core changes: @@ -1045,7 +1052,7 @@ namespace asmjit { //! //! // Type-unsafe, but possible. //! a.emit(x86::Inst::kIdMov, dst, m); -//! // Also possible, `emit()` is typeless and can be used with raw Operand. +//! // Also possible, `emit()` is type-less and can be used with raw Operand. //! a.emit(x86::Inst::kIdMov, dst, op); //! } //! ``` @@ -1139,7 +1146,7 @@ namespace asmjit { //! mem.size(); // 4. //! mem.offset(); // 12. //! -//! mem.setSize(0); // Sets the size to 0 (makes it sizeless). +//! mem.setSize(0); // Sets the size to 0 (makes it size-less). //! mem.addOffset(-1); // Adds -1 to the offset and makes it 11. //! mem.setOffset(0); // Sets the offset to 0. //! mem.setBase(rcx); // Changes BASE to RCX.