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.
This commit is contained in:
Lioncash
2020-06-18 09:00:26 -04:00
committed by merry
parent 054dff7cd5
commit 179951b10f
3 changed files with 90 additions and 5 deletions

View File

@@ -5,9 +5,69 @@
#include "common/bit_util.h"
#include <array>
#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<size_t>(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();