From 00c80cea6e62c138036c165712d4d8ff6d22d5a7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 28 Sep 2023 21:22:34 -0700 Subject: [PATCH 1/2] irjit: Optimize offset logging during compile. As I guessed, this was expensive. using a vector and reserve isn't very. It's nice to keep this before logBlocks_ is > 0, in case it's set mid block. --- Core/MIPS/ARM64/Arm64IRJit.cpp | 15 +++++++++------ Core/MIPS/RiscV/RiscVJit.cpp | 15 +++++++++------ Core/MIPS/x86/X64IRJit.cpp | 16 ++++++++++------ 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/Core/MIPS/ARM64/Arm64IRJit.cpp b/Core/MIPS/ARM64/Arm64IRJit.cpp index ab7692dcc5..0e8a3d408f 100644 --- a/Core/MIPS/ARM64/Arm64IRJit.cpp +++ b/Core/MIPS/ARM64/Arm64IRJit.cpp @@ -93,12 +93,11 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) regs_.Start(block); - std::map addresses; + std::vector addresses; for (int i = 0; i < block->GetNumInstructions(); ++i) { const IRInst &inst = block->GetInstructions()[i]; regs_.SetIRIndex(i); - // TODO: This might be a little wasteful when compiling if we're not debugging jit... - addresses[GetCodePtr()] = i; + addresses.push_back(GetCodePtr()); CompileIRInst(inst); @@ -150,10 +149,14 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) if (logBlocks_ > 0) { --logBlocks_; + std::map addressesLookup; + for (int i = 0; i < (int)addresses.size(); ++i) + addressesLookup[addresses[i]] = i; + INFO_LOG(JIT, "=============== ARM64 (%08x, %d bytes) ===============", startPC, len); for (const u8 *p = blockStart; p < GetCodePointer(); ) { - auto it = addresses.find(p); - if (it != addresses.end()) { + auto it = addressesLookup.find(p); + if (it != addressesLookup.end()) { const IRInst &inst = block->GetInstructions()[it->second]; char temp[512]; @@ -162,7 +165,7 @@ bool Arm64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) } auto next = std::next(it); - const u8 *nextp = next == addresses.end() ? GetCodePointer() : next->first; + const u8 *nextp = next == addressesLookup.end() ? GetCodePointer() : next->first; auto lines = DisassembleArm64(p, (int)(nextp - p)); for (const auto &line : lines) diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp index be4a453482..60d5c5f929 100644 --- a/Core/MIPS/RiscV/RiscVJit.cpp +++ b/Core/MIPS/RiscV/RiscVJit.cpp @@ -82,12 +82,11 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) regs_.Start(block); - std::map addresses; + std::vector addresses; for (int i = 0; i < block->GetNumInstructions(); ++i) { const IRInst &inst = block->GetInstructions()[i]; regs_.SetIRIndex(i); - // TODO: This might be a little wasteful when compiling if we're not debugging jit... - addresses[GetCodePtr()] = i; + addresses.push_back(GetCodePtr()); CompileIRInst(inst); @@ -137,10 +136,14 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) if (logBlocks_ > 0) { --logBlocks_; + std::map addressesLookup; + for (int i = 0; i < (int)addresses.size(); ++i) + addressesLookup[addresses[i]] = i; + INFO_LOG(JIT, "=============== RISCV (%08x, %d bytes) ===============", startPC, len); for (const u8 *p = blockStart; p < GetCodePointer(); ) { - auto it = addresses.find(p); - if (it != addresses.end()) { + auto it = addressesLookup.find(p); + if (it != addressesLookup.end()) { const IRInst &inst = block->GetInstructions()[it->second]; char temp[512]; @@ -149,7 +152,7 @@ bool RiscVJitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) } auto next = std::next(it); - const u8 *nextp = next == addresses.end() ? GetCodePointer() : next->first; + const u8 *nextp = next == addressesLookup.end() ? GetCodePointer() : next->first; #if PPSSPP_ARCH(RISCV64) || (PPSSPP_PLATFORM(WINDOWS) && !defined(__LIBRETRO__)) auto lines = DisassembleRV64(p, (int)(nextp - p)); diff --git a/Core/MIPS/x86/X64IRJit.cpp b/Core/MIPS/x86/X64IRJit.cpp index 98279e3989..dbcddee3f5 100644 --- a/Core/MIPS/x86/X64IRJit.cpp +++ b/Core/MIPS/x86/X64IRJit.cpp @@ -86,12 +86,12 @@ bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { regs_.Start(block); - std::map addresses; + std::vector addresses; + addresses.reserve(block->GetNumInstructions()); for (int i = 0; i < block->GetNumInstructions(); ++i) { const IRInst &inst = block->GetInstructions()[i]; regs_.SetIRIndex(i); - // TODO: This might be a little wasteful when compiling if we're not debugging jit... - addresses[GetCodePtr()] = i; + addresses.push_back(GetCodePtr()); CompileIRInst(inst); @@ -140,10 +140,14 @@ bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { if (logBlocks_ > 0) { --logBlocks_; + std::map addressesLookup; + for (int i = 0; i < (int)addresses.size(); ++i) + addressesLookup[addresses[i]] = i; + INFO_LOG(JIT, "=============== x86 (%08x, %d bytes) ===============", startPC, len); for (const u8 *p = blockStart; p < GetCodePointer(); ) { - auto it = addresses.find(p); - if (it != addresses.end()) { + auto it = addressesLookup.find(p); + if (it != addressesLookup.end()) { const IRInst &inst = block->GetInstructions()[it->second]; char temp[512]; @@ -152,7 +156,7 @@ bool X64JitBackend::CompileBlock(IRBlock *block, int block_num, bool preload) { } auto next = std::next(it); - const u8 *nextp = next == addresses.end() ? GetCodePointer() : next->first; + const u8 *nextp = next == addressesLookup.end() ? GetCodePointer() : next->first; auto lines = DisassembleX86(p, (int)(nextp - p)); for (const auto &line : lines) From cd46f0b4cb82041c24c80786d4e2462093b37df8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 30 Sep 2023 13:54:26 -0700 Subject: [PATCH 2/2] irjit: Cache IR metadata lookups. This improves compilation performance, because all those lookups were adding up. --- Core/MIPS/IR/IRAnalysis.cpp | 97 ++++++++++++++------------------- Core/MIPS/IR/IRAnalysis.h | 39 ++++++++++--- Core/MIPS/IR/IRInst.h | 2 +- Core/MIPS/IR/IRPassSimplify.cpp | 56 +++++++++---------- 4 files changed, 99 insertions(+), 95 deletions(-) diff --git a/Core/MIPS/IR/IRAnalysis.cpp b/Core/MIPS/IR/IRAnalysis.cpp index 272378161b..8dfc6aab11 100644 --- a/Core/MIPS/IR/IRAnalysis.cpp +++ b/Core/MIPS/IR/IRAnalysis.cpp @@ -21,20 +21,18 @@ #include -static bool IRReadsFrom(const IRInst &inst, int reg, char type, bool *directly) { - const IRMeta *m = GetIRMeta(inst.op); - - if (m->types[1] == type && inst.src1 == reg) { +static bool IRReadsFrom(const IRInstMeta &inst, int reg, char type, bool *directly) { + if (inst.m.types[1] == type && inst.src1 == reg) { if (directly) *directly = true; return true; } - if (m->types[2] == type && inst.src2 == reg) { + if (inst.m.types[2] == type && inst.src2 == reg) { if (directly) *directly = true; return true; } - if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == type && inst.src3 == reg) { + if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type && inst.src3 == reg) { if (directly) *directly = true; return true; @@ -42,44 +40,41 @@ static bool IRReadsFrom(const IRInst &inst, int reg, char type, bool *directly) if (directly) *directly = false; - if ((m->flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0) + if ((inst.m.flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0) return true; return false; } -bool IRReadsFromFPR(const IRInst &inst, int reg, bool *directly) { +bool IRReadsFromFPR(const IRInstMeta &inst, int reg, bool *directly) { if (IRReadsFrom(inst, reg, 'F', directly)) return true; - const IRMeta *m = GetIRMeta(inst.op); - // We also need to check V and 2. Indirect reads already checked, don't check again. - if (m->types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4) + if (inst.m.types[1] == 'V' && reg >= inst.src1 && reg < inst.src1 + 4) return true; - if (m->types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2) + if (inst.m.types[1] == '2' && reg >= inst.src1 && reg < inst.src1 + 2) return true; - if (m->types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4) + if (inst.m.types[2] == 'V' && reg >= inst.src2 && reg < inst.src2 + 4) return true; - if (m->types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2) + if (inst.m.types[2] == '2' && reg >= inst.src2 && reg < inst.src2 + 2) return true; - if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) { - if (m->types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4) + if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) { + if (inst.m.types[0] == 'V' && reg >= inst.src3 && reg <= inst.src3 + 4) return true; - if (m->types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2) + if (inst.m.types[0] == '2' && reg >= inst.src3 && reg <= inst.src3 + 2) return true; } return false; } -static int IRReadsFromList(const IRInst &inst, IRReg regs[4], char type) { - const IRMeta *m = GetIRMeta(inst.op); +static int IRReadsFromList(const IRInstMeta &inst, IRReg regs[4], char type) { int c = 0; - if (m->types[1] == type) + if (inst.m.types[1] == type) regs[c++] = inst.src1; - if (m->types[2] == type) + if (inst.m.types[2] == type) regs[c++] = inst.src2; - if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && m->types[0] == type) + if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == type) regs[c++] = inst.src3; if (inst.op == IROp::Interpret || inst.op == IROp::CallReplacement || inst.op == IROp::Syscall || inst.op == IROp::Break) @@ -90,56 +85,50 @@ static int IRReadsFromList(const IRInst &inst, IRReg regs[4], char type) { return c; } -bool IRReadsFromGPR(const IRInst &inst, int reg, bool *directly) { +bool IRReadsFromGPR(const IRInstMeta &inst, int reg, bool *directly) { return IRReadsFrom(inst, reg, 'G', directly); } -int IRDestGPR(const IRInst &inst) { - const IRMeta *m = GetIRMeta(inst.op); - - if ((m->flags & IRFLAG_SRC3) == 0 && m->types[0] == 'G') { +int IRDestGPR(const IRInstMeta &inst) { + if ((inst.m.flags & IRFLAG_SRC3) == 0 && inst.m.types[0] == 'G') { return inst.dest; } return -1; } -bool IRWritesToGPR(const IRInst &inst, int reg) { +bool IRWritesToGPR(const IRInstMeta &inst, int reg) { return IRDestGPR(inst) == reg; } -bool IRWritesToFPR(const IRInst &inst, int reg) { - const IRMeta *m = GetIRMeta(inst.op); - +bool IRWritesToFPR(const IRInstMeta &inst, int reg) { // Doesn't write to anything. - if ((m->flags & IRFLAG_SRC3) != 0) + if ((inst.m.flags & IRFLAG_SRC3) != 0) return false; - if (m->types[0] == 'F' && reg == inst.dest) + if (inst.m.types[0] == 'F' && reg == inst.dest) return true; - if (m->types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4) + if (inst.m.types[0] == 'V' && reg >= inst.dest && reg < inst.dest + 4) return true; - if (m->types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2) + if (inst.m.types[0] == '2' && reg >= inst.dest && reg < inst.dest + 2) return true; return false; } -int IRDestFPRs(const IRInst &inst, IRReg regs[4]) { - const IRMeta *m = GetIRMeta(inst.op); - +int IRDestFPRs(const IRInstMeta &inst, IRReg regs[4]) { // Doesn't write to anything. - if ((m->flags & IRFLAG_SRC3) != 0) + if ((inst.m.flags & IRFLAG_SRC3) != 0) return 0; - if (m->types[0] == 'F') { + if (inst.m.types[0] == 'F') { regs[0] = inst.dest; return 1; } - if (m->types[0] == 'V') { + if (inst.m.types[0] == 'V') { for (int i = 0; i < 4; ++i) regs[i] = inst.dest + i; return 4; } - if (m->types[0] == '2') { + if (inst.m.types[0] == '2') { for (int i = 0; i < 2; ++i) regs[i] = inst.dest + i; return 2; @@ -147,29 +136,27 @@ int IRDestFPRs(const IRInst &inst, IRReg regs[4]) { return 0; } -int IRReadsFromGPRs(const IRInst &inst, IRReg regs[4]) { +int IRReadsFromGPRs(const IRInstMeta &inst, IRReg regs[4]) { return IRReadsFromList(inst, regs, 'G'); } -int IRReadsFromFPRs(const IRInst &inst, IRReg regs[16]) { +int IRReadsFromFPRs(const IRInstMeta &inst, IRReg regs[16]) { int c = IRReadsFromList(inst, regs, 'F'); if (c != 0) return c; - const IRMeta *m = GetIRMeta(inst.op); - // We also need to check V and 2. Indirect reads already checked, don't check again. - if (m->types[1] == 'V' || m->types[1] == '2') { - for (int i = 0; i < (m->types[1] == 'V' ? 4 : 2); ++i) + if (inst.m.types[1] == 'V' || inst.m.types[1] == '2') { + for (int i = 0; i < (inst.m.types[1] == 'V' ? 4 : 2); ++i) regs[c++] = inst.src1 + i; } - if (m->types[2] == 'V' || m->types[2] == '2') { - for (int i = 0; i < (m->types[2] == 'V' ? 4 : 2); ++i) + if (inst.m.types[2] == 'V' || inst.m.types[2] == '2') { + for (int i = 0; i < (inst.m.types[2] == 'V' ? 4 : 2); ++i) regs[c++] = inst.src2 + i; } - if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) { - if (m->types[0] == 'V' || m->types[0] == '2') { - for (int i = 0; i < (m->types[0] == 'V' ? 4 : 2); ++i) + if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) { + if (inst.m.types[0] == 'V' || inst.m.types[0] == '2') { + for (int i = 0; i < (inst.m.types[0] == 'V' ? 4 : 2); ++i) regs[c++] = inst.src3 + i; } } @@ -183,7 +170,7 @@ IRUsage IRNextGPRUsage(int gpr, const IRSituation &info) { int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount); for (int i = 0; i < count; ++i) { - const IRInst inst = info.instructions[info.currentIndex + i]; + const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]); if (IRReadsFromGPR(inst, gpr)) return IRUsage::READ; // We say WRITE when the current instruction writes. It's not useful for spilling. @@ -202,7 +189,7 @@ IRUsage IRNextFPRUsage(int fpr, const IRSituation &info) { int count = std::min(info.numInstructions - info.currentIndex, info.lookaheadCount); for (int i = 0; i < count; ++i) { - const IRInst inst = info.instructions[info.currentIndex + i]; + const IRInstMeta inst = GetIRMeta(info.instructions[info.currentIndex + i]); if (IRReadsFromFPR(inst, fpr)) { // Special case a broadcast that clobbers it. diff --git a/Core/MIPS/IR/IRAnalysis.h b/Core/MIPS/IR/IRAnalysis.h index 9853a33762..a1610f7cd0 100644 --- a/Core/MIPS/IR/IRAnalysis.h +++ b/Core/MIPS/IR/IRAnalysis.h @@ -19,14 +19,37 @@ #include "Core/MIPS/IR/IRInst.h" -bool IRReadsFromFPR(const IRInst &inst, int reg, bool *directly = nullptr); -bool IRReadsFromGPR(const IRInst &inst, int reg, bool *directly = nullptr); -bool IRWritesToGPR(const IRInst &inst, int reg); -bool IRWritesToFPR(const IRInst &inst, int reg); -int IRDestGPR(const IRInst &inst); -int IRDestFPRs(const IRInst &inst, IRReg regs[4]); -int IRReadsFromGPRs(const IRInst &inst, IRReg regs[4]); -int IRReadsFromFPRs(const IRInst &inst, IRReg regs[16]); +struct IRInstMeta { + union { + IRInst i; + struct { + IROp op; + union { + IRReg dest; + IRReg src3; + }; + IRReg src1; + IRReg src2; + u32 constant; + }; + }; + IRMeta m; +}; + +static_assert(offsetof(IRInst, src2) == offsetof(IRInstMeta, src2)); + +inline IRInstMeta GetIRMeta(const IRInst &inst) { + return { { inst }, *GetIRMeta(inst.op) }; +} + +bool IRReadsFromFPR(const IRInstMeta &inst, int reg, bool *directly = nullptr); +bool IRReadsFromGPR(const IRInstMeta &inst, int reg, bool *directly = nullptr); +bool IRWritesToGPR(const IRInstMeta &inst, int reg); +bool IRWritesToFPR(const IRInstMeta &inst, int reg); +int IRDestGPR(const IRInstMeta &inst); +int IRDestFPRs(const IRInstMeta &inst, IRReg regs[4]); +int IRReadsFromGPRs(const IRInstMeta &inst, IRReg regs[4]); +int IRReadsFromFPRs(const IRInstMeta &inst, IRReg regs[16]); struct IRSituation { int lookaheadCount; diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index 1f3b9b2451..e727697d3f 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -341,7 +341,7 @@ enum IRFlags { struct IRMeta { IROp op; const char *name; - const char types[5]; // GGG + char types[5]; // GGG u32 flags; }; diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index 2079b799d6..b98b03f44a 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -919,40 +919,37 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts return logBlocks; } -IRInst IRReplaceSrcGPR(const IRInst &inst, int fromReg, int toReg) { - IRInst newInst = inst; - const IRMeta *m = GetIRMeta(inst.op); +IRInstMeta IRReplaceSrcGPR(const IRInstMeta &inst, int fromReg, int toReg) { + IRInstMeta newInst = inst; - if (m->types[1] == 'G' && inst.src1 == fromReg) { + if (inst.m.types[1] == 'G' && inst.src1 == fromReg) { newInst.src1 = toReg; } - if (m->types[2] == 'G' && inst.src2 == fromReg) { + if (inst.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) { + if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0 && inst.m.types[0] == 'G' && inst.src3 == fromReg) { newInst.src3 = toReg; } return newInst; } -IRInst IRReplaceDestGPR(const IRInst &inst, int fromReg, int toReg) { - IRInst newInst = inst; - const IRMeta *m = GetIRMeta(inst.op); +IRInstMeta IRReplaceDestGPR(const IRInstMeta &inst, int fromReg, int toReg) { + IRInstMeta newInst = inst; - if ((m->flags & IRFLAG_SRC3) == 0 && m->types[0] == 'G' && inst.dest == fromReg) { + if ((inst.m.flags & IRFLAG_SRC3) == 0 && inst.m.types[0] == 'G' && inst.dest == fromReg) { newInst.dest = toReg; } return newInst; } -bool IRMutatesDestGPR(const IRInst &inst, int reg) { - const IRMeta *m = GetIRMeta(inst.op); - return (m->flags & IRFLAG_SRC3DST) != 0 && m->types[0] == 'G' && inst.src3 == reg; +bool IRMutatesDestGPR(const IRInstMeta &inst, int reg) { + return (inst.m.flags & IRFLAG_SRC3DST) != 0 && inst.m.types[0] == 'G' && inst.src3 == reg; } bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { CONDITIONAL_DISABLE; - std::vector insts; + std::vector insts; insts.reserve(in.GetInstructions().size()); // We track writes both to rename regs and to purge dead stores. @@ -979,7 +976,7 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { memset(lastWrittenTo, -1, sizeof(lastWrittenTo)); memset(lastReadFrom, -1, sizeof(lastReadFrom)); - auto readsFromFPRCheck = [](IRInst &inst, Check &check, bool *directly) { + auto readsFromFPRCheck = [](IRInstMeta &inst, Check &check, bool *directly) { if (check.reg < 32) return false; @@ -1001,8 +998,7 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { bool logBlocks = false; size_t firstCheck = 0; for (int i = 0, n = (int)in.GetInstructions().size(); i < n; i++) { - IRInst inst = in.GetInstructions()[i]; - const IRMeta *m = GetIRMeta(inst.op); + IRInstMeta inst = GetIRMeta(in.GetInstructions()[i]); // It helps to skip through rechecking ones we already discarded. for (size_t ch = firstCheck; ch < checks.size(); ++ch) { @@ -1060,14 +1056,13 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { } else { // Legitimately read from, so we can't optimize out. // Unless this is an exit and a temp not read directly by the exit. - if ((m->flags & IRFLAG_EXIT) == 0 || check.readByExit || readsDirectly) + if ((inst.m.flags & IRFLAG_EXIT) == 0 || check.readByExit || readsDirectly) check.reg = 0; } } else if (check.fplen >= 1 && readsFromFPRCheck(inst, check, &readsDirectly)) { // If one or the other is a Vec, they must match. bool lenMismatch = false; - const IRMeta *m = GetIRMeta(inst.op); auto checkMismatch = [&check, &lenMismatch](IRReg src, char type) { int srclen = 1; if (type == 'V') @@ -1083,10 +1078,10 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { } }; - checkMismatch(inst.src1, m->types[1]); - checkMismatch(inst.src2, m->types[2]); - if ((m->flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) - checkMismatch(inst.src3, m->types[3]); + checkMismatch(inst.src1, inst.m.types[1]); + checkMismatch(inst.src2, inst.m.types[2]); + if ((inst.m.flags & (IRFLAG_SRC3 | IRFLAG_SRC3DST)) != 0) + checkMismatch(inst.src3, inst.m.types[3]); bool cannotReplace = !readsDirectly || lenMismatch; if (!cannotReplace && check.srcReg >= 32 && lastWrittenTo[check.srcReg] < check.index) { @@ -1137,10 +1132,10 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { } } else { // Legitimately read from, so we can't optimize out. - if ((m->flags & IRFLAG_EXIT) == 0 || check.readByExit || readsDirectly) + if ((inst.m.flags & IRFLAG_EXIT) == 0 || check.readByExit || readsDirectly) check.reg = 0; } - } else if (check.readByExit && (m->flags & IRFLAG_EXIT) != 0) { + } else if (check.readByExit && (inst.m.flags & IRFLAG_EXIT) != 0) { // This is an exit, and the reg is read by any exit. Clear it. check.reg = 0; } else if (IRDestGPR(inst) == check.reg) { @@ -1261,10 +1256,10 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { } } - for (const IRInst &inst : insts) { + for (const IRInstMeta &inst : insts) { // Simply skip any Mov 0, 0 instructions, since that's how we nuke one. if (inst.op != IROp::Mov || inst.dest != 0 || inst.src1 != 0) { - out.Write(inst); + out.Write(inst.i); } } @@ -1282,12 +1277,11 @@ bool ReduceLoads(const IRWriter &in, IRWriter &out, const IROptions &opts) { IRInst inst = in.GetInstructions()[i]; if (inst.op == IROp::Load32 || inst.op == IROp::Load16 || inst.op == IROp::Load16Ext) { - int dest = IRDestGPR(inst); + int dest = IRDestGPR(GetIRMeta(inst)); for (int j = i + 1; j < n; j++) { - const IRInst &laterInst = in.GetInstructions()[j]; - const IRMeta *m = GetIRMeta(laterInst.op); + const IRInstMeta laterInst = GetIRMeta(in.GetInstructions()[j]); - if ((m->flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0) { + if ((laterInst.m.flags & (IRFLAG_EXIT | IRFLAG_BARRIER)) != 0) { // Exit, so we can't do the optimization. break; }