diff options
| author | 2021-02-24 18:33:07 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:22 -0400 | |
| commit | 3bc857f2f34b2959a545d3b4e26f27ca9751f788 (patch) | |
| tree | 07e3099ce1f91a3612b619257b3d67cfafe0b1bb /src | |
| parent | shader: Fix conditional execution of exit instructions (diff) | |
| download | yuzu-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.cpp | 31 |
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>>; |
| 45 | using StorageInstVector = boost::container::small_vector<StorageInst, 24>; | 45 | using StorageInstVector = boost::container::small_vector<StorageInst, 24>; |
| 46 | using 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 |
| 48 | bool IsGlobalMemory(const IR::Inst& inst) { | 50 | bool 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 |
| 197 | std::optional<StorageBufferAddr> Track(const IR::Value& value, const Bias* bias) { | 199 | std::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); |