Jit: Move rlwimix to ConstantPropagation

This commit is contained in:
JosJuice 2024-09-01 11:44:34 +02:00
parent bac911aac4
commit 502317a485
4 changed files with 163 additions and 171 deletions

View File

@ -1997,135 +1997,118 @@ void Jit64::rlwimix(UGeckoInstruction inst)
int s = inst.RS; int s = inst.RS;
const u32 mask = MakeRotationMask(inst.MB, inst.ME); const u32 mask = MakeRotationMask(inst.MB, inst.ME);
const bool left_shift = mask == 0U - (1U << inst.SH);
const bool right_shift = mask == (1U << inst.SH) - 1;
bool needs_test = false;
if (gpr.IsImm(a, s)) if (mask == 0 || (a == s && inst.SH == 0))
{ {
gpr.SetImmediate32(a, (gpr.Imm32(a) & ~mask) | (std::rotl(gpr.Imm32(s), inst.SH) & mask)); needs_test = true;
if (inst.Rc)
ComputeRC(a);
} }
else if (gpr.IsImm(s) && mask == 0xFFFFFFFF) else if (mask == 0xFFFFFFFF)
{ {
gpr.SetImmediate32(a, std::rotl(gpr.Imm32(s), inst.SH)); RCOpArg Rs = gpr.Use(s, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
if (inst.Rc) RegCache::Realize(Rs, Ra);
ComputeRC(a); RotateLeft(32, Ra, Rs, inst.SH);
needs_test = true;
} }
else else if (gpr.IsImm(s))
{ {
const bool left_shift = mask == 0U - (1U << inst.SH); RCX64Reg Ra = gpr.Bind(a, RCMode::ReadWrite);
const bool right_shift = mask == (1U << inst.SH) - 1; RegCache::Realize(Ra);
bool needs_test = false; AndWithMask(Ra, ~mask);
OR(32, Ra, Imm32(std::rotl(gpr.Imm32(s), inst.SH) & mask));
}
else if (gpr.IsImm(a))
{
const u32 maskA = gpr.Imm32(a) & ~mask;
if (mask == 0 || (a == s && inst.SH == 0)) RCOpArg Rs = gpr.Use(s, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
RegCache::Realize(Rs, Ra);
if (inst.SH == 0)
{ {
needs_test = true; MOV(32, Ra, Rs);
AndWithMask(Ra, mask);
} }
else if (mask == 0xFFFFFFFF) else if (left_shift)
{ {
RCOpArg Rs = gpr.Use(s, RCMode::Read); MOV(32, Ra, Rs);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write); SHL(32, Ra, Imm8(inst.SH));
RegCache::Realize(Rs, Ra);
RotateLeft(32, Ra, Rs, inst.SH);
needs_test = true;
} }
else if (gpr.IsImm(s)) else if (right_shift)
{ {
RCX64Reg Ra = gpr.Bind(a, RCMode::ReadWrite); MOV(32, Ra, Rs);
RegCache::Realize(Ra); SHR(32, Ra, Imm8(32 - inst.SH));
AndWithMask(Ra, ~mask);
OR(32, Ra, Imm32(std::rotl(gpr.Imm32(s), inst.SH) & mask));
}
else if (gpr.IsImm(a))
{
const u32 maskA = gpr.Imm32(a) & ~mask;
RCOpArg Rs = gpr.Use(s, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::Write);
RegCache::Realize(Rs, Ra);
if (inst.SH == 0)
{
MOV(32, Ra, Rs);
AndWithMask(Ra, mask);
}
else if (left_shift)
{
MOV(32, Ra, Rs);
SHL(32, Ra, Imm8(inst.SH));
}
else if (right_shift)
{
MOV(32, Ra, Rs);
SHR(32, Ra, Imm8(32 - inst.SH));
}
else
{
RotateLeft(32, Ra, Rs, inst.SH);
AndWithMask(Ra, mask);
}
if (maskA)
OR(32, Ra, Imm32(maskA));
else
needs_test = true;
}
else if (inst.SH)
{
// TODO: perhaps consider pinsrb or abuse of AH
RCOpArg Rs = gpr.Use(s, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::ReadWrite);
RegCache::Realize(Rs, Ra);
if (left_shift)
{
MOV(32, R(RSCRATCH), Rs);
SHL(32, R(RSCRATCH), Imm8(inst.SH));
}
else if (right_shift)
{
MOV(32, R(RSCRATCH), Rs);
SHR(32, R(RSCRATCH), Imm8(32 - inst.SH));
}
else
{
RotateLeft(32, RSCRATCH, Rs, inst.SH);
}
if (mask == 0xFF || mask == 0xFFFF)
{
MOV(mask == 0xFF ? 8 : 16, Ra, R(RSCRATCH));
needs_test = true;
}
else
{
if (!left_shift && !right_shift)
AndWithMask(RSCRATCH, mask);
AndWithMask(Ra, ~mask);
OR(32, Ra, R(RSCRATCH));
}
} }
else else
{ {
RCX64Reg Rs = gpr.Bind(s, RCMode::Read); RotateLeft(32, Ra, Rs, inst.SH);
RCX64Reg Ra = gpr.Bind(a, RCMode::ReadWrite); AndWithMask(Ra, mask);
RegCache::Realize(Rs, Ra);
if (mask == 0xFF || mask == 0xFFFF)
{
MOV(mask == 0xFF ? 8 : 16, Ra, Rs);
needs_test = true;
}
else
{
XOR(32, Ra, Rs);
AndWithMask(Ra, ~mask);
XOR(32, Ra, Rs);
}
} }
if (inst.Rc)
ComputeRC(a, needs_test); if (maskA)
OR(32, Ra, Imm32(maskA));
else
needs_test = true;
} }
else if (inst.SH)
{
// TODO: perhaps consider pinsrb or abuse of AH
RCOpArg Rs = gpr.Use(s, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::ReadWrite);
RegCache::Realize(Rs, Ra);
if (left_shift)
{
MOV(32, R(RSCRATCH), Rs);
SHL(32, R(RSCRATCH), Imm8(inst.SH));
}
else if (right_shift)
{
MOV(32, R(RSCRATCH), Rs);
SHR(32, R(RSCRATCH), Imm8(32 - inst.SH));
}
else
{
RotateLeft(32, RSCRATCH, Rs, inst.SH);
}
if (mask == 0xFF || mask == 0xFFFF)
{
MOV(mask == 0xFF ? 8 : 16, Ra, R(RSCRATCH));
needs_test = true;
}
else
{
if (!left_shift && !right_shift)
AndWithMask(RSCRATCH, mask);
AndWithMask(Ra, ~mask);
OR(32, Ra, R(RSCRATCH));
}
}
else
{
RCX64Reg Rs = gpr.Bind(s, RCMode::Read);
RCX64Reg Ra = gpr.Bind(a, RCMode::ReadWrite);
RegCache::Realize(Rs, Ra);
if (mask == 0xFF || mask == 0xFFFF)
{
MOV(mask == 0xFF ? 8 : 16, Ra, Rs);
needs_test = true;
}
else
{
XOR(32, Ra, Rs);
AndWithMask(Ra, ~mask);
XOR(32, Ra, Rs);
}
}
if (inst.Rc)
ComputeRC(a, needs_test);
} }
void Jit64::rlwnmx(UGeckoInstruction inst) void Jit64::rlwnmx(UGeckoInstruction inst)

