summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-02-24 18:33:07 -0300
committerGravatar ameerj2021-07-22 21:51:22 -0400
commit3bc857f2f34b2959a545d3b4e26f27ca9751f788 (patch)
tree07e3099ce1f91a3612b619257b3d67cfafe0b1bb /src
parentshader: Fix conditional execution of exit instructions (diff)
downloadyuzu-3bc857f2f34b2959a545d3b4e26f27ca9751f788.tar.gz
yuzu-3bc857f2f34b2959a545d3b4e26f27ca9751f788.tar.xz
yuzu-3bc857f2f34b2959a545d3b4e26f27ca9751f788.zip
shader: Avoid infinite recursion when tracking global memory
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp31
1 files changed, 26 insertions, 5 deletions
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 =
43 boost::container::flat_set<StorageBufferAddr, std::less<StorageBufferAddr>, 43 boost::container::flat_set<StorageBufferAddr, std::less<StorageBufferAddr>,
44 boost::container::small_vector<StorageBufferAddr, 16>>; 44 boost::container::small_vector<StorageBufferAddr, 16>>;
45using StorageInstVector = boost::container::small_vector<StorageInst, 24>; 45using StorageInstVector = boost::container::small_vector<StorageInst, 24>;
46using VisitedBlocks = boost::container::flat_set<IR::Block*, std::less<IR::Block*>,
47 boost::container::small_vector<IR::Block*, 4>>;
46 48
47/// Returns true when the instruction is a global memory instruction 49/// Returns true when the instruction is a global memory instruction
48bool IsGlobalMemory(const IR::Inst& inst) { 50bool IsGlobalMemory(const IR::Inst& inst) {
@@ -194,7 +196,8 @@ std::optional<LowAddrInfo> TrackLowAddress(IR::Inst* inst) {
194} 196}
195 197
196/// Recursively tries to track the storage buffer address used by a global memory instruction 198/// Recursively tries to track the storage buffer address used by a global memory instruction
197std::optional<StorageBufferAddr> Track(const IR::Value& value, const Bias* bias) { 199std::optional<StorageBufferAddr> Track(IR::Block* block, const IR::Value& value, const Bias* bias,
200 VisitedBlocks& visited) {
198 if (value.IsImmediate()) { 201 if (value.IsImmediate()) {
199 // Immediates can't be a storage buffer 202 // Immediates can't be a storage buffer
200 return std::nullopt; 203 return std::nullopt;
@@ -223,8 +226,24 @@ std::optional<StorageBufferAddr> Track(const IR::Value& value, const Bias* bias)
223 } 226 }
224 // Reversed loops are more likely to find the right result 227 // Reversed loops are more likely to find the right result
225 for (size_t arg = inst->NumArgs(); arg--;) { 228 for (size_t arg = inst->NumArgs(); arg--;) {
226 if (const std::optional storage_buffer{Track(inst->Arg(arg), bias)}) { 229 if (inst->Opcode() == IR::Opcode::Phi) {
227 return *storage_buffer; 230 // If we are going through a phi node, mark the current block as visited
231 visited.insert(block);
232 // and skip already visited blocks to avoid looping forever
233 IR::Block* const phi_block{inst->PhiBlock(arg)};
234 if (visited.contains(phi_block)) {
235 // Already visited, skip
236 continue;
237 }
238 const std::optional storage_buffer{Track(phi_block, inst->Arg(arg), bias, visited)};
239 if (storage_buffer) {
240 return *storage_buffer;
241 }
242 } else {
243 const std::optional storage_buffer{Track(block, inst->Arg(arg), bias, visited)};
244 if (storage_buffer) {
245 return *storage_buffer;
246 }
228 } 247 }
229 } 248 }
230 return std::nullopt; 249 return std::nullopt;
@@ -248,10 +267,12 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageBufferSet& s
248 } 267 }
249 // First try to find storage buffers in the NVN address 268 // First try to find storage buffers in the NVN address
250 const IR::U32 low_addr{low_addr_info->value}; 269 const IR::U32 low_addr{low_addr_info->value};
251 std::optional<StorageBufferAddr> storage_buffer{Track(low_addr, &nvn_bias)}; 270 VisitedBlocks visited_blocks;
271 std::optional storage_buffer{Track(&block, low_addr, &nvn_bias, visited_blocks)};
252 if (!storage_buffer) { 272 if (!storage_buffer) {
253 // If it fails, track without a bias 273 // If it fails, track without a bias
254 storage_buffer = Track(low_addr, nullptr); 274 visited_blocks.clear();
275 storage_buffer = Track(&block, low_addr, nullptr, visited_blocks);
255 if (!storage_buffer) { 276 if (!storage_buffer) {
256 // If that also failed, drop the global memory usage 277 // If that also failed, drop the global memory usage
257 DiscardGlobalMemory(block, inst); 278 DiscardGlobalMemory(block, inst);