diff --git a/src/frontend/A32/translate/translate_arm/saturated.cpp b/src/frontend/A32/translate/translate_arm/saturated.cpp index dac7307d..ed0e6bff 100644 --- a/src/frontend/A32/translate/translate_arm/saturated.cpp +++ b/src/frontend/A32/translate/translate_arm/saturated.cpp @@ -18,224 +18,268 @@ static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) { // Saturation instructions +// SSAT , #, {, } bool ArmTranslatorVisitor::arm_SSAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) { - if (d == Reg::PC || n == Reg::PC) + if (d == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - - size_t saturate_to = static_cast(sat_imm) + 1; - ShiftType shift = !sh ? ShiftType::LSL : ShiftType::ASR; - - // SSAT , #, - if (ConditionPassed(cond)) { - auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag()); - auto result = ir.SignedSaturation(operand.result, saturate_to); - ir.SetRegister(d, result.result); - ir.OrQFlag(result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto saturate_to = static_cast(sat_imm) + 1; + const auto shift = !sh ? ShiftType::LSL : ShiftType::ASR; + const auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag()); + const auto result = ir.SignedSaturation(operand.result, saturate_to); + + ir.SetRegister(d, result.result); + ir.OrQFlag(result.overflow); return true; } +// SSAT16 , #, bool ArmTranslatorVisitor::arm_SSAT16(Cond cond, Imm4 sat_imm, Reg d, Reg n) { - if (d == Reg::PC || n == Reg::PC) + if (d == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - - size_t saturate_to = static_cast(sat_imm) + 1; - - // SSAT16 , #, - if (ConditionPassed(cond)) { - auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n))); - auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n))); - auto lo_result = ir.SignedSaturation(lo_operand, saturate_to); - auto hi_result = ir.SignedSaturation(hi_operand, saturate_to); - ir.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result)); - ir.OrQFlag(lo_result.overflow); - ir.OrQFlag(hi_result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto saturate_to = static_cast(sat_imm) + 1; + const auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n))); + const auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n))); + const auto lo_result = ir.SignedSaturation(lo_operand, saturate_to); + const auto hi_result = ir.SignedSaturation(hi_operand, saturate_to); + + ir.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result)); + ir.OrQFlag(lo_result.overflow); + ir.OrQFlag(hi_result.overflow); return true; } +// USAT , #, {, } bool ArmTranslatorVisitor::arm_USAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) { - if (d == Reg::PC || n == Reg::PC) + if (d == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - - size_t saturate_to = static_cast(sat_imm); - ShiftType shift = !sh ? ShiftType::LSL : ShiftType::ASR; - - // USAT , #, - if (ConditionPassed(cond)) { - auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag()); - auto result = ir.UnsignedSaturation(operand.result, saturate_to); - ir.SetRegister(d, result.result); - ir.OrQFlag(result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto saturate_to = static_cast(sat_imm); + const auto shift = !sh ? ShiftType::LSL : ShiftType::ASR; + const auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag()); + const auto result = ir.UnsignedSaturation(operand.result, saturate_to); + + ir.SetRegister(d, result.result); + ir.OrQFlag(result.overflow); return true; } +// USAT16 , #, bool ArmTranslatorVisitor::arm_USAT16(Cond cond, Imm4 sat_imm, Reg d, Reg n) { - if (d == Reg::PC || n == Reg::PC) + if (d == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); - - size_t saturate_to = static_cast(sat_imm); - - // USAT16 , #, - if (ConditionPassed(cond)) { - // UnsignedSaturation takes a *signed* value as input, hence sign extension is required. - auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n))); - auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n))); - auto lo_result = ir.UnsignedSaturation(lo_operand, saturate_to); - auto hi_result = ir.UnsignedSaturation(hi_operand, saturate_to); - ir.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result)); - ir.OrQFlag(lo_result.overflow); - ir.OrQFlag(hi_result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + // UnsignedSaturation takes a *signed* value as input, hence sign extension is required. + const auto saturate_to = static_cast(sat_imm); + const auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n))); + const auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n))); + const auto lo_result = ir.UnsignedSaturation(lo_operand, saturate_to); + const auto hi_result = ir.UnsignedSaturation(hi_operand, saturate_to); + + ir.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result)); + ir.OrQFlag(lo_result.overflow); + ir.OrQFlag(hi_result.overflow); return true; } // Saturated Add/Subtract instructions +// QADD , , bool ArmTranslatorVisitor::arm_QADD(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // QADD , , - if (ConditionPassed(cond)) { - auto a = ir.GetRegister(m); - auto b = ir.GetRegister(n); - auto result = ir.SignedSaturatedAdd(a, b); - ir.SetRegister(d, result.result); - ir.OrQFlag(result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto a = ir.GetRegister(m); + const auto b = ir.GetRegister(n); + const auto result = ir.SignedSaturatedAdd(a, b); + + ir.SetRegister(d, result.result); + ir.OrQFlag(result.overflow); return true; } +// QSUB , , bool ArmTranslatorVisitor::arm_QSUB(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // QSUB , , - if (ConditionPassed(cond)) { - auto a = ir.GetRegister(m); - auto b = ir.GetRegister(n); - auto result = ir.SignedSaturatedSub(a, b); - ir.SetRegister(d, result.result); - ir.OrQFlag(result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto a = ir.GetRegister(m); + const auto b = ir.GetRegister(n); + const auto result = ir.SignedSaturatedSub(a, b); + + ir.SetRegister(d, result.result); + ir.OrQFlag(result.overflow); return true; } +// QDADD , , bool ArmTranslatorVisitor::arm_QDADD(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // QDADD , , - if (ConditionPassed(cond)) { - auto a = ir.GetRegister(m); - auto b = ir.GetRegister(n); - auto doubled = ir.SignedSaturatedAdd(b, b); - ir.OrQFlag(doubled.overflow); - auto result = ir.SignedSaturatedAdd(a, doubled.result); - ir.SetRegister(d, result.result); - ir.OrQFlag(result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto a = ir.GetRegister(m); + const auto b = ir.GetRegister(n); + const auto doubled = ir.SignedSaturatedAdd(b, b); + ir.OrQFlag(doubled.overflow); + + const auto result = ir.SignedSaturatedAdd(a, doubled.result); + ir.SetRegister(d, result.result); + ir.OrQFlag(result.overflow); return true; } +// QDSUB , , bool ArmTranslatorVisitor::arm_QDSUB(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // QDSUB , , - if (ConditionPassed(cond)) { - auto a = ir.GetRegister(m); - auto b = ir.GetRegister(n); - auto doubled = ir.SignedSaturatedAdd(b, b); - ir.OrQFlag(doubled.overflow); - auto result = ir.SignedSaturatedSub(a, doubled.result); - ir.SetRegister(d, result.result); - ir.OrQFlag(result.overflow); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto a = ir.GetRegister(m); + const auto b = ir.GetRegister(n); + const auto doubled = ir.SignedSaturatedAdd(b, b); + ir.OrQFlag(doubled.overflow); + + const auto result = ir.SignedSaturatedSub(a, doubled.result); + ir.SetRegister(d, result.result); + ir.OrQFlag(result.overflow); return true; } // Parallel saturated instructions +// QASX , , bool ArmTranslatorVisitor::arm_QASX(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // QASX , , - if (ConditionPassed(cond)) { - auto Rn = ir.GetRegister(n); - auto Rm = ir.GetRegister(m); - auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn)); - auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn)); - auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm)); - auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm)); - auto diff = ir.SignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result; - auto sum = ir.SignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result; - auto result = Pack2x16To1x32(ir, diff, sum); - ir.SetRegister(d, result); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto Rn = ir.GetRegister(n); + const auto Rm = ir.GetRegister(m); + const auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn)); + const auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn)); + const auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm)); + const auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm)); + const auto diff = ir.SignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result; + const auto sum = ir.SignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result; + const auto result = Pack2x16To1x32(ir, diff, sum); + + ir.SetRegister(d, result); return true; } +// QSAX , , bool ArmTranslatorVisitor::arm_QSAX(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // QSAX , , - if (ConditionPassed(cond)) { - auto Rn = ir.GetRegister(n); - auto Rm = ir.GetRegister(m); - auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn)); - auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn)); - auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm)); - auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm)); - auto sum = ir.SignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result; - auto diff = ir.SignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result; - auto result = Pack2x16To1x32(ir, sum, diff); - ir.SetRegister(d, result); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto Rn = ir.GetRegister(n); + const auto Rm = ir.GetRegister(m); + const auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn)); + const auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn)); + const auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm)); + const auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm)); + const auto sum = ir.SignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result; + const auto diff = ir.SignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result; + const auto result = Pack2x16To1x32(ir, sum, diff); + + ir.SetRegister(d, result); return true; } +// UQASX , , bool ArmTranslatorVisitor::arm_UQASX(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // UQASX , , - if (ConditionPassed(cond)) { - auto Rn = ir.GetRegister(n); - auto Rm = ir.GetRegister(m); - auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn)); - auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn)); - auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm)); - auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm)); - auto diff = ir.UnsignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result; - auto sum = ir.UnsignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result; - auto result = Pack2x16To1x32(ir, diff, sum); - ir.SetRegister(d, result); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto Rn = ir.GetRegister(n); + const auto Rm = ir.GetRegister(m); + const auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn)); + const auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn)); + const auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm)); + const auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm)); + const auto diff = ir.UnsignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result; + const auto sum = ir.UnsignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result; + const auto result = Pack2x16To1x32(ir, diff, sum); + + ir.SetRegister(d, result); return true; } +// UQSAX , , bool ArmTranslatorVisitor::arm_UQSAX(Cond cond, Reg n, Reg d, Reg m) { - if (d == Reg::PC || n == Reg::PC || m == Reg::PC) + if (d == Reg::PC || n == Reg::PC || m == Reg::PC) { return UnpredictableInstruction(); - - // UQSAX , , - if (ConditionPassed(cond)) { - auto Rn = ir.GetRegister(n); - auto Rm = ir.GetRegister(m); - auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn)); - auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn)); - auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm)); - auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm)); - auto sum = ir.UnsignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result; - auto diff = ir.UnsignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result; - auto result = Pack2x16To1x32(ir, sum, diff); - ir.SetRegister(d, result); } + + if (!ConditionPassed(cond)) { + return true; + } + + const auto Rn = ir.GetRegister(n); + const auto Rm = ir.GetRegister(m); + const auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn)); + const auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn)); + const auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm)); + const auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm)); + const auto sum = ir.UnsignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result; + const auto diff = ir.UnsignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result; + const auto result = Pack2x16To1x32(ir, sum, diff); + + ir.SetRegister(d, result); return true; }