From 14df39d7c9987f5daf50901869dfd2583f8e567d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 8 May 2016 10:36:37 +0200 Subject: [PATCH] Fix IRTEMP clash bug. Add more cases to the constant propagation pass. --- Core/MIPS/IR/IRCompALU.cpp | 9 ++++-- Core/MIPS/IR/IRCompBranch.cpp | 28 ++++++++--------- Core/MIPS/IR/IRInst.cpp | 6 ++++ Core/MIPS/IR/IRInst.h | 4 +-- Core/MIPS/IR/IRJit.cpp | 5 +-- Core/MIPS/IR/IRPassSimplify.cpp | 56 ++++++++++++++++++++++++++++----- Core/MIPS/IR/IRPassSimplify.h | 2 +- Core/MIPS/IR/IRRegCache.cpp | 11 ++++++- Core/MIPS/IR/IRRegCache.h | 2 ++ 9 files changed, 94 insertions(+), 29 deletions(-) diff --git a/Core/MIPS/IR/IRCompALU.cpp b/Core/MIPS/IR/IRCompALU.cpp index 46c43ded73..7f21c2c572 100644 --- a/Core/MIPS/IR/IRCompALU.cpp +++ b/Core/MIPS/IR/IRCompALU.cpp @@ -47,6 +47,7 @@ namespace MIPSComp { void IRJit::Comp_IType(MIPSOpcode op) { CONDITIONAL_DISABLE; + s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension u32 uimm = op & 0xFFFF; u32 suimm = (u32)(s32)simm; @@ -236,7 +237,7 @@ void IRJit::Comp_Special3(MIPSOpcode op) { return; switch (op & 0x3f) { - case 0x0: + case 0x0: // ext if (pos != 0) { ir.Write(IROp::ShrImm, rt, rs, pos); ir.Write(IROp::AndConst, rt, rt, ir.AddConstant(mask)); @@ -247,17 +248,21 @@ void IRJit::Comp_Special3(MIPSOpcode op) { case 0x4: //ins { + logBlocks = 1; u32 sourcemask = mask >> pos; u32 destmask = ~(sourcemask << pos); 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::ShlImm, IRTEMP_0, IRTEMP_0, pos); ir.Write(IROp::Or, rt, rt, IRTEMP_0); } break; } } + void IRJit::Comp_Allegrex(MIPSOpcode op) { CONDITIONAL_DISABLE; MIPSGPReg rt = _RT; diff --git a/Core/MIPS/IR/IRCompBranch.cpp b/Core/MIPS/IR/IRCompBranch.cpp index 0cf3e7d8f7..a290784904 100644 --- a/Core/MIPS/IR/IRCompBranch.cpp +++ b/Core/MIPS/IR/IRCompBranch.cpp @@ -73,12 +73,12 @@ void IRJit::BranchRSRTComp(MIPSOpcode op, IRComparison cc, bool likely) MIPSGPReg rhs = rt; if (!delaySlotIsNice) { // if likely, we don't need this if (rs != 0) { - ir.Write(IROp::Mov, IRTEMP_0, rs); - lhs = (MIPSGPReg)IRTEMP_0; + ir.Write(IROp::Mov, IRTEMP_LHS, rs); + lhs = (MIPSGPReg)IRTEMP_LHS; } if (rt != 0) { - ir.Write(IROp::Mov, IRTEMP_1, rt); - rhs = (MIPSGPReg)IRTEMP_1; + ir.Write(IROp::Mov, IRTEMP_RHS, rt); + rhs = (MIPSGPReg)IRTEMP_RHS; } } @@ -113,8 +113,8 @@ void IRJit::BranchRSZeroComp(MIPSOpcode op, IRComparison cc, bool andLink, bool MIPSGPReg lhs = rs; if (!delaySlotIsNice) { // if likely, we don't need this - ir.Write(IROp::Mov, IRTEMP_0, rs); - lhs = (MIPSGPReg)IRTEMP_0; + ir.Write(IROp::Mov, IRTEMP_LHS, rs); + lhs = (MIPSGPReg)IRTEMP_LHS; } if (andLink) 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; MIPSOpcode delaySlotOp = GetOffsetInstruction(1); - ir.Write(IROp::FpCondToReg, IRTEMP_0); + ir.Write(IROp::FpCondToReg, IRTEMP_LHS); if (!likely) CompileDelaySlot(); @@ -187,7 +187,7 @@ void IRJit::BranchFPFlag(MIPSOpcode op, IRComparison cc, bool likely) { FlushAll(); // 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 if (likely) CompileDelaySlot(); @@ -218,8 +218,8 @@ void IRJit::BranchVFPUFlag(MIPSOpcode op, IRComparison cc, bool likely) { u32 targetAddr = GetCompilerPC() + offset + 4; MIPSOpcode delaySlotOp = GetOffsetInstruction(1); - - ir.Write(IROp::VfpuCtrlToReg, IRTEMP_0, VFPU_CTRL_CC); + logBlocks = 1; + ir.Write(IROp::VfpuCtrlToReg, IRTEMP_LHS, VFPU_CTRL_CC); 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); - 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(); - ir.Write(ComparisonToExit(cc), ir.AddConstant(notTakenTarget), IRTEMP_0, 0); + ir.Write(ComparisonToExit(cc), ir.AddConstant(notTakenTarget), IRTEMP_LHS, 0); if (likely) CompileDelaySlot(); @@ -334,8 +334,8 @@ void IRJit::Comp_JumpReg(MIPSOpcode op) { FlushAll(); } else { // Bad delay slot. - ir.Write(IROp::Mov, IRTEMP_0, rs); - destReg = IRTEMP_0; + ir.Write(IROp::Mov, IRTEMP_LHS, rs); + destReg = IRTEMP_LHS; if (andLink) ir.WriteSetConstant(rd, GetCompilerPC() + 8); CompileDelaySlot(); diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index 1fd990adba..1a184e00eb 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -478,6 +478,10 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c default: Crash(); } +#ifdef _DEBUG + if (mips->r[0] != 0) + Crash(); +#endif inst++; } @@ -529,6 +533,8 @@ const char *GetGPRName(int r) { switch (r) { case IRTEMP_0: return "irtemp0"; case IRTEMP_1: return "irtemp1"; + case IRTEMP_LHS: return "irtemp_lhs"; + case IRTEMP_RHS: return "irtemp_rhs"; default: return "(unk)"; } } diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index e044825f1c..062d5189ab 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -204,8 +204,8 @@ inline IROp ComparisonToExit(IRComparison comp) { enum { IRTEMP_0 = 192, IRTEMP_1, - IRTEMP_2, - IRTEMP_3, + IRTEMP_LHS, // Reserved for use in branches + IRTEMP_RHS, // Reserved for use in branches // Hacky way to get to other state IRREG_LO = 226, // offset of lo in MIPSState / 4 diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index 0d8fca504b..09f6acbe61 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -269,7 +269,8 @@ void IRJit::DoJit(u32 em_address, IRBlock *b) { IRWriter *code = &ir; if (true) { - PropagateConstants(ir, simplified); + if (PropagateConstants(ir, simplified)) + logBlocks = 1; code = &simplified; } @@ -362,7 +363,7 @@ void IRJit::Comp_ReplacementFunc(MIPSOpcode op) { } else { ERROR_LOG(HLE, "Replacement function %s has neither jit nor regular impl", entry->name); } -} +} void IRJit::Comp_Generic(MIPSOpcode op) { FlushAll(); diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index 38141951de..d5b943c23c 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -26,6 +26,12 @@ u32 Evaluate(u32 a, u32 b, IROp op) { 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; + 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: return -1; } @@ -38,16 +44,19 @@ IROp ArithToArithConst(IROp op) { case IROp::And: return IROp::AndConst; case IROp::Or: return IROp::OrConst; case IROp::Xor: return IROp::XorConst; + case IROp::Slt: return IROp::SltConst; + case IROp::SltU: return IROp::SltUConst; default: return (IROp)-1; } } -void PropagateConstants(const IRWriter &in, IRWriter &out) { +bool PropagateConstants(const IRWriter &in, IRWriter &out) { IRRegCache gpr(&out); const u32 *constants = in.GetConstants().data(); + bool logBlocks = false; for (int i = 0; i < (int)in.GetInstructions().size(); i++) { IRInst inst = in.GetInstructions()[i]; bool symmetric = true; @@ -57,6 +66,8 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) { break; case IROp::Sub: + case IROp::Slt: + case IROp::SltU: symmetric = false; // fallthrough case IROp::Add: 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) { 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); + if (inst.dest != inst.src1) + out.Write(IROp::Mov, inst.dest, inst.src1); } else { 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::OrConst: case IROp::XorConst: + case IROp::SltConst: + case IROp::SltUConst: if (gpr.IsImm(inst.src1)) { gpr.SetImm(inst.dest, Evaluate(gpr.GetImm(inst.src1), constants[inst.src2], inst.op)); } else { @@ -93,6 +107,18 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) { } 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: if (inst.src1 == inst.src2) { // Nop @@ -107,18 +133,33 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) { case IROp::Store8: case IROp::Store16: case IROp::Store32: - // Just pass through, no excessive flushing - gpr.MapInIn(inst.dest, inst.src1); - goto doDefault; + if (gpr.IsImm(inst.src1) && inst.src1 != inst.dest) { + gpr.MapIn(inst.dest); + 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::Load8Ext: case IROp::Load16: case IROp::Load16Ext: case IROp::Load32: - gpr.MapDirtyIn(inst.dest, inst.src1); - goto doDefault; + if (gpr.IsImm(inst.src1) && inst.src1 != inst.dest && inst.src2 != inst.dest) { + 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::ExitToReg: case IROp::ExitToConstIfEq: @@ -155,4 +196,5 @@ void PropagateConstants(const IRWriter &in, IRWriter &out) { } } } + return logBlocks; } \ No newline at end of file diff --git a/Core/MIPS/IR/IRPassSimplify.h b/Core/MIPS/IR/IRPassSimplify.h index b5d0af1e95..5a57be1cfa 100644 --- a/Core/MIPS/IR/IRPassSimplify.h +++ b/Core/MIPS/IR/IRPassSimplify.h @@ -6,4 +6,4 @@ void SimplifyInPlace(IRInst *inst, int count, const u32 *constPool); -void PropagateConstants(const IRWriter &in, IRWriter &out); \ No newline at end of file +bool PropagateConstants(const IRWriter &in, IRWriter &out); \ No newline at end of file diff --git a/Core/MIPS/IR/IRRegCache.cpp b/Core/MIPS/IR/IRRegCache.cpp index f1c0201395..c7e11aa6d9 100644 --- a/Core/MIPS/IR/IRRegCache.cpp +++ b/Core/MIPS/IR/IRRegCache.cpp @@ -26,10 +26,19 @@ IRRegCache::IRRegCache(IRWriter *ir) : ir_(ir) { void IRRegCache::FlushAll() { 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) { Flush(rs); Flush(rt); diff --git a/Core/MIPS/IR/IRRegCache.h b/Core/MIPS/IR/IRRegCache.h index 1d7e78f7a8..68570f50ac 100644 --- a/Core/MIPS/IR/IRRegCache.h +++ b/Core/MIPS/IR/IRRegCache.h @@ -32,6 +32,8 @@ public: void FlushAll(); + void MapDirty(int rd); + void MapIn(int rd); void MapInIn(int rs, int rt); void MapDirtyIn(int rd, int rs); void MapDirtyInIn(int rd, int rs, int rt);