From cd3f4881a5bc37a566cb68ad11837fa88c37b1cd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 7 Jan 2018 12:11:16 -0800 Subject: [PATCH] irjit: Optimize out temp lhs copies. Common example: li v0, 1 beq s2, v0, somewhere li v0, 2 Which was copying s2 before. This pattern generally doesn't happen in MIPS code, though, so really only catches that (very common) case. --- Core/MIPS/IR/IRPassSimplify.cpp | 44 ++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index f3798c1dfb..d15183ce29 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -558,6 +558,22 @@ bool IRReadsFromGPR(const IRInst &inst, int reg) { return false; } +IRInst IRReplaceSrcGPR(const IRInst &inst, int fromReg, int toReg) { + IRInst newInst = inst; + const IRMeta *m = GetIRMeta(inst.op); + + if (m->types[1] == 'G' && inst.src1 == fromReg) { + newInst.src1 = toReg; + } + if (m->types[2] == 'G' && inst.src2 == fromReg) { + newInst.src2 = toReg; + } + if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == 'G' && inst.src3 == fromReg) { + newInst.src3 = toReg; + } + return newInst; +} + int IRDestGPR(const IRInst &inst) { const IRMeta *m = GetIRMeta(inst.op); @@ -576,14 +592,17 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { } int reg; + int srcReg = -1; int index; bool readByExit; }; std::vector checks; + int lastWrittenTo[256]; + memset(lastWrittenTo, -1, sizeof(lastWrittenTo)); bool logBlocks = false; for (int i = 0, n = (int)in.GetInstructions().size(); i < n; i++) { - const IRInst &inst = in.GetInstructions()[i]; + IRInst inst = in.GetInstructions()[i]; const IRMeta *m = GetIRMeta(inst.op); for (Check &check : checks) { @@ -592,8 +611,16 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { } if (IRReadsFromGPR(inst, check.reg)) { - // Read from, so we can't optimize out. - check.reg = 0; + // Read from, but was this just a copy? + bool mutatesReg = (m->flags & IRFLAG_SRC3DST) != 0 && m->types[0] == 'G' && inst.src3 == check.reg; + bool cannotReplace = inst.op == IROp::Interpret || inst.op == IROp::CallReplacement; + if (!mutatesReg && !cannotReplace && check.srcReg >= 0 && lastWrittenTo[check.srcReg] < check.index) { + // Replace with the srcReg instead. This happens with non-nice delay slots. + inst = IRReplaceSrcGPR(inst, check.reg, check.srcReg); + } else { + // Legitimately read from, so we can't optimize out. + check.reg = 0; + } } else if (check.readByExit && (m->flags & IRFLAG_EXIT) != 0) { check.reg = 0; } else if (IRDestGPR(inst) == check.reg) { @@ -616,10 +643,19 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { case IRTEMP_RHS: // Unlike other ops, these don't need to persist between blocks. // So we consider them not read unless proven read. - checks.push_back(Check(dest, i, false)); + lastWrittenTo[dest] = i; + // If this is a copy, we might be able to optimize out the copy. + if (inst.op == IROp::Mov) { + Check check(dest, i, false); + check.srcReg = inst.src1; + checks.push_back(check); + } else { + checks.push_back(Check(dest, i, false)); + } break; default: + lastWrittenTo[dest] = i; if (dest > IRTEMP_RHS) { // These might sometimes be implicitly read/written by other instructions. break;