irjit: Implement vf2ix.

Used in LittleBigPlanet when playing intro movies.
This commit is contained in:
Unknown W. Brackets 2023-07-29 11:57:30 -07:00
parent b473f1e649
commit a5a2671af3
7 changed files with 81 additions and 5 deletions

View file

@ -986,7 +986,55 @@ namespace MIPSComp {
// d[N] = int(S[N] * mult)
// Note: saturates on overflow.
DISABLE;
VectorSize sz = GetVecSize(op);
int n = GetNumVectorElements(sz);
int imm = (op >> 16) & 0x1f;
u8 sregs[4], dregs[4];
GetVectorRegsPrefixS(sregs, sz, _VS);
GetVectorRegsPrefixD(dregs, sz, _VD);
// Same values as FCR31.
uint8_t rmode = (op >> 21) & 3;
if (((op >> 21) & 0x1C) != 0x10)
INVALIDOP;
u8 tempregs[4];
for (int i = 0; i < n; ++i) {
if (!IsOverlapSafe(dregs[i], n, sregs)) {
tempregs[i] = IRVTEMP_PFX_T + i; // Need IRVTEMP_0 for the scaling factor
} else {
tempregs[i] = dregs[i];
}
}
if (imm != 0) {
for (int i = 0; i < n; i++)
ir.Write(IROp::FCvtScaledWS, dregs[i], sregs[i], (uint8_t)(imm | (rmode << 6)));
} else {
for (int i = 0; i < n; i++) {
switch (rmode) {
case 0: // vf2in
ir.Write(IROp::FRound, dregs[i], sregs[i]);
break;
case 1: // vf2iz
ir.Write(IROp::FTrunc, dregs[i], sregs[i]);
break;
case 2: // vf2iu
ir.Write(IROp::FCeil, dregs[i], sregs[i]);
break;
case 3: // vf2id
ir.Write(IROp::FFloor, dregs[i], sregs[i]);
break;
default:
INVALIDOP;
}
}
}
}
void IRFrontend::Comp_Mftv(MIPSOpcode op) {

View file

@ -105,6 +105,7 @@ static const IRMeta irMeta[] = {
{ IROp::FFloor, "FFloor", "FF" },
{ IROp::FCvtWS, "FCvtWS", "FF" },
{ IROp::FCvtSW, "FCvtSW", "FF" },
{ IROp::FCvtScaledWS, "FCvtScaledWS", "FFI" },
{ IROp::FCmp, "FCmp", "mFF" },
{ IROp::FSat0_1, "FSat(0 - 1)", "FF" },
{ IROp::FSatMinus1_1, "FSat(-1 - 1)", "FF" },

View file

@ -127,6 +127,7 @@ enum class IROp : u8 {
FCvtWS,
FCvtSW,
FCvtScaledWS,
FMovFromGPR,
FMovToGPR,
@ -304,9 +305,6 @@ enum : IRReg {
IRVTEMP_PFX_D = 232 - 32,
IRVTEMP_0 = 236 - 32,
// 16 float temps for vector S and T prefixes and things like that.
// IRVTEMP_0 = 208 - 64, // -64 to be relative to v[0]
// Hacky way to get to other state
IRREG_VFPU_CTRL_BASE = 208,
IRREG_VFPU_CC = 211,

View file

@ -834,7 +834,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
mips->fi[inst->dest] = my_isinf(value) && value < 0.0f ? -2147483648LL : 2147483647LL;
break;
} else {
mips->fs[inst->dest] = (int)floorf(value + 0.5f);
mips->fs[inst->dest] = (int)round_ieee_754(value);
}
break;
}
@ -931,6 +931,32 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
}
break; //cvt.w.s
}
case IROp::FCvtScaledWS:
{
float src = mips->f[inst->src1];
if (my_isnan(src)) {
// TODO: True for negatives too?
mips->fs[inst->dest] = 2147483647L;
break;
}
float mult = (float)(1UL << (inst->src2 & 0x1F));
double sv = src * mult; // (float)0x7fffffff == (float)0x80000000
// Cap/floor it to 0x7fffffff / 0x80000000
if (sv > (double)0x7fffffff) {
mips->fs[inst->dest] = 0x7fffffff;
} 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;
}
}
break;
}
case IROp::ZeroFpCond:
mips->fpcond = 0;

View file

@ -667,6 +667,7 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts
case IROp::FCeil:
case IROp::FFloor:
case IROp::FCvtSW:
case IROp::FCvtScaledWS:
case IROp::FSin:
case IROp::FCos:
case IROp::FSqrt:

View file

@ -190,6 +190,7 @@ void RiscVJit::CompIR_FCvt(IRInst inst) {
switch (inst.op) {
case IROp::FCvtWS:
case IROp::FCvtScaledWS:
case IROp::FCvtSW:
CompIR_Generic(inst);
break;

View file

@ -265,6 +265,7 @@ void RiscVJit::CompileIRInst(IRInst inst) {
case IROp::FCvtWS:
case IROp::FCvtSW:
case IROp::FCvtScaledWS:
CompIR_FCvt(inst);
break;