diff --git a/CMakeLists.txt b/CMakeLists.txt index 12e3542b3..51e872b20 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -849,6 +849,8 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h src/shader_recompiler/ir/basic_block.cpp src/shader_recompiler/ir/basic_block.h src/shader_recompiler/ir/condition.h + src/shader_recompiler/ir/conditional_tree.cpp + src/shader_recompiler/ir/conditional_tree.h src/shader_recompiler/ir/ir_emitter.cpp src/shader_recompiler/ir/ir_emitter.h src/shader_recompiler/ir/microinstruction.cpp diff --git a/src/shader_recompiler/ir/basic_block.h b/src/shader_recompiler/ir/basic_block.h index 74a7d2c56..6e1b19229 100644 --- a/src/shader_recompiler/ir/basic_block.h +++ b/src/shader_recompiler/ir/basic_block.h @@ -11,6 +11,7 @@ #include "common/object_pool.h" #include "common/types.h" +#include "shader_recompiler/ir/abstract_syntax_list.h" #include "shader_recompiler/ir/reg.h" #include "shader_recompiler/ir/value.h" @@ -18,6 +19,12 @@ namespace Shader::IR { class Block { public: + struct ConditionalData { + std::uint32_t depth; + const ConditionalData* parent; + const AbstractSyntaxNode* asl_node; + }; + using InstructionList = boost::intrusive::list; using size_type = InstructionList::size_type; using iterator = InstructionList::iterator; @@ -65,6 +72,16 @@ public: return imm_successors; } + // Set the conditional data for this block. + void SetConditionalData(const ConditionalData& data) { + cond_data = data; + } + + // Get the conditional data for this block. + [[nodiscard]] const ConditionalData& CondData() const { + return cond_data; + } + /// Intrusively store the host definition of this instruction. template void SetDefinition(T def) { @@ -164,6 +181,9 @@ private: /// Block immediate successors std::vector imm_successors; + // Conditional data + Block::ConditionalData cond_data; + /// Intrusively store if the block is sealed in the SSA pass. bool is_ssa_sealed{false}; diff --git a/src/shader_recompiler/ir/conditional_tree.cpp b/src/shader_recompiler/ir/conditional_tree.cpp new file mode 100644 index 000000000..ef00285d9 --- /dev/null +++ b/src/shader_recompiler/ir/conditional_tree.cpp @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "shader_recompiler/ir/conditional_tree.h" +#include "shader_recompiler/ir/basic_block.h" + +#include + +namespace Shader::IR { + +static void AddConditionalTree(std::span asl_span, Block::ConditionalData* parent) { + const auto get_span = [&asl_span](AbstractSyntaxNode& node, Block* merge_block) -> std::span { + auto it = std::find_if(asl_span.begin(), asl_span.end(), + [&node, &merge_block](const AbstractSyntaxNode& n) { + return n.data.block == merge_block; + } + ); + ASSERT(it != asl_span.end()); + std::ptrdiff_t merge_index = std::distance(asl_span.begin(), it); + return std::span(&node + 1, asl_span.data() + merge_index); + }; + const Block::ConditionalData* copied_parent = nullptr; + for (auto it = asl_span.begin(); it < asl_span.end(); ++it) { + AbstractSyntaxNode& node = *it; + if (node.type == AbstractSyntaxNode::Type::If || node.type == AbstractSyntaxNode::Type::Loop) { + ASSERT(copied_parent); + Block* merge_block; + switch (node.type) { + case AbstractSyntaxNode::Type::If: + merge_block = node.data.if_node.merge; + break; + case AbstractSyntaxNode::Type::Loop: + merge_block = node.data.loop.merge; + break; + default: + UNREACHABLE(); + } + auto subspan = get_span(node, merge_block); + Block::ConditionalData cond{copied_parent->depth + 1, copied_parent, &node}; + AddConditionalTree(subspan, &cond); + it += subspan.size(); + } else if (node.type == AbstractSyntaxNode::Type::Block) { + Block* block = node.data.block; + if (!copied_parent) { + block->SetConditionalData(*parent); + copied_parent = &block->CondData(); + } else { + block->SetConditionalData(*copied_parent); + } + } + } +} + +void AddConditionalTreeFromASL(AbstractSyntaxList& syntax_list) { + Block::ConditionalData cond{0, nullptr, nullptr}; + AddConditionalTree(syntax_list, &cond); +} + +} // namespace Shader::IR diff --git a/src/shader_recompiler/ir/conditional_tree.h b/src/shader_recompiler/ir/conditional_tree.h new file mode 100644 index 000000000..9d330bc6d --- /dev/null +++ b/src/shader_recompiler/ir/conditional_tree.h @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "shader_recompiler/ir/abstract_syntax_list.h" + +namespace Shader::IR { + +void AddConditionalTreeFromASL(AbstractSyntaxList& syntax_list); + +} // namespace Shader::IR diff --git a/src/shader_recompiler/recompiler.cpp b/src/shader_recompiler/recompiler.cpp index 2a0f9a819..765d18e05 100644 --- a/src/shader_recompiler/recompiler.cpp +++ b/src/shader_recompiler/recompiler.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "shader_recompiler/frontend/control_flow_graph.h" +#include "shader_recompiler/ir/conditional_tree.h" #include "shader_recompiler/frontend/decode.h" #include "shader_recompiler/frontend/structured_control_flow.h" #include "shader_recompiler/ir/passes/ir_passes.h" @@ -58,6 +59,8 @@ IR::Program TranslateProgram(std::span code, Pools& pools, Info& info program.info, runtime_info, profile); program.blocks = GenerateBlocks(program.syntax_list); program.post_order_blocks = Shader::IR::PostOrder(program.syntax_list.front()); + + Shader::IR::AddConditionalTreeFromASL(program.syntax_list); // Run optimization passes Shader::Optimization::SsaRewritePass(program.post_order_blocks);