Jit64: boolX - Precompute complement of b

PowerPC instructions andcx and orcx complement the value of register b
before performing their respective bitwise operation. If this register
happens to contain a known value, we can precompute the complement,
allowing us to generate simpler code.

- andcx
Before:
BF 00 01 00 00       mov         edi,100h
F7 D7                not         edi
41 23 FE             and         edi,r14d

After:
41 8B FE             mov         edi,r14d
81 E7 FF FE FF FF    and         edi,0FFFFFEFFh

- orc
Before:
41 BE 04 00 00 00    mov         r14d,4
41 F7 D6             not         r14d
45 0B F5             or          r14d,r13d

After:
45 8B F5             mov         r14d,r13d
41 83 CE FB          or          r14d,0FFFFFFFBh
This commit is contained in:
Sintendo 2021-01-25 22:16:41 +01:00
parent caff472dbf
commit 26f70657bc
1 changed files with 92 additions and 0 deletions

View File

@ -662,6 +662,98 @@ void Jit64::boolX(UGeckoInstruction inst)
else if (inst.SUBOP10 == 284) // eqvx else if (inst.SUBOP10 == 284) // eqvx
gpr.SetImmediate32(a, ~(rs_offset ^ rb_offset)); gpr.SetImmediate32(a, ~(rs_offset ^ rb_offset));
} }
else if (gpr.IsImm(s) || gpr.IsImm(b))
{
auto [i, j] = gpr.IsImm(s) ? std::pair(s, b) : std::pair(b, s);
u32 imm = gpr.Imm32(i);
bool complement_b = (inst.SUBOP10 == 60 /* andcx */) || (inst.SUBOP10 == 412 /* orcx */);
bool final_not = (inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */) ||
(inst.SUBOP10 == 284 /* eqvx */);
bool is_and = (inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 60 /* andcx */) ||
(inst.SUBOP10 == 476 /* nandx */);
bool is_or = (inst.SUBOP10 == 444 /* orx */) || (inst.SUBOP10 == 412 /* orcx */) ||
(inst.SUBOP10 == 124 /* norx */);
bool is_xor = (inst.SUBOP10 == 316 /* xorx */) || (inst.SUBOP10 == 284 /* eqvx */);
// Precompute complement when possible
if (complement_b && gpr.IsImm(b))
{
imm = ~imm;
complement_b = false;
}
if (is_xor)
{
RCOpArg Rj = gpr.Use(j, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
RegCache::Realize(Rj, Ra);
if (a != j)
MOV(32, Ra, Rj);
XOR(32, Ra, Imm32(imm));
if (final_not)
{
NOT(32, Ra);
needs_test = true;
}
}
else if (is_and)
{
RCOpArg Rj = gpr.Use(j, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
RegCache::Realize(Rj, Ra);
if (complement_b)
{
if (a != j)
MOV(32, Ra, Rj);
NOT(32, Ra);
AND(32, Ra, Imm32(imm));
}
else
{
if (a != j)
MOV(32, Ra, Rj);
AND(32, Ra, Imm32(imm));
}
if (final_not) {
NOT(32, Ra);
needs_test = true;
}
}
else if (is_or)
{
RCOpArg Rj = gpr.Use(j, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
RegCache::Realize(Rj, Ra);
if (complement_b)
{
if (a != j)
MOV(32, Ra, Rj);
NOT(32, Ra);
OR(32, Ra, Imm32(imm));
}
else
{
if (a != j)
MOV(32, Ra, Rj);
OR(32, Ra, Imm32(imm));
}
if (final_not) {
NOT(32, Ra);
needs_test = true;
}
}
else
{
PanicAlertFmt("WTF!");
}
}
else if (s == b) else if (s == b)
{ {
if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */)) if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */))