IR: Add fbits argument to FixedToFP-related opcodes
This commit is contained in:
parent
616a153c16
commit
90193b0e3d
8 changed files with 154 additions and 134 deletions
|
@ -1201,82 +1201,115 @@ void EmitX64::EmitFPSingleToFixedU64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitFPToFixed(code, ctx, inst, 32, true, 64);
|
EmitFPToFixed(code, ctx, inst, 32, true, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPS32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPFixedS32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
Xbyak::Reg32 from = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
|
||||||
Xbyak::Xmm to = ctx.reg_alloc.ScratchXmm();
|
|
||||||
bool round_to_nearest = args[1].GetImmediateU1();
|
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
|
||||||
|
|
||||||
code.cvtsi2ss(to, from);
|
const Xbyak::Reg32 from = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
||||||
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, to);
|
code.cvtsi2ss(result, from);
|
||||||
|
|
||||||
|
if (fbits != 0) {
|
||||||
|
const u32 scale_factor = static_cast<u32>((127 - fbits) << 23);
|
||||||
|
code.mulss(result, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPU32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPFixedU32ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
const Xbyak::Xmm to = ctx.reg_alloc.ScratchXmm();
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
const bool round_to_nearest = args[1].GetImmediateU1();
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
||||||
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
code.vcvtusi2ss(to, to, from.cvt32());
|
code.vcvtusi2ss(result, result, from.cvt32());
|
||||||
} else {
|
} else {
|
||||||
// We are using a 64-bit GPR register to ensure we don't end up treating the input as signed
|
// We are using a 64-bit GPR register to ensure we don't end up treating the input as signed
|
||||||
const Xbyak::Reg64 from = ctx.reg_alloc.UseScratchGpr(args[0]);
|
const Xbyak::Reg64 from = ctx.reg_alloc.UseScratchGpr(args[0]);
|
||||||
code.mov(from.cvt32(), from.cvt32()); // TODO: Verify if this is necessary
|
code.mov(from.cvt32(), from.cvt32()); // TODO: Verify if this is necessary
|
||||||
code.cvtsi2ss(to, from);
|
code.cvtsi2ss(result, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, to);
|
if (fbits != 0) {
|
||||||
|
const u32 scale_factor = static_cast<u32>((127 - fbits) << 23);
|
||||||
|
code.mulss(result, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPS32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPFixedS32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
|
||||||
Xbyak::Reg32 from = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
|
||||||
Xbyak::Xmm to = ctx.reg_alloc.ScratchXmm();
|
|
||||||
bool round_to_nearest = args[1].GetImmediateU1();
|
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
|
||||||
|
|
||||||
code.cvtsi2sd(to, from);
|
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitX64::EmitFPS64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
const Xbyak::Reg32 from = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
||||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
const bool round_to_nearest = args[1].GetImmediateU1();
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
code.cvtsi2sd(result, from);
|
code.cvtsi2sd(result, from);
|
||||||
|
|
||||||
|
if (fbits != 0) {
|
||||||
|
const u64 scale_factor = static_cast<u64>((1023 - fbits) << 52);
|
||||||
|
code.mulsd(result, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPS64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPFixedS64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
const bool round_to_nearest = args[1].GetImmediateU1();
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
code.cvtsi2ss(result, from);
|
code.cvtsi2sd(result, from);
|
||||||
|
|
||||||
|
if (fbits != 0) {
|
||||||
|
const u64 scale_factor = static_cast<u64>((1023 - fbits) << 52);
|
||||||
|
code.mulsd(result, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPFixedS64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
|
code.cvtsi2ss(result, from);
|
||||||
|
|
||||||
|
if (fbits != 0) {
|
||||||
|
const u32 scale_factor = static_cast<u32>((127 - fbits) << 23);
|
||||||
|
code.mulss(result, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitFPFixedU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
const Xbyak::Xmm to = ctx.reg_alloc.ScratchXmm();
|
const Xbyak::Xmm to = ctx.reg_alloc.ScratchXmm();
|
||||||
const bool round_to_nearest = args[1].GetImmediateU1();
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
||||||
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
|
@ -1288,16 +1321,22 @@ void EmitX64::EmitFPU32ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||||
code.cvtsi2sd(to, from);
|
code.cvtsi2sd(to, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fbits != 0) {
|
||||||
|
const u64 scale_factor = static_cast<u64>((1023 - fbits) << 52);
|
||||||
|
code.mulsd(to, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, to);
|
ctx.reg_alloc.DefineValue(inst, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPFixedU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
const bool round_to_nearest = args[1].GetImmediateU1();
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
||||||
code.vcvtusi2sd(result, result, from);
|
code.vcvtusi2sd(result, result, from);
|
||||||
|
@ -1314,15 +1353,21 @@ void EmitX64::EmitFPU64ToDouble(EmitContext& ctx, IR::Inst* inst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fbits != 0) {
|
||||||
|
const u64 scale_factor = static_cast<u64>((1023 - fbits) << 52);
|
||||||
|
code.mulsd(result, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPFixedU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
|
||||||
const bool round_to_nearest = args[1].GetImmediateU1();
|
const size_t fbits = args[1].GetImmediateU8();
|
||||||
ASSERT_MSG(!round_to_nearest, "round_to_nearest unimplemented");
|
const FP::RoundingMode rounding_mode = static_cast<FP::RoundingMode>(args[2].GetImmediateU8());
|
||||||
|
ASSERT(rounding_mode == ctx.FPSCR_RMode());
|
||||||
|
|
||||||
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
if (code.DoesCpuSupport(Xbyak::util::Cpu::tAVX512F)) {
|
||||||
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
const Xbyak::Reg64 from = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
|
@ -1352,6 +1397,11 @@ void EmitX64::EmitFPU64ToSingle(EmitContext& ctx, IR::Inst* inst) {
|
||||||
code.L(end);
|
code.L(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fbits != 0) {
|
||||||
|
const u32 scale_factor = static_cast<u32>((127 - fbits) << 23);
|
||||||
|
code.mulss(result, code.MConst(xword, scale_factor));
|
||||||
|
}
|
||||||
|
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
} // namespace Dynarmic::BackendX64
|
} // namespace Dynarmic::BackendX64
|
||||||
|
|
|
@ -414,20 +414,20 @@ bool ArmTranslatorVisitor::vfp2_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool s
|
||||||
bool ArmTranslatorVisitor::vfp2_VCVT_to_float(Cond cond, bool D, size_t Vd, bool sz, bool is_signed, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp2_VCVT_to_float(Cond cond, bool D, size_t Vd, bool sz, bool is_signed, bool M, size_t Vm) {
|
||||||
ExtReg d = ToExtReg(sz, Vd, D);
|
ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
ExtReg m = ToExtReg(false, Vm, M);
|
ExtReg m = ToExtReg(false, Vm, M);
|
||||||
bool round_to_nearest = false;
|
FP::RoundingMode rounding_mode = ir.current_location.FPSCR().RMode();
|
||||||
// VCVT.F32.{S32,U32} <Sd>, <Sm>
|
// VCVT.F32.{S32,U32} <Sd>, <Sm>
|
||||||
// VCVT.F64.{S32,U32} <Sd>, <Dm>
|
// VCVT.F64.{S32,U32} <Sd>, <Dm>
|
||||||
if (ConditionPassed(cond)) {
|
if (ConditionPassed(cond)) {
|
||||||
auto reg_m = ir.GetExtendedRegister(m);
|
auto reg_m = ir.GetExtendedRegister(m);
|
||||||
if (sz) {
|
if (sz) {
|
||||||
auto result = is_signed
|
auto result = is_signed
|
||||||
? ir.FPS32ToDouble(reg_m, round_to_nearest, true)
|
? ir.FPSignedFixedToDouble(reg_m, 0, rounding_mode)
|
||||||
: ir.FPU32ToDouble(reg_m, round_to_nearest, true);
|
: ir.FPUnsignedFixedToDouble(reg_m, 0, rounding_mode);
|
||||||
ir.SetExtendedRegister(d, result);
|
ir.SetExtendedRegister(d, result);
|
||||||
} else {
|
} else {
|
||||||
auto result = is_signed
|
auto result = is_signed
|
||||||
? ir.FPS32ToSingle(reg_m, round_to_nearest, true)
|
? ir.FPSignedFixedToSingle(reg_m, 0, rounding_mode)
|
||||||
: ir.FPU32ToSingle(reg_m, round_to_nearest, true);
|
: ir.FPUnsignedFixedToSingle(reg_m, 0, rounding_mode);
|
||||||
ir.SetExtendedRegister(d, result);
|
ir.SetExtendedRegister(d, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,10 @@ bool TranslatorVisitor::SCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) {
|
||||||
const IR::U32U64 intval = X(intsize, Rn);
|
const IR::U32U64 intval = X(intsize, Rn);
|
||||||
IR::U32U64 fltval;
|
IR::U32U64 fltval;
|
||||||
|
|
||||||
if (intsize == 32 && *fltsize == 32) {
|
if (*fltsize == 32) {
|
||||||
fltval = ir.FPS32ToSingle(intval, false, true);
|
fltval = ir.FPSignedFixedToSingle(intval, 0, ir.current_location->FPCR().RMode());
|
||||||
} else if (intsize == 32 && *fltsize == 64) {
|
} else if (*fltsize == 64) {
|
||||||
fltval = ir.FPS32ToDouble(intval, false, true);
|
fltval = ir.FPSignedFixedToDouble(intval, 0, ir.current_location->FPCR().RMode());
|
||||||
} else if (intsize == 64 && *fltsize == 32) {
|
|
||||||
fltval = ir.FPS64ToSingle(intval, false, true);
|
|
||||||
} else if (intsize == 64 && *fltsize == 64) {
|
|
||||||
fltval = ir.FPS64ToDouble(intval, false, true);
|
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -48,14 +44,10 @@ bool TranslatorVisitor::UCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) {
|
||||||
const IR::U32U64 intval = X(intsize, Rn);
|
const IR::U32U64 intval = X(intsize, Rn);
|
||||||
IR::U32U64 fltval;
|
IR::U32U64 fltval;
|
||||||
|
|
||||||
if (intsize == 32 && *fltsize == 32) {
|
if (*fltsize == 32) {
|
||||||
fltval = ir.FPU32ToSingle(intval, false, true);
|
fltval = ir.FPUnsignedFixedToSingle(intval, 0, ir.current_location->FPCR().RMode());
|
||||||
} else if (intsize == 32 && *fltsize == 64) {
|
} else if (*fltsize == 64) {
|
||||||
fltval = ir.FPU32ToDouble(intval, false, true);
|
fltval = ir.FPUnsignedFixedToDouble(intval, 0, ir.current_location->FPCR().RMode());
|
||||||
} else if (intsize == 64 && *fltsize == 32) {
|
|
||||||
fltval = ir.FPU64ToSingle(intval, false, true);
|
|
||||||
} else if (intsize == 64 && *fltsize == 64) {
|
|
||||||
fltval = ir.FPU64ToDouble(intval, false, true);
|
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,13 +195,12 @@ bool TranslatorVisitor::NEG_1(Imm<2> size, Vec Vn, Vec Vd) {
|
||||||
bool TranslatorVisitor::SCVTF_int_2(bool sz, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::SCVTF_int_2(bool sz, Vec Vn, Vec Vd) {
|
||||||
const auto esize = sz ? 64 : 32;
|
const auto esize = sz ? 64 : 32;
|
||||||
|
|
||||||
IR::U32U64 element = V_scalar(esize, Vn);
|
const IR::U32U64 element = V_scalar(esize, Vn);
|
||||||
if (esize == 32) {
|
const IR::U32U64 result = esize == 32
|
||||||
element = ir.FPS32ToSingle(element, false, true);
|
? IR::U32U64(ir.FPSignedFixedToSingle(element, 0, ir.current_location->FPCR().RMode()))
|
||||||
} else {
|
: IR::U32U64(ir.FPSignedFixedToDouble(element, 0, ir.current_location->FPCR().RMode()));
|
||||||
element = ir.FPS64ToDouble(element, false, true);
|
|
||||||
}
|
V_scalar(esize, Vd, result);
|
||||||
V_scalar(esize, Vd, element);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,13 +247,12 @@ bool TranslatorVisitor::SUQADD_1(Imm<2> size, Vec Vn, Vec Vd) {
|
||||||
bool TranslatorVisitor::UCVTF_int_2(bool sz, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::UCVTF_int_2(bool sz, Vec Vn, Vec Vd) {
|
||||||
const auto esize = sz ? 64 : 32;
|
const auto esize = sz ? 64 : 32;
|
||||||
|
|
||||||
IR::U32U64 element = V_scalar(esize, Vn);
|
const IR::U32U64 element = V_scalar(esize, Vn);
|
||||||
if (esize == 32) {
|
const IR::U32U64 result = esize == 32
|
||||||
element = ir.FPU32ToSingle(element, false, true);
|
? IR::U32U64(ir.FPUnsignedFixedToSingle(element, 0, ir.current_location->FPCR().RMode()))
|
||||||
} else {
|
: IR::U32U64(ir.FPUnsignedFixedToDouble(element, 0, ir.current_location->FPCR().RMode()));
|
||||||
element = ir.FPU64ToDouble(element, false, true);
|
|
||||||
}
|
V_scalar(esize, Vd, result);
|
||||||
V_scalar(esize, Vd, element);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1960,44 +1960,28 @@ U64 IREmitter::FPToFixedU64(const U32U64& a, size_t fbits, FP::RoundingMode roun
|
||||||
return Inst<U64>(opcode, a, Imm8(static_cast<u8>(fbits)), Imm8(static_cast<u8>(rounding)));
|
return Inst<U64>(opcode, a, Imm8(static_cast<u8>(fbits)), Imm8(static_cast<u8>(rounding)));
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 IREmitter::FPS32ToSingle(const U32& a, bool round_to_nearest, bool fpcr_controlled) {
|
U32 IREmitter::FPSignedFixedToSingle(const U32U64& a, size_t fbits, FP::RoundingMode rounding) {
|
||||||
ASSERT(fpcr_controlled);
|
ASSERT(fbits <= (a.GetType() == Type::U32 ? 32 : 64));
|
||||||
return Inst<U32>(Opcode::FPS32ToSingle, a, Imm1(round_to_nearest));
|
const Opcode opcode = a.GetType() == Type::U32 ? Opcode::FPFixedS32ToSingle : Opcode::FPFixedS64ToSingle;
|
||||||
|
return Inst<U32>(opcode, a, Imm8(static_cast<u8>(fbits)), Imm8(static_cast<u8>(rounding)));
|
||||||
}
|
}
|
||||||
|
|
||||||
U64 IREmitter::FPS64ToDouble(const U64& a, bool round_to_nearest, bool fpcr_controlled) {
|
U32 IREmitter::FPUnsignedFixedToSingle(const U32U64& a, size_t fbits, FP::RoundingMode rounding) {
|
||||||
ASSERT(fpcr_controlled);
|
ASSERT(fbits <= (a.GetType() == Type::U32 ? 32 : 64));
|
||||||
return Inst<U64>(Opcode::FPS64ToDouble, a, Imm1(round_to_nearest));
|
const Opcode opcode = a.GetType() == Type::U32 ? Opcode::FPFixedU32ToSingle : Opcode::FPFixedU64ToSingle;
|
||||||
|
return Inst<U32>(opcode, a, Imm8(static_cast<u8>(fbits)), Imm8(static_cast<u8>(rounding)));
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 IREmitter::FPS64ToSingle(const U64& a, bool round_to_nearest, bool fpcr_controlled) {
|
U64 IREmitter::FPSignedFixedToDouble(const U32U64& a, size_t fbits, FP::RoundingMode rounding) {
|
||||||
ASSERT(fpcr_controlled);
|
ASSERT(fbits <= (a.GetType() == Type::U32 ? 32 : 64));
|
||||||
return Inst<U32>(Opcode::FPS64ToSingle, a, Imm1(round_to_nearest));
|
const Opcode opcode = a.GetType() == Type::U32 ? Opcode::FPFixedS32ToDouble : Opcode::FPFixedS64ToDouble;
|
||||||
|
return Inst<U64>(opcode, a, Imm8(static_cast<u8>(fbits)), Imm8(static_cast<u8>(rounding)));
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 IREmitter::FPU32ToSingle(const U32& a, bool round_to_nearest, bool fpcr_controlled) {
|
U64 IREmitter::FPUnsignedFixedToDouble(const U32U64& a, size_t fbits, FP::RoundingMode rounding) {
|
||||||
ASSERT(fpcr_controlled);
|
ASSERT(fbits <= (a.GetType() == Type::U32 ? 32 : 64));
|
||||||
return Inst<U32>(Opcode::FPU32ToSingle, a, Imm1(round_to_nearest));
|
const Opcode opcode = a.GetType() == Type::U32 ? Opcode::FPFixedU32ToDouble : Opcode::FPFixedU64ToDouble;
|
||||||
}
|
return Inst<U64>(opcode, a, Imm8(static_cast<u8>(fbits)), Imm8(static_cast<u8>(rounding)));
|
||||||
|
|
||||||
U64 IREmitter::FPS32ToDouble(const U32& a, bool round_to_nearest, bool fpcr_controlled) {
|
|
||||||
ASSERT(fpcr_controlled);
|
|
||||||
return Inst<U64>(Opcode::FPS32ToDouble, a, Imm1(round_to_nearest));
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 IREmitter::FPU32ToDouble(const U32& a, bool round_to_nearest, bool fpcr_controlled) {
|
|
||||||
ASSERT(fpcr_controlled);
|
|
||||||
return Inst<U64>(Opcode::FPU32ToDouble, a, Imm1(round_to_nearest));
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 IREmitter::FPU64ToDouble(const U64& a, bool round_to_nearest, bool fpcr_controlled) {
|
|
||||||
ASSERT(fpcr_controlled);
|
|
||||||
return Inst<U64>(Opcode::FPU64ToDouble, a, Imm1(round_to_nearest));
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 IREmitter::FPU64ToSingle(const U64& a, bool round_to_nearest, bool fpcr_controlled) {
|
|
||||||
ASSERT(fpcr_controlled);
|
|
||||||
return Inst<U32>(Opcode::FPU64ToSingle, a, Imm1(round_to_nearest));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
U128 IREmitter::FPVectorAbs(size_t esize, const U128& a) {
|
U128 IREmitter::FPVectorAbs(size_t esize, const U128& a) {
|
||||||
|
|
|
@ -316,14 +316,10 @@ public:
|
||||||
U64 FPToFixedS64(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
U64 FPToFixedS64(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
||||||
U32 FPToFixedU32(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
U32 FPToFixedU32(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
||||||
U64 FPToFixedU64(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
U64 FPToFixedU64(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
||||||
U32 FPS32ToSingle(const U32& a, bool round_to_nearest, bool fpcr_controlled);
|
U32 FPSignedFixedToSingle(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
||||||
U32 FPU32ToSingle(const U32& a, bool round_to_nearest, bool fpcr_controlled);
|
U32 FPUnsignedFixedToSingle(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
||||||
U64 FPS32ToDouble(const U32& a, bool round_to_nearest, bool fpcr_controlled);
|
U64 FPSignedFixedToDouble(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
||||||
U64 FPS64ToDouble(const U64& a, bool round_to_nearest, bool fpcr_controlled);
|
U64 FPUnsignedFixedToDouble(const U32U64& a, size_t fbits, FP::RoundingMode rounding);
|
||||||
U32 FPS64ToSingle(const U64& a, bool round_to_nearest, bool fpcr_controlled);
|
|
||||||
U64 FPU32ToDouble(const U32& a, bool round_to_nearest, bool fpcr_controlled);
|
|
||||||
U64 FPU64ToDouble(const U64& a, bool round_to_nearest, bool fpcr_controlled);
|
|
||||||
U32 FPU64ToSingle(const U64& a, bool round_to_nearest, bool fpcr_controlled);
|
|
||||||
|
|
||||||
U128 FPVectorAbs(size_t esize, const U128& a);
|
U128 FPVectorAbs(size_t esize, const U128& a);
|
||||||
U128 FPVectorAdd(size_t esize, const U128& a, const U128& b);
|
U128 FPVectorAdd(size_t esize, const U128& a, const U128& b);
|
||||||
|
|
|
@ -293,14 +293,14 @@ bool Inst::ReadsFromAndWritesToFPSRCumulativeExceptionBits() const {
|
||||||
case Opcode::FPSingleToFixedS64:
|
case Opcode::FPSingleToFixedS64:
|
||||||
case Opcode::FPSingleToFixedU32:
|
case Opcode::FPSingleToFixedU32:
|
||||||
case Opcode::FPSingleToFixedU64:
|
case Opcode::FPSingleToFixedU64:
|
||||||
case Opcode::FPU32ToSingle:
|
case Opcode::FPFixedU32ToSingle:
|
||||||
case Opcode::FPS32ToSingle:
|
case Opcode::FPFixedS32ToSingle:
|
||||||
case Opcode::FPU32ToDouble:
|
case Opcode::FPFixedU32ToDouble:
|
||||||
case Opcode::FPU64ToDouble:
|
case Opcode::FPFixedU64ToDouble:
|
||||||
case Opcode::FPU64ToSingle:
|
case Opcode::FPFixedU64ToSingle:
|
||||||
case Opcode::FPS32ToDouble:
|
case Opcode::FPFixedS32ToDouble:
|
||||||
case Opcode::FPS64ToDouble:
|
case Opcode::FPFixedS64ToDouble:
|
||||||
case Opcode::FPS64ToSingle:
|
case Opcode::FPFixedS64ToSingle:
|
||||||
case Opcode::FPVectorAdd32:
|
case Opcode::FPVectorAdd32:
|
||||||
case Opcode::FPVectorAdd64:
|
case Opcode::FPVectorAdd64:
|
||||||
case Opcode::FPVectorDiv32:
|
case Opcode::FPVectorDiv32:
|
||||||
|
|
|
@ -504,14 +504,14 @@ OPCODE(FPSingleToFixedS32, U32, U32,
|
||||||
OPCODE(FPSingleToFixedS64, U64, U32, U8, U8 )
|
OPCODE(FPSingleToFixedS64, U64, U32, U8, U8 )
|
||||||
OPCODE(FPSingleToFixedU32, U32, U32, U8, U8 )
|
OPCODE(FPSingleToFixedU32, U32, U32, U8, U8 )
|
||||||
OPCODE(FPSingleToFixedU64, U64, U32, U8, U8 )
|
OPCODE(FPSingleToFixedU64, U64, U32, U8, U8 )
|
||||||
OPCODE(FPU32ToSingle, U32, U32, U1 )
|
OPCODE(FPFixedU32ToSingle, U32, U32, U8, U8 )
|
||||||
OPCODE(FPS32ToSingle, U32, U32, U1 )
|
OPCODE(FPFixedS32ToSingle, U32, U32, U8, U8 )
|
||||||
OPCODE(FPU32ToDouble, U64, U32, U1 )
|
OPCODE(FPFixedU32ToDouble, U64, U32, U8, U8 )
|
||||||
OPCODE(FPU64ToDouble, U64, U64, U1 )
|
OPCODE(FPFixedU64ToDouble, U64, U64, U8, U8 )
|
||||||
OPCODE(FPU64ToSingle, U32, U64, U1 )
|
OPCODE(FPFixedU64ToSingle, U32, U64, U8, U8 )
|
||||||
OPCODE(FPS32ToDouble, U64, U32, U1 )
|
OPCODE(FPFixedS32ToDouble, U64, U32, U8, U8 )
|
||||||
OPCODE(FPS64ToDouble, U64, U64, U1 )
|
OPCODE(FPFixedS64ToDouble, U64, U64, U8, U8 )
|
||||||
OPCODE(FPS64ToSingle, U32, U64, U1 )
|
OPCODE(FPFixedS64ToSingle, U32, U64, U8, U8 )
|
||||||
|
|
||||||
// Floating-point vector instructions
|
// Floating-point vector instructions
|
||||||
OPCODE(FPVectorAbs16, U128, U128 )
|
OPCODE(FPVectorAbs16, U128, U128 )
|
||||||
|
|
Loading…
Reference in a new issue