Merge pull request #12672 from JosJuice/jit64-extract-with-byte-offset

Jit64: Clean up ExtractWithByteOffset
This commit is contained in:
Tilka
2024-04-20 12:41:29 +01:00
committed by GitHub
3 changed files with 66 additions and 66 deletions

View File

@ -2065,69 +2065,83 @@ void Jit64::rlwinmx(UGeckoInstruction inst)
bool needs_sext = true; bool needs_sext = true;
int mask_size = inst.ME - inst.MB + 1; int mask_size = inst.ME - inst.MB + 1;
RCOpArg Rs = gpr.Use(s, RCMode::Read); if (simple_mask && !(inst.SH & (mask_size - 1)) && !gpr.IsBound(s))
RCX64Reg Ra = gpr.Bind(a, RCMode::Write); {
RegCache::Realize(Rs, Ra); // optimized case: byte/word extract from m_ppc_state
if (a != s && left_shift && Rs.IsSimpleReg() && inst.SH <= 3) // Note: If a == s, calling Realize(Ra) will allocate a host register for Rs,
{ // so we have to get mem_source from Rs before calling Realize(Ra)
LEA(32, Ra, MScaled(Rs.GetSimpleReg(), SCALE_1 << inst.SH, 0));
} RCOpArg Rs = gpr.Use(s, RCMode::Read);
// common optimized case: byte/word extract RegCache::Realize(Rs);
else if (simple_mask && !(inst.SH & (mask_size - 1))) OpArg mem_source = Rs.Location();
{
MOVZX(32, mask_size, Ra, Rs.ExtractWithByteOffset(inst.SH ? (32 - inst.SH) >> 3 : 0));
needs_sext = false;
}
// another optimized special case: byte/word extract plus rotate
else if (simple_prerotate_mask && !left_shift)
{
MOVZX(32, prerotate_mask == 0xff ? 8 : 16, Ra, Rs);
if (inst.SH) if (inst.SH)
ROL(32, Ra, Imm8(inst.SH)); mem_source.AddMemOffset((32 - inst.SH) >> 3);
needs_sext = (mask & 0x80000000) != 0; Rs.Unlock();
}
// Use BEXTR where possible: Only AMD implements this in one uop
else if (field_extract && cpu_info.bBMI1 && cpu_info.vendor == CPUVendor::AMD)
{
MOV(32, R(RSCRATCH), Imm32((mask_size << 8) | (32 - inst.SH)));
BEXTR(32, Ra, Rs, RSCRATCH);
needs_sext = false;
}
else if (left_shift)
{
if (a != s)
MOV(32, Ra, Rs);
SHL(32, Ra, Imm8(inst.SH)); RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
} RegCache::Realize(Ra);
else if (right_shift) MOVZX(32, mask_size, Ra, mem_source);
{
if (a != s)
MOV(32, Ra, Rs);
SHR(32, Ra, Imm8(inst.MB));
needs_sext = false; needs_sext = false;
} }
else else
{ {
RotateLeft(32, Ra, Rs, inst.SH); RCOpArg Rs = gpr.Use(s, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
RegCache::Realize(Rs, Ra);
if (!(inst.MB == 0 && inst.ME == 31)) if (a != s && left_shift && Rs.IsSimpleReg() && inst.SH <= 3)
{ {
// we need flags if we're merging the branch LEA(32, Ra, MScaled(Rs.GetSimpleReg(), SCALE_1 << inst.SH, 0));
if (inst.Rc && CheckMergedBranch(0)) }
AND(32, Ra, Imm32(mask)); // optimized case: byte/word extract plus rotate
else else if (simple_prerotate_mask && !left_shift)
AndWithMask(Ra, mask); {
needs_sext = inst.MB == 0; MOVZX(32, prerotate_mask == 0xff ? 8 : 16, Ra, Rs);
needs_test = false; if (inst.SH)
ROL(32, Ra, Imm8(inst.SH));
needs_sext = (mask & 0x80000000) != 0;
}
// Use BEXTR where possible: Only AMD implements this in one uop
else if (field_extract && cpu_info.bBMI1 && cpu_info.vendor == CPUVendor::AMD)
{
MOV(32, R(RSCRATCH), Imm32((mask_size << 8) | (32 - inst.SH)));
BEXTR(32, Ra, Rs, RSCRATCH);
needs_sext = false;
}
else if (left_shift)
{
if (a != s)
MOV(32, Ra, Rs);
SHL(32, Ra, Imm8(inst.SH));
}
else if (right_shift)
{
if (a != s)
MOV(32, Ra, Rs);
SHR(32, Ra, Imm8(inst.MB));
needs_sext = false;
}
else
{
RotateLeft(32, Ra, Rs, inst.SH);
if (!(inst.MB == 0 && inst.ME == 31))
{
// we need flags if we're merging the branch
if (inst.Rc && CheckMergedBranch(0))
AND(32, Ra, Imm32(mask));
else
AndWithMask(Ra, mask);
needs_sext = inst.MB == 0;
needs_test = false;
}
} }
} }
Rs.Unlock();
Ra.Unlock();
if (inst.Rc) if (inst.Rc)
ComputeRC(a, needs_test, needs_sext); ComputeRC(a, needs_test, needs_sext);
} }

View File

@ -109,19 +109,6 @@ OpArg RCOpArg::Location() const
return {}; return {};
} }
OpArg RCOpArg::ExtractWithByteOffset(int offset)
{
if (offset == 0)
return Location();
ASSERT(rc);
const preg_t preg = std::get<preg_t>(contents);
rc->StoreFromRegister(preg, RegCache::FlushMode::MaintainState);
OpArg result = rc->GetDefaultLocation(preg);
result.AddMemOffset(offset);
return result;
}
void RCOpArg::Unlock() void RCOpArg::Unlock()
{ {
if (const preg_t* preg = std::get_if<preg_t>(&contents)) if (const preg_t* preg = std::get_if<preg_t>(&contents))

View File

@ -47,9 +47,6 @@ public:
bool IsSimpleReg(Gen::X64Reg reg) const { return Location().IsSimpleReg(reg); } bool IsSimpleReg(Gen::X64Reg reg) const { return Location().IsSimpleReg(reg); }
Gen::X64Reg GetSimpleReg() const { return Location().GetSimpleReg(); } Gen::X64Reg GetSimpleReg() const { return Location().GetSimpleReg(); }
// Use to extract bytes from a register using the regcache. offset is in bytes.
Gen::OpArg ExtractWithByteOffset(int offset);
void Unlock(); void Unlock();
bool IsImm() const; bool IsImm() const;
@ -159,6 +156,8 @@ public:
u32 Imm32(preg_t preg) const { return R(preg).Imm32(); } u32 Imm32(preg_t preg) const { return R(preg).Imm32(); }
s32 SImm32(preg_t preg) const { return R(preg).SImm32(); } s32 SImm32(preg_t preg) const { return R(preg).SImm32(); }
bool IsBound(preg_t preg) const { return m_regs[preg].IsBound(); }
RCOpArg Use(preg_t preg, RCMode mode); RCOpArg Use(preg_t preg, RCMode mode);
RCOpArg UseNoImm(preg_t preg, RCMode mode); RCOpArg UseNoImm(preg_t preg, RCMode mode);
RCOpArg BindOrImm(preg_t preg, RCMode mode); RCOpArg BindOrImm(preg_t preg, RCMode mode);