diff --git a/Common/x64Emitter.h b/Common/x64Emitter.h index ccff753935..cc8a5bac31 100644 --- a/Common/x64Emitter.h +++ b/Common/x64Emitter.h @@ -126,7 +126,6 @@ enum class XEmitter; -// RIP addressing does not benefit from micro op fusion on Core arch struct OpArg { OpArg() {} // dummy op arg, used for storage diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 98675a0f2e..77973d8f45 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -250,6 +250,8 @@ namespace MIPSComp { case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); { + // TODO: Fastpath like FPULS. + // CC might be set by slow path below, so load regs first. fpr.MapRegV(vt, MAP_DIRTY | MAP_NOINIT); if (gpr.IsImm(rs)) { @@ -1837,4 +1839,50 @@ namespace MIPSComp fpr.ReleaseSpillLocksAndDiscardTemps(); } + + void Jit::Comp_Vocp(MIPSOpcode op) { + CONDITIONAL_DISABLE; + if (js.HasUnknownPrefix() || disablePrefixes) { + DISABLE; + } + + VectorSize sz = GetVecSize(op); + int n = GetNumVectorElements(sz); + + u8 sregs[4], dregs[4]; + // Actually, not sure that this instruction accepts an S prefix. We don't apply it in the + // interpreter. But whatever. + GetVectorRegsPrefixS(sregs, sz, _VS); + GetVectorRegsPrefixD(dregs, sz, _VD); + + MIPSReg tempregs[4]; + for (int i = 0; i < n; ++i) { + if (!IsOverlapSafe(dregs[i], i, n, sregs)) { + tempregs[i] = fpr.GetTempV(); + } else { + tempregs[i] = dregs[i]; + } + } + + MOVI2F(S0, 1.0f, R0); + for (int i = 0; i < n; ++i) { + fpr.MapDirtyInV(tempregs[i], sregs[i]); + // Let's do it integer registers for now. NEON later. + // There's gotta be a shorter way, can't find one though that takes + // care of NaNs like the interpreter (ignores them and just operates on the bits). + VSUB(fpr.V(tempregs[i]), S0, fpr.V(sregs[i])); + } + + for (int i = 0; i < n; ++i) { + if (dregs[i] != tempregs[i]) { + fpr.MapDirtyInV(dregs[i], tempregs[i]); + VMOV(fpr.V(dregs[i]), fpr.V(tempregs[i])); + } + } + + ApplyPrefixD(dregs, sz); + + fpr.ReleaseSpillLocksAndDiscardTemps(); + } + } diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index b5954e736e..b6a60ec6b9 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -132,6 +132,7 @@ public: void Comp_Vfim(MIPSOpcode op); void Comp_VCrossQuat(MIPSOpcode op); void Comp_Vsgn(MIPSOpcode op); + void Comp_Vocp(MIPSOpcode op); JitBlockCache *GetBlockCache() { return &blocks; } diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index b8c437e3bf..5ea0697ec9 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -737,7 +737,7 @@ const MIPSInstruction tableVFPU9[32] = // 110100 00010 xxxxx . ....... . ....... INSTR("vbfy1", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vbfy2", &Jit::Comp_Generic, Dis_Vbfy, Int_Vbfy, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), //4 - INSTR("vocp", &Jit::Comp_Generic, Dis_Vbfy, Int_Vocp, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), // one's complement + INSTR("vocp", &Jit::Comp_Vocp, Dis_Vbfy, Int_Vocp, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), // one's complement INSTR("vsocp", &Jit::Comp_Generic, Dis_Vbfy, Int_Vsocp, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vfad", &Jit::Comp_Vhoriz, Dis_Vfad, Int_Vfad, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), // TODO: Flags may not be correct (prefixes, etc.) diff --git a/Core/MIPS/PPC/PpcCompVFPU.cpp b/Core/MIPS/PPC/PpcCompVFPU.cpp index cfde013261..80cdd53926 100644 --- a/Core/MIPS/PPC/PpcCompVFPU.cpp +++ b/Core/MIPS/PPC/PpcCompVFPU.cpp @@ -1117,4 +1117,8 @@ namespace MIPSComp void Jit::Comp_Vsgn(MIPSOpcode op) { DISABLE; } -} \ No newline at end of file + void Jit::Comp_Vocp(MIPSOpcode op) { + DISABLE; + } +} + diff --git a/Core/MIPS/PPC/PpcJit.h b/Core/MIPS/PPC/PpcJit.h index aef427332b..8838548c00 100644 --- a/Core/MIPS/PPC/PpcJit.h +++ b/Core/MIPS/PPC/PpcJit.h @@ -237,6 +237,7 @@ namespace MIPSComp void Comp_Vfim(MIPSOpcode op); void Comp_VCrossQuat(MIPSOpcode op); void Comp_Vsgn(MIPSOpcode op); + void Comp_Vocp(MIPSOpcode op); // Utility compilation functions diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 8c40da0bee..d6a504309b 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -1178,7 +1178,7 @@ void Jit::Comp_Vh2f(MIPSOpcode op) { X64Reg tempR = fpr.GetFreeXReg(); MOVSS(XMM0, fpr.V(sregs[0])); - if (sz != V_Single) { + if (sz != V_Single) { MOVSS(XMM1, fpr.V(sregs[1])); PUNPCKLDQ(XMM0, R(XMM1)); } @@ -1452,6 +1452,55 @@ void Jit::Comp_Vsgn(MIPSOpcode op) { fpr.ReleaseSpillLocks(); } +void Jit::Comp_Vocp(MIPSOpcode op) { + CONDITIONAL_DISABLE; + + if (js.HasUnknownPrefix()) + DISABLE; + + VectorSize sz = GetVecSize(op); + int n = GetNumVectorElements(sz); + + u8 sregs[4], dregs[4]; + GetVectorRegsPrefixS(sregs, sz, _VS); + GetVectorRegsPrefixD(dregs, sz, _VD); + + X64Reg tempxregs[4]; + for (int i = 0; i < n; ++i) + { + if (!IsOverlapSafeAllowS(dregs[i], i, n, sregs)) + { + int reg = fpr.GetTempV(); + fpr.MapRegV(reg, MAP_NOINIT | MAP_DIRTY); + fpr.SpillLockV(reg); + tempxregs[i] = fpr.VX(reg); + } + else + { + fpr.MapRegV(dregs[i], (dregs[i] == sregs[i] ? 0 : MAP_NOINIT) | MAP_DIRTY); + fpr.SpillLockV(dregs[i]); + tempxregs[i] = fpr.VX(dregs[i]); + } + } + + MOVSS(XMM1, M((void *)&one)); + for (int i = 0; i < n; ++i) + { + MOVSS(XMM0, R(XMM1)); + SUBSS(XMM0, fpr.V(sregs[i])); + MOVSS(tempxregs[i], R(XMM0)); + } + + for (int i = 0; i < n; ++i) { + if (!fpr.V(dregs[i]).IsSimpleReg(tempxregs[i])) + MOVSS(fpr.V(dregs[i]), tempxregs[i]); + } + + ApplyPrefixD(dregs, sz); + + fpr.ReleaseSpillLocks(); +} + void Jit::Comp_VV2Op(MIPSOpcode op) { CONDITIONAL_DISABLE; @@ -2101,5 +2150,4 @@ void Jit::Comp_VRot(MIPSOpcode op) { fpr.ReleaseSpillLocks(); } - } diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index db16633812..d11a261abd 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -136,6 +136,7 @@ public: void Comp_Vfim(MIPSOpcode op); void Comp_VCrossQuat(MIPSOpcode op); void Comp_Vsgn(MIPSOpcode op); + void Comp_Vocp(MIPSOpcode op); void Comp_DoNothing(MIPSOpcode op);