diff --git a/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp b/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp index 28cba14a..82a17e87 100644 --- a/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp +++ b/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp @@ -9,19 +9,23 @@ namespace Dynarmic::A64 { namespace { -enum class ShiftExtraBehavior { +enum class Rounding { None, - Accumulate, Round }; +enum class Accumulating { + None, + Accumulate +}; + enum class Signedness { Signed, Unsigned }; bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, - ShiftExtraBehavior behavior, Signedness signedness) { + Rounding rounding, Accumulating accumulating, Signedness signedness) { if (immh == 0b0000) { return v.DecodeError(); } @@ -34,8 +38,10 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, const size_t datasize = Q ? 128 : 64; const u8 shift_amount = static_cast(2 * esize) - concatenate(immh, immb).ZeroExtend(); + const u64 round_value = 1ULL << (shift_amount - 1); const IR::U128 operand = v.V(datasize, Vn); + IR::U128 result = [&] { if (signedness == Signedness::Signed) { return v.ir.VectorArithmeticShiftRight(esize, operand, shift_amount); @@ -43,7 +49,13 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, return v.ir.VectorLogicalShiftRight(esize, operand, shift_amount); }(); - if (behavior == ShiftExtraBehavior::Accumulate) { + if (rounding == Rounding::Round) { + const IR::U128 round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value)); + const IR::U128 round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(operand, round_const), round_const); + result = v.ir.VectorSub(esize, result, round_correction); + } + + if (accumulating == Accumulating::Accumulate) { const IR::U128 accumulator = v.V(datasize, Vd); result = v.ir.VectorAdd(esize, result, accumulator); } @@ -52,44 +64,8 @@ bool ShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, return true; } -bool RoundingShiftRight(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, - ShiftExtraBehavior behavior, Signedness signedness) { - if (immh == 0b0000) { - return v.DecodeError(); - } - - if (!Q && immh.Bit<3>()) { - return v.ReservedValue(); - } - - const size_t datasize = Q ? 128 : 64; - const size_t esize = 8 << Common::HighestSetBit(immh.ZeroExtend()); - const u8 shift_amount = static_cast((esize * 2) - concatenate(immh, immb).ZeroExtend()); - const u64 round_value = 1ULL << (shift_amount - 1); - - const IR::U128 operand = v.V(datasize, Vn); - const IR::U128 round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value)); - const IR::U128 round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(operand, round_const), round_const); - - const IR::U128 result = [&] { - if (signedness == Signedness::Signed) { - return v.ir.VectorArithmeticShiftRight(esize, operand, shift_amount); - } - return v.ir.VectorLogicalShiftRight(esize, operand, shift_amount); - }(); - IR::U128 corrected_result = v.ir.VectorSub(esize, result, round_correction); - - if (behavior == ShiftExtraBehavior::Accumulate) { - const IR::U128 accumulator = v.V(datasize, Vd); - corrected_result = v.ir.VectorAdd(esize, accumulator, corrected_result); - } - - v.V(datasize, Vd, corrected_result); - return true; -} - bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, - ShiftExtraBehavior behavior) { + Rounding rounding) { if (immh == 0b0000) { return v.DecodeError(); } @@ -103,17 +79,19 @@ bool ShiftRightNarrowing(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, const size_t part = Q ? 1 : 0; const u8 shift_amount = static_cast(source_esize - concatenate(immh, immb).ZeroExtend()); + const u64 round_value = 1ULL << (shift_amount - 1); - IR::U128 operand = v.ir.GetQ(Vn); + const IR::U128 operand = v.V(128, Vn); - if (behavior == ShiftExtraBehavior::Round) { - const u64 round_const = 1ULL << (shift_amount - 1); - const IR::U128 round_operand = v.ir.VectorBroadcast(source_esize, v.I(source_esize, round_const)); - operand = v.ir.VectorAdd(source_esize, operand, round_operand); + IR::U128 wide_result = v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount); + + if (rounding == Rounding::Round) { + const IR::U128 round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value)); + const IR::U128 round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(operand, round_const), round_const); + wide_result = v.ir.VectorSub(esize, wide_result, round_correction); } - const IR::U128 result = v.ir.VectorNarrow(source_esize, - v.ir.VectorLogicalShiftRight(source_esize, operand, shift_amount)); + const IR::U128 result = v.ir.VectorNarrow(source_esize, wide_result); v.Vpart(64, Vd, part, result); return true; @@ -150,19 +128,19 @@ bool ShiftLeftLong(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec V } // Anonymous namespace bool TranslatorVisitor::SSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Signed); } bool TranslatorVisitor::SRSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Signed); } bool TranslatorVisitor::SRSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Signed); } bool TranslatorVisitor::SSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Signed); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Signed); } bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { @@ -185,11 +163,11 @@ bool TranslatorVisitor::SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) } bool TranslatorVisitor::SHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::None); + return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::None); } bool TranslatorVisitor::RSHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::Round); + return ShiftRightNarrowing(*this, Q, immh, immb, Vn, Vd, Rounding::Round); } bool TranslatorVisitor::SSHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { @@ -197,19 +175,19 @@ bool TranslatorVisitor::SSHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) } bool TranslatorVisitor::URSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::None, Signedness::Unsigned); } bool TranslatorVisitor::URSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return RoundingShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::Round, Accumulating::Accumulate, Signedness::Unsigned); } bool TranslatorVisitor::USHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::None, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::None, Signedness::Unsigned); } bool TranslatorVisitor::USRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { - return ShiftRight(*this, Q, immh, immb, Vn, Vd, ShiftExtraBehavior::Accumulate, Signedness::Unsigned); + return ShiftRight(*this, Q, immh, immb, Vn, Vd, Rounding::None, Accumulating::Accumulate, Signedness::Unsigned); } bool TranslatorVisitor::USHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {