A32: Implement ASIMD VQRDMULH (scalar)
This commit is contained in:
parent
ab5efe8632
commit
20a2bf29fc
3 changed files with 49 additions and 26 deletions
|
@ -75,8 +75,8 @@ INST(asimd_VMLAL_scalar, "VMLAL (scalar)", "1111001U1dzznnnndddd0o1
|
||||||
INST(asimd_VMUL_scalar, "VMUL (scalar)", "1111001Q1Dzznnnndddd100FN1M0mmmm") // ASIMD
|
INST(asimd_VMUL_scalar, "VMUL (scalar)", "1111001Q1Dzznnnndddd100FN1M0mmmm") // ASIMD
|
||||||
INST(asimd_VMULL_scalar, "VMULL (scalar)", "1111001U1Dzznnnndddd1010N1M0mmmm") // ASIMD
|
INST(asimd_VMULL_scalar, "VMULL (scalar)", "1111001U1Dzznnnndddd1010N1M0mmmm") // ASIMD
|
||||||
//INST(asimd_VQDMULL_scalar, "VQDMULL (scalar)", "111100101-BB--------1011-1-0----") // ASIMD
|
//INST(asimd_VQDMULL_scalar, "VQDMULL (scalar)", "111100101-BB--------1011-1-0----") // ASIMD
|
||||||
INST(asimd_VQDMULH_scalar, "VQDMULH", "1111001Q1Dzznnnndddd1100N1M0mmmm") // ASIMD
|
INST(asimd_VQDMULH_scalar, "VQDMULH (scalar)", "1111001Q1Dzznnnndddd1100N1M0mmmm") // ASIMD
|
||||||
//INST(asimd_VQRDMULH_scalar, "VQRDMULH", "1111001U1-BB--------1101-1-0----") // ASIMD
|
INST(asimd_VQRDMULH_scalar, "VQRDMULH (scalar)", "1111001Q1Dzznnnndddd1101N1M0mmmm") // ASIMD
|
||||||
|
|
||||||
// Two registers and a shift amount
|
// Two registers and a shift amount
|
||||||
INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD
|
INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD
|
||||||
|
|
|
@ -24,6 +24,11 @@ enum class MultiplyBehavior {
|
||||||
MultiplySubtract,
|
MultiplySubtract,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Rounding {
|
||||||
|
None,
|
||||||
|
Round,
|
||||||
|
};
|
||||||
|
|
||||||
bool ScalarMultiply(ArmTranslatorVisitor& v, bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool F, bool N, bool M, size_t Vm,
|
bool ScalarMultiply(ArmTranslatorVisitor& v, bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool F, bool N, bool M, size_t Vm,
|
||||||
MultiplyBehavior multiply) {
|
MultiplyBehavior multiply) {
|
||||||
if (sz == 0b11) {
|
if (sz == 0b11) {
|
||||||
|
@ -105,6 +110,43 @@ bool ScalarMultiplyLong(ArmTranslatorVisitor& v, bool U, bool D, size_t sz, size
|
||||||
v.ir.SetVector(d, result);
|
v.ir.SetVector(d, result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScalarMultiplyReturnHigh(ArmTranslatorVisitor& v, bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm,
|
||||||
|
Rounding round) {
|
||||||
|
if (sz == 0b11) {
|
||||||
|
// TODO: This should be a decode error.
|
||||||
|
return v.UndefinedInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sz == 0b00) {
|
||||||
|
return v.UndefinedInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vn))) {
|
||||||
|
return v.UndefinedInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t esize = 8U << sz;
|
||||||
|
const auto d = ToVector(Q, Vd, D);
|
||||||
|
const auto n = ToVector(Q, Vn, N);
|
||||||
|
const auto [m, index] = GetScalarLocation(esize, M, Vm);
|
||||||
|
|
||||||
|
const auto scalar = v.ir.VectorGetElement(esize, v.ir.GetVector(m), index);
|
||||||
|
const auto reg_n = v.ir.GetVector(n);
|
||||||
|
const auto reg_m = v.ir.VectorBroadcast(esize, scalar);
|
||||||
|
const auto result = [&] {
|
||||||
|
const auto tmp = v.ir.VectorSignedSaturatedDoublingMultiply(esize, reg_n, reg_m);
|
||||||
|
|
||||||
|
if (round == Rounding::Round) {
|
||||||
|
return v.ir.VectorAdd(esize, tmp.upper, v.ir.VectorLogicalShiftRight(esize, tmp.lower, static_cast<u8>(esize - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp.upper;
|
||||||
|
}();
|
||||||
|
|
||||||
|
v.ir.SetVector(d, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::asimd_VMLA_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool F, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::asimd_VMLA_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool F, bool N, bool M, size_t Vm) {
|
||||||
|
@ -128,31 +170,11 @@ bool ArmTranslatorVisitor::asimd_VMULL_scalar(bool U, bool D, size_t sz, size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::asimd_VQDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::asimd_VQDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm) {
|
||||||
if (sz == 0b11) {
|
return ScalarMultiplyReturnHigh(*this, Q, D, sz, Vn, Vd, N, M, Vm, Rounding::None);
|
||||||
// TODO: This should be a decode error.
|
}
|
||||||
return UndefinedInstruction();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sz == 0b00) {
|
bool ArmTranslatorVisitor::asimd_VQRDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm) {
|
||||||
return UndefinedInstruction();
|
return ScalarMultiplyReturnHigh(*this, Q, D, sz, Vn, Vd, N, M, Vm, Rounding::Round);
|
||||||
}
|
|
||||||
|
|
||||||
if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vn))) {
|
|
||||||
return UndefinedInstruction();
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t esize = 8U << sz;
|
|
||||||
const auto d = ToVector(Q, Vd, D);
|
|
||||||
const auto n = ToVector(Q, Vn, N);
|
|
||||||
const auto [m, index] = GetScalarLocation(esize, M, Vm);
|
|
||||||
|
|
||||||
const auto scalar = ir.VectorGetElement(esize, ir.GetVector(m), index);
|
|
||||||
const auto reg_n = ir.GetVector(n);
|
|
||||||
const auto reg_m = ir.VectorBroadcast(esize, scalar);
|
|
||||||
const auto result = ir.VectorSignedSaturatedDoublingMultiply(esize, reg_n, reg_m).upper;
|
|
||||||
|
|
||||||
ir.SetVector(d, result);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
} // namespace Dynarmic::A32
|
||||||
|
|
|
@ -511,6 +511,7 @@ struct ArmTranslatorVisitor final {
|
||||||
bool asimd_VMUL_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool F, bool N, bool M, size_t Vm);
|
bool asimd_VMUL_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool F, bool N, bool M, size_t Vm);
|
||||||
bool asimd_VMULL_scalar(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
|
bool asimd_VMULL_scalar(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
|
||||||
bool asimd_VQDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
|
bool asimd_VQDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
|
||||||
|
bool asimd_VQRDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
|
||||||
|
|
||||||
// Two registers and a shift amount
|
// Two registers and a shift amount
|
||||||
bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
|
bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm);
|
||||||
|
|
Loading…
Reference in a new issue