From 0a229a43dca70d9d4b4b367ffeb79bad81ea00ba Mon Sep 17 00:00:00 2001 From: tototomate123 Date: Thu, 8 Oct 2026 16:48:25 +0200 Subject: [PATCH] fix(shader): evaluate signed minimum in runtime SRT expressions --- .../libSceAgcDriver/tests/ShaderMemory.cpp | 24 +++++++++++++++++++ .../src/SrtWalker/SrtEvaluator.cpp | 6 +++++ .../SrtWalker/SrtInstructionPredicates.cpp | 1 + 3 files changed, 31 insertions(+) diff --git a/core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp b/core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp index bc78344e5..8db39381c 100644 --- a/core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp @@ -7,6 +7,7 @@ #include "Optimization/ShaderStageInputInfo.hpp" #include "Optimization/SrtWalker/SrtDescriptorEvaluation.hpp" #include "Optimization/SrtWalker/SrtEvaluator.hpp" +#include "Optimization/SrtWalker/SrtInstructionPredicates.hpp" #include "Optimization/SrtWalker/SrtFlatSlotClasses.hpp" #include "SpirvBackend/SpirvAnalysis.hpp" #if ANYPS5_ENABLE_SPIRV_TOOLS @@ -360,6 +361,28 @@ void verifyRegisterSources() { require(!EquivalentValue(plan, &samplerRegister, &firstVector), "different register types were merged"); } +void verifySignedMinimum() { + using namespace ShaderRecompiler; + IrResourcePlan plan; + IrValue reg(IrOpcode::Void, IrType::ScalarReg, 0); + reg.SetRegister({RegisterBank::Scalar, 0}); + IrValue input(IrOpcode::GetUserData, IrType::U32, 1); + input.AddArgument(®); + IrValue limit(IrOpcode::Void, IrType::U32, 2); + limit.SetImmediateU32(8); + IrValue minimum(IrOpcode::SMin32, IrType::U32, 3); + minimum.AddArgument(&input); + minimum.AddArgument(&limit); + require(Detail::IsRuntimeUniformOp(IrOpcode::SMin32), "signed minimum must be a runtime uniform operation"); + for (const auto& [value, expected] : std::array, 6>{{{0, 0}, {4, 4}, {20, 8}, {0x7fffffffu, 8}, {0xffffffffu, 0xffffffffu}, {0x80000000u, 0x80000000u}}}) { + std::array data{value}; + SrtRuntime runtime{data}; + Detail::Evaluator evaluator(plan, runtime); + std::uint32_t result = 0; + require(evaluator.Evaluate(&minimum, result) && result == expected, "SRT signed minimum used unsigned ordering or failed evaluation"); + } +} + void verifyEvaluatedValues() { using namespace ShaderRecompiler; std::vector> values; @@ -2568,6 +2591,7 @@ int main(int argc, char** argv) { verifyEvaluatedValues(); verifyFrontendPair(); verifySignedSrtComparison(); + verifySignedMinimum(); verifyPureFlatSlots(); verifyBindlessTable(); verifyDescriptorPhis(); diff --git a/core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp b/core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp index 76c6ceb53..d658afb33 100644 --- a/core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp +++ b/core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp @@ -256,6 +256,12 @@ bool Evaluator::EvaluateInst(IrValue& inst, std::uint64_t& result) { return true; } return false; + case IrOpcode::SMin32: + if (binary()) { + result = static_cast(std::min(std::bit_cast(static_cast(a)), std::bit_cast(static_cast(b)))); + return true; + } + return false; case IrOpcode::UMin32: if (binary()) { result = std::min(static_cast(a), static_cast(b)); diff --git a/core/shader/recompiler/Optimization/src/SrtWalker/SrtInstructionPredicates.cpp b/core/shader/recompiler/Optimization/src/SrtWalker/SrtInstructionPredicates.cpp index 274524be7..0f3a3a6af 100644 --- a/core/shader/recompiler/Optimization/src/SrtWalker/SrtInstructionPredicates.cpp +++ b/core/shader/recompiler/Optimization/src/SrtWalker/SrtInstructionPredicates.cpp @@ -70,6 +70,7 @@ bool IsRuntimeUniformOp(IrOpcode opcode) { case IrOpcode::ISub64: case IrOpcode::IMul32: case IrOpcode::IMul64: + case IrOpcode::SMin32: case IrOpcode::UMin32: case IrOpcode::ShiftLeftLogical32: case IrOpcode::ShiftLeftLogical64: