Merge pull request #17874 from unknownbrackets/irjit-exits

IR: Simplify exits to ExitToConst when viable
This commit is contained in:
Henrik Rydgård 2023-08-09 09:11:52 +02:00 committed by GitHub
commit bac4e8d42d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 22 deletions

View File

@ -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:

View File

@ -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(&reg_, 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);
}

View File

@ -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;