Merge pull request #18047 from unknownbrackets/x86-jit-round

x86jit: Implement float to integer
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2023-09-02 11:43:08 +02:00
commit cec67bb30d
6 files changed
+142 -17

No files matched your search

+5 -5
View File
@@ -1196,20 +1196,20 @@ namespace MIPSComp {
ir.Write(IROp::FCvtScaledWS, dregs[i], sregs[i], imm | (rmode << 6));
} else {
for (int i = 0; i < n; i++) {
switch (rmode) {
case 0: // vf2in
switch (IRRoundMode(rmode)) {
case IRRoundMode::RINT_0: // vf2in
ir.Write(IROp::FRound, dregs[i], sregs[i]);
break;
case 1: // vf2iz
case IRRoundMode::CAST_1: // vf2iz
ir.Write(IROp::FTrunc, dregs[i], sregs[i]);
break;
case 2: // vf2iu
case IRRoundMode::CEIL_2: // vf2iu
ir.Write(IROp::FCeil, dregs[i], sregs[i]);
break;
case 3: // vf2id
case IRRoundMode::FLOOR_3: // vf2id
ir.Write(IROp::FFloor, dregs[i], sregs[i]);
break;
+7
View File
@@ -252,6 +252,13 @@ enum class Vec4Init {
Set_0001,
};
enum class IRRoundMode : uint8_t {
RINT_0 = 0,
CAST_1 = 1,
CEIL_2 = 2,
FLOOR_3 = 3,
};
// Hm, unused
inline IRComparison Invert(IRComparison comp) {
switch (comp) {
+10 -10
View File
@@ -966,11 +966,11 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
mips->fs[inst->dest] = my_isinf(src) && src < 0.0f ? -2147483648LL : 2147483647LL;
break;
}
switch (mips->fcr31 & 3) {
case 0: mips->fs[inst->dest] = (int)round_ieee_754(src); break; // RINT_0
case 1: mips->fs[inst->dest] = (int)src; break; // CAST_1
case 2: mips->fs[inst->dest] = (int)ceilf(src); break; // CEIL_2
case 3: mips->fs[inst->dest] = (int)floorf(src); break; // FLOOR_3
switch (IRRoundMode(mips->fcr31 & 3)) {
case IRRoundMode::RINT_0: mips->fs[inst->dest] = (int)round_ieee_754(src); break;
case IRRoundMode::CAST_1: mips->fs[inst->dest] = (int)src; break;
case IRRoundMode::CEIL_2: mips->fs[inst->dest] = (int)ceilf(src); break;
case IRRoundMode::FLOOR_3: mips->fs[inst->dest] = (int)floorf(src); break;
}
break; //cvt.w.s
}
@@ -994,11 +994,11 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
} else if (sv <= (double)(int)0x80000000) {
mips->fs[inst->dest] = 0x80000000;
} else {
switch (inst->src2 >> 6) {
case 0: mips->fs[inst->dest] = (int)round_ieee_754(sv); break;
case 1: mips->fs[inst->dest] = src >= 0 ? (int)floor(sv) : (int)ceil(sv); break;
case 2: mips->fs[inst->dest] = (int)ceil(sv); break;
case 3: mips->fs[inst->dest] = (int)floor(sv); break;
switch (IRRoundMode(inst->src2 >> 6)) {
case IRRoundMode::RINT_0: mips->fs[inst->dest] = (int)round_ieee_754(sv); break;
case IRRoundMode::CAST_1: mips->fs[inst->dest] = src >= 0 ? (int)floor(sv) : (int)ceil(sv); break;
case IRRoundMode::CEIL_2: mips->fs[inst->dest] = (int)ceil(sv); break;
case IRRoundMode::FLOOR_3: mips->fs[inst->dest] = (int)floor(sv); break;
}
}
break;
+116 -2
View File
@@ -56,6 +56,21 @@ void X64JitBackend::EmitFPUConstants() {
Write32(val);
}
constants.mulTableVf2i = (const double *)GetCodePointer();
for (uint8_t i = 0; i < 32; ++i) {
double fval = (1UL << i);
uint64_t val;
memcpy(&val, &fval, sizeof(val));
Write64(val);
}
// Note: this first one is (double)(int)0x80000000, sign extended.
constants.minIntAsDouble = (const double *)GetCodePointer();
Write64(0xC1E0000000000000ULL);
constants.maxIntAsDouble = (const double *)GetCodePointer();
Write64(0x41DFFFFFFFC00000ULL);
}
void X64JitBackend::CompIR_FArith(IRInst inst) {
@@ -533,8 +548,18 @@ void X64JitBackend::CompIR_FCvt(IRInst inst) {
switch (inst.op) {
case IROp::FCvtWS:
CompIR_Generic(inst);
{
regs_.Map(inst);
UCOMISS(regs_.FX(inst.src1), M(constants.positiveInfinity)); // rip accessible
CVTPS2DQ(regs_.FX(inst.dest), regs_.F(inst.src1));
// UCOMISS set ZF if EQUAL (to infinity) or UNORDERED.
FixupBranch skip = J_CC(CC_NZ);
MOVAPS(regs_.FX(inst.dest), M(constants.noSignMask)); // rip accessible
SetJumpTarget(skip);
break;
}
case IROp::FCvtSW:
regs_.Map(inst);
@@ -542,7 +567,96 @@ void X64JitBackend::CompIR_FCvt(IRInst inst) {
break;
case IROp::FCvtScaledWS:
CompIR_Generic(inst);
regs_.Map(inst);
if (cpu_info.bSSE4_1) {
int scale = inst.src2 & 0x1F;
int rmode = inst.src2 >> 6;
CVTSS2SD(regs_.FX(inst.dest), regs_.F(inst.src1));
if (scale != 0)
MULSD(regs_.FX(inst.dest), M(&constants.mulTableVf2i[scale])); // rip accessible
// On NAN, we want maxInt anyway, so let's let it be the second param.
MAXSD(regs_.FX(inst.dest), M(constants.minIntAsDouble)); // rip accessible
MINSD(regs_.FX(inst.dest), M(constants.maxIntAsDouble)); // rip accessible
switch (rmode) {
case 0:
ROUNDNEARPD(regs_.FX(inst.dest), regs_.F(inst.dest));
CVTPD2DQ(regs_.FX(inst.dest), regs_.F(inst.dest));
break;
case 1:
CVTTPD2DQ(regs_.FX(inst.dest), regs_.F(inst.dest));
break;
case 2:
ROUNDCEILPD(regs_.FX(inst.dest), regs_.F(inst.dest));
CVTPD2DQ(regs_.FX(inst.dest), regs_.F(inst.dest));
break;
case 3:
ROUNDFLOORPD(regs_.FX(inst.dest), regs_.F(inst.dest));
CVTPD2DQ(regs_.FX(inst.dest), regs_.F(inst.dest));
break;
}
} else {
int scale = inst.src2 & 0x1F;
int rmode = inst.src2 >> 6;
int setMXCSR = -1;
bool useTrunc = false;
switch (rmode) {
case 0:
// TODO: Could skip if hasSetRounding, but we don't have the flag.
setMXCSR = 0;
break;
case 1:
useTrunc = true;
break;
case 2:
setMXCSR = 2;
break;
case 3:
setMXCSR = 1;
break;
}
// Except for truncate, we need to update MXCSR to our preferred rounding mode.
// TODO: Might be possible to cache this and update between instructions?
// Probably kinda expensive to switch each time...
if (setMXCSR != -1) {
STMXCSR(MDisp(CTXREG, mxcsrTempOffset));
MOV(32, R(SCRATCH1), MDisp(CTXREG, mxcsrTempOffset));
AND(32, R(SCRATCH1), Imm32(~(3 << 13)));
if (setMXCSR != 0) {
OR(32, R(SCRATCH1), Imm32(setMXCSR << 13));
}
MOV(32, MDisp(CTXREG, tempOffset), R(SCRATCH1));
LDMXCSR(MDisp(CTXREG, tempOffset));
}
CVTSS2SD(regs_.FX(inst.dest), regs_.F(inst.src1));
if (scale != 0)
MULSD(regs_.FX(inst.dest), M(&constants.mulTableVf2i[scale]));
// On NAN, we want maxInt anyway, so let's let it be the second param.
MAXSD(regs_.FX(inst.dest), M(constants.minIntAsDouble));
MINSD(regs_.FX(inst.dest), M(constants.maxIntAsDouble));
if (useTrunc) {
CVTTSD2SI(SCRATCH1, regs_.F(inst.dest));
} else {
CVTSD2SI(SCRATCH1, regs_.F(inst.dest));
}
MOVD_xmm(regs_.FX(inst.dest), R(SCRATCH1));
// Return MXCSR to its previous value.
if (setMXCSR != -1) {
LDMXCSR(MDisp(CTXREG, mxcsrTempOffset));
}
}
break;
case IROp::FCvtScaledSW:
+3
View File
@@ -148,6 +148,9 @@ private:
const void *negativeOnes;
const void *qNAN;
const float *mulTableVi2f;
const double *mulTableVf2i;
const double *minIntAsDouble;
const double *maxIntAsDouble;
const Float4Constant *vec4InitValues;
};
Constants constants;
+1
View File
@@ -42,6 +42,7 @@ static constexpr auto downcountOffset = offsetof(MIPSState, downcount) - 128;
static constexpr auto tempOffset = offsetof(MIPSState, temp) - 128;
static constexpr auto fcr31Offset = offsetof(MIPSState, fcr31) - 128;
static constexpr auto pcOffset = offsetof(MIPSState, pc) - 128;
static constexpr auto mxcsrTempOffset = offsetof(MIPSState, mxcsrTemp) - 128;
enum class X64Map : uint8_t {
NONE = 0,