mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-30 08:50:33 +00:00
Merge pull request #17874 from unknownbrackets/irjit-exits
IR: Simplify exits to ExitToConst when viable
This commit is contained in:
commit
bac4e8d42d
@ -418,9 +418,10 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions
|
||||
|
||||
bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts) {
|
||||
CONDITIONAL_DISABLE;
|
||||
IRRegCache gpr(&out);
|
||||
IRImmRegCache gpr(&out);
|
||||
|
||||
bool logBlocks = false;
|
||||
bool skipNextExitToConst = false;
|
||||
for (int i = 0; i < (int)in.GetInstructions().size(); i++) {
|
||||
IRInst inst = in.GetInstructions()[i];
|
||||
bool symmetric = true;
|
||||
@ -804,20 +805,78 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts
|
||||
gpr.MapDirtyIn(IRREG_VFPU_CC, IRREG_VFPU_CC);
|
||||
goto doDefault;
|
||||
|
||||
case IROp::ExitToConstIfEq:
|
||||
case IROp::ExitToConstIfNeq:
|
||||
if (gpr.IsImm(inst.src1) && gpr.IsImm(inst.src2)) {
|
||||
bool passed = false;
|
||||
switch (inst.op) {
|
||||
case IROp::ExitToConstIfEq: passed = gpr.GetImm(inst.src1) == gpr.GetImm(inst.src2); break;
|
||||
case IROp::ExitToConstIfNeq: passed = gpr.GetImm(inst.src1) != gpr.GetImm(inst.src2); break;
|
||||
default: _assert_(false); break;
|
||||
}
|
||||
|
||||
// This is a bit common for the first cycle of loops.
|
||||
// Reduce bloat by skipping on fail, and const exit on pass.
|
||||
if (passed) {
|
||||
gpr.FlushAll();
|
||||
out.Write(IROp::ExitToConst, out.AddConstant(inst.constant));
|
||||
skipNextExitToConst = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
gpr.FlushAll();
|
||||
goto doDefault;
|
||||
|
||||
case IROp::ExitToConstIfGtZ:
|
||||
case IROp::ExitToConstIfGeZ:
|
||||
case IROp::ExitToConstIfLtZ:
|
||||
case IROp::ExitToConstIfLeZ:
|
||||
if (gpr.IsImm(inst.src1)) {
|
||||
bool passed = false;
|
||||
switch (inst.op) {
|
||||
case IROp::ExitToConstIfGtZ: passed = (s32)gpr.GetImm(inst.src1) > 0; break;
|
||||
case IROp::ExitToConstIfGeZ: passed = (s32)gpr.GetImm(inst.src1) >= 0; break;
|
||||
case IROp::ExitToConstIfLtZ: passed = (s32)gpr.GetImm(inst.src1) < 0; break;
|
||||
case IROp::ExitToConstIfLeZ: passed = (s32)gpr.GetImm(inst.src1) <= 0; break;
|
||||
default: _assert_(false); break;
|
||||
}
|
||||
|
||||
if (passed) {
|
||||
gpr.FlushAll();
|
||||
out.Write(IROp::ExitToConst, out.AddConstant(inst.constant));
|
||||
skipNextExitToConst = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
gpr.FlushAll();
|
||||
goto doDefault;
|
||||
|
||||
case IROp::ExitToConst:
|
||||
if (skipNextExitToConst) {
|
||||
skipNextExitToConst = false;
|
||||
break;
|
||||
}
|
||||
gpr.FlushAll();
|
||||
goto doDefault;
|
||||
|
||||
case IROp::ExitToReg:
|
||||
if (gpr.IsImm(inst.src1)) {
|
||||
// This happens sometimes near loops.
|
||||
// Prefer ExitToConst to allow block linking.
|
||||
u32 dest = gpr.GetImm(inst.src1);
|
||||
gpr.FlushAll();
|
||||
out.Write(IROp::ExitToConst, out.AddConstant(dest));
|
||||
break;
|
||||
}
|
||||
gpr.FlushAll();
|
||||
goto doDefault;
|
||||
|
||||
case IROp::CallReplacement:
|
||||
case IROp::Break:
|
||||
case IROp::Syscall:
|
||||
case IROp::Interpret:
|
||||
case IROp::ExitToConst:
|
||||
case IROp::ExitToReg:
|
||||
case IROp::ExitToConstIfEq:
|
||||
case IROp::ExitToConstIfNeq:
|
||||
case IROp::ExitToConstIfFpFalse:
|
||||
case IROp::ExitToConstIfFpTrue:
|
||||
case IROp::ExitToConstIfGeZ:
|
||||
case IROp::ExitToConstIfGtZ:
|
||||
case IROp::ExitToConstIfLeZ:
|
||||
case IROp::ExitToConstIfLtZ:
|
||||
case IROp::Breakpoint:
|
||||
case IROp::MemoryCheck:
|
||||
default:
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "Core/MIPS/IR/IRRegCache.h"
|
||||
#include "Core/MIPS/IR/IRInst.h"
|
||||
|
||||
void IRRegCache::Flush(IRReg rd) {
|
||||
void IRImmRegCache::Flush(IRReg rd) {
|
||||
if (rd == 0) {
|
||||
return;
|
||||
}
|
||||
@ -14,52 +14,52 @@ void IRRegCache::Flush(IRReg rd) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRRegCache::Discard(IRReg rd) {
|
||||
void IRImmRegCache::Discard(IRReg rd) {
|
||||
if (rd == 0) {
|
||||
return;
|
||||
}
|
||||
reg_[rd].isImm = false;
|
||||
}
|
||||
|
||||
IRRegCache::IRRegCache(IRWriter *ir) : ir_(ir) {
|
||||
IRImmRegCache::IRImmRegCache(IRWriter *ir) : ir_(ir) {
|
||||
memset(®_, 0, sizeof(reg_));
|
||||
reg_[0].isImm = true;
|
||||
ir_ = ir;
|
||||
}
|
||||
|
||||
void IRRegCache::FlushAll() {
|
||||
void IRImmRegCache::FlushAll() {
|
||||
for (int i = 0; i < TOTAL_MAPPABLE_MIPSREGS; i++) {
|
||||
Flush(i);
|
||||
}
|
||||
}
|
||||
|
||||
void IRRegCache::MapIn(IRReg rd) {
|
||||
void IRImmRegCache::MapIn(IRReg rd) {
|
||||
Flush(rd);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirty(IRReg rd) {
|
||||
void IRImmRegCache::MapDirty(IRReg rd) {
|
||||
Discard(rd);
|
||||
}
|
||||
|
||||
void IRRegCache::MapInIn(IRReg rs, IRReg rt) {
|
||||
void IRImmRegCache::MapInIn(IRReg rs, IRReg rt) {
|
||||
Flush(rs);
|
||||
Flush(rt);
|
||||
}
|
||||
|
||||
void IRRegCache::MapInInIn(IRReg rd, IRReg rs, IRReg rt) {
|
||||
void IRImmRegCache::MapInInIn(IRReg rd, IRReg rs, IRReg rt) {
|
||||
Flush(rd);
|
||||
Flush(rs);
|
||||
Flush(rt);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirtyIn(IRReg rd, IRReg rs) {
|
||||
void IRImmRegCache::MapDirtyIn(IRReg rd, IRReg rs) {
|
||||
if (rs != rd) {
|
||||
Discard(rd);
|
||||
}
|
||||
Flush(rs);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt) {
|
||||
void IRImmRegCache::MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt) {
|
||||
if (rs != rd && rt != rd) {
|
||||
Discard(rd);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// IRRegCache is only to perform pre-constant folding. This is worth it to get cleaner
|
||||
// IRImmRegCache is only to perform pre-constant folding. This is worth it to get cleaner
|
||||
// IR.
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
@ -19,9 +19,9 @@ struct RegIR {
|
||||
class IRWriter;
|
||||
|
||||
// Transient
|
||||
class IRRegCache {
|
||||
class IRImmRegCache {
|
||||
public:
|
||||
IRRegCache(IRWriter *ir);
|
||||
IRImmRegCache(IRWriter *ir);
|
||||
|
||||
void SetImm(IRReg r, u32 immVal) {
|
||||
reg_[r].isImm = true;
|
||||
|
Loading…
Reference in New Issue
Block a user