x86jit: Use BMI2 for variable shifts.

We don't actually regalloc ECX, but this still saves a copy, and on modern
CPUs these seem to be pretty fast.
This commit is contained in:
Unknown W. Brackets 2022-01-31 19:36:28 -08:00
parent bd06569609
commit 16dca4f69b
2 changed files with 30 additions and 7 deletions

View File

@ -1458,6 +1458,7 @@ void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg
{
CheckFlags();
_assert_msg_(cpu_info.bBMI1, "Trying to use BMI1 on a system that doesn't support it.");
_assert_msg_(!arg.IsImm(), "Imm arg unsupported for this BMI1 instruction");
WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes);
}
@ -1465,6 +1466,7 @@ void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg
{
CheckFlags();
_assert_msg_(cpu_info.bBMI2, "Trying to use BMI2 on a system that doesn't support it.");
_assert_msg_(!arg.IsImm(), "Imm arg unsupported for this BMI2 instruction");
WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes);
}

View File

@ -22,6 +22,7 @@
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/CPUDetect.h"
#include "Core/MIPS/MIPSCodeUtils.h"
#include "Core/MIPS/x86/Jit.h"
#include "Core/MIPS/x86/RegCache.h"
@ -647,16 +648,36 @@ namespace MIPSComp
}
gpr.Lock(rd, rt, rs);
if (gpr.IsImm(rs))
{
if (gpr.IsImm(rs)) {
int sa = gpr.GetImm(rs);
gpr.MapReg(rd, rd == rt, true);
if (rd != rt)
if (cpu_info.bBMI2 && shift == &XEmitter::ROR) {
_assert_(!gpr.IsImm(rt));
RORX(32, gpr.RX(rd), gpr.R(rt), sa & 0x1F);
} else {
if (rd != rt)
MOV(32, gpr.R(rd), gpr.R(rt));
(this->*shift)(32, gpr.R(rd), Imm8(sa & 0x1F));
}
} else if (cpu_info.bBMI2 && shift != &XEmitter::ROR) {
gpr.MapReg(rd, rd == rt || rd == rs, true);
gpr.MapReg(rs, true, false);
MIPSGPReg src = rt;
if (gpr.IsImm(rt) && rd == rs) {
gpr.MapReg(rt, true, false);
} else if (gpr.IsImm(rt)) {
MOV(32, gpr.R(rd), gpr.R(rt));
(this->*shift)(32, gpr.R(rd), Imm8(sa));
}
else
{
src = rd;
}
if (shift == &XEmitter::SHL)
SHLX(32, gpr.RX(rd), gpr.R(src), gpr.RX(rs));
else if (shift == &XEmitter::SHR)
SHRX(32, gpr.RX(rd), gpr.R(src), gpr.RX(rs));
else if (shift == &XEmitter::SAR)
SARX(32, gpr.RX(rd), gpr.R(src), gpr.RX(rs));
else
_assert_msg_(false, "Unexpected shift type");
} else {
gpr.FlushLockX(ECX);
gpr.MapReg(rd, rd == rt || rd == rs, true);
MOV(32, R(ECX), gpr.R(rs)); // Only ECX can be used for variable shifts.