void Jit64::ps_sign(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); int d = inst.FD; int b = inst.FB; fpr.Lock(d, b); if (d != b) { fpr.BindToRegister(d, false); MOVAPD(fpr.RX(d), fpr.R(b)); } else { fpr.BindToRegister(d, true); } switch (inst.SUBOP10) { case 40: //neg PXOR(fpr.RX(d), M((void*)&psSignBits)); break; case 136: //nabs POR(fpr.RX(d), M((void*)&psSignBits)); break; case 264: //abs PAND(fpr.RX(d), M((void*)&psAbsMask)); break; } fpr.UnlockAll(); }
void Jit64::ps_sel(UGeckoInstruction inst) { // we can't use (V)BLENDVPD here because it just looks at the sign bit // but we need -0 = +0 INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); int d = inst.FD; int a = inst.FA; int b = inst.FB; int c = inst.FC; fpr.Lock(a, b, c, d); MOVAPD(XMM0, fpr.R(a)); PXOR(XMM1, R(XMM1)); // XMM0 = XMM0 < 0 ? all 1s : all 0s CMPPD(XMM0, R(XMM1), LT); MOVAPD(XMM1, R(XMM0)); PAND(XMM0, fpr.R(b)); PANDN(XMM1, fpr.R(c)); POR(XMM0, R(XMM1)); fpr.BindToRegister(d, false); MOVAPD(fpr.RX(d), R(XMM0)); fpr.UnlockAll(); }
void Jit64::fsign(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); int d = inst.FD; int b = inst.FB; fpr.Lock(b, d); fpr.BindToRegister(d, true, true); MOVSD(XMM0, fpr.R(b)); switch (inst.SUBOP10) { case 40: // fnegx PXOR(XMM0, M((void*)&psSignBits2)); break; case 264: // fabsx PAND(XMM0, M((void*)&psAbsMask2)); break; case 136: // fnabs POR(XMM0, M((void*)&psSignBits2)); break; default: PanicAlert("fsign bleh"); break; } MOVSD(fpr.R(d), XMM0); fpr.UnlockAll(); }
bool SamplerJitCache::Jit_Decode4444() { MOVD_xmm(fpScratchReg1, R(resultReg)); PUNPCKLBW(fpScratchReg1, R(fpScratchReg1)); if (RipAccessible(color4444mask)) { PAND(fpScratchReg1, M(color4444mask)); // rip accessible } else { Crash(); } MOVSS(fpScratchReg2, R(fpScratchReg1)); MOVSS(fpScratchReg3, R(fpScratchReg1)); PSRLW(fpScratchReg2, 4); PSLLW(fpScratchReg3, 4); POR(fpScratchReg1, R(fpScratchReg2)); POR(fpScratchReg1, R(fpScratchReg3)); MOVD_xmm(R(resultReg), fpScratchReg1); return true; }
void Jit::Comp_FPU2op(MIPSOpcode op) { CONDITIONAL_DISABLE; int fs = _FS; int fd = _FD; switch (op & 0x3f) { case 5: //F(fd) = fabsf(F(fs)); break; //abs fpr.SpillLock(fd, fs); fpr.MapReg(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); PAND(fpr.RX(fd), M(ssNoSignMask)); break; case 6: //F(fd) = F(fs); break; //mov if (fd != fs) { fpr.SpillLock(fd, fs); fpr.MapReg(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); } break; case 7: //F(fd) = -F(fs); break; //neg fpr.SpillLock(fd, fs); fpr.MapReg(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); PXOR(fpr.RX(fd), M(ssSignBits2)); break; case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt fpr.SpillLock(fd, fs); // this probably works, just badly tested fpr.MapReg(fd, fd == fs, true); SQRTSS(fpr.RX(fd), fpr.R(fs)); break; case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s { fpr.SpillLock(fs, fd); fpr.StoreFromRegister(fd); CVTTSS2SI(EAX, fpr.R(fs)); // Did we get an indefinite integer value? CMP(32, R(EAX), Imm32(0x80000000)); FixupBranch skip = J_CC(CC_NE); MOVSS(XMM0, fpr.R(fs)); XORPS(XMM1, R(XMM1)); CMPSS(XMM0, R(XMM1), CMP_LT); // At this point, -inf = 0xffffffff, inf/nan = 0x00000000. // We want -inf to be 0x80000000 inf/nan to be 0x7fffffff, so we flip those bits. MOVD_xmm(R(EAX), XMM0); XOR(32, R(EAX), Imm32(0x7fffffff)); SetJumpTarget(skip); MOV(32, fpr.R(fd), R(EAX)); } break; case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w // Store to memory so we can read it as an integer value. fpr.StoreFromRegister(fs); CVTSI2SS(XMM0, fpr.R(fs)); MOVSS(fpr.R(fd), XMM0); break; case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s default: DISABLE; return; } fpr.ReleaseSpillLocks(); }
void Jit::Comp_FPU2op(u32 op) { CONDITIONAL_DISABLE; int fs = _FS; int fd = _FD; switch (op & 0x3f) { case 5: //F(fd) = fabsf(F(fs)); break; //abs fpr.Lock(fd, fs); fpr.BindToRegister(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); PAND(fpr.RX(fd), M((void *)ssNoSignMask)); fpr.UnlockAll(); break; case 6: //F(fd) = F(fs); break; //mov if (fd != fs) { fpr.Lock(fd, fs); fpr.BindToRegister(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); fpr.UnlockAll(); } break; case 7: //F(fd) = -F(fs); break; //neg fpr.Lock(fd, fs); fpr.BindToRegister(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); PXOR(fpr.RX(fd), M((void *)ssSignBits2)); fpr.UnlockAll(); break; case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt /* fpr.Lock(fd, fs); // this probably works, just badly tested fpr.BindToRegister(fd, fd == fs, true); SQRTSS(fpr.RX(fd), fpr.R(fs)); fpr.UnlockAll(); break;*/ Comp_Generic(op); return; case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s fpr.Lock(fs, fd); fpr.StoreFromRegister(fd); CVTTSS2SI(EAX, fpr.R(fs)); MOV(32, fpr.R(fd), R(EAX)); fpr.UnlockAll(); break; case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s default: Comp_Generic(op); return; } }
void Jit::Comp_FPU2op(MIPSOpcode op) { CONDITIONAL_DISABLE; int fs = _FS; int fd = _FD; auto execRounding = [&](void (XEmitter::*conv)(X64Reg, OpArg), int setMXCSR) { fpr.SpillLock(fs); // Small optimization: 0 is our default mode anyway. if (setMXCSR == 0 && !js.hasSetRounding) { setMXCSR = -1; } if (setMXCSR != -1) { STMXCSR(M(&mxcsrTemp)); MOV(32, R(TEMPREG), M(&mxcsrTemp)); AND(32, R(TEMPREG), Imm32(~(3 << 13))); OR(32, R(TEMPREG), Imm32(setMXCSR << 13)); MOV(32, M(&mips_->temp), R(TEMPREG)); LDMXCSR(M(&mips_->temp)); } (this->*conv)(TEMPREG, fpr.R(fs)); // Did we get an indefinite integer value? CMP(32, R(TEMPREG), Imm32(0x80000000)); FixupBranch skip = J_CC(CC_NE); MOVSS(XMM0, fpr.R(fs)); XORPS(XMM1, R(XMM1)); CMPSS(XMM0, R(XMM1), CMP_LT); // At this point, -inf = 0xffffffff, inf/nan = 0x00000000. // We want -inf to be 0x80000000 inf/nan to be 0x7fffffff, so we flip those bits. MOVD_xmm(R(TEMPREG), XMM0); XOR(32, R(TEMPREG), Imm32(0x7fffffff)); SetJumpTarget(skip); fpr.DiscardR(fd); MOV(32, fpr.R(fd), R(TEMPREG)); if (setMXCSR != -1) { LDMXCSR(M(&mxcsrTemp)); } }; switch (op & 0x3f) { case 5: //F(fd) = fabsf(F(fs)); break; //abs fpr.SpillLock(fd, fs); fpr.MapReg(fd, fd == fs, true); if (fd != fs) { MOVSS(fpr.RX(fd), fpr.R(fs)); } PAND(fpr.RX(fd), M(ssNoSignMask)); break; case 6: //F(fd) = F(fs); break; //mov if (fd != fs) { fpr.SpillLock(fd, fs); fpr.MapReg(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); } break; case 7: //F(fd) = -F(fs); break; //neg fpr.SpillLock(fd, fs); fpr.MapReg(fd, fd == fs, true); if (fd != fs) { MOVSS(fpr.RX(fd), fpr.R(fs)); } XORPS(fpr.RX(fd), M(ssSignBits2)); break; case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt fpr.SpillLock(fd, fs); // this probably works, just badly tested fpr.MapReg(fd, fd == fs, true); SQRTSS(fpr.RX(fd), fpr.R(fs)); break; case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s execRounding(&XEmitter::CVTTSS2SI, -1); break; case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w fpr.SpillLock(fd, fs); fpr.MapReg(fd, fs == fd, true); if (fpr.R(fs).IsSimpleReg()) { CVTDQ2PS(fpr.RX(fd), fpr.R(fs)); } else { // If fs was fd, we'd be in the case above since we mapped fd. MOVSS(fpr.RX(fd), fpr.R(fs)); CVTDQ2PS(fpr.RX(fd), fpr.R(fd)); } break; case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s // Uses the current rounding mode. execRounding(&XEmitter::CVTSS2SI, -1); break; case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s execRounding(&XEmitter::CVTSS2SI, 0); break; case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s execRounding(&XEmitter::CVTSS2SI, 2); break; case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s execRounding(&XEmitter::CVTSS2SI, 1); break; default: DISABLE; return; } fpr.ReleaseSpillLocks(); }