From 3bc857f2f34b2959a545d3b4e26f27ca9751f788 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 24 Feb 2021 18:33:07 -0300 Subject: shader: Avoid infinite recursion when tracking global memory --- .../global_memory_to_storage_buffer_pass.cpp | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp') diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index 03bd547b7..98e3dfef7 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp @@ -43,6 +43,8 @@ using StorageBufferSet = boost::container::flat_set, boost::container::small_vector>; using StorageInstVector = boost::container::small_vector; +using VisitedBlocks = boost::container::flat_set, + boost::container::small_vector>; /// Returns true when the instruction is a global memory instruction bool IsGlobalMemory(const IR::Inst& inst) { @@ -194,7 +196,8 @@ std::optional TrackLowAddress(IR::Inst* inst) { } /// Recursively tries to track the storage buffer address used by a global memory instruction -std::optional Track(const IR::Value& value, const Bias* bias) { +std::optional Track(IR::Block* block, const IR::Value& value, const Bias* bias, + VisitedBlocks& visited) { if (value.IsImmediate()) { // Immediates can't be a storage buffer return std::nullopt; @@ -223,8 +226,24 @@ std::optional Track(const IR::Value& value, const Bias* bias) } // Reversed loops are more likely to find the right result for (size_t arg = inst->NumArgs(); arg--;) { - if (const std::optional storage_buffer{Track(inst->Arg(arg), bias)}) { - return *storage_buffer; + if (inst->Opcode() == IR::Opcode::Phi) { + // If we are going through a phi node, mark the current block as visited + visited.insert(block); + // and skip already visited blocks to avoid looping forever + IR::Block* const phi_block{inst->PhiBlock(arg)}; + if (visited.contains(phi_block)) { + // Already visited, skip + continue; + } + const std::optional storage_buffer{Track(phi_block, inst->Arg(arg), bias, visited)}; + if (storage_buffer) { + return *storage_buffer; + } + } else { + const std::optional storage_buffer{Track(block, inst->Arg(arg), bias, visited)}; + if (storage_buffer) { + return *storage_buffer; + } } } return std::nullopt; @@ -248,10 +267,12 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageBufferSet& s } // First try to find storage buffers in the NVN address const IR::U32 low_addr{low_addr_info->value}; - std::optional storage_buffer{Track(low_addr, &nvn_bias)}; + VisitedBlocks visited_blocks; + std::optional storage_buffer{Track(&block, low_addr, &nvn_bias, visited_blocks)}; if (!storage_buffer) { // If it fails, track without a bias - storage_buffer = Track(low_addr, nullptr); + visited_blocks.clear(); + storage_buffer = Track(&block, low_addr, nullptr, visited_blocks); if (!storage_buffer) { // If that also failed, drop the global memory usage DiscardGlobalMemory(block, inst); -- cgit v1.2.3