From ed6ca5805896fe3f2e38b3558211f5919d65af52 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 20 Jun 2020 00:05:58 +0100 Subject: [PATCH] A32: Implement ASIMD VCEQ, VCGE, VCGT, VCLE, VCLT with zero Fairly self-explanatory, we can leverage the existing IR functions for the purpose of these instructions. In the integer case, we can just insert function pointers into an array and index it, given all comparison primitives exist already for the integer side of things. --- src/frontend/A32/decoder/asimd.inc | 10 +-- .../translate/impl/asimd_two_regs_misc.cpp | 84 ++++++++++++++++++- .../A32/translate/impl/translate_arm.h | 5 ++ tests/A32/test_arm_instructions.cpp | 2 +- 4 files changed, 93 insertions(+), 8 deletions(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 64ab59f9..46b10ce0 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -85,11 +85,11 @@ INST(asimd_VMVN_reg, "VMVN_reg", "111100111D11zz00dddd010 //INST(asimd_VPADAL, "VPADAL", "111100111-11--00----0110xx-0----") // ASIMD INST(asimd_VQABS, "VQABS", "111100111D11zz00dddd01110QM0mmmm") // ASIMD INST(asimd_VQNEG, "VQNEG", "111100111D11zz00dddd01111QM0mmmm") // ASIMD -//INST(asimd_VCGT_zero, "VCGT (zero)", "111100111-11--01----0x000x-0----") // ASIMD -//INST(asimd_VCGE_zero, "VCGE (zero)", "111100111-11--01----0x001x-0----") // ASIMD -//INST(asimd_VCEQ_zero, "VCEQ (zero)", "111100111-11--01----0x010x-0----") // ASIMD -//INST(asimd_VCLE_zero, "VCLE (zero)", "111100111-11--01----0x011x-0----") // ASIMD -//INST(asimd_VCLT_zero, "VCLT (zero)", "111100111-11--01----0x100x-0----") // ASIMD +INST(asimd_VCGT_zero, "VCGT (zero)", "111100111D11zz01dddd0F000QM0mmmm") // ASIMD +INST(asimd_VCGE_zero, "VCGE (zero)", "111100111D11zz01dddd0F001QM0mmmm") // ASIMD +INST(asimd_VCEQ_zero, "VCEQ (zero)", "111100111D11zz01dddd0F010QM0mmmm") // ASIMD +INST(asimd_VCLE_zero, "VCLE (zero)", "111100111D11zz01dddd0F011QM0mmmm") // ASIMD +INST(asimd_VCLT_zero, "VCLT (zero)", "111100111D11zz01dddd0F100QM0mmmm") // ASIMD INST(asimd_VABS, "VABS", "111100111D11zz01dddd0F110QM0mmmm") // ASIMD INST(asimd_VNEG, "VNEG", "111100111D11zz01dddd0F111QM0mmmm") // ASIMD INST(asimd_VSWP, "VSWP", "111100111D110010dddd00000QM0mmmm") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp index d6294012..d06ab5a2 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp @@ -5,9 +5,69 @@ #include "common/bit_util.h" +#include + #include "frontend/A32/translate/impl/translate_arm.h" namespace Dynarmic::A32 { +namespace { +enum class Comparison { + EQ, + GE, + GT, + LE, + LT, +}; + +bool CompareWithZero(ArmTranslatorVisitor& v, bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm, Comparison type) { + if (sz == 0b11 || (F && sz != 0b10)) { + return v.UndefinedInstruction(); + } + + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return v.UndefinedInstruction(); + } + + const auto d = ToVector(Q, Vd, D); + const auto m = ToVector(Q, Vm, M); + const auto result = [&] { + const auto reg_m = v.ir.GetVector(m); + const auto zero = v.ir.ZeroVector(); + + if (F) { + switch (type) { + case Comparison::EQ: + return v.ir.FPVectorEqual(32, reg_m, zero, false); + case Comparison::GE: + return v.ir.FPVectorGreaterEqual(32, reg_m, zero, false); + case Comparison::GT: + return v.ir.FPVectorGreater(32, reg_m, zero, false); + case Comparison::LE: + return v.ir.FPVectorGreaterEqual(32, zero, reg_m, false); + case Comparison::LT: + return v.ir.FPVectorGreater(32, zero, reg_m, false); + } + + return IR::U128{}; + } else { + static constexpr std::array fns{ + &IREmitter::VectorEqual, + &IREmitter::VectorGreaterEqualSigned, + &IREmitter::VectorGreaterSigned, + &IREmitter::VectorLessEqualSigned, + &IREmitter::VectorLessSigned, + }; + + const size_t esize = 8U << sz; + return (v.ir.*fns[static_cast(type)])(esize, reg_m, zero); + } + }(); + + v.ir.SetVector(d, result); + return true; +} + +} // Anonymous namespace bool ArmTranslatorVisitor::asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm) { if (op + sz >= 3) { @@ -64,7 +124,7 @@ bool ArmTranslatorVisitor::asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, b return ir.VectorOr(ir.VectorLogicalShiftRight(esize, reg_m, 8), ir.VectorLogicalShiftLeft(esize, reg_m, 8)); }(); - + ir.SetVector(d, result); return true; } @@ -192,6 +252,26 @@ bool ArmTranslatorVisitor::asimd_VQNEG(bool D, size_t sz, size_t Vd, bool Q, boo return true; } +bool ArmTranslatorVisitor::asimd_VCGT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GT); +} + +bool ArmTranslatorVisitor::asimd_VCGE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::GE); +} + +bool ArmTranslatorVisitor::asimd_VCEQ_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::EQ); +} + +bool ArmTranslatorVisitor::asimd_VCLE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LE); +} + +bool ArmTranslatorVisitor::asimd_VCLT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { + return CompareWithZero(*this, D, sz, Vd, F, Q, M, Vm, Comparison::LT); +} + bool ArmTranslatorVisitor::asimd_VABS(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { if (sz == 0b11 || (F && sz != 0b10)) { return UndefinedInstruction(); @@ -222,7 +302,7 @@ bool ArmTranslatorVisitor::asimd_VNEG(bool D, size_t sz, size_t Vd, bool F, bool if (sz == 0b11 || (F && sz != 0b10)) { return UndefinedInstruction(); } - + 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 a1f6eadc..c958b918 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -479,6 +479,11 @@ struct ArmTranslatorVisitor final { bool asimd_VMVN_reg(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm); bool asimd_VQABS(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm); bool asimd_VQNEG(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm); + bool asimd_VCGT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); + bool asimd_VCGE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); + bool asimd_VCEQ_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); + bool asimd_VCLE_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); + bool asimd_VCLT_zero(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); bool asimd_VABS(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); bool asimd_VNEG(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); bool asimd_VSWP(bool D, size_t Vd, bool Q, bool M, size_t Vm); diff --git a/tests/A32/test_arm_instructions.cpp b/tests/A32/test_arm_instructions.cpp index 1aeb31bb..23d0c35a 100644 --- a/tests/A32/test_arm_instructions.cpp +++ b/tests/A32/test_arm_instructions.cpp @@ -466,7 +466,7 @@ TEST_CASE("arm: PackedAbsDiffSumS8", "[arm][A32]") { REQUIRE(jit.Cpsr() == 0xb0000010); } -TEST_CASE("arm: vclt.f32 with zero", "[arm][A32][.]") { +TEST_CASE("arm: vclt.f32 with zero", "[arm][A32]") { ArmTestEnv test_env; A32::Jit jit{GetUserConfig(&test_env)}; test_env.code_mem = {