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:
parent
054dff7cd5
commit
179951b10f
3 changed files with 90 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue