From dcc51d8b18ba53b138698d124d2a013fd6eee101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 10 Nov 2026 20:26:45 +0100 Subject: [PATCH] IR: Keep IRWriter's instructions in a FastVec, and inline Write The compiler didn't inline std::vector::push_back into IRWriter::Write, which the frontend and every pass call for each instruction. FastVec's append is a compare and a store. Co-Authored-By: Claude Opus 5.5 --- Core/MIPS/IR/IRFrontend.cpp | 4 ++-- Core/MIPS/IR/IRInst.cpp | 10 ---------- Core/MIPS/IR/IRInst.h | 27 +++++++++++++++++++++++---- unittest/TestIRPassSimplify.cpp | 2 +- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Core/MIPS/IR/IRFrontend.cpp b/Core/MIPS/IR/IRFrontend.cpp index 080a34ef09..f828f720b8 100644 --- a/Core/MIPS/IR/IRFrontend.cpp +++ b/Core/MIPS/IR/IRFrontend.cpp @@ -387,10 +387,10 @@ void IRFrontend::DoJit(u32 em_address, std::vector &instructions, u32 &m } if (!mipsTracer.tracing_enabled) { - instructions = code->GetInstructions(); + instructions.assign(code->GetInstructions().begin(), code->GetInstructions().end()); } else { - std::vector block_instructions = code->GetInstructions(); + std::vector block_instructions(code->GetInstructions().begin(), code->GetInstructions().end()); instructions.reserve(block_instructions.size() + 2); // +2 for Downcount and LogIRBlock // The first instruction is "Downcount" instructions.push_back(block_instructions.front()); diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index c4f0a151a2..5afaa69140 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -231,16 +231,6 @@ void InitIR() { } } -void IRWriter::Write(IROp op, u8 dst, u8 src1, u8 src2, u32 constant) { - IRInst inst; - inst.op = op; - inst.dest = dst; - inst.src1 = src1; - inst.src2 = src2; - inst.constant = constant; - insts_.push_back(inst); -} - void IRWriter::WriteFC(IROp op, u8 dst, u8 src1, u8 src2, float fconstant) { u32 constant; memcpy(&constant, &fconstant, sizeof(u32)); diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index 10b5b034b8..ae53c6af63 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -5,6 +5,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/Data/Collections/FastVec.h" #include "Core/MIPS/MIPS.h" // Basic IR @@ -424,8 +425,17 @@ u32 IRInterpret(MIPSState *ms, const IRInst *inst, const IRInst *chainArena = nu // Each IR block gets a constant pool. class IRWriter { public: + IRWriter() {} + IRWriter(const IRWriter &w) { + *this = w; + } + IRWriter(IRWriter &&w) noexcept : insts_(std::move(w.insts_)) {} IRWriter &operator =(const IRWriter &w) { - insts_ = w.insts_; + if (this != &w) { + insts_.clear(); + if (!w.insts_.empty()) + insts_.extend(w.insts_.data(), w.insts_.size()); + } return *this; } IRWriter &operator =(IRWriter &&w) noexcept { @@ -433,7 +443,16 @@ public: return *this; } - void Write(IROp op, u8 dst = 0, u8 src1 = 0, u8 src2 = 0, u32 constant = 0); + // Inline (with FastVec rather than std::vector, which the compiler didn't inline), since the + // frontend and every pass write each instruction through these. + void Write(IROp op, u8 dst = 0, u8 src1 = 0, u8 src2 = 0, u32 constant = 0) { + IRInst &inst = insts_.push_uninitialized(); + inst.op = op; + inst.dest = dst; + inst.src1 = src1; + inst.src2 = src2; + inst.constant = constant; + } void WriteFC(IROp op, u8 dst, u8 src1, u8 src2, float fconstant); void WriteSetConstant(u8 dst, u32 value); @@ -450,10 +469,10 @@ public: } void ReplaceConstant(size_t instNumber, u32 newConstant); - const std::vector &GetInstructions() const { return insts_; } + const FastVec &GetInstructions() const { return insts_; } private: - std::vector insts_; + FastVec insts_; }; // How far IRFrontend compiles on past conditional branches. The interpreter ends its blocks in the diff --git a/unittest/TestIRPassSimplify.cpp b/unittest/TestIRPassSimplify.cpp index 43669d3c63..0a1c9f30c7 100644 --- a/unittest/TestIRPassSimplify.cpp +++ b/unittest/TestIRPassSimplify.cpp @@ -57,7 +57,7 @@ static bool VerifyPass(const IRVerification &v) { return false; } - const std::vector actual = out.GetInstructions(); + const std::vector actual(out.GetInstructions().begin(), out.GetInstructions().end()); if (actual.size() != v.expected.size()) { printf("%s FAILED: produced %d instructions, expected %d\n", v.name, (int)actual.size(), (int)v.expected.size()); printf("Actual:\n");