diff --git a/Core/MIPS/x86/X64IRCompSystem.cpp b/Core/MIPS/x86/X64IRCompSystem.cpp index 7e1061f494..a98edb27a6 100644 --- a/Core/MIPS/x86/X64IRCompSystem.cpp +++ b/Core/MIPS/x86/X64IRCompSystem.cpp @@ -55,6 +55,15 @@ void X64JitBackend::CompIR_Basic(IRInst inst) { break; case IROp::SetConstF: + regs_.Map(inst); + if (inst.constant == 0) { + XORPS(regs_.FX(inst.dest), regs_.F(inst.dest)); + } else { + MOV(32, R(SCRATCH1), Imm32(inst.constant)); + MOVD_xmm(regs_.FX(inst.dest), R(SCRATCH1)); + } + break; + case IROp::SetPC: case IROp::SetPCConst: CompIR_Generic(inst); @@ -109,11 +118,24 @@ void X64JitBackend::CompIR_Transfer(IRInst inst) { case IROp::FpCtrlFromReg: case IROp::FpCtrlToReg: case IROp::VfpuCtrlToReg: - case IROp::FMovFromGPR: - case IROp::FMovToGPR: CompIR_Generic(inst); break; + case IROp::FMovFromGPR: + if (regs_.IsGPRImm(inst.src1) && regs_.GetGPRImm(inst.src1) == 0) { + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); + XORPS(regs_.FX(inst.dest), regs_.F(inst.dest)); + } else { + regs_.Map(inst); + MOVD_xmm(regs_.FX(inst.dest), regs_.R(inst.src1)); + } + break; + + case IROp::FMovToGPR: + regs_.Map(inst); + MOVD_xmm(regs_.R(inst.dest), regs_.FX(inst.src1)); + break; + default: INVALIDOP; break; diff --git a/Core/MIPS/x86/X64IRCompVec.cpp b/Core/MIPS/x86/X64IRCompVec.cpp index cc7af5025f..9c9370c8f5 100644 --- a/Core/MIPS/x86/X64IRCompVec.cpp +++ b/Core/MIPS/x86/X64IRCompVec.cpp @@ -19,6 +19,7 @@ #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) #include +#include "Common/CPUDetect.h" #include "Core/MemMap.h" #include "Core/MIPS/x86/X64IRJit.h" #include "Core/MIPS/x86/X64IRRegCache.h" @@ -38,15 +39,109 @@ namespace MIPSComp { using namespace Gen; using namespace X64IRJitConstants; +alignas(16) static const float vec4InitValues[8][4] = { + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, + { -1.0f, -1.0f, -1.0f, -1.0f }, + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f }, +}; + +static bool Overlap(IRReg r1, int l1, IRReg r2, int l2) { + return r1 < r2 + l2 && r1 + l1 > r2; +} + void X64JitBackend::CompIR_VecArith(IRInst inst) { CONDITIONAL_DISABLE; switch (inst.op) { case IROp::Vec4Add: + regs_.Map(inst); + if (inst.dest == inst.src1) { + ADDPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } else if (inst.dest == inst.src2) { + ADDPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + } else if (cpu_info.bAVX) { + VADDPS(128, regs_.FX(inst.dest), regs_.FX(inst.src1), regs_.F(inst.src2)); + } else { + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + ADDPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } + break; + case IROp::Vec4Sub: + if (inst.dest == inst.src1) { + regs_.Map(inst); + SUBPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } else if (cpu_info.bAVX) { + regs_.Map(inst); + VSUBPS(128, regs_.FX(inst.dest), regs_.FX(inst.src1), regs_.F(inst.src2)); + } else if (inst.dest == inst.src2) { + X64Reg tempReg = regs_.MapWithFPRTemp(inst); + MOVAPS(tempReg, regs_.F(inst.src2)); + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + SUBPS(regs_.FX(inst.dest), R(tempReg)); + } else { + regs_.Map(inst); + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + SUBPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } + break; + case IROp::Vec4Mul: + regs_.Map(inst); + if (inst.dest == inst.src1) { + MULPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } else if (inst.dest == inst.src2) { + MULPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + } else if (cpu_info.bAVX) { + VMULPS(128, regs_.FX(inst.dest), regs_.FX(inst.src1), regs_.F(inst.src2)); + } else { + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + MULPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } + break; + case IROp::Vec4Div: + if (inst.dest == inst.src1) { + regs_.Map(inst); + DIVPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } else if (cpu_info.bAVX) { + regs_.Map(inst); + VDIVPS(128, regs_.FX(inst.dest), regs_.FX(inst.src1), regs_.F(inst.src2)); + } else if (inst.dest == inst.src2) { + X64Reg tempReg = regs_.MapWithFPRTemp(inst); + MOVAPS(tempReg, regs_.F(inst.src2)); + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + DIVPS(regs_.FX(inst.dest), R(tempReg)); + } else { + regs_.Map(inst); + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + DIVPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } + break; + case IROp::Vec4Scale: + // TODO: Handle "aliasing" of sizes. + if (Overlap(inst.dest, 4, inst.src2, 1) || Overlap(inst.src1, 4, inst.src2, 1)) + DISABLE; + + regs_.Map(inst); + SHUFPS(regs_.FX(inst.src2), regs_.F(inst.src2), 0); + if (inst.dest == inst.src1) { + MULPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } else if (inst.dest == inst.src2) { + MULPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + } else if (cpu_info.bAVX) { + VMULPS(128, regs_.FX(inst.dest), regs_.FX(inst.src1), regs_.F(inst.src2)); + } else { + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + MULPS(regs_.FX(inst.dest), regs_.F(inst.src2)); + } + break; + case IROp::Vec4Neg: case IROp::Vec4Abs: CompIR_Generic(inst); @@ -63,11 +158,41 @@ void X64JitBackend::CompIR_VecAssign(IRInst inst) { switch (inst.op) { case IROp::Vec4Init: + regs_.Map(inst); + if (inst.src1 == (int)Vec4Init::AllZERO) { + XORPS(regs_.FX(inst.dest), regs_.F(inst.dest)); + } else if (RipAccessible(&vec4InitValues[inst.src1])) { + MOVAPS(regs_.FX(inst.dest), M(&vec4InitValues[inst.src1])); // rip accessible + } else { + MOV(PTRBITS, R(SCRATCH1), ImmPtr(&vec4InitValues[inst.src1])); + MOVAPS(regs_.FX(inst.dest), MatR(SCRATCH1)); + } + break; + case IROp::Vec4Shuffle: - case IROp::Vec4Blend: CompIR_Generic(inst); break; + case IROp::Vec4Blend: + if (cpu_info.bAVX) { + regs_.Map(inst); + VBLENDPS(128, regs_.FX(inst.dest), regs_.FX(inst.src1), regs_.F(inst.src2), (uint8_t)inst.constant); + } else if (cpu_info.bSSE4_1) { + regs_.Map(inst); + if (inst.dest == inst.src1) { + BLENDPS(regs_.FX(inst.dest), regs_.F(inst.src2), (uint8_t)inst.constant); + } else if (inst.dest == inst.src2) { + BLENDPS(regs_.FX(inst.dest), regs_.F(inst.src1), (uint8_t)~inst.constant); + } else { + MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1)); + BLENDPS(regs_.FX(inst.dest), regs_.F(inst.src2), (uint8_t)inst.constant); + } + } else { + // Could use some shuffles... + DISABLE; + } + break; + case IROp::Vec4Mov: regs_.Map(inst); MOVAPS(regs_.FX(inst.dest), regs_.F(inst.src1));