From 179951b10f6f7eb7b608574703ec8fe46bf5f63f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 18 Jun 2020 09:00:26 -0400 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 | 80 +++++++++++++++++++ .../A32/translate/impl/translate_arm.h | 5 ++ 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 0925fc51..9d808ba4 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -85,11 +85,11 @@ INST(asimd_VCNT, "VCNT", "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 6588a295..1399f59c 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); + case Comparison::GE: + return v.ir.FPVectorGreaterEqual(32, reg_m, zero); + case Comparison::GT: + return v.ir.FPVectorGreater(32, reg_m, zero); + case Comparison::LE: + return v.ir.FPVectorGreaterEqual(32, zero, reg_m); + case Comparison::LT: + return v.ir.FPVectorGreater(32, zero, reg_m); + } + + 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) { @@ -173,6 +233,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(); diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 077026a8..fb095f90 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -459,6 +459,11 @@ struct ArmTranslatorVisitor final { bool asimd_VCNT(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);