Use the regcache in a new (incomplete) pass, PropagateConstants.

This commit is contained in:
Henrik Rydgard 2016-05-08 01:06:07 +02:00
parent a33f8b68c6
commit 09969c0156
9 changed files with 231 additions and 55 deletions

View File

@ -61,12 +61,7 @@ void IRJit::Comp_IType(MIPSOpcode op) {
switch (op >> 26) { switch (op >> 26) {
case 8: // same as addiu? case 8: // same as addiu?
case 9: // R(rt) = R(rs) + simm; break; //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. ir.Write(IROp::AddConst, rt, rs, ir.AddConstant(simm));
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));
}
break; break;
case 12: ir.Write(IROp::AndConst, rt, rs, ir.AddConstant(uimm)); break; case 12: ir.Write(IROp::AndConst, rt, rs, ir.AddConstant(uimm)); break;

View File

@ -121,6 +121,7 @@ void IRJit::Comp_FPUComp(MIPSOpcode op) {
void IRJit::Comp_FPU2op(MIPSOpcode op) { void IRJit::Comp_FPU2op(MIPSOpcode op) {
CONDITIONAL_DISABLE; CONDITIONAL_DISABLE;
int fs = _FS; int fs = _FS;
int fd = _FD; int fd = _FD;

View File

@ -9,7 +9,7 @@
#include "math/math_util.h" #include "math/math_util.h"
static const IRMeta irMeta[] = { static const IRMeta irMeta[] = {
{ IROp::SetConst, "SetConst", "GC_" }, { IROp::SetConst, "SetConst", "GC" },
{ IROp::Mov, "Mov", "GG" }, { IROp::Mov, "Mov", "GG" },
{ IROp::Add, "Add", "GGG" }, { IROp::Add, "Add", "GGG" },
{ IROp::Sub, "Sub", "GGG" }, { IROp::Sub, "Sub", "GGG" },
@ -81,7 +81,7 @@ static const IRMeta irMeta[] = {
{ IROp::FMovFromGPR, "FMovFromGPR", "FG" }, { IROp::FMovFromGPR, "FMovFromGPR", "FG" },
{ IROp::FMovToGPR, "FMovToGPR", "GF" }, { IROp::FMovToGPR, "FMovToGPR", "GF" },
{ IROp::FpCondToReg, "FpCondToReg", "G" }, { IROp::FpCondToReg, "FpCondToReg", "G" },
{ IROp::SetCtrlVFPU, "SetCtrlVFPU", "T" }, { IROp::SetCtrlVFPU, "SetCtrlVFPU", "TC" },
{ IROp::Interpret, "Interpret", "_C" }, { IROp::Interpret, "Interpret", "_C" },
{ IROp::Downcount, "Downcount", "_II" }, { IROp::Downcount, "Downcount", "_II" },
{ IROp::ExitToConst, "Exit", "C" }, { IROp::ExitToConst, "Exit", "C" },
@ -94,7 +94,9 @@ static const IRMeta irMeta[] = {
{ IROp::ExitToReg, "ExitToReg", "G" }, { IROp::ExitToReg, "ExitToReg", "G" },
{ IROp::Syscall, "Syscall", "_C" }, { IROp::Syscall, "Syscall", "_C" },
{ IROp::Break, "Break", ""}, { IROp::Break, "Break", ""},
{ IROp::SetPC, "SetPC", "_G"}, { IROp::SetPC, "SetPC", "_G" },
{ IROp::SetPCConst, "SetPC", "_C" },
{ IROp::CallReplacement, "CallRepl", "_C"},
}; };
const IRMeta *metaIndex[256]; const IRMeta *metaIndex[256];
@ -454,6 +456,10 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
Crash(); Crash();
break; break;
case IROp::SetCtrlVFPU:
mips->vfpuCtrl[inst->dest] = constPool[inst->src1];
break;
default: default:
Crash(); Crash();
} }
@ -498,7 +504,7 @@ int IRWriter::AddConstantFloat(float value) {
} }
void IRWriter::Simplify() { void IRWriter::Simplify() {
SimplifyInPlace(&insts_[0], insts_.size(), constPool_.data()); SimplifyInPlace(&insts_[0], (int)insts_.size(), constPool_.data());
} }
const char *GetGPRName(int r) { 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) { 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) { if (!meta) {
snprintf(buf, bufsize, "Unknown %d", (int)inst.op); snprintf(buf, bufsize, "Unknown %d", (int)inst.op);
return; return;

View File

@ -249,6 +249,9 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
class IRWriter { class IRWriter {
public: public:
void Write(IROp op, u8 dst = 0, u8 src1 = 0, u8 src2 = 0); 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); void WriteSetConstant(u8 dst, u32 value);
int AddConstant(u32 value); int AddConstant(u32 value);
@ -261,13 +264,14 @@ public:
void Simplify(); void Simplify();
const std::vector<IRInst> &GetInstructions() { return insts_; } const std::vector<IRInst> &GetInstructions() const { return insts_; }
const std::vector<u32> &GetConstants() { return constPool_; } const std::vector<u32> &GetConstants() const { return constPool_; }
private: private:
std::vector<IRInst> insts_; std::vector<IRInst> insts_;
std::vector<u32> constPool_; std::vector<u32> constPool_;
}; };
const IRMeta *GetIRMeta(IROp op);
void DisassembleIR(char *buf, size_t bufsize, IRInst inst, const u32 *constPool); void DisassembleIR(char *buf, size_t bufsize, IRInst inst, const u32 *constPool);
void InitIR(); void InitIR();

View File

@ -36,6 +36,7 @@
#include "Core/HLE/sceKernelMemory.h" #include "Core/HLE/sceKernelMemory.h"
#include "Core/MIPS/IR/IRRegCache.h" #include "Core/MIPS/IR/IRRegCache.h"
#include "Core/MIPS/IR/IRJit.h" #include "Core/MIPS/IR/IRJit.h"
#include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/MIPS/JitCommon/JitCommon.h"
namespace MIPSComp namespace MIPSComp
@ -44,11 +45,11 @@ namespace MIPSComp
IRJit::IRJit(MIPSState *mips) : mips_(mips) { IRJit::IRJit(MIPSState *mips) : mips_(mips) {
logBlocks = 0; logBlocks = 0;
dontLogBlocks = 0; dontLogBlocks = 0;
js.startDefaultPrefix = true; js.startDefaultPrefix = mips_->HasDefaultPrefix();
js.currentRoundingFunc = convertS0ToSCRATCH1[0]; js.currentRoundingFunc = convertS0ToSCRATCH1[0];
u32 size = 128 * 1024; u32 size = 128 * 1024;
blTrampolines_ = kernelMemory.Alloc(size, true, "trampoline"); blTrampolines_ = kernelMemory.Alloc(size, true, "trampoline");
logBlocks = 100; logBlocks = 12;
InitIR(); InitIR();
} }
@ -88,8 +89,7 @@ void IRJit::DoDummyState(PointerWrap &p) {
} }
void IRJit::FlushAll() { void IRJit::FlushAll() {
// gpr.FlushAll(); FlushPrefixV();
// FlushPrefixV();
} }
void IRJit::FlushPrefixV() { void IRJit::FlushPrefixV() {
@ -259,7 +259,15 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
ir.Simplify(); 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) { if (logBlocks > 0 && dontLogBlocks == 0) {
char temp2[256]; char temp2[256];
@ -272,7 +280,7 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
} }
if (logBlocks > 0 && dontLogBlocks == 0) { 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++) { for (int i = 0; i < ir.GetInstructions().size(); i++) {
char buf[256]; char buf[256];
DisassembleIR(buf, sizeof(buf), ir.GetInstructions()[i], ir.GetConstants().data()); DisassembleIR(buf, sizeof(buf), ir.GetInstructions()[i], ir.GetConstants().data());
@ -281,6 +289,16 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
ILOG("=============== end ================="); 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) if (logBlocks > 0)
logBlocks--; logBlocks--;
if (dontLogBlocks > 0) if (dontLogBlocks > 0)

View File

@ -1,4 +1,5 @@
#include "Core/MIPS/IR/IRPassSimplify.h" #include "Core/MIPS/IR/IRPassSimplify.h"
#include "Core/MIPS/IR/IRRegCache.h"
void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool) { void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
@ -15,4 +16,143 @@ void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool) {
break; 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;
}
}
}
} }

