diff options
| author | JosJuice <josjuice@gmail.com> | 2026-01-23 21:43:18 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-23 21:43:18 +0100 |
| commit | 3221e982d371afd39793628bf8973f3cc951db35 (patch) | |
| tree | 9a05b6a7b3225612b3b0a4dd9e20269da0051ff0 /Source/Core/Common | |
| parent | b18abc41edcce4b98aeaf13a52c693fcd724d07b (diff) | |
| parent | 3b1a4739bc02942fe4995ede8908bb625a4226f1 (diff) | |
Merge pull request #13900 from JosJuice/jit-fma-double-rounding
Jit: Implement error-free transformation for single-precision FMA
Diffstat (limited to 'Source/Core/Common')
| -rw-r--r-- | Source/Core/Common/Arm64Emitter.cpp | 62 | ||||
| -rw-r--r-- | Source/Core/Common/Arm64Emitter.h | 16 | ||||
| -rw-r--r-- | Source/Core/Common/x64Emitter.cpp | 31 | ||||
| -rw-r--r-- | Source/Core/Common/x64Emitter.h | 25 |
4 files changed, 112 insertions, 22 deletions
diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index d78257cf4f..cdb0b7e625 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -3156,6 +3156,10 @@ void ARM64FloatEmitter::DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) EmitCopy(IsQuad(Rd), 0, imm5, 0, Rd, Rn); } +void ARM64FloatEmitter::EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, 0, 3, Rd, Rn, Rm); +} void ARM64FloatEmitter::FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn) { Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0xF, Rd, Rn); @@ -3505,6 +3509,53 @@ void ARM64FloatEmitter::UCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale) EmitConversion2(sf, 0, false, type, 0, 3, 64 - scale, Rd, Rn); } +// Comparison +void ARM64FloatEmitter::CMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, MathUtil::IntLog2(size) - 3, 0x11, Rd, Rn, Rm); +} +void ARM64FloatEmitter::CMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(IsQuad(Rd), 0, MathUtil::IntLog2(size) - 3, 0x9, Rd, Rn); +} +void ARM64FloatEmitter::CMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, MathUtil::IntLog2(size) - 3, 0x7, Rd, Rn, Rm); +} +void ARM64FloatEmitter::CMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(IsQuad(Rd), 1, MathUtil::IntLog2(size) - 3, 0x8, Rd, Rn); +} +void ARM64FloatEmitter::CMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, MathUtil::IntLog2(size) - 3, 0x6, Rd, Rn, Rm); +} +void ARM64FloatEmitter::CMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(IsQuad(Rd), 0, MathUtil::IntLog2(size) - 3, 0x8, Rd, Rn); +} +void ARM64FloatEmitter::CMHI(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, MathUtil::IntLog2(size) - 3, 0x6, Rd, Rn, Rm); +} +void ARM64FloatEmitter::CMHS(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(1, MathUtil::IntLog2(size) - 3, 0x7, Rd, Rn, Rm); +} +void ARM64FloatEmitter::CMLE(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(IsQuad(Rd), 1, MathUtil::IntLog2(size) - 3, 0x9, Rd, Rn); +} +void ARM64FloatEmitter::CMLT(u8 size, ARM64Reg Rd, ARM64Reg Rn) +{ + Emit2RegMisc(IsQuad(Rd), 0, MathUtil::IntLog2(size) - 3, 0xA, Rd, Rn); +} +void ARM64FloatEmitter::CMTST(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +{ + EmitThreeSame(0, MathUtil::IntLog2(size) - 3, 0x11, Rd, Rn, Rm); +} + +// Float comparison void ARM64FloatEmitter::FCMP(ARM64Reg Rn, ARM64Reg Rm) { EmitCompare(0, 0, 0, 0, Rn, Rm); @@ -3664,7 +3715,7 @@ void ARM64FloatEmitter::SHL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { ASSERT_MSG(DYNA_REC, shift < src_size, "Shift amount must be less than the element size! {} {}", shift, src_size); - EmitShiftImm(1, 0, src_size | shift, 0b01010, Rd, Rn); + EmitShiftImm(IsQuad(Rd), 0, src_size | shift, 0b01010, Rd, Rn); } void ARM64FloatEmitter::SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) @@ -3674,11 +3725,18 @@ void ARM64FloatEmitter::SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, EmitShiftImm(upper, 0, src_size | shift, 0b10100, Rd, Rn); } +void ARM64FloatEmitter::SSHR(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) +{ + ASSERT_MSG(DYNA_REC, shift < src_size, "Shift amount must be less than the element size! {} {}", + shift, src_size); + EmitShiftImm(IsQuad(Rd), 0, src_size * 2 - shift, 0b00000, Rd, Rn); +} + void ARM64FloatEmitter::URSHR(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { ASSERT_MSG(DYNA_REC, shift < src_size, "Shift amount must be less than the element size! {} {}", shift, src_size); - EmitShiftImm(1, 1, src_size * 2 - shift, 0b00100, Rd, Rn); + EmitShiftImm(IsQuad(Rd), 1, src_size * 2 - shift, 0b00100, Rd, Rn); } void ARM64FloatEmitter::USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index 134f9b64cc..d0c91abd61 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -800,6 +800,7 @@ public: ARM64Reg zr = Is64Bit(Rd) ? ARM64Reg::ZR : ARM64Reg::WZR; CSINV(Rd, zr, zr, (CCFlags)((u32)cond ^ 1)); } + void CNEG(ARM64Reg Rd, ARM64Reg Rn, CCFlags cond) { CSNEG(Rd, Rn, Rn, (CCFlags)((u32)cond ^ 1)); } void NEG(ARM64Reg Rd, ARM64Reg Rs) { SUB(Rd, Is64Bit(Rd) ? ARM64Reg::ZR : ARM64Reg::WZR, Rs); } void NEG(ARM64Reg Rd, ARM64Reg Rs, ArithOption Option) { @@ -1281,6 +1282,7 @@ public: void BIT(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); void BSL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); + void EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); void FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn); void FADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); void FMAX(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); @@ -1342,6 +1344,19 @@ public: void SCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale); void UCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale); + // Comparison + void CMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void CMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void CMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void CMHI(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CMHS(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CMLE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void CMLT(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void CMTST(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + // Float comparison void FCMP(ARM64Reg Rn, ARM64Reg Rm); void FCMP(ARM64Reg Rn); @@ -1380,6 +1395,7 @@ public: void SHL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); void SSHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); + void SSHR(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); void URSHR(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); void USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); void USHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); diff --git a/Source/Core/Common/x64Emitter.cpp b/Source/Core/Common/x64Emitter.cpp index 0a122e1121..f9a8a015f9 100644 --- a/Source/Core/Common/x64Emitter.cpp +++ b/Source/Core/Common/x64Emitter.cpp @@ -2519,19 +2519,19 @@ void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg& arg) WriteSSEOp(0x66, 0x6C, dest, arg); } -void XEmitter::PSRLW(X64Reg reg, int shift) +void XEmitter::PSRLW(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); Write8(shift); } -void XEmitter::PSRLD(X64Reg reg, int shift) +void XEmitter::PSRLD(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); Write8(shift); } -void XEmitter::PSRLQ(X64Reg reg, int shift) +void XEmitter::PSRLQ(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); Write8(shift); @@ -2542,38 +2542,38 @@ void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) WriteSSEOp(0x66, 0xd3, reg, arg); } -void XEmitter::PSRLDQ(X64Reg reg, int shift) +void XEmitter::PSRLDQ(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x73, (X64Reg)3, R(reg)); Write8(shift); } -void XEmitter::PSLLW(X64Reg reg, int shift) +void XEmitter::PSLLW(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); Write8(shift); } -void XEmitter::PSLLD(X64Reg reg, int shift) +void XEmitter::PSLLD(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); Write8(shift); } -void XEmitter::PSLLQ(X64Reg reg, int shift) +void XEmitter::PSLLQ(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); Write8(shift); } -void XEmitter::PSLLDQ(X64Reg reg, int shift) +void XEmitter::PSLLDQ(X64Reg reg, u8 shift) { WriteSSEOp(0x66, 0x73, (X64Reg)7, R(reg)); Write8(shift); } // WARNING not REX compatible -void XEmitter::PSRAW(X64Reg reg, int shift) +void XEmitter::PSRAW(X64Reg reg, u8 shift) { if (reg > 7) PanicAlertFmt("The PSRAW-emitter does not support regs above 7"); @@ -2585,7 +2585,7 @@ void XEmitter::PSRAW(X64Reg reg, int shift) } // WARNING not REX compatible -void XEmitter::PSRAD(X64Reg reg, int shift) +void XEmitter::PSRAD(X64Reg reg, u8 shift) { if (reg > 7) PanicAlertFmt("The PSRAD-emitter does not support regs above 7"); @@ -2695,6 +2695,11 @@ void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) Write8(blend); } +void XEmitter::PCMPEQQ(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3829, dest, arg); +} + void XEmitter::PAND(X64Reg dest, const OpArg& arg) { WriteSSEOp(0x66, 0xDB, dest, arg); @@ -3038,6 +3043,12 @@ void XEmitter::VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg); } +void XEmitter::VPSLLQ(X64Reg regOp1, X64Reg regOp2, u8 shift) +{ + WriteAVXOp(0x66, 0x73, (X64Reg)6, regOp1, R(regOp2)); + Write8(shift); +} + void XEmitter::VMOVAPS(const OpArg& arg, X64Reg regOp) { WriteAVXOp(0x00, 0x29, regOp, X64Reg::INVALID_REG, arg); diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index 6953770986..35d88a46bc 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -801,19 +801,19 @@ public: void PSHUFLW(X64Reg dest, const OpArg& arg, u8 shuffle); void PSHUFHW(X64Reg dest, const OpArg& arg, u8 shuffle); - void PSRLW(X64Reg reg, int shift); - void PSRLD(X64Reg reg, int shift); - void PSRLQ(X64Reg reg, int shift); + void PSRLW(X64Reg reg, u8 shift); + void PSRLD(X64Reg reg, u8 shift); + void PSRLQ(X64Reg reg, u8 shift); void PSRLQ(X64Reg reg, const OpArg& arg); - void PSRLDQ(X64Reg reg, int shift); + void PSRLDQ(X64Reg reg, u8 shift); - void PSLLW(X64Reg reg, int shift); - void PSLLD(X64Reg reg, int shift); - void PSLLQ(X64Reg reg, int shift); - void PSLLDQ(X64Reg reg, int shift); + void PSLLW(X64Reg reg, u8 shift); + void PSLLD(X64Reg reg, u8 shift); + void PSLLQ(X64Reg reg, u8 shift); + void PSLLDQ(X64Reg reg, u8 shift); - void PSRAW(X64Reg reg, int shift); - void PSRAD(X64Reg reg, int shift); + void PSRAW(X64Reg reg, u8 shift); + void PSRAD(X64Reg reg, u8 shift); // SSE4: data type conversions void PMOVSXBW(X64Reg dest, const OpArg& arg); @@ -836,6 +836,9 @@ public: void BLENDPS(X64Reg dest, const OpArg& arg, u8 blend); void BLENDPD(X64Reg dest, const OpArg& arg, u8 blend); + // SSE4: compare instructions + void PCMPEQQ(X64Reg dest, const OpArg& arg); + // AVX void VADDSS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); void VSUBSS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); @@ -878,6 +881,8 @@ public: void VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); void VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VPSLLQ(X64Reg regOp1, X64Reg regOp2, u8 shift); + void VMOVAPS(const OpArg& arg, X64Reg regOp); void VZEROUPPER(); |
