mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Fix IRTEMP clash bug. Add more cases to the constant propagation pass.
This commit is contained in:
parent
aae32bd929
commit
14df39d7c9
9 changed files with 94 additions and 29 deletions
|
@ -47,6 +47,7 @@ namespace MIPSComp {
|
||||||
|
|
||||||
void IRJit::Comp_IType(MIPSOpcode op) {
|
void IRJit::Comp_IType(MIPSOpcode op) {
|
||||||
CONDITIONAL_DISABLE;
|
CONDITIONAL_DISABLE;
|
||||||
|
|
||||||
s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension
|
s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension
|
||||||
u32 uimm = op & 0xFFFF;
|
u32 uimm = op & 0xFFFF;
|
||||||
u32 suimm = (u32)(s32)simm;
|
u32 suimm = (u32)(s32)simm;
|
||||||
|
@ -236,7 +237,7 @@ void IRJit::Comp_Special3(MIPSOpcode op) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (op & 0x3f) {
|
switch (op & 0x3f) {
|
||||||
case 0x0:
|
case 0x0: // ext
|
||||||
if (pos != 0) {
|
if (pos != 0) {
|
||||||
ir.Write(IROp::ShrImm, rt, rs, pos);
|
ir.Write(IROp::ShrImm, rt, rs, pos);
|
||||||
ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(mask));
|
ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(mask));
|
||||||
|
@ -247,17 +248,21 @@ void IRJit::Comp_Special3(MIPSOpcode op) {
|
||||||
|
|
||||||
case 0x4: //ins
|
case 0x4: //ins
|
||||||
{
|
{
|
||||||
|
logBlocks = 1;
|
||||||
u32 sourcemask = mask >> pos;
|
u32 sourcemask = mask >> pos;
|
||||||
u32 destmask = ~(sourcemask << pos);
|
u32 destmask = ~(sourcemask << pos);
|
||||||
ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(sourcemask));
|
ir.Write(IROp::AndConst, IRTEMP_0, rs, ir.AddConstant(sourcemask));
|
||||||
|
if (pos != 0) {
|
||||||
|
ir.Write(IROp::ShlImm, IRTEMP_0, IRTEMP_0, pos);
|
||||||
|
}
|
||||||
ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(destmask));
|
ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(destmask));
|
||||||
ir.Write(IROp::ShlImm, IRTEMP_0, IRTEMP_0, pos);
|
|
||||||
ir.Write(IROp::Or, rt, rt, IRTEMP_0);
|
ir.Write(IROp::Or, rt, rt, IRTEMP_0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IRJit::Comp_Allegrex(MIPSOpcode op) {
|
void IRJit::Comp_Allegrex(MIPSOpcode op) {
|
||||||
CONDITIONAL_DISABLE;
|
CONDITIONAL_DISABLE;
|
||||||
MIPSGPReg rt = _RT;
|
MIPSGPReg rt = _RT;
|
||||||
|
|
|
@ -73,12 +73,12 @@ void IRJit::BranchRSRTComp(MIPSOpcode op, IRComparison cc, bool likely)
|
||||||
MIPSGPReg rhs = rt;
|
MIPSGPReg rhs = rt;
|
||||||
if (!delaySlotIsNice) { // if likely, we don't need this
|
if (!delaySlotIsNice) { // if likely, we don't need this
|
||||||
if (rs != 0) {
|
if (rs != 0) {
|
||||||
ir.Write(IROp::Mov, IRTEMP_0, rs);
|
ir.Write(IROp::Mov, IRTEMP_LHS, rs);
|
||||||
lhs = (MIPSGPReg)IRTEMP_0;
|
lhs = (MIPSGPReg)IRTEMP_LHS;
|
||||||
}
|
}
|
||||||
if (rt != 0) {
|
if (rt != 0) {
|
||||||
ir.Write(IROp::Mov, IRTEMP_1, rt);
|
ir.Write(IROp::Mov, IRTEMP_RHS, rt);
|
||||||
rhs = (MIPSGPReg)IRTEMP_1;
|
rhs = (MIPSGPReg)IRTEMP_RHS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +113,8 @@ void IRJit::BranchRSZeroComp(MIPSOpcode op, IRComparison cc, bool andLink, bool
|
||||||
|
|
||||||
MIPSGPReg lhs = rs;
|
MIPSGPReg lhs = rs;
|
||||||
if (!delaySlotIsNice) { // if likely, we don't need this
|
if (!delaySlotIsNice) { // if likely, we don't need this
|
||||||
ir.Write(IROp::Mov, IRTEMP_0, rs);
|
ir.Write(IROp::Mov, IRTEMP_LHS, rs);
|
||||||
lhs = (MIPSGPReg)IRTEMP_0;
|
lhs = (MIPSGPReg)IRTEMP_LHS;
|
||||||
}
|
}
|
||||||
if (andLink)
|
if (andLink)
|
||||||
ir.WriteSetConstant(MIPS_REG_RA, GetCompilerPC() + 8);
|
ir.WriteSetConstant(MIPS_REG_RA, GetCompilerPC() + 8);
|
||||||
|
@ -179,7 +179,7 @@ void IRJit::BranchFPFlag(MIPSOpcode op, IRComparison cc, bool likely) {
|
||||||
u32 targetAddr = GetCompilerPC() + offset + 4;
|
u32 targetAddr = GetCompilerPC() + offset + 4;
|
||||||
|
|
||||||
MIPSOpcode delaySlotOp = GetOffsetInstruction(1);
|
MIPSOpcode delaySlotOp = GetOffsetInstruction(1);
|
||||||
ir.Write(IROp::FpCondToReg, IRTEMP_0);
|
ir.Write(IROp::FpCondToReg, IRTEMP_LHS);
|
||||||
if (!likely)
|
if (!likely)
|
||||||
CompileDelaySlot();
|
CompileDelaySlot();
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ void IRJit::BranchFPFlag(MIPSOpcode op, IRComparison cc, bool likely) {
|
||||||
|
|
||||||
FlushAll();
|
FlushAll();
|
||||||
// Not taken
|
// Not taken
|
||||||
ir.Write(ComparisonToExit(cc), ir.AddConstant(GetCompilerPC() + 8), IRTEMP_0, 0);
|
ir.Write(ComparisonToExit(cc), ir.AddConstant(GetCompilerPC() + 8), IRTEMP_LHS, 0);
|
||||||
// Taken
|
// Taken
|
||||||
if (likely)
|
if (likely)
|
||||||
CompileDelaySlot();
|
CompileDelaySlot();
|
||||||
|
@ -218,8 +218,8 @@ void IRJit::BranchVFPUFlag(MIPSOpcode op, IRComparison cc, bool likely) {
|
||||||
u32 targetAddr = GetCompilerPC() + offset + 4;
|
u32 targetAddr = GetCompilerPC() + offset + 4;
|
||||||
|
|
||||||
MIPSOpcode delaySlotOp = GetOffsetInstruction(1);
|
MIPSOpcode delaySlotOp = GetOffsetInstruction(1);
|
||||||
|
logBlocks = 1;
|
||||||
ir.Write(IROp::VfpuCtrlToReg, IRTEMP_0, VFPU_CTRL_CC);
|
ir.Write(IROp::VfpuCtrlToReg, IRTEMP_LHS, VFPU_CTRL_CC);
|
||||||
|
|
||||||
ir.Write(IROp::Downcount, 0, js.downcountAmount & 0xFF, js.downcountAmount >> 8);
|
ir.Write(IROp::Downcount, 0, js.downcountAmount & 0xFF, js.downcountAmount >> 8);
|
||||||
|
|
||||||
|
@ -237,9 +237,9 @@ void IRJit::BranchVFPUFlag(MIPSOpcode op, IRComparison cc, bool likely) {
|
||||||
|
|
||||||
u32 notTakenTarget = GetCompilerPC() + (delaySlotIsBranch ? 4 : 8);
|
u32 notTakenTarget = GetCompilerPC() + (delaySlotIsBranch ? 4 : 8);
|
||||||
|
|
||||||
ir.Write(IROp::AndConst, IRTEMP_0, IRTEMP_0, ir.AddConstant(1 << imm3));
|
ir.Write(IROp::AndConst, IRTEMP_LHS, IRTEMP_LHS, ir.AddConstant(1 << imm3));
|
||||||
FlushAll();
|
FlushAll();
|
||||||
ir.Write(ComparisonToExit(cc), ir.AddConstant(notTakenTarget), IRTEMP_0, 0);
|
ir.Write(ComparisonToExit(cc), ir.AddConstant(notTakenTarget), IRTEMP_LHS, 0);
|
||||||
|
|
||||||
if (likely)
|
if (likely)
|
||||||
CompileDelaySlot();
|
CompileDelaySlot();
|
||||||
|
@ -334,8 +334,8 @@ void IRJit::Comp_JumpReg(MIPSOpcode op) {
|
||||||
FlushAll();
|
FlushAll();
|
||||||
} else {
|
} else {
|
||||||
// Bad delay slot.
|
// Bad delay slot.
|
||||||
ir.Write(IROp::Mov, IRTEMP_0, rs);
|
ir.Write(IROp::Mov, IRTEMP_LHS, rs);
|
||||||
destReg = IRTEMP_0;
|
destReg = IRTEMP_LHS;
|
||||||
if (andLink)
|
if (andLink)
|
||||||
ir.WriteSetConstant(rd, GetCompilerPC() + 8);
|
ir.WriteSetConstant(rd, GetCompilerPC() + 8);
|
||||||
CompileDelaySlot();
|
CompileDelaySlot();
|
||||||
|
|
|
@ -478,6 +478,10 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c
|
||||||
default:
|
default:
|
||||||
Crash();
|
Crash();
|
||||||
}
|
}
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (mips->r[0] != 0)
|
||||||
|
Crash();
|
||||||
|
#endif
|
||||||
inst++;
|
inst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,6 +533,8 @@ const char *GetGPRName(int r) {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case IRTEMP_0: return "irtemp0";
|
case IRTEMP_0: return "irtemp0";
|
||||||
case IRTEMP_1: return "irtemp1";
|
case IRTEMP_1: return "irtemp1";
|
||||||
|
case IRTEMP_LHS: return "irtemp_lhs";
|
||||||
|
case IRTEMP_RHS: return "irtemp_rhs";
|
||||||
default: return "(unk)";
|
default: return "(unk)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,8 +204,8 @@ inline IROp ComparisonToExit(IRComparison comp) {
|
||||||
enum {
|
enum {
|
||||||
IRTEMP_0 = 192,
|
IRTEMP_0 = 192,
|
||||||
IRTEMP_1,
|
IRTEMP_1,
|
||||||
IRTEMP_2,
|
IRTEMP_LHS, // Reserved for use in branches
|
||||||
IRTEMP_3,
|
IRTEMP_RHS, // Reserved for use in branches
|
||||||
|
|
||||||
// Hacky way to get to other state
|
// Hacky way to get to other state
|
||||||
IRREG_LO = 226, // offset of lo in MIPSState / 4
|
IRREG_LO = 226, // offset of lo in MIPSState / 4
|
||||||
|
|
|
@ -269,7 +269,8 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) {
|
||||||
|
|
||||||
IRWriter *code = &ir;
|
IRWriter *code = &ir;
|
||||||
if (true) {
|
if (true) {
|
||||||
PropagateConstants(ir, simplified);
|
if (PropagateConstants(ir, simplified))
|
||||||
|
logBlocks = 1;
|
||||||
code = &simplified;
|
code = &simplified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,12 @@ u32 Evaluate(u32 a, u32 b, IROp op) {
|
||||||
case IROp::And: case IROp::AndConst: return a & b;
|
case IROp::And: case IROp::AndConst: return a & b;
|
||||||
case IROp::Or: case IROp::OrConst: return a | b;
|
case IROp::Or: case IROp::OrConst: return a | b;
|
||||||
case IROp::Xor: case IROp::XorConst: return a ^ b;
|
case IROp::Xor: case IROp::XorConst: return a ^ b;
|
||||||
|
case IROp::Shr: case IROp::ShrImm: return a >> b;
|
||||||
|
case IROp::Sar: case IROp::SarImm: return (s32)a >> b;
|
||||||
|
case IROp::Ror: case IROp::RorImm: return (a >> b) | (a << (32 - b));
|
||||||
|
case IROp::Shl: case IROp::ShlImm: return a << b;
|
||||||
|
case IROp::Slt: case IROp::SltConst: return ((s32)a < (s32)b);
|
||||||
|
case IROp::SltU: case IROp::SltUConst: return (a < b);
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -38,16 +44,19 @@ IROp ArithToArithConst(IROp op) {
|
||||||
case IROp::And: return IROp::AndConst;
|
case IROp::And: return IROp::AndConst;
|
||||||
case IROp::Or: return IROp::OrConst;
|
case IROp::Or: return IROp::OrConst;
|
||||||
case IROp::Xor: return IROp::XorConst;
|
case IROp::Xor: return IROp::XorConst;
|
||||||
|
case IROp::Slt: return IROp::SltConst;
|
||||||
|
case IROp::SltU: return IROp::SltUConst;
|
||||||
default:
|
default:
|
||||||
return (IROp)-1;
|
return (IROp)-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
bool PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||||
IRRegCache gpr(&out);
|
IRRegCache gpr(&out);
|
||||||
|
|
||||||
const u32 *constants = in.GetConstants().data();
|
const u32 *constants = in.GetConstants().data();
|
||||||
|
bool logBlocks = false;
|
||||||
for (int i = 0; i < (int)in.GetInstructions().size(); i++) {
|
for (int i = 0; i < (int)in.GetInstructions().size(); i++) {
|
||||||
IRInst inst = in.GetInstructions()[i];
|
IRInst inst = in.GetInstructions()[i];
|
||||||
bool symmetric = true;
|
bool symmetric = true;
|
||||||
|
@ -57,6 +66,8 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IROp::Sub:
|
case IROp::Sub:
|
||||||
|
case IROp::Slt:
|
||||||
|
case IROp::SltU:
|
||||||
symmetric = false; // fallthrough
|
symmetric = false; // fallthrough
|
||||||
case IROp::Add:
|
case IROp::Add:
|
||||||
case IROp::And:
|
case IROp::And:
|
||||||
|
@ -67,7 +78,8 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||||
} else if (gpr.IsImm(inst.src2) && inst.src1 != inst.src2 && inst.dest != inst.src2) {
|
} else if (gpr.IsImm(inst.src2) && inst.src1 != inst.src2 && inst.dest != inst.src2) {
|
||||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||||
if (gpr.GetImm(inst.src2) == 0 && (inst.op == IROp::Add || inst.op == IROp::Or)) {
|
if (gpr.GetImm(inst.src2) == 0 && (inst.op == IROp::Add || inst.op == IROp::Or)) {
|
||||||
out.Write(IROp::Mov, inst.dest, inst.src1);
|
if (inst.dest != inst.src1)
|
||||||
|
out.Write(IROp::Mov, inst.dest, inst.src1);
|
||||||
} else {
|
} else {
|
||||||
out.Write(ArithToArithConst(inst.op), inst.dest, inst.src1, out.AddConstant(gpr.GetImm(inst.src2)));
|
out.Write(ArithToArithConst(inst.op), inst.dest, inst.src1, out.AddConstant(gpr.GetImm(inst.src2)));
|
||||||
}
|
}
|
||||||
|
@ -85,6 +97,8 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||||
case IROp::AndConst:
|
case IROp::AndConst:
|
||||||
case IROp::OrConst:
|
case IROp::OrConst:
|
||||||
case IROp::XorConst:
|
case IROp::XorConst:
|
||||||
|
case IROp::SltConst:
|
||||||
|
case IROp::SltUConst:
|
||||||
if (gpr.IsImm(inst.src1)) {
|
if (gpr.IsImm(inst.src1)) {
|
||||||
gpr.SetImm(inst.dest, Evaluate(gpr.GetImm(inst.src1), constants[inst.src2], inst.op));
|
gpr.SetImm(inst.dest, Evaluate(gpr.GetImm(inst.src1), constants[inst.src2], inst.op));
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,6 +107,18 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IROp::ShlImm:
|
||||||
|
case IROp::ShrImm:
|
||||||
|
case IROp::RorImm:
|
||||||
|
case IROp::SarImm:
|
||||||
|
if (gpr.IsImm(inst.src1)) {
|
||||||
|
gpr.SetImm(inst.dest, Evaluate(gpr.GetImm(inst.src1), inst.src2, inst.op));
|
||||||
|
} else {
|
||||||
|
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||||
|
goto doDefault;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case IROp::Mov:
|
case IROp::Mov:
|
||||||
if (inst.src1 == inst.src2) {
|
if (inst.src1 == inst.src2) {
|
||||||
// Nop
|
// Nop
|
||||||
|
@ -107,18 +133,33 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||||
case IROp::Store8:
|
case IROp::Store8:
|
||||||
case IROp::Store16:
|
case IROp::Store16:
|
||||||
case IROp::Store32:
|
case IROp::Store32:
|
||||||
// Just pass through, no excessive flushing
|
if (gpr.IsImm(inst.src1) && inst.src1 != inst.dest) {
|
||||||
gpr.MapInIn(inst.dest, inst.src1);
|
gpr.MapIn(inst.dest);
|
||||||
goto doDefault;
|
out.Write(inst.op, inst.dest, 0, out.AddConstant(gpr.GetImm(inst.src1) + constants[inst.src2]));
|
||||||
|
} else {
|
||||||
|
// Just pass through, no excessive flushing
|
||||||
|
gpr.MapInIn(inst.dest, inst.src1);
|
||||||
|
goto doDefault;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case IROp::Load8:
|
case IROp::Load8:
|
||||||
case IROp::Load8Ext:
|
case IROp::Load8Ext:
|
||||||
case IROp::Load16:
|
case IROp::Load16:
|
||||||
case IROp::Load16Ext:
|
case IROp::Load16Ext:
|
||||||
case IROp::Load32:
|
case IROp::Load32:
|
||||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
if (gpr.IsImm(inst.src1) && inst.src1 != inst.dest && inst.src2 != inst.dest) {
|
||||||
goto doDefault;
|
gpr.MapDirty(inst.dest);
|
||||||
|
out.Write(inst.op, inst.dest, 0, out.AddConstant(gpr.GetImm(inst.src1) + constants[inst.src2]));
|
||||||
|
logBlocks = true;
|
||||||
|
} else {
|
||||||
|
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||||
|
goto doDefault;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IROp::Syscall:
|
||||||
|
case IROp::Interpret:
|
||||||
case IROp::ExitToConst:
|
case IROp::ExitToConst:
|
||||||
case IROp::ExitToReg:
|
case IROp::ExitToReg:
|
||||||
case IROp::ExitToConstIfEq:
|
case IROp::ExitToConstIfEq:
|
||||||
|
@ -155,4 +196,5 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return logBlocks;
|
||||||
}
|
}
|
|
@ -6,4 +6,4 @@
|
||||||
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);
|
bool PropagateConstants(const IRWriter &in, IRWriter &out);
|
|
@ -26,10 +26,19 @@ IRRegCache::IRRegCache(IRWriter *ir) : ir_(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++) {
|
||||||
Flush(i);
|
if (i < IRTEMP_0)
|
||||||
|
Flush(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IRRegCache::MapIn(int rd) {
|
||||||
|
Flush(rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRRegCache::MapDirty(int rd) {
|
||||||
|
Discard(rd);
|
||||||
|
}
|
||||||
|
|
||||||
void IRRegCache::MapInIn(int rs, int rt) {
|
void IRRegCache::MapInIn(int rs, int rt) {
|
||||||
Flush(rs);
|
Flush(rs);
|
||||||
Flush(rt);
|
Flush(rt);
|
||||||
|
|
|
@ -32,6 +32,8 @@ public:
|
||||||
|
|
||||||
void FlushAll();
|
void FlushAll();
|
||||||
|
|
||||||
|
void MapDirty(int rd);
|
||||||
|
void MapIn(int rd);
|
||||||
void MapInIn(int rs, int rt);
|
void MapInIn(int rs, int rt);
|
||||||
void MapDirtyIn(int rd, int rs);
|
void MapDirtyIn(int rd, int rs);
|
||||||
void MapDirtyInIn(int rd, int rs, int rt);
|
void MapDirtyInIn(int rd, int rs, int rt);
|
||||||
|
|
Loading…
Add table
Reference in a new issue