diff --git a/core/libs/prx/libSceAgcDriver/tests/IrReclaim.cpp b/core/libs/prx/libSceAgcDriver/tests/IrReclaim.cpp index 9c8a8e5769..4256def9d9 100644 --- a/core/libs/prx/libSceAgcDriver/tests/IrReclaim.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/IrReclaim.cpp @@ -96,6 +96,23 @@ int main() { keptReader.AddArgument(&kept); replaced = std::move(replacement); if (kept.UseCount() != 1u || kept.OperandUses().front().user != &keptReader) throw std::runtime_error("move assignment invalidated the assigned program's use lists"); + IrProgram cached; + auto& source = cached.CreateValue(IrOpcode::IAdd32, IrType::U32); + std::vector users; + for (std::uint32_t number = 0; number < 40u; ++number) { + auto& user = cached.CreateValue(IrOpcode::IAdd32, IrType::U32); + user.AddArgument(&source); + users.push_back(&user); + } + cached.ReleaseUseArena(); + if (source.OperandUses().get_allocator().Arena() != nullptr || users.front()->OperandUses().get_allocator().Arena() != nullptr) throw std::runtime_error("releasing the use arena left a use list in it"); + if (source.UseCount() != users.size()) throw std::runtime_error("releasing the use arena lost a use"); + for (std::size_t index = 0; index < users.size(); ++index) { + if (source.OperandUses()[index].user != users[index] || users[index]->Argument(0) != &source) throw std::runtime_error("releasing the use arena reordered a use list"); + } + auto& late = cached.CreateValue(IrOpcode::IAdd32, IrType::U32); + late.AddArgument(&source); + if (late.OperandUses().get_allocator().Arena() == nullptr || source.UseCount() != users.size() + 1u || source.OperandUses().back().user != &late) throw std::runtime_error("a value created after releasing the use arena did not get a new one"); IrProgram moved = std::move(program); if (value.Id() != id || value.ImmediateU32() != 42u || moved.ReclaimUnusedValues() != 1u) throw std::runtime_error("moving a program invalidated its allocation owner"); IrProgram assigned; diff --git a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrProgram.hpp b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrProgram.hpp index a93cd962c5..bb66d00d95 100644 --- a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrProgram.hpp +++ b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrProgram.hpp @@ -32,6 +32,7 @@ public: IrValue& CreateValue(IrOpcode opcode, IrType type, std::uint64_t flags); void SetEntryBlock(IrBlock& block); std::size_t ReclaimUnusedValues(); + void ReleaseUseArena(); [[nodiscard]] std::vector& BlockOrder(); [[nodiscard]] const std::vector& BlockOrder() const; diff --git a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrValue.hpp b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrValue.hpp index a452593474..699436a0e3 100644 --- a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrValue.hpp +++ b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrValue.hpp @@ -184,6 +184,7 @@ public: [[nodiscard]] IrValue* Argument(std::size_t index) const; [[nodiscard]] IrBlock* PhiBlock(std::size_t index) const; [[nodiscard]] const IrUseList& OperandUses() const; + void MoveUsesToHeap(); [[nodiscard]] std::uint64_t ImmediateU64() const; [[nodiscard]] std::uint16_t ImmediateF16Bits() const; [[nodiscard]] float ImmediateF32() const; diff --git a/core/shader/recompiler/IntermediateRepresentation/src/IrProgram.cpp b/core/shader/recompiler/IntermediateRepresentation/src/IrProgram.cpp index 8d134e86f1..34a251932b 100644 --- a/core/shader/recompiler/IntermediateRepresentation/src/IrProgram.cpp +++ b/core/shader/recompiler/IntermediateRepresentation/src/IrProgram.cpp @@ -274,6 +274,11 @@ std::size_t IrProgram::ReclaimUnusedValues() { return removed; } +void IrProgram::ReleaseUseArena() { + for (const auto& value : values) value->MoveUsesToHeap(); + useArena = IrUseArena{}; +} + std::vector>& IrProgram::Blocks() { return blocks; } diff --git a/core/shader/recompiler/IntermediateRepresentation/src/IrValue.cpp b/core/shader/recompiler/IntermediateRepresentation/src/IrValue.cpp index b910a7bd6a..b549aa7393 100644 --- a/core/shader/recompiler/IntermediateRepresentation/src/IrValue.cpp +++ b/core/shader/recompiler/IntermediateRepresentation/src/IrValue.cpp @@ -125,6 +125,11 @@ const IrUseList& IrValue::OperandUses() const { return operandUses; } +void IrValue::MoveUsesToHeap() { + if (operandUses.get_allocator().Arena() == nullptr) return; + operandUses = IrUseList(operandUses.begin(), operandUses.end(), IrUseAllocator{}); +} + std::uint64_t IrValue::ImmediateU64() const { return immediateBits; } diff --git a/core/shader/recompiler/Recompiler.cpp b/core/shader/recompiler/Recompiler.cpp index 73da42c9aa..2dced2f200 100644 --- a/core/shader/recompiler/Recompiler.cpp +++ b/core/shader/recompiler/Recompiler.cpp @@ -536,6 +536,7 @@ std::shared_ptr getSource(const RecompileRequest& request, ShaderPr ResourceProgram resource(request, preparation, reclaim); source->plan = std::move(resource.plan); if (!hasPreparedArtifact && std::ranges::none_of(source->variants, [&](const auto& variant) { return sameLayout(variant->layout, request.layout); })) { + resource.program->ReleaseUseArena(); source->program = std::move(resource.program); } } catch (...) {