diff --git a/CodeEmitter/CodeEmitter/SVEOps.inl b/CodeEmitter/CodeEmitter/SVEOps.inl index eb2b68185..46bad1105 100644 --- a/CodeEmitter/CodeEmitter/SVEOps.inl +++ b/CodeEmitter/CodeEmitter/SVEOps.inl @@ -2312,15 +2312,15 @@ public: // SVE floating-point convert precision void fcvt(SubRegSize to, SubRegSize from, ZRegister zd, PRegisterMerge pg, ZRegister zn) { + LOGMAN_THROW_A_FMT(to != from, "to and from sizes cannot be the same."); + LOGMAN_THROW_A_FMT(to != SubRegSize::i8Bit && from != SubRegSize::i8Bit, "Can't use 8-bit element size"); SVEFPConvertPrecision(to, from, zd, pg, zn); } void fcvtx(ZRegister zd, PRegisterMerge pg, ZRegister zn) { - LOGMAN_THROW_A_FMT(pg <= PReg::p7, "Can only use p0-p7 as a governing predicate"); - uint32_t Instr = 0b0110'0101'0000'1010'1010'0000'0000'0000; - Instr |= pg.Idx() << 10; - Instr |= zn.Idx() << 5; - Instr |= zd.Idx(); - dc32(Instr); + SVEFPConvertPrecision(SubRegSize::i32Bit, SubRegSize::i8Bit, zd, pg, zn); + } + void bfcvt(ZRegister zd, PRegisterMerge pg, ZRegister zn) { + SVEFPConvertPrecision(SubRegSize::i32Bit, SubRegSize::i32Bit, zd, pg, zn); } // SVE floating-point unary operations @@ -3847,14 +3847,19 @@ private: void SVEFPConvertPrecision(SubRegSize to, SubRegSize from, ZRegister zd, PRegister pg, ZRegister zn) { LOGMAN_THROW_A_FMT(pg <= PReg::p7, "Can only use p0-p7 as a governing predicate"); - LOGMAN_THROW_A_FMT(to != from, "to and from sizes cannot be the same."); - LOGMAN_THROW_A_FMT(to != SubRegSize::i8Bit && to != SubRegSize::i128Bit && from != SubRegSize::i8Bit && from != SubRegSize::i128Bit, - "Can't use 8-bit or 128-bit element size"); + LOGMAN_THROW_A_FMT(to != SubRegSize::i128Bit && from != SubRegSize::i128Bit, "Can't use 128-bit element size"); // Encodings for the to and from sizes can get a little funky // depending on what is being converted to/from. const uint32_t op = [&] { switch (from) { + case SubRegSize::i8Bit: { + switch (to) { + case SubRegSize::i32Bit: return 0x00020000U; + default: return UINT32_MAX; + } + } + case SubRegSize::i16Bit: { switch (to) { case SubRegSize::i32Bit: return 0x00810000U; @@ -3866,6 +3871,7 @@ private: case SubRegSize::i32Bit: { switch (to) { case SubRegSize::i16Bit: return 0x00800000U; + case SubRegSize::i32Bit: return 0x00820000U; case SubRegSize::i64Bit: return 0x00C30000U; default: return UINT32_MAX; } diff --git a/FEXCore/unittests/Emitter/SVE_Tests.cpp b/FEXCore/unittests/Emitter/SVE_Tests.cpp index b72ac57d4..f9a10fadd 100644 --- a/FEXCore/unittests/Emitter/SVE_Tests.cpp +++ b/FEXCore/unittests/Emitter/SVE_Tests.cpp @@ -4392,6 +4392,8 @@ TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point convert pre TEST_SINGLE(fcvt(SubRegSize::i64Bit, SubRegSize::i32Bit, ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvt z30.d, p6/m, z29.s"); TEST_SINGLE(fcvtx(ZReg::z30, PReg::p6.Merging(), ZReg::z29), "fcvtx z30.s, p6/m, z29.d"); + + TEST_SINGLE(bfcvt(ZReg::z30, PReg::p6.Merging(), ZReg::z29), "bfcvt z30.h, p6/m, z29.s"); } TEST_CASE_METHOD(TestDisassembler, "Emitter: SVE: SVE floating-point unary operations") {