From 6c142bc5cce7c8a45b2206763268c4c9c85d3063 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 09:34:31 -0400 Subject: [PATCH 1/8] A32: Implement ASIMD VSHR --- src/CMakeLists.txt | 1 + src/frontend/A32/decoder/asimd.inc | 2 +- .../translate/impl/asimd_two_regs_shift.cpp | 52 +++++++++++++++++++ .../A32/translate/impl/translate_arm.h | 3 ++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49837ea9..a96500ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -127,6 +127,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS) frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp frontend/A32/translate/impl/asimd_three_same.cpp frontend/A32/translate/impl/asimd_two_regs_misc.cpp + frontend/A32/translate/impl/asimd_two_regs_shift.cpp frontend/A32/translate/impl/barrier.cpp frontend/A32/translate/impl/branch.cpp frontend/A32/translate/impl/coprocessor.cpp diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index e03a58e6..faa483a0 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -58,7 +58,7 @@ INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd001 //INST(asimd_VQRDMULH, "VQRDMULH", "1111001U1-BB--------1101-1-0----") // ASIMD // Two registers and a shift amount -//INST(asimd_SHR, "SHR", "1111001U1-vvv-------0000LB-1----") // ASIMD +INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD //INST(asimd_SRA, "SRA", "1111001U1-vvv-------0001LB-1----") // ASIMD //INST(asimd_VRSHR, "VRSHR", "1111001U1-vvv-------0010LB-1----") // ASIMD //INST(asimd_VRSRA, "VRSRA", "1111001U1-vvv-------0011LB-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp new file mode 100644 index 00000000..bac8ceee --- /dev/null +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -0,0 +1,52 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2020 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "common/bit_util.h" + +#include "frontend/A32/translate/impl/translate_arm.h" + +namespace Dynarmic::A32 { +namespace { +std::pair ElementSizeAndShiftAmount(bool L, size_t imm6) { + if (L) { + return {64, 64U - imm6}; + } + + const int highest = Common::HighestSetBit(imm6 >> 3); + if (highest == 0) { + return {8, 16 - imm6}; + } + + if (highest == 1) { + return {16, 32U - imm6}; + } + + return {32, 64U - imm6}; +} +} // Anonymous namespace + +bool ArmTranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return UndefinedInstruction(); + } + + // Technically just a related encoding (One register and modified immediate instructions) + if (!L && Common::Bits<3, 5>(imm6) == 0) { + return UndefinedInstruction(); + } + + const auto [esize, shift_amount] = ElementSizeAndShiftAmount(L, imm6); + const auto d = ToVector(Q, Vd, D); + const auto m = ToVector(Q, Vm, M); + + const auto reg_m = ir.GetVector(m); + const auto result = U ? ir.VectorLogicalShiftRight(esize, reg_m, static_cast(shift_amount)) + : ir.VectorArithmeticShiftRight(esize, reg_m, static_cast(shift_amount)); + + ir.SetVector(d, result); + return true; +} + +} // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 369b90c7..b0527ffe 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -451,6 +451,9 @@ struct ArmTranslatorVisitor final { bool asimd_VHSUB(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm); bool asimd_VQSUB(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm); + // Two registers and a shift amount + bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + // Advanced SIMD two register, miscellaneous bool asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm); bool asimd_VCLS(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm); From 276e0b71dc0c85b0248f957e722a5861478bd117 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 10:53:19 -0400 Subject: [PATCH 2/8] A32: Implement ASIMD VSRA --- src/frontend/A32/decoder/asimd.inc | 2 +- .../translate/impl/asimd_two_regs_shift.cpp | 50 ++++++++++++------- .../A32/translate/impl/translate_arm.h | 1 + 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index faa483a0..82d431b7 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -59,7 +59,7 @@ INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd001 // Two registers and a shift amount INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD -//INST(asimd_SRA, "SRA", "1111001U1-vvv-------0001LB-1----") // ASIMD +INST(asimd_SRA, "SRA", "1111001U1Diiiiiidddd0001LQM1mmmm") // ASIMD //INST(asimd_VRSHR, "VRSHR", "1111001U1-vvv-------0010LB-1----") // ASIMD //INST(asimd_VRSRA, "VRSRA", "1111001U1-vvv-------0011LB-1----") // ASIMD //INST(asimd_VSRI, "VSRI", "111100111-vvv-------0100LB-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index bac8ceee..f5602b28 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -9,44 +9,56 @@ namespace Dynarmic::A32 { namespace { +enum class Accumulating { + None, + Accumulate +}; + std::pair ElementSizeAndShiftAmount(bool L, size_t imm6) { if (L) { - return {64, 64U - imm6}; + return {64, 64 - imm6}; } - const int highest = Common::HighestSetBit(imm6 >> 3); - if (highest == 0) { - return {8, 16 - imm6}; - } - - if (highest == 1) { - return {16, 32U - imm6}; - } - - return {32, 64U - imm6}; + const size_t esize = 8U << Common::HighestSetBit(imm6 >> 3); + const size_t shift_amount = (esize * 2) - imm6; + return {esize, shift_amount}; } -} // Anonymous namespace -bool ArmTranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { +bool ShiftRight(ArmTranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, + Accumulating accumulate) { if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { - return UndefinedInstruction(); + return v.UndefinedInstruction(); } // Technically just a related encoding (One register and modified immediate instructions) if (!L && Common::Bits<3, 5>(imm6) == 0) { - return UndefinedInstruction(); + return v.UndefinedInstruction(); } const auto [esize, shift_amount] = ElementSizeAndShiftAmount(L, imm6); const auto d = ToVector(Q, Vd, D); const auto m = ToVector(Q, Vm, M); - const auto reg_m = ir.GetVector(m); - const auto result = U ? ir.VectorLogicalShiftRight(esize, reg_m, static_cast(shift_amount)) - : ir.VectorArithmeticShiftRight(esize, reg_m, static_cast(shift_amount)); + const auto reg_m = v.ir.GetVector(m); + auto result = U ? v.ir.VectorLogicalShiftRight(esize, reg_m, static_cast(shift_amount)) + : v.ir.VectorArithmeticShiftRight(esize, reg_m, static_cast(shift_amount)); - ir.SetVector(d, result); + if (accumulate == Accumulating::Accumulate) { + const auto reg_d = v.ir.GetVector(d); + result = v.ir.VectorAdd(esize, result, reg_d); + } + + v.ir.SetVector(d, result); return true; } +} // Anonymous namespace + +bool ArmTranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, Accumulating::None); +} + +bool ArmTranslatorVisitor::asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, Accumulating::Accumulate); +} } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index b0527ffe..8af65ee4 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -453,6 +453,7 @@ struct ArmTranslatorVisitor final { // Two registers and a shift amount bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + bool asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); // Advanced SIMD two register, miscellaneous bool asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm); From 14fdd15199efd2610b4cc3d0d2f0b43dcbd6405a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 11:00:13 -0400 Subject: [PATCH 3/8] A32: Implement ASIMD VRSHR --- src/frontend/A32/decoder/asimd.inc | 2 +- .../translate/impl/asimd_two_regs_shift.cpp | 31 ++++++++++++++++--- .../A32/translate/impl/translate_arm.h | 1 + 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 82d431b7..9067a74b 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -60,7 +60,7 @@ INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd001 // Two registers and a shift amount INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD INST(asimd_SRA, "SRA", "1111001U1Diiiiiidddd0001LQM1mmmm") // ASIMD -//INST(asimd_VRSHR, "VRSHR", "1111001U1-vvv-------0010LB-1----") // ASIMD +INST(asimd_VRSHR, "VRSHR", "1111001U1Diiiiiidddd0010LQM1mmmm") // ASIMD //INST(asimd_VRSRA, "VRSRA", "1111001U1-vvv-------0011LB-1----") // ASIMD //INST(asimd_VSRI, "VSRI", "111100111-vvv-------0100LB-1----") // ASIMD //INST(asimd_VSHL, "VSHL", "111100101-vvv-------0101LB-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index f5602b28..44511205 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -14,6 +14,17 @@ enum class Accumulating { Accumulate }; +enum class Rounding { + None, + Round, +}; + +IR::U128 PerformRoundingCorrection(ArmTranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) { + const auto round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value)); + const auto round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(original, round_const), round_const); + return v.ir.VectorSub(esize, shifted, round_correction); +} + std::pair ElementSizeAndShiftAmount(bool L, size_t imm6) { if (L) { return {64, 64 - imm6}; @@ -25,7 +36,7 @@ std::pair ElementSizeAndShiftAmount(bool L, size_t imm6) { } bool ShiftRight(ArmTranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, - Accumulating accumulate) { + Accumulating accumulate, Rounding rounding) { if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { return v.UndefinedInstruction(); } @@ -41,7 +52,12 @@ bool ShiftRight(ArmTranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, const auto reg_m = v.ir.GetVector(m); auto result = U ? v.ir.VectorLogicalShiftRight(esize, reg_m, static_cast(shift_amount)) - : v.ir.VectorArithmeticShiftRight(esize, reg_m, static_cast(shift_amount)); + : v.ir.VectorArithmeticShiftRight(esize, reg_m, static_cast(shift_amount)); + + if (rounding == Rounding::Round) { + const u64 round_value = 1ULL << (shift_amount - 1); + result = PerformRoundingCorrection(v, esize, round_value, reg_m, result); + } if (accumulate == Accumulating::Accumulate) { const auto reg_d = v.ir.GetVector(d); @@ -54,11 +70,18 @@ bool ShiftRight(ArmTranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, } // Anonymous namespace bool ArmTranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { - return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, Accumulating::None); + return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, + Accumulating::None, Rounding::None); } bool ArmTranslatorVisitor::asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { - return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, Accumulating::Accumulate); + return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, + Accumulating::Accumulate, Rounding::None); +} + +bool ArmTranslatorVisitor::asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, + Accumulating::None, Rounding::Round); } } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 8af65ee4..dbf1a0a2 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -454,6 +454,7 @@ struct ArmTranslatorVisitor final { // Two registers and a shift amount bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + bool asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); // Advanced SIMD two register, miscellaneous bool asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm); From 69c999bc6678c7de7d9f4c335f452aca39ecb221 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 11:03:29 -0400 Subject: [PATCH 4/8] A32: Implement ASIMD VRSRA Now that we have the accumulation and rounding code in place, VRSRA is extremely trivial to implement. --- src/frontend/A32/decoder/asimd.inc | 2 +- src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp | 5 +++++ src/frontend/A32/translate/impl/translate_arm.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 9067a74b..09b4909b 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -61,7 +61,7 @@ INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd001 INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD INST(asimd_SRA, "SRA", "1111001U1Diiiiiidddd0001LQM1mmmm") // ASIMD INST(asimd_VRSHR, "VRSHR", "1111001U1Diiiiiidddd0010LQM1mmmm") // ASIMD -//INST(asimd_VRSRA, "VRSRA", "1111001U1-vvv-------0011LB-1----") // ASIMD +INST(asimd_VRSRA, "VRSRA", "1111001U1Diiiiiidddd0011LQM1mmmm") // ASIMD //INST(asimd_VSRI, "VSRI", "111100111-vvv-------0100LB-1----") // ASIMD //INST(asimd_VSHL, "VSHL", "111100101-vvv-------0101LB-1----") // ASIMD //INST(asimd_VSLI, "VSLI", "111100111-vvv-------0101LB-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index 44511205..2e4c6f5f 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -84,4 +84,9 @@ bool ArmTranslatorVisitor::asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, b Accumulating::None, Rounding::Round); } +bool ArmTranslatorVisitor::asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + return ShiftRight(*this, U, D, imm6, Vd, L, Q, M, Vm, + Accumulating::Accumulate, Rounding::Round); +} + } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index dbf1a0a2..b4985135 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -455,6 +455,7 @@ struct ArmTranslatorVisitor final { bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + bool asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); // Advanced SIMD two register, miscellaneous bool asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm); From 8b98c91ecc398c1ff3920602a47df3cd4d786373 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 11:12:17 -0400 Subject: [PATCH 5/8] A32: Implement ASIMD VSHL --- src/frontend/A32/decoder/asimd.inc | 2 +- .../translate/impl/asimd_two_regs_shift.cpp | 47 +++++++++++++++---- .../A32/translate/impl/translate_arm.h | 1 + 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 09b4909b..8388b4e2 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -63,7 +63,7 @@ INST(asimd_SRA, "SRA", "1111001U1Diiiiiidddd000 INST(asimd_VRSHR, "VRSHR", "1111001U1Diiiiiidddd0010LQM1mmmm") // ASIMD INST(asimd_VRSRA, "VRSRA", "1111001U1Diiiiiidddd0011LQM1mmmm") // ASIMD //INST(asimd_VSRI, "VSRI", "111100111-vvv-------0100LB-1----") // ASIMD -//INST(asimd_VSHL, "VSHL", "111100101-vvv-------0101LB-1----") // ASIMD +INST(asimd_VSHL, "VSHL", "111100101Diiiiiidddd0101LQM1mmmm") // ASIMD //INST(asimd_VSLI, "VSLI", "111100111-vvv-------0101LB-1----") // ASIMD //INST(asimd_VQSHL, "VQSHL" , "1111001U1-vvv-------011xLB-1----") // ASIMD //INST(asimd_VSHRN, "VSHRN", "111100101-vvv-------100000-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index 2e4c6f5f..65cbaf47 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -25,14 +25,24 @@ IR::U128 PerformRoundingCorrection(ArmTranslatorVisitor& v, size_t esize, u64 ro return v.ir.VectorSub(esize, shifted, round_correction); } -std::pair ElementSizeAndShiftAmount(bool L, size_t imm6) { - if (L) { - return {64, 64 - imm6}; - } +std::pair ElementSizeAndShiftAmount(bool right_shift, bool L, size_t imm6) { + if (right_shift) { + if (L) { + return {64, 64 - imm6}; + } - const size_t esize = 8U << Common::HighestSetBit(imm6 >> 3); - const size_t shift_amount = (esize * 2) - imm6; - return {esize, shift_amount}; + const size_t esize = 8U << Common::HighestSetBit(imm6 >> 3); + const size_t shift_amount = (esize * 2) - imm6; + return {esize, shift_amount}; + } else { + if (L) { + return {64, imm6}; + } + + const size_t esize = 8U << Common::HighestSetBit(imm6 >> 3); + const size_t shift_amount = imm6 - esize; + return {esize, shift_amount}; + } } bool ShiftRight(ArmTranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm, @@ -46,7 +56,7 @@ bool ShiftRight(ArmTranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, return v.UndefinedInstruction(); } - const auto [esize, shift_amount] = ElementSizeAndShiftAmount(L, imm6); + const auto [esize, shift_amount] = ElementSizeAndShiftAmount(true, L, imm6); const auto d = ToVector(Q, Vd, D); const auto m = ToVector(Q, Vm, M); @@ -89,4 +99,25 @@ bool ArmTranslatorVisitor::asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, b Accumulating::Accumulate, Rounding::Round); } +bool ArmTranslatorVisitor::asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return UndefinedInstruction(); + } + + // Technically just a related encoding (One register and modified immediate instructions) + if (!L && Common::Bits<3, 5>(imm6) == 0) { + return UndefinedInstruction(); + } + + const auto [esize, shift_amount] = ElementSizeAndShiftAmount(false, L, imm6); + const auto d = ToVector(Q, Vd, D); + const auto m = ToVector(Q, Vm, M); + + const auto reg_m = ir.GetVector(m); + const auto result = ir.VectorLogicalShiftLeft(esize, reg_m, static_cast(shift_amount)); + + ir.SetVector(d, result); + return true; +} + } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index b4985135..aeb91380 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -456,6 +456,7 @@ struct ArmTranslatorVisitor final { bool asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + bool asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); // Advanced SIMD two register, miscellaneous bool asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm); From 887732d8a8d82c0b2b6a4369cc5311da265b4354 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 11:28:12 -0400 Subject: [PATCH 6/8] A32: Implement ASIMD VSRI --- src/frontend/A32/decoder/asimd.inc | 2 +- .../translate/impl/asimd_two_regs_shift.cpp | 27 +++++++++++++++++++ .../A32/translate/impl/translate_arm.h | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 8388b4e2..63aa28be 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -62,7 +62,7 @@ INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd000 INST(asimd_SRA, "SRA", "1111001U1Diiiiiidddd0001LQM1mmmm") // ASIMD INST(asimd_VRSHR, "VRSHR", "1111001U1Diiiiiidddd0010LQM1mmmm") // ASIMD INST(asimd_VRSRA, "VRSRA", "1111001U1Diiiiiidddd0011LQM1mmmm") // ASIMD -//INST(asimd_VSRI, "VSRI", "111100111-vvv-------0100LB-1----") // ASIMD +INST(asimd_VSRI, "VSRI", "111100111Diiiiiidddd0100LQM1mmmm") // ASIMD INST(asimd_VSHL, "VSHL", "111100101Diiiiiidddd0101LQM1mmmm") // ASIMD //INST(asimd_VSLI, "VSLI", "111100111-vvv-------0101LB-1----") // ASIMD //INST(asimd_VQSHL, "VQSHL" , "1111001U1-vvv-------011xLB-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index 65cbaf47..c5ad9a34 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -99,6 +99,33 @@ bool ArmTranslatorVisitor::asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, b Accumulating::Accumulate, Rounding::Round); } +bool ArmTranslatorVisitor::asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return UndefinedInstruction(); + } + + // Technically just a related encoding (One register and modified immediate instructions) + if (!L && Common::Bits<3, 5>(imm6) == 0) { + return UndefinedInstruction(); + } + + const auto [esize, shift_amount] = ElementSizeAndShiftAmount(true, L, imm6); + const u64 mask = shift_amount == esize ? 0 : Common::Ones(esize) >> shift_amount; + + const auto d = ToVector(Q, Vd, D); + const auto m = ToVector(Q, Vm, M); + + const auto reg_m = ir.GetVector(m); + const auto reg_d = ir.GetVector(d); + + const auto shifted = ir.VectorLogicalShiftRight(esize, reg_m, static_cast(shift_amount)); + const auto mask_vec = ir.VectorBroadcast(esize, I(esize, mask)); + const auto result = ir.VectorOr(ir.VectorAnd(reg_d, ir.VectorNot(mask_vec)), shifted); + + ir.SetVector(d, result); + return true; +} + bool ArmTranslatorVisitor::asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { return UndefinedInstruction(); diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index aeb91380..905ccf09 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -456,6 +456,7 @@ struct ArmTranslatorVisitor final { bool asimd_SRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + bool asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); // Advanced SIMD two register, miscellaneous From 6ca20c2fe3b8a6d263d30192b95497b3feca15ae Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 11:32:06 -0400 Subject: [PATCH 7/8] A32: Implement ASIMD VSLI --- src/frontend/A32/decoder/asimd.inc | 2 +- .../translate/impl/asimd_two_regs_shift.cpp | 27 +++++++++++++++++++ .../A32/translate/impl/translate_arm.h | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 63aa28be..99a762d1 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -64,7 +64,7 @@ INST(asimd_VRSHR, "VRSHR", "1111001U1Diiiiiidddd001 INST(asimd_VRSRA, "VRSRA", "1111001U1Diiiiiidddd0011LQM1mmmm") // ASIMD INST(asimd_VSRI, "VSRI", "111100111Diiiiiidddd0100LQM1mmmm") // ASIMD INST(asimd_VSHL, "VSHL", "111100101Diiiiiidddd0101LQM1mmmm") // ASIMD -//INST(asimd_VSLI, "VSLI", "111100111-vvv-------0101LB-1----") // ASIMD +INST(asimd_VSLI, "VSLI", "111100111Diiiiiidddd0101LQM1mmmm") // ASIMD //INST(asimd_VQSHL, "VQSHL" , "1111001U1-vvv-------011xLB-1----") // ASIMD //INST(asimd_VSHRN, "VSHRN", "111100101-vvv-------100000-1----") // ASIMD //INST(asimd_VRSHRN, "VRSHRN", "111100101-vvv-------100001-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index c5ad9a34..cdfa9c02 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -126,6 +126,33 @@ bool ArmTranslatorVisitor::asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bo return true; } +bool ArmTranslatorVisitor::asimd_VSLI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return UndefinedInstruction(); + } + + // Technically just a related encoding (One register and modified immediate instructions) + if (!L && Common::Bits<3, 5>(imm6) == 0) { + return UndefinedInstruction(); + } + + const auto [esize, shift_amount] = ElementSizeAndShiftAmount(false, L, imm6); + const u64 mask = Common::Ones(esize) << shift_amount; + + const auto d = ToVector(Q, Vd, D); + const auto m = ToVector(Q, Vm, M); + + const auto reg_m = ir.GetVector(m); + const auto reg_d = ir.GetVector(d); + + const auto shifted = ir.VectorLogicalShiftLeft(esize, reg_m, static_cast(shift_amount)); + const auto mask_vec = ir.VectorBroadcast(esize, I(esize, mask)); + const auto result = ir.VectorOr(ir.VectorAnd(reg_d, ir.VectorNot(mask_vec)), shifted); + + ir.SetVector(d, result); + return true; +} + bool ArmTranslatorVisitor::asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { return UndefinedInstruction(); diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 905ccf09..28b9dbc9 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -457,6 +457,7 @@ struct ArmTranslatorVisitor final { bool asimd_VRSHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VRSRA(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + bool asimd_VSLI(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); bool asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); // Advanced SIMD two register, miscellaneous From 00b2f9b319f64ebe794511e8efc7fd58faccb69d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 14:59:32 -0400 Subject: [PATCH 8/8] asimd: Prevent misdecodes from occurring Pointed out by Mary when reviewing the shift code. --- src/frontend/A32/decoder/asimd.h | 10 ++++++++++ .../A32/translate/impl/asimd_two_regs_shift.cpp | 7 ++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/frontend/A32/decoder/asimd.h b/src/frontend/A32/decoder/asimd.h index 8df54f9f..61a26e51 100644 --- a/src/frontend/A32/decoder/asimd.h +++ b/src/frontend/A32/decoder/asimd.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "common/bit_util.h" @@ -35,6 +36,15 @@ std::vector> GetASIMDDecodeTable() { return Common::BitCount(matcher1.GetMask()) > Common::BitCount(matcher2.GetMask()); }); + // Exceptions to the above rule of thumb. + const std::set comes_first{ + "VBIC, VMOV, VMVN, VORR (immediate)" + }; + + std::stable_partition(table.begin(), table.end(), [&](const auto& matcher) { + return comes_first.count(matcher.GetName()) > 0; + }); + return table; } diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index cdfa9c02..a6ed0be9 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -3,6 +3,7 @@ * SPDX-License-Identifier: 0BSD */ +#include "common/assert.h" #include "common/bit_util.h" #include "frontend/A32/translate/impl/translate_arm.h" @@ -53,7 +54,7 @@ bool ShiftRight(ArmTranslatorVisitor& v, bool U, bool D, size_t imm6, size_t Vd, // Technically just a related encoding (One register and modified immediate instructions) if (!L && Common::Bits<3, 5>(imm6) == 0) { - return v.UndefinedInstruction(); + ASSERT_FALSE(); } const auto [esize, shift_amount] = ElementSizeAndShiftAmount(true, L, imm6); @@ -106,7 +107,7 @@ bool ArmTranslatorVisitor::asimd_VSRI(bool D, size_t imm6, size_t Vd, bool L, bo // Technically just a related encoding (One register and modified immediate instructions) if (!L && Common::Bits<3, 5>(imm6) == 0) { - return UndefinedInstruction(); + ASSERT_FALSE(); } const auto [esize, shift_amount] = ElementSizeAndShiftAmount(true, L, imm6); @@ -160,7 +161,7 @@ bool ArmTranslatorVisitor::asimd_VSHL(bool D, size_t imm6, size_t Vd, bool L, bo // Technically just a related encoding (One register and modified immediate instructions) if (!L && Common::Bits<3, 5>(imm6) == 0) { - return UndefinedInstruction(); + ASSERT_FALSE(); } const auto [esize, shift_amount] = ElementSizeAndShiftAmount(false, L, imm6);