View File

@ -1975,74 +1975,64 @@ void JitArm64::rlwimix(UGeckoInstruction inst)
const u32 width = inst.ME - inst.MB + 1; const u32 width = inst.ME - inst.MB + 1;
const u32 rot_dist = inst.SH ? 32 - inst.SH : 0; const u32 rot_dist = inst.SH ? 32 - inst.SH : 0;
if (gpr.IsImm(a) && gpr.IsImm(s)) if (mask == 0 || (a == s && inst.SH == 0))
{ {
u32 res = (gpr.GetImm(a) & ~mask) | (std::rotl(gpr.GetImm(s), inst.SH) & mask); // Do Nothing
gpr.SetImmediate(a, res);
if (inst.Rc)
ComputeRC0(res);
} }
else else if (mask == 0xFFFFFFFF)
{ {
if (mask == 0 || (a == s && inst.SH == 0)) if (inst.SH || a != s)
{ gpr.BindToRegister(a, a == s);
// Do Nothing
}
else if (mask == 0xFFFFFFFF)
{
if (inst.SH || a != s)
gpr.BindToRegister(a, a == s);
if (inst.SH) if (inst.SH)
ROR(gpr.R(a), gpr.R(s), rot_dist); ROR(gpr.R(a), gpr.R(s), rot_dist);
else if (a != s) else if (a != s)
MOV(gpr.R(a), gpr.R(s)); MOV(gpr.R(a), gpr.R(s));
} }
else if (lsb == 0 && inst.MB <= inst.ME && rot_dist + width <= 32) else if (lsb == 0 && inst.MB <= inst.ME && rot_dist + width <= 32)
{
// Destination is in least significant position
// No mask inversion
// Source field pre-rotation is contiguous
gpr.BindToRegister(a, true);
BFXIL(gpr.R(a), gpr.R(s), rot_dist, width);
}
else if (inst.SH == 0 && inst.MB <= inst.ME)
{
// No rotation
// No mask inversion
gpr.BindToRegister(a, true);
auto WA = gpr.GetScopedReg();
UBFX(WA, gpr.R(s), lsb, width);
BFI(gpr.R(a), WA, lsb, width);
}
else if (inst.SH && inst.MB <= inst.ME)
{
// No mask inversion
gpr.BindToRegister(a, true);
if ((rot_dist + lsb) % 32 == 0)
{ {
// Destination is in least significant position BFI(gpr.R(a), gpr.R(s), lsb, width);
// No mask inversion
// Source field pre-rotation is contiguous
gpr.BindToRegister(a, true);
BFXIL(gpr.R(a), gpr.R(s), rot_dist, width);
}
else if (inst.SH == 0 && inst.MB <= inst.ME)
{
// No rotation
// No mask inversion
gpr.BindToRegister(a, true);
auto WA = gpr.GetScopedReg();
UBFX(WA, gpr.R(s), lsb, width);
BFI(gpr.R(a), WA, lsb, width);
}
else if (inst.SH && inst.MB <= inst.ME)
{
// No mask inversion
gpr.BindToRegister(a, true);
if ((rot_dist + lsb) % 32 == 0)
{
BFI(gpr.R(a), gpr.R(s), lsb, width);
}
else
{
auto WA = gpr.GetScopedReg();
ROR(WA, gpr.R(s), (rot_dist + lsb) % 32);
BFI(gpr.R(a), WA, lsb, width);
}
} }
else else
{ {
gpr.BindToRegister(a, true);
ARM64Reg RA = gpr.R(a);
auto WA = gpr.GetScopedReg(); auto WA = gpr.GetScopedReg();
const u32 inverted_mask = ~mask; ROR(WA, gpr.R(s), (rot_dist + lsb) % 32);
BFI(gpr.R(a), WA, lsb, width);
AND(WA, gpr.R(s), LogicalImm(std::rotl(mask, rot_dist), GPRSize::B32));
AND(RA, RA, LogicalImm(inverted_mask, GPRSize::B32));
ORR(RA, RA, WA, ArithOption(WA, ShiftType::ROR, rot_dist));
} }
if (inst.Rc)
ComputeRC0(gpr.R(a));
} }
else
{
gpr.BindToRegister(a, true);
ARM64Reg RA = gpr.R(a);
auto WA = gpr.GetScopedReg();
const u32 inverted_mask = ~mask;
AND(WA, gpr.R(s), LogicalImm(std::rotl(mask, rot_dist), GPRSize::B32));
AND(RA, RA, LogicalImm(inverted_mask, GPRSize::B32));
ORR(RA, RA, WA, ArithOption(WA, ShiftType::ROR, rot_dist));
}
if (inst.Rc)
ComputeRC0(gpr.R(a));
} }

