translate_arm/multiply: Invert conditionals where applicable

This commit is contained in:
Lioncash 2019-03-01 01:21:00 -05:00 committed by MerryMage
parent c8dad40d81
commit c711188f46

View file

@ -8,149 +8,209 @@
namespace Dynarmic::A32 { namespace Dynarmic::A32 {
// Multiply (Normal) instructions // MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) { bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
if (!ConditionPassed(cond)) {
return true;
}
const auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
ir.SetRegister(d, result); ir.SetRegister(d, result);
if (S) { if (S) {
ir.SetNFlag(ir.MostSignificantBit(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result)); ir.SetZFlag(ir.IsZero(result));
} }
}
return true; return true;
} }
// MUL{S}<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) { bool ArmTranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
if (!ConditionPassed(cond)) {
return true;
}
const auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
ir.SetRegister(d, result); ir.SetRegister(d, result);
if (S) { if (S) {
ir.SetNFlag(ir.MostSignificantBit(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result)); ir.SetZFlag(ir.IsZero(result));
} }
}
return true; return true;
} }
// Multiply (Long) instructions // SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { bool ArmTranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m)); if (!ConditionPassed(cond)) {
auto product = ir.Mul(n64, m64); return true;
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); }
auto result = ir.Add(product, addend);
auto lo = ir.LeastSignificantWord(result); const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto hi = ir.MostSignificantWord(result).result; const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
const auto product = ir.Mul(n64, m64);
const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
const auto result = ir.Add(product, addend);
const auto lo = ir.LeastSignificantWord(result);
const auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
ir.SetRegister(dHi, hi); ir.SetRegister(dHi, hi);
if (S) { if (S) {
ir.SetNFlag(ir.MostSignificantBit(hi)); ir.SetNFlag(ir.MostSignificantBit(hi));
ir.SetZFlag(ir.IsZero(result)); ir.SetZFlag(ir.IsZero(result));
} }
}
return true; return true;
} }
// SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { bool ArmTranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m)); if (!ConditionPassed(cond)) {
auto result = ir.Mul(n64, m64); return true;
auto lo = ir.LeastSignificantWord(result); }
auto hi = ir.MostSignificantWord(result).result;
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
const auto result = ir.Mul(n64, m64);
const auto lo = ir.LeastSignificantWord(result);
const auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
ir.SetRegister(dHi, hi); ir.SetRegister(dHi, hi);
if (S) { if (S) {
ir.SetNFlag(ir.MostSignificantBit(hi)); ir.SetNFlag(ir.MostSignificantBit(hi));
ir.SetZFlag(ir.IsZero(result)); ir.SetZFlag(ir.IsZero(result));
} }
}
return true; return true;
} }
// UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) { bool ArmTranslatorVisitor::arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
auto lo64 = ir.ZeroExtendWordToLong(ir.GetRegister(dLo));
auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi)); if (!ConditionPassed(cond)) {
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n)); return true;
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m)); }
auto result = ir.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64);
const auto lo64 = ir.ZeroExtendWordToLong(ir.GetRegister(dLo));
const auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi));
const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
const auto result = ir.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
}
return true; return true;
} }
// UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { bool ArmTranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n)); if (!ConditionPassed(cond)) {
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m)); return true;
auto result = ir.Add(ir.Mul(n64, m64), addend); }
auto lo = ir.LeastSignificantWord(result);
auto hi = ir.MostSignificantWord(result).result; const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
const auto result = ir.Add(ir.Mul(n64, m64), addend);
const auto lo = ir.LeastSignificantWord(result);
const auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
ir.SetRegister(dHi, hi); ir.SetRegister(dHi, hi);
if (S) { if (S) {
ir.SetNFlag(ir.MostSignificantBit(hi)); ir.SetNFlag(ir.MostSignificantBit(hi));
ir.SetZFlag(ir.IsZero(result)); ir.SetZFlag(ir.IsZero(result));
} }
}
return true; return true;
} }
// UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) { bool ArmTranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m)); if (!ConditionPassed(cond)) {
auto result = ir.Mul(n64, m64); return true;
auto lo = ir.LeastSignificantWord(result); }
auto hi = ir.MostSignificantWord(result).result;
const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
const auto result = ir.Mul(n64, m64);
const auto lo = ir.LeastSignificantWord(result);
const auto hi = ir.MostSignificantWord(result).result;
ir.SetRegister(dLo, lo); ir.SetRegister(dLo, lo);
ir.SetRegister(dHi, hi); ir.SetRegister(dHi, hi);
if (S) { if (S) {
ir.SetNFlag(ir.MostSignificantBit(hi)); ir.SetNFlag(ir.MostSignificantBit(hi));
ir.SetZFlag(ir.IsZero(result)); ir.SetZFlag(ir.IsZero(result));
} }
}
return true; return true;
} }
// SMLAL<x><y><c> <RdLo>, <RdHi>, <Rn>, <Rm>
// Multiply (Halfword) instructions
bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, bool N, Reg n) { bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, bool N, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
@ -158,18 +218,24 @@ bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool
const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
: ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U64 product = ir.SignExtendWordToLong(ir.Mul(n16, m16)); const IR::U64 product = ir.SignExtendWordToLong(ir.Mul(n16, m16));
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto result = ir.Add(product, addend); const auto result = ir.Add(product, addend);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
}
return true; return true;
} }
// SMLA<x><y><c> <Rd>, <Rn>, <Rm>, <Ra>
bool ArmTranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bool N, Reg n) { bool ArmTranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bool N, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
@ -177,17 +243,23 @@ bool ArmTranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bo
const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
: ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 product = ir.Mul(n16, m16); const IR::U32 product = ir.Mul(n16, m16);
auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0)); const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
ir.SetRegister(d, result_overflow.result); ir.SetRegister(d, result_overflow.result);
ir.OrQFlag(result_overflow.overflow); ir.OrQFlag(result_overflow.overflow);
}
return true; return true;
} }
// SMUL<x><y><c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, Reg n) { bool ArmTranslatorVisitor::arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
@ -195,236 +267,326 @@ bool ArmTranslatorVisitor::arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, R
const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
: ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 result = ir.Mul(n16, m16); const IR::U32 result = ir.Mul(n16, m16);
ir.SetRegister(d, result); ir.SetRegister(d, result);
}
return true; return true;
} }
// SMLAW<y><c> <Rd>, <Rn>, <Rm>, <Ra>
// Multiply (word by halfword) instructions
bool ArmTranslatorVisitor::arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n)); const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
IR::U32 m32 = ir.GetRegister(m); IR::U32 m32 = ir.GetRegister(m);
if (M) if (M) {
m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
}
const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16))); const auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0)); const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
ir.SetRegister(d, result_overflow.result); ir.SetRegister(d, result_overflow.result);
ir.OrQFlag(result_overflow.overflow); ir.OrQFlag(result_overflow.overflow);
}
return true; return true;
} }
// SMULW<y><c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMULWy(Cond cond, Reg d, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMULWy(Cond cond, Reg d, Reg m, bool M, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n)); const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
IR::U32 m32 = ir.GetRegister(m); IR::U32 m32 = ir.GetRegister(m);
if (M) if (M) {
m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
}
const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)); const auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16));
ir.SetRegister(d, ir.LeastSignificantWord(result)); ir.SetRegister(d, ir.LeastSignificantWord(result));
}
return true; return true;
} }
// SMMLA{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
// Multiply (Most significant word) instructions
bool ArmTranslatorVisitor::arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) { bool ArmTranslatorVisitor::arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC /* no check for a */) if (d == Reg::PC || n == Reg::PC || m == Reg::PC /* no check for a */) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
auto temp = ir.Add(a64, ir.Mul(n64, m64));
auto result_carry = ir.MostSignificantWord(temp);
auto result = result_carry.result;
if (R)
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
ir.SetRegister(d, result);
} }
if (!ConditionPassed(cond)) {
return true;
}
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
const auto temp = ir.Add(a64, ir.Mul(n64, m64));
const auto result_carry = ir.MostSignificantWord(temp);
auto result = result_carry.result;
if (R) {
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
}
ir.SetRegister(d, result);
return true; return true;
} }
// SMMLS{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
bool ArmTranslatorVisitor::arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) { bool ArmTranslatorVisitor::arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
auto temp = ir.Sub(a64, ir.Mul(n64, m64));
auto result_carry = ir.MostSignificantWord(temp);
auto result = result_carry.result;
if (R)
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
ir.SetRegister(d, result);
} }
if (!ConditionPassed(cond)) {
return true;
}
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
const auto temp = ir.Sub(a64, ir.Mul(n64, m64));
const auto result_carry = ir.MostSignificantWord(temp);
auto result = result_carry.result;
if (R) {
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
}
ir.SetRegister(d, result);
return true; return true;
} }
// SMMUL{R}<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n) { bool ArmTranslatorVisitor::arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
auto product = ir.Mul(n64, m64);
auto result_carry = ir.MostSignificantWord(product);
auto result = result_carry.result;
if (R)
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
ir.SetRegister(d, result);
} }
if (!ConditionPassed(cond)) {
return true;
}
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
const auto product = ir.Mul(n64, m64);
const auto result_carry = ir.MostSignificantWord(product);
auto result = result_carry.result;
if (R) {
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
}
ir.SetRegister(d, result);
return true; return true;
} }
// SMLAD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
// Multiply (Dual) instructions
bool ArmTranslatorVisitor::arm_SMLAD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMLAD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
if (a == Reg::PC) if (a == Reg::PC) {
return arm_SMUAD(cond, d, m, M, n); return arm_SMUAD(cond, d, m, M, n);
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) }
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result; const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
if (M) if (M) {
std::swap(m_lo, m_hi); std::swap(m_lo, m_hi);
}
const IR::U32 product_lo = ir.Mul(n_lo, m_lo); const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
const IR::U32 product_hi = ir.Mul(n_hi, m_hi); const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
const IR::U32 addend = ir.GetRegister(a); const IR::U32 addend = ir.GetRegister(a);
auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0)); auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
ir.OrQFlag(result_overflow.overflow); ir.OrQFlag(result_overflow.overflow);
result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0)); result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0));
ir.SetRegister(d, result_overflow.result); ir.SetRegister(d, result_overflow.result);
ir.OrQFlag(result_overflow.overflow); ir.OrQFlag(result_overflow.overflow);
}
return true; return true;
} }
// SMLALD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMLALD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMLALD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result; const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
if (M) if (M) {
std::swap(m_lo, m_hi); std::swap(m_lo, m_hi);
}
const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo)); const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi)); const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto result = ir.Add(ir.Add(product_lo, product_hi), addend); const auto result = ir.Add(ir.Add(product_lo, product_hi), addend);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
}
return true; return true;
} }
// SMLSD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
bool ArmTranslatorVisitor::arm_SMLSD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMLSD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
if (a == Reg::PC) if (a == Reg::PC) {
return arm_SMUSD(cond, d, m, M, n); return arm_SMUSD(cond, d, m, M, n);
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) }
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result; const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
if (M) if (M) {
std::swap(m_lo, m_hi); std::swap(m_lo, m_hi);
}
const IR::U32 product_lo = ir.Mul(n_lo, m_lo); const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
const IR::U32 product_hi = ir.Mul(n_hi, m_hi); const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
const IR::U32 addend = ir.GetRegister(a); const IR::U32 addend = ir.GetRegister(a);
const IR::U32 product = ir.Sub(product_lo, product_hi); const IR::U32 product = ir.Sub(product_lo, product_hi);
auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0)); auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0));
ir.SetRegister(d, result_overflow.result); ir.SetRegister(d, result_overflow.result);
ir.OrQFlag(result_overflow.overflow); ir.OrQFlag(result_overflow.overflow);
}
return true; return true;
} }
// SMLSLD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMLSLD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMLSLD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (dLo == dHi) }
if (dLo == dHi) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result; const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
if (M) if (M) {
std::swap(m_lo, m_hi); std::swap(m_lo, m_hi);
}
const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo)); const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi)); const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
auto result = ir.Add(ir.Sub(product_lo, product_hi), addend); const auto result = ir.Add(ir.Sub(product_lo, product_hi), addend);
ir.SetRegister(dLo, ir.LeastSignificantWord(result)); ir.SetRegister(dLo, ir.LeastSignificantWord(result));
ir.SetRegister(dHi, ir.MostSignificantWord(result).result); ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
}
return true; return true;
} }
// SMUAD{X}<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMUAD(Cond cond, Reg d, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMUAD(Cond cond, Reg d, Reg m, bool M, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result; const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
if (M) if (M) {
std::swap(m_lo, m_hi); std::swap(m_lo, m_hi);
}
const IR::U32 product_lo = ir.Mul(n_lo, m_lo); const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
const IR::U32 product_hi = ir.Mul(n_hi, m_hi); const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0)); const auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
ir.SetRegister(d, result_overflow.result); ir.SetRegister(d, result_overflow.result);
ir.OrQFlag(result_overflow.overflow); ir.OrQFlag(result_overflow.overflow);
}
return true; return true;
} }
// SMUSD{X}<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_SMUSD(Cond cond, Reg d, Reg m, bool M, Reg n) { bool ArmTranslatorVisitor::arm_SMUSD(Cond cond, Reg d, Reg m, bool M, Reg n) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
if (ConditionPassed(cond)) { }
if (!ConditionPassed(cond)) {
return true;
}
const IR::U32 n32 = ir.GetRegister(n); const IR::U32 n32 = ir.GetRegister(n);
const IR::U32 m32 = ir.GetRegister(m); const IR::U32 m32 = ir.GetRegister(m);
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result; const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
if (M) if (M) {
std::swap(m_lo, m_hi); std::swap(m_lo, m_hi);
}
const IR::U32 product_lo = ir.Mul(n_lo, m_lo); const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
const IR::U32 product_hi = ir.Mul(n_hi, m_hi); const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
auto result = ir.Sub(product_lo, product_hi); auto result = ir.Sub(product_lo, product_hi);
ir.SetRegister(d, result); ir.SetRegister(d, result);
}
return true; return true;
} }