VFPv4: Implement VCVTB, VCVTT

This commit is contained in:
MerryMage 2020-05-10 14:45:18 +01:00
parent 010fab9a0e
commit 3c86d58064
4 changed files with 82 additions and 2 deletions

View file

@ -19,8 +19,8 @@ INST(vfp_VMOV_reg, "VMOV (reg)", "cccc11101D110000dddd101z0
INST(vfp_VABS, "VABS", "cccc11101D110000dddd101z11M0mmmm") // VFPv2
INST(vfp_VNEG, "VNEG", "cccc11101D110001dddd101z01M0mmmm") // VFPv2
INST(vfp_VSQRT, "VSQRT", "cccc11101D110001dddd101z11M0mmmm") // VFPv2
//INST(vfp_VCVTB, "VCVTB", "cccc11101D11001odddd1010T1M0mmmm") // VFPv3HP
//INST(vfp_VCVTT, "VCVTT", "cccc11101D11001odddd1010T1M0mmmm") // VFPv3HP
INST(vfp_VCVTB, "VCVTB", "cccc11101D11001odddd101z01M0mmmm") // VFPv3HP
INST(vfp_VCVTT, "VCVTT", "cccc11101D11001odddd101z11M0mmmm") // VFPv3HP
INST(vfp_VCMP, "VCMP", "cccc11101D110100dddd101zE1M0mmmm") // VFPv2
INST(vfp_VCMP_zero, "VCMP (with zero)", "cccc11101D110101dddd101zE1000000") // VFPv2
INST(vfp_VCVT_f_to_f, "VCVT (f32<->f64)", "cccc11101D110111dddd101z11M0mmmm") // VFPv2

View file

@ -1280,6 +1280,20 @@ public:
return fmt::format("vsqrt{}.{} {}, {}", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D), FPRegStr(sz, Vm, M));
}
std::string vfp_VCVTB(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) {
const bool convert_from_half = !op;
const char* const to = convert_from_half ? (sz ? "f64" : "f32") : "f16";
const char* const from = convert_from_half ? "f16" : (sz ? "f64" : "f32");
return fmt::format("vcvtb{}.{}.{} {}, {}", CondToString(cond), to, from, FPRegStr(convert_from_half ? sz : false, Vd, D), FPRegStr(convert_from_half ? false : sz, Vm, M));
}
std::string vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) {
const bool convert_from_half = !op;
const char* const to = convert_from_half ? (sz ? "f64" : "f32") : "f16";
const char* const from = convert_from_half ? "f16" : (sz ? "f64" : "f32");
return fmt::format("vcvtt{}.{}.{} {}, {}", CondToString(cond), to, from, FPRegStr(convert_from_half ? sz : false, Vd, D), FPRegStr(convert_from_half ? false : sz, Vm, M));
}
std::string vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
return fmt::format("vcvt{}.{}.{} {}, {}", CondToString(cond), !sz ? "f64" : "f32", sz ? "f64" : "f32", FPRegStr(!sz, Vd, D), FPRegStr(sz, Vm, M));
}

View file

@ -391,6 +391,8 @@ struct ArmTranslatorVisitor final {
bool vfp_VABS(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VNEG(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VSQRT(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVTB(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm);
bool vfp_VCVT_from_int(Cond cond, bool D, size_t Vd, bool sz, bool is_signed, bool M, size_t Vm);
bool vfp_VCVT_to_u32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);

View file

@ -548,6 +548,70 @@ bool ArmTranslatorVisitor::vfp_VSQRT(Cond cond, bool D, size_t Vd, bool sz, bool
});
}
// VCVTB<c>.f32.f16 <Dd>, <Dm>
// VCVTB<c>.f64.f16 <Dd>, <Dm>
// VCVTB<c>.f16.f32 <Dd>, <Dm>
// VCVTB<c>.f16.f64 <Dd>, <Dm>
bool ArmTranslatorVisitor::vfp_VCVTB(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) {
if (!ConditionPassed(cond)) {
return true;
}
const bool convert_from_half = !op;
const auto rounding_mode = ir.current_location.FPSCR().RMode();
if (convert_from_half) {
const auto d = ToExtReg(sz, Vd, D);
const auto m = ToExtReg(false, Vm, M);
return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) {
const auto reg_m = ir.LeastSignificantHalf(ir.GetExtendedRegister(m));
const auto result = sz ? IR::U32U64{ir.FPHalfToDouble(reg_m, rounding_mode)} : IR::U32U64{ir.FPHalfToSingle(reg_m, rounding_mode)};
ir.SetExtendedRegister(d, result);
});
} else {
const auto d = ToExtReg(false, Vd, D);
const auto m = ToExtReg(sz, Vm, M);
return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) {
const auto reg_m = ir.GetExtendedRegister(m);
const auto result = sz ? ir.FPDoubleToHalf(reg_m, rounding_mode) : ir.FPSingleToHalf(reg_m, rounding_mode);
ir.SetExtendedRegister(d, ir.Or(ir.And(ir.GetExtendedRegister(d), ir.Imm32(0xFFFF0000)), ir.ZeroExtendToWord(result)));
});
}
}
// VCVTT<c>.f32.f16 <Dd>, <Dm>
// VCVTT<c>.f64.f16 <Dd>, <Dm>
// VCVTT<c>.f16.f32 <Dd>, <Dm>
// VCVTT<c>.f16.f64 <Dd>, <Dm>
bool ArmTranslatorVisitor::vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) {
if (!ConditionPassed(cond)) {
return true;
}
const bool convert_from_half = !op;
const auto rounding_mode = ir.current_location.FPSCR().RMode();
if (convert_from_half) {
const auto d = ToExtReg(sz, Vd, D);
const auto m = ToExtReg(false, Vm, M);
return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) {
const auto reg_m = ir.LeastSignificantHalf(ir.LogicalShiftRight(ir.GetExtendedRegister(m), ir.Imm8(16)));
const auto result = sz ? IR::U32U64{ir.FPHalfToDouble(reg_m, rounding_mode)} : IR::U32U64{ir.FPHalfToSingle(reg_m, rounding_mode)};
ir.SetExtendedRegister(d, result);
});
} else {
const auto d = ToExtReg(false, Vd, D);
const auto m = ToExtReg(sz, Vm, M);
return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) {
const auto reg_m = ir.GetExtendedRegister(m);
const auto result = sz ? ir.FPDoubleToHalf(reg_m, rounding_mode) : ir.FPSingleToHalf(reg_m, rounding_mode);
ir.SetExtendedRegister(d, ir.Or(ir.And(ir.GetExtendedRegister(d), ir.Imm32(0x0000FFFF)), ir.LogicalShiftLeft(ir.ZeroExtendToWord(result), ir.Imm8(16))));
});
}
}
// VCVT<c>.F64.F32 <Dd>, <Sm>
// VCVT<c>.F32.F64 <Sd>, <Dm>
bool ArmTranslatorVisitor::vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {