diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 1c7ac048..95eb2e59 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -500,9 +500,9 @@ INST(FCVTZU_fix_1, "FCVTZU (vector, fixed-point)", "01111 //INST(SQDMULH_elt_1, "SQDMULH (by element)", "01011111zzLMmmmm1100H0nnnnnddddd") //INST(SQRDMULH_elt_1, "SQRDMULH (by element)", "01011111zzLMmmmm1101H0nnnnnddddd") //INST(FMLA_elt_1, "FMLA (by element)", "0101111100LMmmmm0001H0nnnnnddddd") -//INST(FMLA_elt_2, "FMLA (by element)", "010111111zLMmmmm0001H0nnnnnddddd") +INST(FMLA_elt_2, "FMLA (by element)", "010111111zLMmmmm0001H0nnnnnddddd") //INST(FMLS_elt_1, "FMLS (by element)", "0101111100LMmmmm0101H0nnnnnddddd") -//INST(FMLS_elt_2, "FMLS (by element)", "010111111zLMmmmm0101H0nnnnnddddd") +INST(FMLS_elt_2, "FMLS (by element)", "010111111zLMmmmm0101H0nnnnnddddd") //INST(FMUL_elt_1, "FMUL (by element)", "0101111100LMmmmm1001H0nnnnnddddd") INST(FMUL_elt_2, "FMUL (by element)", "010111111zLMmmmm1001H0nnnnnddddd") //INST(SQRDMLAH_elt_1, "SQRDMLAH (by element)", "01111111zzLMmmmm1101H0nnnnnddddd") diff --git a/src/frontend/A64/translate/impl/impl.h b/src/frontend/A64/translate/impl/impl.h index 642ba544..0da93c88 100644 --- a/src/frontend/A64/translate/impl/impl.h +++ b/src/frontend/A64/translate/impl/impl.h @@ -662,10 +662,10 @@ struct TranslatorVisitor final { bool SQDMULL_elt_1(Imm<2> size, bool L, bool M, Vec Vm, bool H, Reg Rn, Vec Vd); bool SQDMULH_elt_1(Imm<2> size, bool L, bool M, Vec Vm, bool H, Vec Vn, Vec Vd); bool SQRDMULH_elt_1(Imm<2> size, bool L, bool M, Vec Vm, bool H, Vec Vn, Vec Vd); - bool FMLA_elt_1(bool L, bool M, Vec Vm, bool H, Vec Vn, Vec Vd); - bool FMLA_elt_2(bool sz, bool L, bool M, Vec Vm, bool H, Vec Vn, Vec Vd); - bool FMLS_elt_1(bool L, bool M, Vec Vm, bool H, Vec Vn, Vec Vd); - bool FMLS_elt_2(bool sz, bool L, bool M, Vec Vm, bool H, Vec Vn, Vec Vd); + bool FMLA_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd); + bool FMLA_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd); + bool FMLS_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd); + bool FMLS_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd); bool FMUL_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd); bool FMUL_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd); bool SQRDMLAH_elt_1(Imm<2> size, bool L, bool M, Vec Vm, bool H, Vec Vn, Vec Vd); diff --git a/src/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp b/src/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp index 6a88127c..6e2b53cf 100644 --- a/src/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp +++ b/src/frontend/A64/translate/impl/simd_scalar_x_indexed_element.cpp @@ -7,10 +7,17 @@ #include "frontend/A64/translate/impl/impl.h" namespace Dynarmic::A64 { +namespace { +enum class ExtraBehavior { + None, + Accumulate, + Subtract +}; -bool TranslatorVisitor::FMUL_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { +bool MultiplyByElement(TranslatorVisitor& v, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd, ExtraBehavior extra_behavior) { if (sz && L == 1) { - return UnallocatedEncoding(); + return v.UnallocatedEncoding(); } const size_t idxdsize = H == 1 ? 128 : 64; @@ -18,12 +25,37 @@ bool TranslatorVisitor::FMUL_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm const Vec Vm = concatenate(M, Vmlo).ZeroExtend(); const size_t esize = sz ? 64 : 32; - const IR::U32U64 operand = V_scalar(esize, Vn); - const IR::U32U64 element = ir.VectorGetElement(esize, V(idxdsize, Vm), index); - const IR::U32U64 result = ir.FPMul(operand, element, true); + const IR::U32U64 element = v.ir.VectorGetElement(esize, v.V(idxdsize, Vm), index); + const IR::U32U64 result = [&] { + IR::U32U64 operand1 = v.V_scalar(esize, Vn); - V_scalar(esize, Vd, result); + if (extra_behavior == ExtraBehavior::None) { + return v.ir.FPMul(operand1, element, true); + } + + if (extra_behavior == ExtraBehavior::Subtract) { + operand1 = v.ir.FPNeg(operand1); + } + + const IR::U32U64 operand2 = v.V_scalar(esize, Vd); + return v.ir.FPMulAdd(operand2, operand1, element, true); + }(); + + v.V_scalar(esize, Vd, result); return true; } +} // Anonymous namespace + +bool TranslatorVisitor::FMLA_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return MultiplyByElement(*this, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Accumulate); +} + +bool TranslatorVisitor::FMLS_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return MultiplyByElement(*this, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::Subtract); +} + +bool TranslatorVisitor::FMUL_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return MultiplyByElement(*this, sz, L, M, Vmlo, H, Vn, Vd, ExtraBehavior::None); +} } // namespace Dynarmic::A64