translate_arm/saturated: Invert conditionals where applicable

This commit is contained in:
Lioncash 2019-03-01 02:05:30 -05:00 committed by MerryMage
parent a72813599a
commit c6aa1a708a

View file

@ -18,224 +18,268 @@ static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
// Saturation instructions // Saturation instructions
// SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
bool ArmTranslatorVisitor::arm_SSAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) { 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(); return UnpredictableInstruction();
size_t saturate_to = static_cast<size_t>(sat_imm) + 1;
ShiftType shift = !sh ? ShiftType::LSL : ShiftType::ASR;
// SSAT <Rd>, #<saturate_to>, <Rn>
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; return true;
} }
const auto saturate_to = static_cast<size_t>(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<c> <Rd>, #<imm>, <Rn>
bool ArmTranslatorVisitor::arm_SSAT16(Cond cond, Imm4 sat_imm, Reg d, Reg n) { 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(); return UnpredictableInstruction();
size_t saturate_to = static_cast<size_t>(sat_imm) + 1;
// SSAT16 <Rd>, #<saturate_to>, <Rn>
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; return true;
} }
const auto saturate_to = static_cast<size_t>(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<c> <Rd>, #<imm5>, <Rn>{, <shift>}
bool ArmTranslatorVisitor::arm_USAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) { 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(); return UnpredictableInstruction();
}
size_t saturate_to = static_cast<size_t>(sat_imm); if (!ConditionPassed(cond)) {
ShiftType shift = !sh ? ShiftType::LSL : ShiftType::ASR; return true;
}
const auto saturate_to = static_cast<size_t>(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);
// USAT <Rd>, #<saturate_to>, <Rn>
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.SetRegister(d, result.result);
ir.OrQFlag(result.overflow); ir.OrQFlag(result.overflow);
}
return true; return true;
} }
// USAT16<c> <Rd>, #<imm4>, <Rn>
bool ArmTranslatorVisitor::arm_USAT16(Cond cond, Imm4 sat_imm, Reg d, Reg n) { 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(); return UnpredictableInstruction();
}
size_t saturate_to = static_cast<size_t>(sat_imm); if (!ConditionPassed(cond)) {
return true;
}
// USAT16 <Rd>, #<saturate_to>, <Rn>
if (ConditionPassed(cond)) {
// UnsignedSaturation takes a *signed* value as input, hence sign extension is required. // UnsignedSaturation takes a *signed* value as input, hence sign extension is required.
auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n))); const auto saturate_to = static_cast<size_t>(sat_imm);
auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n))); const auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n)));
auto lo_result = ir.UnsignedSaturation(lo_operand, saturate_to); const auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n)));
auto hi_result = ir.UnsignedSaturation(hi_operand, saturate_to); 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.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result));
ir.OrQFlag(lo_result.overflow); ir.OrQFlag(lo_result.overflow);
ir.OrQFlag(hi_result.overflow); ir.OrQFlag(hi_result.overflow);
}
return true; return true;
} }
// Saturated Add/Subtract instructions // Saturated Add/Subtract instructions
// QADD<c> <Rd>, <Rm>, <Rn>
bool ArmTranslatorVisitor::arm_QADD(Cond cond, Reg n, Reg d, Reg m) { 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(); return UnpredictableInstruction();
// QADD <Rd>, <Rm>, <Rn>
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; 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<c> <Rd>, <Rm>, <Rn>
bool ArmTranslatorVisitor::arm_QSUB(Cond cond, Reg n, Reg d, Reg m) { 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(); return UnpredictableInstruction();
// QSUB <Rd>, <Rm>, <Rn>
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; 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<c> <Rd>, <Rm>, <Rn>
bool ArmTranslatorVisitor::arm_QDADD(Cond cond, Reg n, Reg d, Reg m) { 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(); return UnpredictableInstruction();
// QDADD <Rd>, <Rm>, <Rn>
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; return true;
} }
bool ArmTranslatorVisitor::arm_QDSUB(Cond cond, Reg n, Reg d, Reg m) { const auto a = ir.GetRegister(m);
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) const auto b = ir.GetRegister(n);
return UnpredictableInstruction(); const auto doubled = ir.SignedSaturatedAdd(b, b);
// QDSUB <Rd>, <Rm>, <Rn>
if (ConditionPassed(cond)) {
auto a = ir.GetRegister(m);
auto b = ir.GetRegister(n);
auto doubled = ir.SignedSaturatedAdd(b, b);
ir.OrQFlag(doubled.overflow); ir.OrQFlag(doubled.overflow);
auto result = ir.SignedSaturatedSub(a, doubled.result);
const auto result = ir.SignedSaturatedAdd(a, doubled.result);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.OrQFlag(result.overflow); ir.OrQFlag(result.overflow);
return true;
} }
// QDSUB<c> <Rd>, <Rm>, <Rn>
bool ArmTranslatorVisitor::arm_QDSUB(Cond cond, Reg n, Reg d, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
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; return true;
} }
// Parallel saturated instructions // Parallel saturated instructions
// QASX<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_QASX(Cond cond, Reg n, Reg d, Reg m) { 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(); return UnpredictableInstruction();
// QASX <Rd>, <Rn>, <Rm>
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; 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<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_QSAX(Cond cond, Reg n, Reg d, Reg m) { 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(); return UnpredictableInstruction();
// QSAX <Rd>, <Rn>, <Rm>
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; 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<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_UQASX(Cond cond, Reg n, Reg d, Reg m) { 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(); return UnpredictableInstruction();
// UQASX <Rd>, <Rn>, <Rm>
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; return true;
} }
bool ArmTranslatorVisitor::arm_UQSAX(Cond cond, Reg n, Reg d, Reg m) { const auto Rn = ir.GetRegister(n);
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) const auto Rm = ir.GetRegister(m);
return UnpredictableInstruction(); 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);
// UQSAX <Rd>, <Rn>, <Rm>
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); ir.SetRegister(d, result);
return true;
} }
// UQSAX<c> <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_UQSAX(Cond cond, Reg n, Reg d, Reg m) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return UnpredictableInstruction();
}
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; return true;
} }