diff --git a/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h b/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h index 037c8c4af..fb1780bdc 100644 --- a/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h +++ b/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/Emitter.h @@ -544,6 +544,11 @@ namespace FEXCore::ARMEmitter { ROTATE_270 = 0b11, }; + // Concept for contraining some instructions to accept only an XRegister or WRegister. + // Particularly for operations that differ encodings depending on which one is used. + template + concept IsXOrWRegister = std::is_same_v || std::is_same_v; + // This is an emitter that is designed around the smallest code bloat as possible. // Eschewing most developer convenience in order to keep code as small as possible. diff --git a/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/SVEOps.inl b/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/SVEOps.inl index 11d900d39..5d8e1b3a7 100644 --- a/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/SVEOps.inl +++ b/External/FEXCore/Source/Interface/Core/ArchHelpers/CodeEmitter/SVEOps.inl @@ -1419,7 +1419,55 @@ public: // SVE Integer Compare - Scalars // SVE integer compare scalar count and limit - // XXX: + template + requires IsXOrWRegister + void whilege(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar(IsXRegister << 2, 0, pd.Idx(), size, rn, rm); + } + template + requires IsXOrWRegister + void whilegt(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar(IsXRegister << 2, 1, pd.Idx(), size, rn, rm); + } + template + requires IsXOrWRegister + void whilelt(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar((IsXRegister << 2) | 0b001, 0, pd.Idx(), size, rn, rm); + } + template + requires IsXOrWRegister + void whilele(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar((IsXRegister << 2) | 0b001, 1, pd.Idx(), size, rn, rm); + } + template + requires IsXOrWRegister + void whilehs(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar((IsXRegister << 2) | 0b010, 0, pd.Idx(), size, rn, rm); + } + template + requires IsXOrWRegister + void whilehi(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar((IsXRegister << 2) | 0b010, 1, pd.Idx(), size, rn, rm); + } + template + requires IsXOrWRegister + void whilelo(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar((IsXRegister << 2) | 0b011, 0, pd.Idx(), size, rn, rm); + } + template + requires IsXOrWRegister + void whilels(SubRegSize size, PRegister pd, T rn, T rm) { + constexpr auto IsXRegister = static_cast(std::is_same_v); + SVEIntCompareScalar((IsXRegister << 2) | 0b011, 1, pd.Idx(), size, rn, rm); + } + // SVE conditionally terminate scalars // XXX: // SVE pointer conflict compare @@ -4081,3 +4129,16 @@ private: Instr |= pd.Idx(); dc32(Instr); } + + void SVEIntCompareScalar(uint32_t op1, uint32_t b4, uint32_t op2, SubRegSize size, Register rn, Register rm) { + LOGMAN_THROW_A_FMT(size != SubRegSize::i128Bit, "Can't use 128-bit size"); + + uint32_t Instr = 0b0010'0101'0010'0000'0000'0000'0000'0000; + Instr |= FEXCore::ToUnderlying(size) << 22; + Instr |= rm.Idx() << 16; + Instr |= op1 << 10; + Instr |= rn.Idx() << 5; + Instr |= b4 << 4; + Instr |= op2; + dc32(Instr); + } diff --git a/External/FEXCore/unittests/Emitter/SVE_Tests.cpp b/External/FEXCore/unittests/Emitter/SVE_Tests.cpp index db6ec649a..7830e48bb 100644 --- a/External/FEXCore/unittests/Emitter/SVE_Tests.cpp +++ b/External/FEXCore/unittests/Emitter/SVE_Tests.cpp @@ -1601,7 +1601,77 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE predicate initialize") { } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE integer compare scalar count and limit") { - // TODO: Implement in emitter. + TEST_SINGLE(whilege(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.b, x30, x29"); + TEST_SINGLE(whilege(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.h, x30, x29"); + TEST_SINGLE(whilege(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.s, x30, x29"); + TEST_SINGLE(whilege(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilege p15.d, x30, x29"); + TEST_SINGLE(whilege(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.b, w30, w29"); + TEST_SINGLE(whilege(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.h, w30, w29"); + TEST_SINGLE(whilege(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.s, w30, w29"); + TEST_SINGLE(whilege(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilege p15.d, w30, w29"); + + TEST_SINGLE(whilegt(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.b, x30, x29"); + TEST_SINGLE(whilegt(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.h, x30, x29"); + TEST_SINGLE(whilegt(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.s, x30, x29"); + TEST_SINGLE(whilegt(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilegt p15.d, x30, x29"); + TEST_SINGLE(whilegt(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.b, w30, w29"); + TEST_SINGLE(whilegt(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.h, w30, w29"); + TEST_SINGLE(whilegt(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.s, w30, w29"); + TEST_SINGLE(whilegt(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilegt p15.d, w30, w29"); + + TEST_SINGLE(whilelt(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.b, x30, x29"); + TEST_SINGLE(whilelt(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.h, x30, x29"); + TEST_SINGLE(whilelt(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.s, x30, x29"); + TEST_SINGLE(whilelt(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilelt p15.d, x30, x29"); + TEST_SINGLE(whilelt(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.b, w30, w29"); + TEST_SINGLE(whilelt(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.h, w30, w29"); + TEST_SINGLE(whilelt(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.s, w30, w29"); + TEST_SINGLE(whilelt(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilelt p15.d, w30, w29"); + + TEST_SINGLE(whilele(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.b, x30, x29"); + TEST_SINGLE(whilele(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.h, x30, x29"); + TEST_SINGLE(whilele(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.s, x30, x29"); + TEST_SINGLE(whilele(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilele p15.d, x30, x29"); + TEST_SINGLE(whilele(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.b, w30, w29"); + TEST_SINGLE(whilele(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.h, w30, w29"); + TEST_SINGLE(whilele(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.s, w30, w29"); + TEST_SINGLE(whilele(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilele p15.d, w30, w29"); + + TEST_SINGLE(whilehs(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.b, x30, x29"); + TEST_SINGLE(whilehs(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.h, x30, x29"); + TEST_SINGLE(whilehs(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.s, x30, x29"); + TEST_SINGLE(whilehs(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilehs p15.d, x30, x29"); + TEST_SINGLE(whilehs(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.b, w30, w29"); + TEST_SINGLE(whilehs(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.h, w30, w29"); + TEST_SINGLE(whilehs(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.s, w30, w29"); + TEST_SINGLE(whilehs(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilehs p15.d, w30, w29"); + + TEST_SINGLE(whilehi(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.b, x30, x29"); + TEST_SINGLE(whilehi(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.h, x30, x29"); + TEST_SINGLE(whilehi(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.s, x30, x29"); + TEST_SINGLE(whilehi(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilehi p15.d, x30, x29"); + TEST_SINGLE(whilehi(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.b, w30, w29"); + TEST_SINGLE(whilehi(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.h, w30, w29"); + TEST_SINGLE(whilehi(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.s, w30, w29"); + TEST_SINGLE(whilehi(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilehi p15.d, w30, w29"); + + TEST_SINGLE(whilelo(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.b, x30, x29"); + TEST_SINGLE(whilelo(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.h, x30, x29"); + TEST_SINGLE(whilelo(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.s, x30, x29"); + TEST_SINGLE(whilelo(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilelo p15.d, x30, x29"); + TEST_SINGLE(whilelo(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.b, w30, w29"); + TEST_SINGLE(whilelo(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.h, w30, w29"); + TEST_SINGLE(whilelo(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.s, w30, w29"); + TEST_SINGLE(whilelo(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilelo p15.d, w30, w29"); + + TEST_SINGLE(whilels(SubRegSize::i8Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.b, x30, x29"); + TEST_SINGLE(whilels(SubRegSize::i16Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.h, x30, x29"); + TEST_SINGLE(whilels(SubRegSize::i32Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.s, x30, x29"); + TEST_SINGLE(whilels(SubRegSize::i64Bit, PReg::p15, XReg::x30, XReg::x29), "whilels p15.d, x30, x29"); + TEST_SINGLE(whilels(SubRegSize::i8Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.b, w30, w29"); + TEST_SINGLE(whilels(SubRegSize::i16Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.h, w30, w29"); + TEST_SINGLE(whilels(SubRegSize::i32Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.s, w30, w29"); + TEST_SINGLE(whilels(SubRegSize::i64Bit, PReg::p15, WReg::w30, WReg::w29), "whilels p15.d, w30, w29"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE conditionally terminate scalars") {