View File

@ -4,3 +4,6 @@
// Dumb example of a simplification pass that can't add or remove instructions. // Dumb example of a simplification pass that can't add or remove instructions.
void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool); void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool);
void PropagateConstants(const IRWriter &in, IRWriter &out);

View File

@ -1,7 +1,7 @@
#include "Core/MIPS/IR/IRRegCache.h" #include "Core/MIPS/IR/IRRegCache.h"
#include "Core/MIPS/IR/IRInst.h" #include "Core/MIPS/IR/IRInst.h"
void IRRegCache::Dirty(MIPSGPReg rd) { void IRRegCache::Flush(int rd) {
if (rd == 0) { if (rd == 0) {
return; return;
} }
@ -11,31 +11,14 @@ void IRRegCache::Dirty(MIPSGPReg rd) {
} }
} }
void IRRegCache::MapIn(MIPSGPReg rd) { void IRRegCache::Discard(int rd) {
Dirty(rd); if (rd == 0) {
return;
}
reg_[rd].isImm = false;
} }
void IRRegCache::MapInIn(MIPSGPReg rs, MIPSGPReg rt) { IRRegCache::IRRegCache(IRWriter *ir) : ir_(ir) {
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) {
memset(&reg_, 0, sizeof(reg_)); memset(&reg_, 0, sizeof(reg_));
reg_[0].isImm = true; reg_[0].isImm = true;
ir_ = ir; ir_ = ir;
@ -43,6 +26,27 @@ void IRRegCache::Start(IRWriter *ir) {
void IRRegCache::FlushAll() { void IRRegCache::FlushAll() {
for (int i = 0; i < TOTAL_MAPPABLE_MIPSREGS; i++) { 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);
}

View File

@ -17,27 +17,28 @@ struct RegIR {
class IRWriter; class IRWriter;
// Transient
class IRRegCache { class IRRegCache {
public: public:
void SetImm(MIPSGPReg r, u32 immVal) { IRRegCache(IRWriter *ir);
void SetImm(int r, u32 immVal) {
reg_[r].isImm = true; reg_[r].isImm = true;
reg_[r].immVal = immVal; reg_[r].immVal = immVal;
} }
bool IsImm(MIPSGPReg r) const { return reg_[r].isImm; } bool IsImm(int r) const { return reg_[r].isImm; }
u32 GetImm(MIPSGPReg r) const { return reg_[r].immVal; } 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 FlushAll();
void MapInIn(int rs, int rt);
void MapDirtyIn(int rd, int rs);
void MapDirtyInIn(int rd, int rs, int rt);
private: private:
void Dirty(MIPSGPReg rd); void Flush(int rd);
void Discard(int rd);
RegIR reg_[TOTAL_MAPPABLE_MIPSREGS]; RegIR reg_[TOTAL_MAPPABLE_MIPSREGS];
IRWriter *ir_; IRWriter *ir_;
}; };