Implement some multiplies
This commit is contained in:
parent
72c503016c
commit
eb2e6e8bea
4 changed files with 174 additions and 21 deletions
|
@ -246,15 +246,15 @@ boost::optional<const ArmMatcher<V>&> DecodeArm(u32 instruction) {
|
|||
//INST(&V::arm_USAT16, "USAT16", "cccc01101110vvvvdddd11110011nnnn"), // v6
|
||||
|
||||
// Multiply (Normal) instructions
|
||||
//INST(&V::arm_MLA, "MLA", "cccc0000001Sddddaaaammmm1001nnnn"), // v2
|
||||
//INST(&V::arm_MUL, "MUL", "cccc0000000Sdddd0000mmmm1001nnnn"), // v2
|
||||
INST(&V::arm_MLA, "MLA", "cccc0000001Sddddaaaammmm1001nnnn"), // v2
|
||||
INST(&V::arm_MUL, "MUL", "cccc0000000Sdddd0000mmmm1001nnnn"), // v2
|
||||
|
||||
// Multiply (Long) instructions
|
||||
//INST(&V::arm_SMLAL, "SMLAL", "cccc0000111Sddddaaaammmm1001nnnn"), // v3M
|
||||
//INST(&V::arm_SMULL, "SMULL", "cccc0000110Sddddaaaammmm1001nnnn"), // v3M
|
||||
//INST(&V::arm_UMAAL, "UMAAL", "cccc00000100ddddaaaammmm1001nnnn"), // v6
|
||||
//INST(&V::arm_UMLAL, "UMLAL", "cccc0000101Sddddaaaammmm1001nnnn"), // v3M
|
||||
//INST(&V::arm_UMULL, "UMULL", "cccc0000100Sddddaaaammmm1001nnnn"), // v3M
|
||||
INST(&V::arm_SMLAL, "SMLAL", "cccc0000111Sddddaaaammmm1001nnnn"), // v3M
|
||||
INST(&V::arm_SMULL, "SMULL", "cccc0000110Sddddaaaammmm1001nnnn"), // v3M
|
||||
INST(&V::arm_UMAAL, "UMAAL", "cccc00000100ddddaaaammmm1001nnnn"), // v6
|
||||
INST(&V::arm_UMLAL, "UMLAL", "cccc0000101Sddddaaaammmm1001nnnn"), // v3M
|
||||
INST(&V::arm_UMULL, "UMULL", "cccc0000100Sddddaaaammmm1001nnnn"), // v3M
|
||||
|
||||
// Multiply (Halfword) instructions
|
||||
//INST(&V::arm_SMLALxy, "SMLALXY", "cccc00010100ddddaaaammmm1xy0nnnn"), // v5xP
|
||||
|
|
|
@ -383,15 +383,29 @@ public:
|
|||
std::string arm_USAT16(Cond cond, Imm4 sat_imm, Reg d, Reg n) { return "ice"; }
|
||||
|
||||
// Multiply (Normal) instructions
|
||||
std::string arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) { return "ice"; }
|
||||
std::string arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) { return "ice"; }
|
||||
std::string arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
|
||||
return Common::StringFromFormat("mla%s%s %s, %s, %s, %s", S ? "s" : "", CondToString(cond), RegToString(d), RegToString(n), RegToString(m), RegToString(a));
|
||||
}
|
||||
std::string arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) {
|
||||
return Common::StringFromFormat("mul%s%s %s, %s, %s", S ? "s" : "", CondToString(cond), RegToString(d), RegToString(n), RegToString(m));
|
||||
}
|
||||
|
||||
// Multiply (Long) instructions
|
||||
std::string arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { return "ice"; }
|
||||
std::string arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { return "ice"; }
|
||||
std::string arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) { return "ice"; }
|
||||
std::string arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { return "ice"; }
|
||||
std::string arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { return "ice"; }
|
||||
std::string arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return Common::StringFromFormat("smlal%s%s %s, %s, %s, %s", S ? "s" : "", CondToString(cond), RegToString(dLo), RegToString(dHi), RegToString(n), RegToString(m));
|
||||
}
|
||||
std::string arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return Common::StringFromFormat("smull%s%s %s, %s, %s, %s", S ? "s" : "", CondToString(cond), RegToString(dLo), RegToString(dHi), RegToString(n), RegToString(m));
|
||||
}
|
||||
std::string arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return Common::StringFromFormat("umaal%s %s, %s, %s, %s", CondToString(cond), RegToString(dLo), RegToString(dHi), RegToString(n), RegToString(m));
|
||||
}
|
||||
std::string arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return Common::StringFromFormat("umlal%s%s %s, %s, %s, %s", S ? "s" : "", CondToString(cond), RegToString(dLo), RegToString(dHi), RegToString(n), RegToString(m));
|
||||
}
|
||||
std::string arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return Common::StringFromFormat("umull%s%s %s, %s, %s, %s", S ? "s" : "", CondToString(cond), RegToString(dLo), RegToString(dHi), RegToString(n), RegToString(m));
|
||||
}
|
||||
|
||||
// Multiply (Halfword) instructions
|
||||
std::string arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, bool N, Reg n) { return "ice"; }
|
||||
|
|
|
@ -11,33 +11,137 @@ namespace Arm {
|
|||
|
||||
// Multiply (Normal) instructions
|
||||
bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
|
||||
return InterpretThisInstruction();
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
|
||||
ir.SetRegister(d, result);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) {
|
||||
return InterpretThisInstruction();
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Multiply (Long) instructions
|
||||
bool ArmTranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return InterpretThisInstruction();
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
auto product = ir.Mul64(n64, m64);
|
||||
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
auto result = ir.Add64(product, addend);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result);
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero64(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return InterpretThisInstruction();
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Mul64(n64, m64);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result);
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero64(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return InterpretThisInstruction();
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto lo64 = ir.ZeroExtendWordToLong(ir.GetRegister(dLo));
|
||||
auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi));
|
||||
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Add64(ir.Add64(ir.Mul64(n64, m64), hi64), lo64);
|
||||
ir.SetRegister(dLo, ir.LeastSignificantWord(result));
|
||||
ir.SetRegister(dHi, ir.MostSignificantWord(result));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return InterpretThisInstruction();
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Add64(ir.Mul64(n64, m64), addend);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result);
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero64(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
return InterpretThisInstruction();
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Mul64(n64, m64);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result);
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero64(result));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -601,3 +601,38 @@ TEST_CASE("Fuzz ARM Load/Store instructions", "[JitX64]") {
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
TEST_CASE("Fuzz ARM multiply instructions", "[JitX64]") {
|
||||
auto validate_d_m_n = [](u32 inst) -> bool {
|
||||
return Dynarmic::Common::Bits<16, 19>(inst) != 15 &&
|
||||
Dynarmic::Common::Bits<8, 11>(inst) != 15 &&
|
||||
Dynarmic::Common::Bits<0, 3>(inst) != 15;
|
||||
};
|
||||
auto validate_d_a_m_n = [&](u32 inst) -> bool {
|
||||
return validate_d_m_n(inst) &&
|
||||
Dynarmic::Common::Bits<12, 15>(inst) != 15;
|
||||
};
|
||||
auto validate_h_l_m_n = [&](u32 inst) -> bool {
|
||||
return validate_d_a_m_n(inst) &&
|
||||
Dynarmic::Common::Bits<12, 15>(inst) != Dynarmic::Common::Bits<16, 19>(inst);
|
||||
};
|
||||
|
||||
const std::array<InstructionGenerator, 7> instructions = {
|
||||
{
|
||||
InstructionGenerator("cccc0000001Sddddaaaammmm1001nnnn", validate_d_a_m_n), // MLA
|
||||
InstructionGenerator("cccc0000000Sdddd0000mmmm1001nnnn", validate_d_m_n), // MUL
|
||||
|
||||
InstructionGenerator("cccc0000111Sddddaaaammmm1001nnnn", validate_h_l_m_n), // SMLAL
|
||||
InstructionGenerator("cccc0000110Sddddaaaammmm1001nnnn", validate_h_l_m_n), // SMULL
|
||||
InstructionGenerator("cccc00000100ddddaaaammmm1001nnnn", validate_h_l_m_n), // UMAAL
|
||||
InstructionGenerator("cccc0000101Sddddaaaammmm1001nnnn", validate_h_l_m_n), // UMLAL
|
||||
InstructionGenerator("cccc0000100Sddddaaaammmm1001nnnn", validate_h_l_m_n), // UMULL
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("Multiply") {
|
||||
FuzzJitArm(2, 2, 10000, [&]() -> u32 {
|
||||
return instructions[RandInt<size_t>(0, instructions.size() - 1)].Generate();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue