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
656419286c
commit
ed6ca58058
4 changed files with 93 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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, 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<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) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in a new issue