mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
IR: Fix lwl/lwr pairing into the base reg, and sp validation past barriers
- An lwl/lwr pair was combined into one load even when the first half loads into the base register, which changes the address of the second half. - ApplyMemoryValidation shared one sp check across the block even past an Interpret or CallReplacement, which may change sp. - Drop a duplicate FSqrt meta entry, and name Load8Ext correctly. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
1dbb62d570
commit
25e8f1d57c
3 files changed
+64
-5
No files matched your search
@@ -78,7 +78,7 @@ static const IRMeta irMeta[] = {
|
||||
{ IROp::Ext16to32, "Ext16to32", "GG" },
|
||||
{ IROp::ReverseBits, "ReverseBits", "GG" },
|
||||
{ IROp::Load8, "Load8", "GGC" },
|
||||
{ IROp::Load8Ext, "Load8", "GGC" },
|
||||
{ IROp::Load8Ext, "Load8Ext", "GGC" },
|
||||
{ IROp::Load16, "Load16", "GGC" },
|
||||
{ IROp::Load16Ext, "Load16Ext", "GGC" },
|
||||
{ IROp::Load32, "Load32", "GGC" },
|
||||
@@ -105,7 +105,6 @@ static const IRMeta irMeta[] = {
|
||||
{ IROp::FSqrt, "FSqrt", "FF" },
|
||||
{ IROp::FSin, "FSin", "FF" },
|
||||
{ IROp::FCos, "FCos", "FF" },
|
||||
{ IROp::FSqrt, "FSqrt", "FF" },
|
||||
{ IROp::FRSqrt, "FRSqrt", "FF" },
|
||||
{ IROp::FRecip, "FRecip", "FF" },
|
||||
{ IROp::FAsin, "FAsin", "FF" },
|
||||
|
||||
@@ -254,6 +254,9 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions
|
||||
const IRInst &next = nextOp();
|
||||
if (next.op != matchOp || next.dest != inst.dest || next.src1 != inst.src1)
|
||||
return false;
|
||||
// A load into its own base changes the address the second half reads from.
|
||||
if (replaceOp == IROp::Load32 && inst.dest == inst.src1)
|
||||
return false;
|
||||
if (inst.constant + matchOff != next.constant)
|
||||
return false;
|
||||
|
||||
@@ -1863,9 +1866,11 @@ bool ApplyMemoryValidation(const IRWriter &in, IRWriter &out, const IROptions &o
|
||||
}
|
||||
|
||||
const IRMeta *m = GetIRMeta(inst.op);
|
||||
if (m->types[0] == 'G' && (m->flags & IRFLAG_SRC3) == 0 && inst.dest == MIPS_REG_SP) {
|
||||
bool writesSP = m->types[0] == 'G' && (m->flags & IRFLAG_SRC3) == 0 && inst.dest == MIPS_REG_SP;
|
||||
// A barrier (Interpret, CallReplacement) may write any GPR.
|
||||
if (writesSP || (m->flags & IRFLAG_BARRIER) != 0) {
|
||||
// We only care if it changes after we start combining.
|
||||
spModified = spUpper != -1;
|
||||
spModified = spModified || spUpper != -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "Core/MIPS/IR/IRInst.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/MIPS/IR/IRPassSimplify.h"
|
||||
|
||||
struct IRVerification {
|
||||
@@ -25,6 +26,10 @@ struct IRVerification {
|
||||
const std::vector<IRInst> input;
|
||||
const std::vector<IRInst> expected;
|
||||
const std::vector<IRPassFunc> passes;
|
||||
// Leaves lwl/lwr halves alone, among other things.
|
||||
bool optimizeForInterpreter = false;
|
||||
// ApplyMemoryValidation only runs without fast memory.
|
||||
bool slowMemory = false;
|
||||
};
|
||||
|
||||
static void LogInstructions(const std::vector<IRInst> &insts) {
|
||||
@@ -39,10 +44,15 @@ static bool VerifyPass(const IRVerification &v) {
|
||||
IRWriter in, out;
|
||||
IROptions opts{};
|
||||
opts.unalignedLoadStore = true;
|
||||
opts.optimizeForInterpreter = v.optimizeForInterpreter;
|
||||
|
||||
for (const auto &inst : v.input)
|
||||
in.Write(inst);
|
||||
if (IRApplyPasses(v.passes.data(), v.passes.size(), in, out, opts)) {
|
||||
const bool fastMemory = g_Config.bFastMemory;
|
||||
g_Config.bFastMemory = !v.slowMemory;
|
||||
bool logged = IRApplyPasses(v.passes.data(), v.passes.size(), in, out, opts);
|
||||
g_Config.bFastMemory = fastMemory;
|
||||
if (logged) {
|
||||
printf("%s FAILED: Unable to apply passes (or wanted to log)\n", v.name);
|
||||
return false;
|
||||
}
|
||||
@@ -267,6 +277,51 @@ static const IRVerification tests[] = {
|
||||
},
|
||||
{ &PurgeTemps },
|
||||
},
|
||||
{
|
||||
"CombineLoadLeftRight",
|
||||
{
|
||||
{ IROp::Load32Left, { MIPS_REG_A0 }, MIPS_REG_A1, 0, 3 },
|
||||
{ IROp::Load32Right, { MIPS_REG_A0 }, MIPS_REG_A1, 0, 0 },
|
||||
},
|
||||
{
|
||||
{ IROp::Load32, { MIPS_REG_A0 }, MIPS_REG_A1, 0, 0 },
|
||||
},
|
||||
{ &RemoveLoadStoreLeftRight },
|
||||
true,
|
||||
},
|
||||
{
|
||||
// The lwl changes a0, so the lwr reads from a different address.
|
||||
"NoCombineLoadLeftRightIntoBase",
|
||||
{
|
||||
{ IROp::Load32Left, { MIPS_REG_A0 }, MIPS_REG_A0, 0, 3 },
|
||||
{ IROp::Load32Right, { MIPS_REG_A0 }, MIPS_REG_A0, 0, 0 },
|
||||
},
|
||||
{
|
||||
{ IROp::Load32Left, { MIPS_REG_A0 }, MIPS_REG_A0, 0, 3 },
|
||||
{ IROp::Load32Right, { MIPS_REG_A0 }, MIPS_REG_A0, 0, 0 },
|
||||
},
|
||||
{ &RemoveLoadStoreLeftRight },
|
||||
true,
|
||||
},
|
||||
{
|
||||
// The sp accesses share one validation, but not across something that may change sp.
|
||||
"ValidateSPAcrossInterpret",
|
||||
{
|
||||
{ IROp::Load32, { MIPS_REG_A0 }, MIPS_REG_SP, 0, 0 },
|
||||
{ IROp::Interpret, { 0 }, 0, 0, 0 },
|
||||
{ IROp::Load32, { MIPS_REG_A1 }, MIPS_REG_SP, 0, 8 },
|
||||
},
|
||||
{
|
||||
{ IROp::ValidateAddress32, { 0 }, MIPS_REG_SP, 0, 0 },
|
||||
{ IROp::Load32, { MIPS_REG_A0 }, MIPS_REG_SP, 0, 0 },
|
||||
{ IROp::Interpret, { 0 }, 0, 0, 0 },
|
||||
{ IROp::ValidateAddress32, { 0 }, MIPS_REG_SP, 0, 8 },
|
||||
{ IROp::Load32, { MIPS_REG_A1 }, MIPS_REG_SP, 0, 8 },
|
||||
},
|
||||
{ &ApplyMemoryValidation },
|
||||
false,
|
||||
true,
|
||||
},
|
||||
};
|
||||
|
||||
bool TestIRPassSimplify() {
|
||||
|
||||
Reference in new issue
Block a user