diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 7dcc8f15..d762a15e 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -659,7 +659,7 @@ INST(FCMLE_4, "FCMLE (zero)", "0Q101 //INST(FSQRT_2, "FSQRT (vector)", "0Q1011101z100001111110nnnnnddddd") // Data Processing - FP and SIMD - SIMD across lanes -//INST(SADDLV, "SADDLV", "0Q001110zz110000001110nnnnnddddd") +INST(SADDLV, "SADDLV", "0Q001110zz110000001110nnnnnddddd") //INST(SMAXV, "SMAXV", "0Q001110zz110000101010nnnnnddddd") //INST(SMINV, "SMINV", "0Q001110zz110001101010nnnnnddddd") INST(ADDV, "ADDV", "0Q001110zz110001101110nnnnnddddd") diff --git a/src/frontend/A64/translate/impl/simd_across_lanes.cpp b/src/frontend/A64/translate/impl/simd_across_lanes.cpp index b172a1a4..559adee2 100644 --- a/src/frontend/A64/translate/impl/simd_across_lanes.cpp +++ b/src/frontend/A64/translate/impl/simd_across_lanes.cpp @@ -7,6 +7,49 @@ #include "frontend/A64/translate/impl/impl.h" namespace Dynarmic::A64 { +namespace { +enum class Signedness { + Signed, + Unsigned +}; + +bool LongAdd(TranslatorVisitor& v, bool Q, Imm<2> size, Vec Vn, Vec Vd, Signedness sign) { + if ((size == 0b10 && !Q) || size == 0b11) { + return v.ReservedValue(); + } + + const size_t esize = 8 << size.ZeroExtend(); + const size_t datasize = Q ? 128 : 64; + const size_t elements = datasize / esize; + + const IR::U128 operand = v.V(datasize, Vn); + + const auto get_element = [&](IR::U128 vec, size_t element) { + const auto vec_element = v.ir.VectorGetElement(esize, vec, element); + + if (sign == Signedness::Signed) { + return v.ir.SignExtendToLong(vec_element); + } + + return v.ir.ZeroExtendToLong(vec_element); + }; + + IR::U64 sum = get_element(operand, 0); + for (size_t i = 1; i < elements; i++) { + sum = v.ir.Add(sum, get_element(operand, i)); + } + + if (size == 0b00) { + v.V(datasize, Vd, v.ir.ZeroExtendToQuad(v.ir.LeastSignificantHalf(sum))); + } else if (size == 0b01) { + v.V(datasize, Vd, v.ir.ZeroExtendToQuad(v.ir.LeastSignificantWord(sum))); + } else { + v.V(datasize, Vd, v.ir.ZeroExtendToQuad(sum)); + } + + return true; +} +} // Anonymous namespace bool TranslatorVisitor::ADDV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { if ((size == 0b10 && !Q) || size == 0b11) { @@ -39,35 +82,11 @@ bool TranslatorVisitor::ADDV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { return true; } -bool TranslatorVisitor::UADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { - if ((size == 0b10 && !Q) || size == 0b11) { - return ReservedValue(); - } - - const size_t esize = 8 << size.ZeroExtend(); - const size_t datasize = Q ? 128 : 64; - const size_t elements = datasize / esize; - - const IR::U128 operand = V(datasize, Vn); - - const auto get_element = [&](IR::U128 vec, size_t element) { - return ir.ZeroExtendToLong(ir.VectorGetElement(esize, vec, element)); - }; - - IR::U64 sum = get_element(operand, 0); - for (size_t i = 1; i < elements; i++) { - sum = ir.Add(sum, get_element(operand, i)); - } - - if (size == 0b00) { - V(datasize, Vd, ir.ZeroExtendToQuad(ir.LeastSignificantHalf(sum))); - } else if (size == 0b01) { - V(datasize, Vd, ir.ZeroExtendToQuad(ir.LeastSignificantWord(sum))); - } else { - V(datasize, Vd, ir.ZeroExtendToQuad(sum)); - } - - return true; +bool TranslatorVisitor::SADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return LongAdd(*this, Q, size, Vn, Vd, Signedness::Signed); } +bool TranslatorVisitor::UADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return LongAdd(*this, Q, size, Vn, Vd, Signedness::Unsigned); +} } // namespace Dynarmic::A64