From 34893dd8c84a70e76f3049f0c2860b2b75783669 Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 13 Oct 2026 04:15:48 +0200 Subject: [PATCH] shader: recognize unconditional predicates in implication proofs --- .../recompiler/ir/passes/ResourceTracking.cpp | 2 +- tests/ResourceTrackingTests.cpp | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp index c286a6ac8..59d2d11af 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp @@ -1187,7 +1187,7 @@ private: bool Implies(Value guard, Value required) const { guard = SimplifyGuard(guard); required = required.Resolve(); - if (EquivalentValue(m_program, guard, required)) return true; + if (required == Value(true) || EquivalentValue(m_program, guard, required)) return true; const auto* test = required.TryInstruction(); if (test != nullptr && test->GetOpcode() == ValueOpcode::INotEqual32) { for (uint32_t arg = 0; arg < 2u; ++arg) diff --git a/tests/ResourceTrackingTests.cpp b/tests/ResourceTrackingTests.cpp index 50cf38ffe..8d7c5daea 100644 --- a/tests/ResourceTrackingTests.cpp +++ b/tests/ResourceTrackingTests.cpp @@ -2411,8 +2411,8 @@ void TestScalarBufferSelectorDomain() { void TestPrivateLdsForwarding() { namespace CFG = Libs::Graphics::ShaderRecompiler::CFG; - enum class Variant { Valid, Overlap, Duplicate, CrossLane, Truncated, OutOfBounds, Mask, Bypass }; - for (const auto variant : {Variant::Valid, Variant::Overlap, Variant::Duplicate, + enum class Variant { Valid, MaskedLoad, Overlap, Duplicate, CrossLane, Truncated, OutOfBounds, Mask, Bypass }; + for (const auto variant : {Variant::Valid, Variant::MaskedLoad, Variant::Overlap, Variant::Duplicate, Variant::CrossLane, Variant::Truncated, Variant::OutOfBounds, Variant::Mask, Variant::Bypass}) { Fixture fixture; @@ -2454,7 +2454,8 @@ void TestPrivateLdsForwarding() { body->terminator = {.kind = CFG::TerminatorKind::Branch, .true_block = exit}; const auto load = fixture.Emit(ValueOpcode::LoadSharedU32, {variant == Variant::CrossLane - ? fixture.Emit(ValueOpcode::IAdd32, {address, Value(4u)}) : address, Value(true)}, + ? fixture.Emit(ValueOpcode::IAdd32, {address, Value(4u)}) : address, + variant == Variant::MaskedLoad ? active : Value(true)}, fixture.AddMemory(memory, 0x20), exit); const auto use = fixture.Emit(ValueOpcode::ReferenceU32, {load}, 0, exit); ShaderComputeInputInfo compute; @@ -2464,8 +2465,13 @@ void TestPrivateLdsForwarding() { fixture.PlanAndTrack({.compute = &compute}); const auto result = use.Instruction()->Arg(0).ResolveInstruction(); Check(result != nullptr && - (result->GetOpcode() == ValueOpcode::SelectU32) == (variant == Variant::Valid), + (result->GetOpcode() == ValueOpcode::SelectU32) == + (variant == Variant::Valid || variant == Variant::MaskedLoad), "private LDS forwarding lost its value or crossed an alias, mask, bound or dominance hazard"); + if (variant == Variant::MaskedLoad) + Check(result->Arg(0) == active && result->Arg(1) == Value(0x12345678u) && + result->Arg(2) == Value(0u), + "forwarding an unconditional store lost the load's inactive-lane zero value"); } }