From c711188f46959ba22bcedf9af2cf97426fffe25f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 1 Mar 2019 01:21:00 -0500 Subject: [PATCH] translate_arm/multiply: Invert conditionals where applicable --- .../A32/translate/translate_arm/multiply.cpp | 748 +++++++++++------- 1 file changed, 455 insertions(+), 293 deletions(-) diff --git a/src/frontend/A32/translate/translate_arm/multiply.cpp b/src/frontend/A32/translate/translate_arm/multiply.cpp index 0cc9ca17..e6ac9215 100644 --- a/src/frontend/A32/translate/translate_arm/multiply.cpp +++ b/src/frontend/A32/translate/translate_arm/multiply.cpp @@ -8,423 +8,585 @@ namespace Dynarmic::A32 { -// Multiply (Normal) instructions +// MLA{S} , , , 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(); - 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)); - } } + + 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); + if (S) { + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + } + return true; } +// MUL{S} , , 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(); - 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)); - } } + + if (!ConditionPassed(cond)) { + return true; + } + + const 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 +// SMLAL{S} , , , 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(); - 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.Mul(n64, m64); - auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); - auto result = ir.Add(product, addend); - auto lo = ir.LeastSignificantWord(result); - auto hi = ir.MostSignificantWord(result).result; - ir.SetRegister(dLo, lo); - ir.SetRegister(dHi, hi); - if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); - } } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + 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 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(dHi, hi); + if (S) { + ir.SetNFlag(ir.MostSignificantBit(hi)); + ir.SetZFlag(ir.IsZero(result)); + } + return true; } +// SMULL{S} , , , 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(); - 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.Mul(n64, m64); - auto lo = ir.LeastSignificantWord(result); - auto hi = ir.MostSignificantWord(result).result; - ir.SetRegister(dLo, lo); - ir.SetRegister(dHi, hi); - if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); - } } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + 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(dHi, hi); + if (S) { + ir.SetNFlag(ir.MostSignificantBit(hi)); + ir.SetZFlag(ir.IsZero(result)); + } + return true; } +// UMAAL , , , 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(); - 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.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64); - ir.SetRegister(dLo, ir.LeastSignificantWord(result)); - ir.SetRegister(dHi, ir.MostSignificantWord(result).result); } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + 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(dHi, ir.MostSignificantWord(result).result); return true; } +// UMLAL{S} , , , 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(); - 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.Add(ir.Mul(n64, m64), addend); - auto lo = ir.LeastSignificantWord(result); - auto hi = ir.MostSignificantWord(result).result; - ir.SetRegister(dLo, lo); - ir.SetRegister(dHi, hi); - if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); - } } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + 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(dHi, hi); + if (S) { + ir.SetNFlag(ir.MostSignificantBit(hi)); + ir.SetZFlag(ir.IsZero(result)); + } + return true; } +// UMULL{S} , , , 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(); - 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.Mul(n64, m64); - auto lo = ir.LeastSignificantWord(result); - auto hi = ir.MostSignificantWord(result).result; - ir.SetRegister(dLo, lo); - ir.SetRegister(dHi, hi); - if (S) { - ir.SetNFlag(ir.MostSignificantBit(hi)); - ir.SetZFlag(ir.IsZero(result)); - } } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + 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(dHi, hi); + if (S) { + ir.SetNFlag(ir.MostSignificantBit(hi)); + ir.SetZFlag(ir.IsZero(result)); + } + return true; } - -// Multiply (Halfword) instructions +// SMLAL , , , 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(); - if (dLo == dHi) - return UnpredictableInstruction(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result - : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); - const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result - : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); - const IR::U64 product = ir.SignExtendWordToLong(ir.Mul(n16, m16)); - auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); - auto result = ir.Add(product, addend); - ir.SetRegister(dLo, ir.LeastSignificantWord(result)); - ir.SetRegister(dHi, ir.MostSignificantWord(result).result); } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result + : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result + : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); + const IR::U64 product = ir.SignExtendWordToLong(ir.Mul(n16, m16)); + const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); + const auto result = ir.Add(product, addend); + + ir.SetRegister(dLo, ir.LeastSignificantWord(result)); + ir.SetRegister(dHi, ir.MostSignificantWord(result).result); return true; } +// SMLA , , , 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(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result - : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); - const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result - : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); - const IR::U32 product = ir.Mul(n16, m16); - auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0)); - ir.SetRegister(d, result_overflow.result); - ir.OrQFlag(result_overflow.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result + : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result + : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); + const IR::U32 product = ir.Mul(n16, m16); + const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0)); + + ir.SetRegister(d, result_overflow.result); + ir.OrQFlag(result_overflow.overflow); return true; } +// SMUL , , 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(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result - : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); - const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result - : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); - const IR::U32 result = ir.Mul(n16, m16); - ir.SetRegister(d, result); } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result + : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result + : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)); + const IR::U32 result = ir.Mul(n16, m16); + + ir.SetRegister(d, result); return true; } - -// Multiply (word by halfword) instructions +// SMLAW , , , 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(); - if (ConditionPassed(cond)) { - const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n)); - IR::U32 m32 = ir.GetRegister(m); - if (M) - m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); - 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)); - ir.SetRegister(d, result_overflow.result); - ir.OrQFlag(result_overflow.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n)); + IR::U32 m32 = ir.GetRegister(m); + if (M) { + m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; + } + const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); + const auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16))); + const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0)); + + ir.SetRegister(d, result_overflow.result); + ir.OrQFlag(result_overflow.overflow); return true; } +// SMULW , , 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(); - if (ConditionPassed(cond)) { - const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n)); - IR::U32 m32 = ir.GetRegister(m); - if (M) - m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); - auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)); - ir.SetRegister(d, ir.LeastSignificantWord(result)); } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n)); + IR::U32 m32 = ir.GetRegister(m); + if (M) { + m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; + } + const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32))); + const auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)); + + ir.SetRegister(d, ir.LeastSignificantWord(result)); return true; } - -// Multiply (Most significant word) instructions +// SMMLA{R} , , , 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(); - 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; } +// SMMLS{R} , , , 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(); - 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; } +// SMMUL{R} , , 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(); - 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; } - -// Multiply (Dual) instructions +// SMLAD{X} , , , 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); - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) - return UnpredictableInstruction(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - 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; - IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - if (M) - std::swap(m_lo, m_hi); - 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 addend = ir.GetRegister(a); - auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0)); - ir.OrQFlag(result_overflow.overflow); - result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0)); - ir.SetRegister(d, result_overflow.result); - ir.OrQFlag(result_overflow.overflow); } + + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + 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; + if (M) { + std::swap(m_lo, m_hi); + } + + 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 addend = ir.GetRegister(a); + + auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0)); + ir.OrQFlag(result_overflow.overflow); + result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0)); + ir.SetRegister(d, result_overflow.result); + ir.OrQFlag(result_overflow.overflow); return true; } +// SMLALD{X} , , , 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(); - if (dLo == dHi) - return UnpredictableInstruction(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - 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; - IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - if (M) - std::swap(m_lo, m_hi); - 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)); - auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); - auto result = ir.Add(ir.Add(product_lo, product_hi), addend); - ir.SetRegister(dLo, ir.LeastSignificantWord(result)); - ir.SetRegister(dHi, ir.MostSignificantWord(result).result); } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + 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; + if (M) { + std::swap(m_lo, m_hi); + } + + 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 auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); + const auto result = ir.Add(ir.Add(product_lo, product_hi), addend); + + ir.SetRegister(dLo, ir.LeastSignificantWord(result)); + ir.SetRegister(dHi, ir.MostSignificantWord(result).result); return true; } +// SMLSD{X} , , , 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); - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) - return UnpredictableInstruction(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - 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; - IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - if (M) - std::swap(m_lo, m_hi); - 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 addend = ir.GetRegister(a); - const IR::U32 product = ir.Sub(product_lo, product_hi); - auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0)); - ir.SetRegister(d, result_overflow.result); - ir.OrQFlag(result_overflow.overflow); } + + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + 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; + if (M) { + std::swap(m_lo, m_hi); + } + + 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 addend = ir.GetRegister(a); + const IR::U32 product = ir.Sub(product_lo, product_hi); + auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0)); + + ir.SetRegister(d, result_overflow.result); + ir.OrQFlag(result_overflow.overflow); return true; } +// SMLSLD{X} , , , 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(); - if (dLo == dHi) - return UnpredictableInstruction(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - 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; - IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - if (M) - std::swap(m_lo, m_hi); - 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)); - auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); - auto result = ir.Add(ir.Sub(product_lo, product_hi), addend); - ir.SetRegister(dLo, ir.LeastSignificantWord(result)); - ir.SetRegister(dHi, ir.MostSignificantWord(result).result); } + + if (dLo == dHi) { + return UnpredictableInstruction(); + } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + 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; + if (M) { + std::swap(m_lo, m_hi); + } + + 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 auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi)); + const auto result = ir.Add(ir.Sub(product_lo, product_hi), addend); + + ir.SetRegister(dLo, ir.LeastSignificantWord(result)); + ir.SetRegister(dHi, ir.MostSignificantWord(result).result); return true; } +// SMUAD{X} , , 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(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - 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; - IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - if (M) - std::swap(m_lo, m_hi); - const IR::U32 product_lo = ir.Mul(n_lo, m_lo); - const IR::U32 product_hi = ir.Mul(n_hi, m_hi); - auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0)); - ir.SetRegister(d, result_overflow.result); - ir.OrQFlag(result_overflow.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + 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; + if (M) { + std::swap(m_lo, m_hi); + } + + const IR::U32 product_lo = ir.Mul(n_lo, m_lo); + const IR::U32 product_hi = ir.Mul(n_hi, m_hi); + const auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0)); + + ir.SetRegister(d, result_overflow.result); + ir.OrQFlag(result_overflow.overflow); return true; } +// SMUSD{X} , , 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(); - if (ConditionPassed(cond)) { - const IR::U32 n32 = ir.GetRegister(n); - const IR::U32 m32 = ir.GetRegister(m); - 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; - IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result; - if (M) - std::swap(m_lo, m_hi); - const IR::U32 product_lo = ir.Mul(n_lo, m_lo); - const IR::U32 product_hi = ir.Mul(n_hi, m_hi); - auto result = ir.Sub(product_lo, product_hi); - ir.SetRegister(d, result); } + + if (!ConditionPassed(cond)) { + return true; + } + + const IR::U32 n32 = ir.GetRegister(n); + const IR::U32 m32 = ir.GetRegister(m); + const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32)); + 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; + if (M) { + std::swap(m_lo, m_hi); + } + + const IR::U32 product_lo = ir.Mul(n_lo, m_lo); + const IR::U32 product_hi = ir.Mul(n_hi, m_hi); + auto result = ir.Sub(product_lo, product_hi); + ir.SetRegister(d, result); return true; }