mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 18:49:51 +01:00
Merge pull request #18047 from unknownbrackets/x86-jit-round
x86jit: Implement float to integer
This commit is contained in:
6 files changed
+142
-17
No files matched your search
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user