Implement some multiplies

This commit is contained in:
Tillmann Karras 2016-08-05 02:03:23 +01:00
parent 72c503016c
commit eb2e6e8bea
4 changed files with 174 additions and 21 deletions

View file

@ -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

View file

@ -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"; }

View file

@ -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;
}

View file

@ -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();
});
}
}