mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-24 16:49:50 +00:00
Use the regcache in a new (incomplete) pass, PropagateConstants.
This commit is contained in:
parent
a33f8b68c6
commit
09969c0156
@ -61,12 +61,7 @@ void IRJit::Comp_IType(MIPSOpcode op) {
|
||||
switch (op >> 26) {
|
||||
case 8: // same as addiu?
|
||||
case 9: // R(rt) = R(rs) + simm; break; //addiu
|
||||
// Special-case for small adjustments of pointerified registers. Commonly for SP but happens for others.
|
||||
if (simm >= 0) {
|
||||
ir.Write(IROp::AddConst, rt, rs, ir.AddConstant(simm));
|
||||
} else if (simm < 0) {
|
||||
ir.Write(IROp::SubConst, rt, rs, ir.AddConstant(-simm));
|
||||
}
|
||||
ir.Write(IROp::AddConst, rt, rs, ir.AddConstant(simm));
|
||||
break;
|
||||
|
||||
case 12: ir.Write(IROp::AndConst, rt, rs, ir.AddConstant(uimm)); break;
|
||||
|
@ -121,6 +121,7 @@ void IRJit::Comp_FPUComp(MIPSOpcode op) {
|
||||
|
||||
void IRJit::Comp_FPU2op(MIPSOpcode op) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
int fs = _FS;
|
||||
int fd = _FD;
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "math/math_util.h"
|
||||
|
||||
static const IRMeta irMeta[] = {
|
||||
{ IROp::SetConst, "SetConst", "GC_" },
|
||||
{ IROp::SetConst, "SetConst", "GC" },
|
||||
{ IROp::Mov, "Mov", "GG" },
|
||||
{ IROp::Add, "Add", "GGG" },
|
||||
{ IROp::Sub, "Sub", "GGG" },
|
||||
@ -81,7 +81,7 @@ static const IRMeta irMeta[] = {
|
||||
{ IROp::FMovFromGPR, "FMovFromGPR", "FG" },
|
||||
{ IROp::FMovToGPR, "FMovToGPR", "GF" },
|
||||
{ IROp::FpCondToReg, "FpCondToReg", "G" },
|
||||
{ IROp::SetCtrlVFPU, "SetCtrlVFPU", "T" },
|
||||
{ IROp::SetCtrlVFPU, "SetCtrlVFPU", "TC" },
|
||||
{ IROp::Interpret, "Interpret", "_C" },
|
||||
{ IROp::Downcount, "Downcount", "_II" },
|
||||
{ IROp::ExitToConst, "Exit", "C" },
|
||||
@ -94,7 +94,9 @@ static const IRMeta irMeta[] = {
|
||||
{ IROp::ExitToReg, "ExitToReg", "G" },
|
||||
{ IROp::Syscall, "Syscall", "_C" },
|
||||
{ IROp::Break, "Break", ""},
|
||||
{ IROp::SetPC, "SetPC", "_G"},
|
||||
{ IROp::SetPC, "SetPC", "_G" },
|
||||
{ IROp::SetPCConst, "SetPC", "_C" },
|
||||
{ IROp::CallReplacement, "CallRepl", "_C"},
|
||||
};
|
||||
|
||||
const IRMeta *metaIndex[256];
|
||||
@ -454,6 +456,10 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
|
||||
Crash();
|
||||
break;
|
||||
|
||||
case IROp::SetCtrlVFPU:
|
||||
mips->vfpuCtrl[inst->dest] = constPool[inst->src1];
|
||||
break;
|
||||
|
||||
default:
|
||||
Crash();
|
||||
}
|
||||
@ -498,7 +504,7 @@ int IRWriter::AddConstantFloat(float value) {
|
||||
}
|
||||
|
||||
void IRWriter::Simplify() {
|
||||
SimplifyInPlace(&insts_[0], insts_.size(), constPool_.data());
|
||||
SimplifyInPlace(&insts_[0], (int)insts_.size(), constPool_.data());
|
||||
}
|
||||
|
||||
const char *GetGPRName(int r) {
|
||||
@ -536,8 +542,12 @@ void DisassembleParam(char *buf, int bufSize, u8 param, char type, const u32 *co
|
||||
}
|
||||
}
|
||||
|
||||
const IRMeta *GetIRMeta(IROp op) {
|
||||
return metaIndex[(int)op];
|
||||
}
|
||||
|
||||
void DisassembleIR(char *buf, size_t bufsize, IRInst inst, const u32 *constPool) {
|
||||
const IRMeta *meta = metaIndex[(int)inst.op];
|
||||
const IRMeta *meta = GetIRMeta(inst.op);
|
||||
if (!meta) {
|
||||
snprintf(buf, bufsize, "Unknown %d", (int)inst.op);
|
||||
return;
|
||||
|
@ -249,6 +249,9 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
|
||||
class IRWriter {
|
||||
public:
|
||||
void Write(IROp op, u8 dst = 0, u8 src1 = 0, u8 src2 = 0);
|
||||
void Write(IRInst inst) {
|
||||
insts_.push_back(inst);
|
||||
}
|
||||
void WriteSetConstant(u8 dst, u32 value);
|
||||
|
||||
int AddConstant(u32 value);
|
||||
@ -261,13 +264,14 @@ public:
|
||||
|
||||
void Simplify();
|
||||
|
||||
const std::vector<IRInst> &GetInstructions() { return insts_; }
|
||||
const std::vector<u32> &GetConstants() { return constPool_; }
|
||||
const std::vector<IRInst> &GetInstructions() const { return insts_; }
|
||||
const std::vector<u32> &GetConstants() const { return constPool_; }
|
||||
|
||||
private:
|
||||
std::vector<IRInst> insts_;
|
||||
std::vector<u32> constPool_;
|
||||
};
|
||||
|
||||
const IRMeta *GetIRMeta(IROp op);
|
||||
void DisassembleIR(char *buf, size_t bufsize, IRInst inst, const u32 *constPool);
|
||||
void InitIR();
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/MIPS/IR/IRRegCache.h"
|
||||
#include "Core/MIPS/IR/IRJit.h"
|
||||
#include "Core/MIPS/IR/IRPassSimplify.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
|
||||
namespace MIPSComp
|
||||
@ -44,11 +45,11 @@ namespace MIPSComp
|
||||
IRJit::IRJit(MIPSState *mips) : mips_(mips) {
|
||||
logBlocks = 0;
|
||||
dontLogBlocks = 0;
|
||||
js.startDefaultPrefix = true;
|
||||
js.startDefaultPrefix = mips_->HasDefaultPrefix();
|
||||
js.currentRoundingFunc = convertS0ToSCRATCH1[0];
|
||||
u32 size = 128 * 1024;
|
||||
blTrampolines_ = kernelMemory.Alloc(size, true, "trampoline");
|
||||
logBlocks = 100;
|
||||
logBlocks = 12;
|
||||
InitIR();
|
||||
}
|
||||
|
||||
@ -88,8 +89,7 @@ void IRJit::DoDummyState(PointerWrap &p) {
|
||||
}
|
||||
|
||||
void IRJit::FlushAll() {
|
||||
// gpr.FlushAll();
|
||||
// FlushPrefixV();
|
||||
FlushPrefixV();
|
||||
}
|
||||
|
||||
void IRJit::FlushPrefixV() {
|
||||
@ -259,7 +259,15 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
|
||||
|
||||
ir.Simplify();
|
||||
|
||||
b->SetInstructions(ir.GetInstructions(), ir.GetConstants());
|
||||
IRWriter simplified;
|
||||
|
||||
IRWriter *code = &ir;
|
||||
if (true) {
|
||||
PropagateConstants(ir, simplified);
|
||||
code = &simplified;
|
||||
}
|
||||
|
||||
b->SetInstructions(code->GetInstructions(), code->GetConstants());
|
||||
|
||||
if (logBlocks > 0 && dontLogBlocks == 0) {
|
||||
char temp2[256];
|
||||
@ -272,7 +280,7 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
|
||||
}
|
||||
|
||||
if (logBlocks > 0 && dontLogBlocks == 0) {
|
||||
ILOG("=============== IR (%d instructions) ===============", js.numInstructions);
|
||||
ILOG("=============== Original IR (%d instructions) ===============", (int)ir.GetInstructions().size());
|
||||
for (int i = 0; i < ir.GetInstructions().size(); i++) {
|
||||
char buf[256];
|
||||
DisassembleIR(buf, sizeof(buf), ir.GetInstructions()[i], ir.GetConstants().data());
|
||||
@ -281,6 +289,16 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
|
||||
ILOG("=============== end =================");
|
||||
}
|
||||
|
||||
if (logBlocks > 0 && dontLogBlocks == 0) {
|
||||
ILOG("=============== IR (%d instructions) ===============", (int)code->GetInstructions().size());
|
||||
for (int i = 0; i < code->GetInstructions().size(); i++) {
|
||||
char buf[256];
|
||||
DisassembleIR(buf, sizeof(buf), code->GetInstructions()[i], code->GetConstants().data());
|
||||
ILOG("%s", buf);
|
||||
}
|
||||
ILOG("=============== end =================");
|
||||
}
|
||||
|
||||
if (logBlocks > 0)
|
||||
logBlocks--;
|
||||
if (dontLogBlocks > 0)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "Core/MIPS/IR/IRPassSimplify.h"
|
||||
#include "Core/MIPS/IR/IRRegCache.h"
|
||||
|
||||
void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
@ -15,4 +16,143 @@ void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 Evaluate(u32 a, u32 b, IROp op) {
|
||||
switch (op) {
|
||||
case IROp::Add: case IROp::AddConst: return a + b;
|
||||
case IROp::Sub: case IROp::SubConst: return a - b;
|
||||
case IROp::And: case IROp::AndConst: return a & b;
|
||||
case IROp::Or: case IROp::OrConst: return a | b;
|
||||
case IROp::Xor: case IROp::XorConst: return a ^ b;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
IROp ArithToArithConst(IROp op) {
|
||||
switch (op) {
|
||||
case IROp::Add: return IROp::AddConst;
|
||||
case IROp::Sub: return IROp::SubConst;
|
||||
case IROp::And: return IROp::AndConst;
|
||||
case IROp::Or: return IROp::OrConst;
|
||||
case IROp::Xor: return IROp::XorConst;
|
||||
default:
|
||||
return (IROp)-1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||
IRRegCache gpr(&out);
|
||||
|
||||
const u32 *constants = in.GetConstants().data();
|
||||
for (int i = 0; i < (int)in.GetInstructions().size(); i++) {
|
||||
IRInst inst = in.GetInstructions()[i];
|
||||
bool symmetric = true;
|
||||
switch (inst.op) {
|
||||
case IROp::SetConst:
|
||||
gpr.SetImm((MIPSGPReg)inst.dest, constants[inst.src1]);
|
||||
break;
|
||||
|
||||
case IROp::Sub:
|
||||
symmetric = false; // fallthrough
|
||||
case IROp::Add:
|
||||
case IROp::And:
|
||||
case IROp::Or:
|
||||
case IROp::Xor:
|
||||
if (gpr.IsImm(inst.src1) && gpr.IsImm(inst.src2)) {
|
||||
gpr.SetImm(inst.dest, Evaluate(gpr.GetImm(inst.src1), gpr.GetImm(inst.src2), inst.op));
|
||||
} else if (gpr.IsImm(inst.src2) && inst.src1 != inst.src2 && inst.dest != inst.src2) {
|
||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||
if (gpr.GetImm(inst.src2) == 0 && (inst.op == IROp::Add || inst.op == IROp::Or)) {
|
||||
out.Write(IROp::Mov, inst.dest, inst.src1);
|
||||
} else {
|
||||
out.Write(ArithToArithConst(inst.op), inst.dest, inst.src1, out.AddConstant(gpr.GetImm(inst.src2)));
|
||||
}
|
||||
} else if (gpr.IsImm(inst.src1) && inst.src1 != inst.src2 && inst.dest != inst.src2 && symmetric) {
|
||||
gpr.MapDirtyIn(inst.dest, inst.src2);
|
||||
out.Write(ArithToArithConst(inst.op), inst.dest, inst.src2, out.AddConstant(gpr.GetImm(inst.src1)));
|
||||
} else {
|
||||
gpr.MapDirtyInIn(inst.dest, inst.src1, inst.src2);
|
||||
goto doDefault;
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::AddConst:
|
||||
case IROp::SubConst:
|
||||
case IROp::AndConst:
|
||||
case IROp::OrConst:
|
||||
case IROp::XorConst:
|
||||
if (gpr.IsImm(inst.src1)) {
|
||||
gpr.SetImm(inst.dest, Evaluate(gpr.GetImm(inst.src1), constants[inst.src2], inst.op));
|
||||
} else {
|
||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||
goto doDefault;
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::Mov:
|
||||
if (inst.src1 == inst.src2) {
|
||||
// Nop
|
||||
} else if (gpr.IsImm(inst.src1)) {
|
||||
gpr.SetImm(inst.dest, gpr.GetImm(inst.src1));
|
||||
} else {
|
||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||
goto doDefault;
|
||||
}
|
||||
break;
|
||||
|
||||
case IROp::Store8:
|
||||
case IROp::Store16:
|
||||
case IROp::Store32:
|
||||
// Just pass through, no excessive flushing
|
||||
gpr.MapInIn(inst.dest, inst.src1);
|
||||
goto doDefault;
|
||||
|
||||
case IROp::Load8:
|
||||
case IROp::Load8Ext:
|
||||
case IROp::Load16:
|
||||
case IROp::Load16Ext:
|
||||
case IROp::Load32:
|
||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||
goto doDefault;
|
||||
|
||||
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:
|
||||
default:
|
||||
{
|
||||
gpr.FlushAll();
|
||||
doDefault:
|
||||
// Remap constants to the new reality
|
||||
const IRMeta *m = GetIRMeta(inst.op);
|
||||
switch (m->types[0]) {
|
||||
case 'C':
|
||||
inst.dest = out.AddConstant(constants[inst.dest]);
|
||||
break;
|
||||
}
|
||||
switch (m->types[1]) {
|
||||
case 'C':
|
||||
inst.src1 = out.AddConstant(constants[inst.src1]);
|
||||
break;
|
||||
}
|
||||
switch (m->types[2]) {
|
||||
case 'C':
|
||||
inst.src2 = out.AddConstant(constants[inst.src2]);
|
||||
break;
|
||||
}
|
||||
out.Write(inst);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,3 +4,6 @@
|
||||
|
||||
// Dumb example of a simplification pass that can't add or remove instructions.
|
||||
void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool);
|
||||
|
||||
|
||||
void PropagateConstants(const IRWriter &in, IRWriter &out);
|
@ -1,7 +1,7 @@
|
||||
#include "Core/MIPS/IR/IRRegCache.h"
|
||||
#include "Core/MIPS/IR/IRInst.h"
|
||||
|
||||
void IRRegCache::Dirty(MIPSGPReg rd) {
|
||||
void IRRegCache::Flush(int rd) {
|
||||
if (rd == 0) {
|
||||
return;
|
||||
}
|
||||
@ -11,31 +11,14 @@ void IRRegCache::Dirty(MIPSGPReg rd) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRRegCache::MapIn(MIPSGPReg rd) {
|
||||
Dirty(rd);
|
||||
void IRRegCache::Discard(int rd) {
|
||||
if (rd == 0) {
|
||||
return;
|
||||
}
|
||||
reg_[rd].isImm = false;
|
||||
}
|
||||
|
||||
void IRRegCache::MapInIn(MIPSGPReg rs, MIPSGPReg rt) {
|
||||
Dirty(rs);
|
||||
Dirty(rt);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirty(MIPSGPReg rd) {
|
||||
Dirty(rd);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirtyIn(MIPSGPReg rd, MIPSGPReg rs) {
|
||||
Dirty(rd);
|
||||
Dirty(rs);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirtyInIn(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt) {
|
||||
Dirty(rd);
|
||||
Dirty(rs);
|
||||
Dirty(rt);
|
||||
}
|
||||
|
||||
void IRRegCache::Start(IRWriter *ir) {
|
||||
IRRegCache::IRRegCache(IRWriter *ir) : ir_(ir) {
|
||||
memset(®_, 0, sizeof(reg_));
|
||||
reg_[0].isImm = true;
|
||||
ir_ = ir;
|
||||
@ -43,6 +26,27 @@ void IRRegCache::Start(IRWriter *ir) {
|
||||
|
||||
void IRRegCache::FlushAll() {
|
||||
for (int i = 0; i < TOTAL_MAPPABLE_MIPSREGS; i++) {
|
||||
Dirty((MIPSGPReg)i);
|
||||
Flush(i);
|
||||
}
|
||||
}
|
||||
|
||||
void IRRegCache::MapInIn(int rs, int rt) {
|
||||
Flush(rs);
|
||||
Flush(rt);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirtyIn(int rd, int rs) {
|
||||
if (rs != rd) {
|
||||
Discard(rd);
|
||||
}
|
||||
Flush(rs);
|
||||
}
|
||||
|
||||
void IRRegCache::MapDirtyInIn(int rd, int rs, int rt) {
|
||||
if (rs != rd && rt != rd) {
|
||||
Discard(rd);
|
||||
}
|
||||
Flush(rs);
|
||||
Flush(rt);
|
||||
}
|
||||
|
||||
|
@ -17,27 +17,28 @@ struct RegIR {
|
||||
|
||||
class IRWriter;
|
||||
|
||||
// Transient
|
||||
class IRRegCache {
|
||||
public:
|
||||
void SetImm(MIPSGPReg r, u32 immVal) {
|
||||
IRRegCache(IRWriter *ir);
|
||||
|
||||
void SetImm(int r, u32 immVal) {
|
||||
reg_[r].isImm = true;
|
||||
reg_[r].immVal = immVal;
|
||||
}
|
||||
|
||||
bool IsImm(MIPSGPReg r) const { return reg_[r].isImm; }
|
||||
u32 GetImm(MIPSGPReg r) const { return reg_[r].immVal; }
|
||||
bool IsImm(int r) const { return reg_[r].isImm; }
|
||||
u32 GetImm(int r) const { return reg_[r].immVal; }
|
||||
|
||||
void MapIn(MIPSGPReg rd);
|
||||
void MapInIn(MIPSGPReg rs, MIPSGPReg rt);
|
||||
void MapDirty(MIPSGPReg rd);
|
||||
void MapDirtyIn(MIPSGPReg rd, MIPSGPReg rs);
|
||||
void MapDirtyInIn(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt);
|
||||
|
||||
void Start(IRWriter *ir);
|
||||
void FlushAll();
|
||||
|
||||
void MapInIn(int rs, int rt);
|
||||
void MapDirtyIn(int rd, int rs);
|
||||
void MapDirtyInIn(int rd, int rs, int rt);
|
||||
|
||||
private:
|
||||
void Dirty(MIPSGPReg rd);
|
||||
void Flush(int rd);
|
||||
void Discard(int rd);
|
||||
RegIR reg_[TOTAL_MAPPABLE_MIPSREGS];
|
||||
IRWriter *ir_;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user