mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Add new IR optimization pass, OptimizeLoadsAfterStores
This commit is contained in:
parent
da88011805
commit
bd0beb68a4
@ -284,6 +284,7 @@ void IRFrontend::DoJit(u32 em_address, std::vector<IRInst> &instructions, u32 &m
|
||||
&PropagateConstants,
|
||||
&PurgeTemps,
|
||||
&ReduceVec4Flush,
|
||||
&OptimizeLoadsAfterStores,
|
||||
// &ReorderLoadStore,
|
||||
// &MergeLoadStore,
|
||||
// &ThreeOpToTwoOp,
|
||||
|
@ -255,15 +255,19 @@ void IRJit::RunLoopUntil(u64 globalticks) {
|
||||
u32 opcode = inst & 0xFF000000;
|
||||
if (opcode == MIPS_EMUHACK_OPCODE) {
|
||||
u32 offset = inst & 0x00FFFFFF; // Alternatively, inst - opcode
|
||||
const IRInst *instPtr = blocks_.GetArenaPtr() + offset;
|
||||
_dbg_assert_(instPtr->op == IROp::Downcount);
|
||||
mips->downcount -= instPtr->constant;
|
||||
instPtr++;
|
||||
#ifdef IR_PROFILING
|
||||
IRBlock *block = blocks_.GetBlock(blocks_.GetBlockNumFromOffset(offset));
|
||||
TimeSpan span;
|
||||
mips->pc = IRInterpret(mips, blocks_.GetArenaPtr() + offset);
|
||||
mips->pc = IRInterpret(mips, instPtr);
|
||||
int64_t elapsedNanos = span.ElapsedNanos();
|
||||
block->profileStats_.executions += 1;
|
||||
block->profileStats_.totalNanos += elapsedNanos;
|
||||
#else
|
||||
mips->pc = IRInterpret(mips, blocks_.GetArenaPtr() + offset);
|
||||
mips->pc = IRInterpret(mips, instPtr);
|
||||
#endif
|
||||
// Note: this will "jump to zero" on a badly constructed block missing exits.
|
||||
if (!Memory::IsValid4AlignedAddress(mips->pc)) {
|
||||
|
@ -2150,6 +2150,45 @@ bool ReduceVec4Flush(const IRWriter &in, IRWriter &out, const IROptions &opts) {
|
||||
return logBlocks;
|
||||
}
|
||||
|
||||
// This optimizes away redundant loads-after-stores, which are surprisingly not that uncommon.
|
||||
bool OptimizeLoadsAfterStores(const IRWriter &in, IRWriter &out, const IROptions &opts) {
|
||||
CONDITIONAL_DISABLE;
|
||||
// This tells us to skip an AND op that has been optimized out.
|
||||
// Maybe we could skip multiple, but that'd slow things down and is pretty uncommon.
|
||||
int nextSkip = -1;
|
||||
|
||||
bool logBlocks = false;
|
||||
for (int i = 0, n = (int)in.GetInstructions().size(); i < n; i++) {
|
||||
IRInst inst = in.GetInstructions()[i];
|
||||
|
||||
// Just copy the last instruction.
|
||||
if (i == n - 1) {
|
||||
out.Write(inst);
|
||||
break;
|
||||
}
|
||||
|
||||
out.Write(inst);
|
||||
|
||||
IRInst next = in.GetInstructions()[i + 1];
|
||||
switch (inst.op) {
|
||||
case IROp::Store32:
|
||||
if (next.op == IROp::Load32 &&
|
||||
next.constant == inst.constant &&
|
||||
next.dest == inst.src3 &&
|
||||
next.src1 == inst.src1) {
|
||||
// The upcoming load is completely redundant.
|
||||
// Skip it.
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return logBlocks;
|
||||
}
|
||||
|
||||
bool OptimizeForInterpreter(const IRWriter &in, IRWriter &out, const IROptions &opts) {
|
||||
CONDITIONAL_DISABLE;
|
||||
// This tells us to skip an AND op that has been optimized out.
|
||||
|
@ -17,4 +17,5 @@ bool MergeLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts);
|
||||
bool ApplyMemoryValidation(const IRWriter &in, IRWriter &out, const IROptions &opts);
|
||||
bool ReduceVec4Flush(const IRWriter &in, IRWriter &out, const IROptions &opts);
|
||||
|
||||
bool OptimizeLoadsAfterStores(const IRWriter &in, IRWriter &out, const IROptions &opts);
|
||||
bool OptimizeForInterpreter(const IRWriter &in, IRWriter &out, const IROptions &opts);
|
||||
|
Loading…
Reference in New Issue
Block a user