View File

@ -41,6 +41,8 @@ ConstantPropagationResult ConstantPropagation::EvaluateInstruction(UGeckoInstruc
case 14: // addi case 14: // addi
case 15: // addis case 15: // addis
return EvaluateAddImm(inst); return EvaluateAddImm(inst);
case 20: // rlwimix
return EvaluateRlwimix(inst);
case 21: // rlwinmx case 21: // rlwinmx
return EvaluateRlwinmxRlwnmx(inst, inst.SH); return EvaluateRlwinmxRlwnmx(inst, inst.SH);
case 23: // rlwnmx case 23: // rlwnmx
@ -114,6 +116,22 @@ ConstantPropagationResult ConstantPropagation::EvaluateAddImmCarry(UGeckoInstruc
return result; return result;
} }
ConstantPropagationResult ConstantPropagation::EvaluateRlwimix(UGeckoInstruction inst) const
{
if (!HasGPR(inst.RS))
return {};
const u32 mask = MakeRotationMask(inst.MB, inst.ME);
if (mask == 0xFFFFFFFF)
return ConstantPropagationResult(inst.RA, std::rotl(GetGPR(inst.RS), inst.SH), inst.Rc);
if (!HasGPR(inst.RA))
return {};
return ConstantPropagationResult(
inst.RA, (GetGPR(inst.RA) & ~mask) | (std::rotl(GetGPR(inst.RS), inst.SH) & mask), inst.Rc);
}
ConstantPropagationResult ConstantPropagation::EvaluateRlwinmxRlwnmx(UGeckoInstruction inst, ConstantPropagationResult ConstantPropagation::EvaluateRlwinmxRlwnmx(UGeckoInstruction inst,
u32 shift) const u32 shift) const
{ {

View File

@ -81,6 +81,7 @@ private:
ConstantPropagationResult EvaluateSubImmCarry(UGeckoInstruction inst) const; ConstantPropagationResult EvaluateSubImmCarry(UGeckoInstruction inst) const;
ConstantPropagationResult EvaluateAddImm(UGeckoInstruction inst) const; ConstantPropagationResult EvaluateAddImm(UGeckoInstruction inst) const;
ConstantPropagationResult EvaluateAddImmCarry(UGeckoInstruction inst) const; ConstantPropagationResult EvaluateAddImmCarry(UGeckoInstruction inst) const;
ConstantPropagationResult EvaluateRlwimix(UGeckoInstruction inst) const;
ConstantPropagationResult EvaluateRlwinmxRlwnmx(UGeckoInstruction inst, u32 shift) const; ConstantPropagationResult EvaluateRlwinmxRlwnmx(UGeckoInstruction inst, u32 shift) const;
ConstantPropagationResult EvaluateBitwiseImm(UGeckoInstruction inst, ConstantPropagationResult EvaluateBitwiseImm(UGeckoInstruction inst,
u32 (*do_op)(u32, u32)) const; u32 (*do_op)(u32, u32)) const;