Skip to content

Commit

Permalink
Merge pull request #17874 from unknownbrackets/irjit-exits
Browse files Browse the repository at this point in the history
IR: Simplify exits to ExitToConst when viable
  • Loading branch information
hrydgard committed Aug 9, 2023
2 parents 6758675 + 31ff237 commit bac4e8d
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 22 deletions.
77 changes: 68 additions & 9 deletions Core/MIPS/IR/IRPassSimplify.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
20 changes: 10 additions & 10 deletions Core/MIPS/IR/IRRegCache.cpp
Expand Up @@ -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;
}
Expand All @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions Core/MIPS/IR/IRRegCache.h
@@ -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"
Expand All @@ -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;
Expand Down

0 comments on commit bac4e8d

Please sign in to comment.