summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2021-05-14 05:40:54 +0200
committerameerj <52414509+ameerj@users.noreply.github.com>2021-07-23 03:51:31 +0200
commitd54d7de40e7295827b0e4e4026441b53d3fc9569 (patch)
tree29b5074f851292dace7aeb5da7716675544b3735 /src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
parentglasm: Implement Storage atomics (diff)
downloadyuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar
yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar.gz
yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar.bz2
yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar.lz
yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar.xz
yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.tar.zst
yuzu-d54d7de40e7295827b0e4e4026441b53d3fc9569.zip
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp')
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp235
1 files changed, 136 insertions, 99 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index cc5410c6d..e7e2e9c82 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -36,7 +36,6 @@ using Tree = boost::intrusive::list<Statement,
// Avoid linear complexity on splice, size is never called
boost::intrusive::constant_time_size<false>>;
using Node = Tree::iterator;
-using ConstNode = Tree::const_iterator;
enum class StatementType {
Code,
@@ -91,7 +90,8 @@ struct IndirectBranchCond {};
#pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement
#endif
struct Statement : ListBaseHook {
- Statement(IR::Block* code_, Statement* up_) : code{code_}, up{up_}, type{StatementType::Code} {}
+ Statement(const Flow::Block* block_, Statement* up_)
+ : block{block_}, up{up_}, type{StatementType::Code} {}
Statement(Goto, Statement* cond_, Node label_, Statement* up_)
: label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {}
Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {}
@@ -125,7 +125,7 @@ struct Statement : ListBaseHook {
}
union {
- IR::Block* code;
+ const Flow::Block* block;
Node label;
Tree children;
IR::Condition guest_cond;
@@ -171,8 +171,8 @@ std::string DumpTree(const Tree& tree, u32 indentation = 0) {
switch (stmt->type) {
case StatementType::Code:
ret += fmt::format("{} Block {:04x} -> {:04x} (0x{:016x});\n", indent,
- stmt->code->LocationBegin(), stmt->code->LocationEnd(),
- reinterpret_cast<uintptr_t>(stmt->code));
+ stmt->block->begin, stmt->block->end,
+ reinterpret_cast<uintptr_t>(stmt->block));
break;
case StatementType::Goto:
ret += fmt::format("{} if ({}) goto L{};\n", indent, DumpExpr(stmt->cond),
@@ -407,11 +407,7 @@ private:
}};
root.push_front(make_reset_variable());
root.insert(ip, make_reset_variable());
-
- const u32 begin_offset{block.begin.Offset()};
- const u32 end_offset{block.end.Offset()};
- IR::Block* const ir_block{block_pool.Create(inst_pool, begin_offset, end_offset)};
- root.insert(ip, *pool.Create(ir_block, &root_stmt));
+ root.insert(ip, *pool.Create(&block, &root_stmt));
switch (block.end_class) {
case Flow::EndClass::Branch: {
@@ -620,13 +616,13 @@ private:
Statement root_stmt{FunctionTag{}};
};
-IR::Block* TryFindForwardBlock(const Statement& stmt) {
- const Tree& tree{stmt.up->children};
- const ConstNode end{tree.cend()};
- ConstNode forward_node{std::next(Tree::s_iterator_to(stmt))};
+[[nodiscard]] Statement* TryFindForwardBlock(Statement& stmt) {
+ Tree& tree{stmt.up->children};
+ const Node end{tree.end()};
+ Node forward_node{std::next(Tree::s_iterator_to(stmt))};
while (forward_node != end && !HasChildren(forward_node->type)) {
if (forward_node->type == StatementType::Code) {
- return forward_node->code;
+ return &*forward_node;
}
++forward_node;
}
@@ -654,21 +650,29 @@ class TranslatePass {
public:
TranslatePass(ObjectPool<IR::Inst>& inst_pool_, ObjectPool<IR::Block>& block_pool_,
ObjectPool<Statement>& stmt_pool_, Environment& env_, Statement& root_stmt,
- IR::BlockList& block_list_)
+ IR::AbstractSyntaxList& syntax_list_)
: stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_},
- block_list{block_list_} {
+ syntax_list{syntax_list_} {
Visit(root_stmt, nullptr, nullptr);
- IR::Block& first_block{*block_list.front()};
+ IR::Block& first_block{*syntax_list.front().block};
IR::IREmitter ir{first_block, first_block.begin()};
ir.Prologue();
}
private:
- void Visit(Statement& parent, IR::Block* continue_block, IR::Block* break_block) {
+ void Visit(Statement& parent, IR::Block* break_block, IR::Block* fallthrough_block) {
+ IR::Block* current_block{};
+ const auto ensure_block{[&] {
+ if (current_block) {
+ return;
+ }
+ current_block = block_pool.Create(inst_pool);
+ auto& node{syntax_list.emplace_back()};
+ node.type = IR::AbstractSyntaxNode::Type::Block;
+ node.block = current_block;
+ }};
Tree& tree{parent.children};
- IR::Block* current_block{nullptr};
-
for (auto it = tree.begin(); it != tree.end(); ++it) {
Statement& stmt{*it};
switch (stmt.type) {
@@ -676,124 +680,157 @@ private:
// Labels can be ignored
break;
case StatementType::Code: {
- if (current_block && current_block != stmt.code) {
- IR::IREmitter{*current_block}.Branch(stmt.code);
- }
- current_block = stmt.code;
- Translate(env, stmt.code);
- block_list.push_back(stmt.code);
+ ensure_block();
+ Translate(env, current_block, stmt.block->begin.Offset(), stmt.block->end.Offset());
break;
}
case StatementType::SetVariable: {
- if (!current_block) {
- current_block = MergeBlock(parent, stmt);
- }
+ ensure_block();
IR::IREmitter ir{*current_block};
ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op));
break;
}
case StatementType::SetIndirectBranchVariable: {
- if (!current_block) {
- current_block = MergeBlock(parent, stmt);
- }
+ ensure_block();
IR::IREmitter ir{*current_block};
IR::U32 address{ir.IAdd(ir.GetReg(stmt.branch_reg), ir.Imm32(stmt.branch_offset))};
ir.SetIndirectBranchVariable(address);
break;
}
case StatementType::If: {
- if (!current_block) {
- current_block = block_pool.Create(inst_pool);
- block_list.push_back(current_block);
- }
+ ensure_block();
IR::Block* const merge_block{MergeBlock(parent, stmt)};
- // Visit children
- const size_t first_block_index{block_list.size()};
- Visit(stmt, merge_block, break_block);
-
// Implement if header block
- IR::Block* const first_if_block{block_list.at(first_block_index)};
IR::IREmitter ir{*current_block};
const IR::U1 cond{VisitExpr(ir, *stmt.cond)};
- ir.SelectionMerge(merge_block);
- ir.BranchConditional(cond, first_if_block, merge_block);
+ ir.BranchConditionRef(cond);
+ const size_t if_node_index{syntax_list.size()};
+ syntax_list.emplace_back();
+
+ // Visit children
+ const size_t then_block_index{syntax_list.size()};
+ Visit(stmt, break_block, merge_block);
+
+ IR::Block* const then_block{syntax_list.at(then_block_index).block};
+ current_block->AddBranch(then_block);
+ current_block->AddBranch(merge_block);
current_block = merge_block;
+
+ auto& if_node{syntax_list[if_node_index]};
+ if_node.type = IR::AbstractSyntaxNode::Type::If;
+ if_node.if_node.cond = cond;
+ if_node.if_node.body = then_block;
+ if_node.if_node.merge = merge_block;
+
+ auto& endif_node{syntax_list.emplace_back()};
+ endif_node.type = IR::AbstractSyntaxNode::Type::EndIf;
+ endif_node.end_if.merge = merge_block;
+
+ auto& merge{syntax_list.emplace_back()};
+ merge.type = IR::AbstractSyntaxNode::Type::Block;
+ merge.block = merge_block;
break;
}
case StatementType::Loop: {
IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
if (current_block) {
- IR::IREmitter{*current_block}.Branch(loop_header_block);
+ current_block->AddBranch(loop_header_block);
}
- block_list.push_back(loop_header_block);
+ auto& header_node{syntax_list.emplace_back()};
+ header_node.type = IR::AbstractSyntaxNode::Type::Block;
+ header_node.block = loop_header_block;
- IR::Block* const new_continue_block{block_pool.Create(inst_pool)};
+ IR::Block* const continue_block{block_pool.Create(inst_pool)};
IR::Block* const merge_block{MergeBlock(parent, stmt)};
+ const size_t loop_node_index{syntax_list.size()};
+ syntax_list.emplace_back();
+
// Visit children
- const size_t first_block_index{block_list.size()};
- Visit(stmt, new_continue_block, merge_block);
+ const size_t body_block_index{syntax_list.size()};
+ Visit(stmt, merge_block, continue_block);
// The continue block is located at the end of the loop
- block_list.push_back(new_continue_block);
+ IR::IREmitter ir{*continue_block};
+ const IR::U1 cond{VisitExpr(ir, *stmt.cond)};
+ ir.BranchConditionRef(cond);
- // Implement loop header block
- IR::Block* const first_loop_block{block_list.at(first_block_index)};
- IR::IREmitter ir{*loop_header_block};
- ir.LoopMerge(merge_block, new_continue_block);
- ir.Branch(first_loop_block);
+ IR::Block* const body_block{syntax_list.at(body_block_index).block};
+ loop_header_block->AddBranch(body_block);
- // Implement continue block
- IR::IREmitter continue_ir{*new_continue_block};
- const IR::U1 continue_cond{VisitExpr(continue_ir, *stmt.cond)};
- continue_ir.BranchConditional(continue_cond, ir.block, merge_block);
+ continue_block->AddBranch(loop_header_block);
+ continue_block->AddBranch(merge_block);
current_block = merge_block;
+
+ auto& loop{syntax_list[loop_node_index]};
+ loop.type = IR::AbstractSyntaxNode::Type::Loop;
+ loop.loop.body = body_block;
+ loop.loop.continue_block = continue_block;
+ loop.loop.merge = merge_block;
+
+ auto& continue_block_node{syntax_list.emplace_back()};
+ continue_block_node.type = IR::AbstractSyntaxNode::Type::Block;
+ continue_block_node.block = continue_block;
+
+ auto& repeat{syntax_list.emplace_back()};
+ repeat.type = IR::AbstractSyntaxNode::Type::Repeat;
+ repeat.repeat.cond = cond;
+ repeat.repeat.loop_header = loop_header_block;
+ repeat.repeat.merge = merge_block;
+
+ auto& merge{syntax_list.emplace_back()};
+ merge.type = IR::AbstractSyntaxNode::Type::Block;
+ merge.block = merge_block;
break;
}
case StatementType::Break: {
- if (!current_block) {
- current_block = block_pool.Create(inst_pool);
- block_list.push_back(current_block);
- }
+ ensure_block();
IR::Block* const skip_block{MergeBlock(parent, stmt)};
IR::IREmitter ir{*current_block};
- ir.BranchConditional(VisitExpr(ir, *stmt.cond), break_block, skip_block);
-
+ const IR::U1 cond{VisitExpr(ir, *stmt.cond)};
+ ir.BranchConditionRef(cond);
+ current_block->AddBranch(break_block);
+ current_block->AddBranch(skip_block);
current_block = skip_block;
+
+ auto& break_node{syntax_list.emplace_back()};
+ break_node.type = IR::AbstractSyntaxNode::Type::Break;
+ break_node.break_node.cond = cond;
+ break_node.break_node.merge = break_block;
+ break_node.break_node.skip = skip_block;
+
+ auto& merge{syntax_list.emplace_back()};
+ merge.type = IR::AbstractSyntaxNode::Type::Block;
+ merge.block = skip_block;
break;
}
case StatementType::Return: {
- if (!current_block) {
- current_block = block_pool.Create(inst_pool);
- block_list.push_back(current_block);
- }
- IR::IREmitter ir{*current_block};
- ir.Epilogue();
- ir.Return();
+ ensure_block();
+ IR::IREmitter{*current_block}.Epilogue();
current_block = nullptr;
+ syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return;
break;
}
case StatementType::Kill: {
- if (!current_block) {
- current_block = block_pool.Create(inst_pool);
- block_list.push_back(current_block);
- }
+ ensure_block();
IR::Block* demote_block{MergeBlock(parent, stmt)};
- IR::IREmitter{*current_block}.DemoteToHelperInvocation(demote_block);
+ IR::IREmitter{*current_block}.DemoteToHelperInvocation();
+ current_block->AddBranch(demote_block);
current_block = demote_block;
+
+ auto& merge{syntax_list.emplace_back()};
+ merge.type = IR::AbstractSyntaxNode::Type::Block;
+ merge.block = demote_block;
break;
}
case StatementType::Unreachable: {
- if (!current_block) {
- current_block = block_pool.Create(inst_pool);
- block_list.push_back(current_block);
- }
- IR::IREmitter{*current_block}.Unreachable();
+ ensure_block();
current_block = nullptr;
+ syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Unreachable;
break;
}
default:
@@ -801,42 +838,42 @@ private:
}
}
if (current_block) {
- IR::IREmitter ir{*current_block};
- if (continue_block) {
- ir.Branch(continue_block);
+ if (fallthrough_block) {
+ current_block->AddBranch(fallthrough_block);
} else {
- ir.Unreachable();
+ syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Unreachable;
}
}
}
IR::Block* MergeBlock(Statement& parent, Statement& stmt) {
- if (IR::Block* const block{TryFindForwardBlock(stmt)}) {
- return block;
+ Statement* merge_stmt{TryFindForwardBlock(stmt)};
+ if (!merge_stmt) {
+ // Create a merge block we can visit later
+ merge_stmt = stmt_pool.Create(&dummy_flow_block, &parent);
+ parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt);
}
- // Create a merge block we can visit later
- IR::Block* const block{block_pool.Create(inst_pool)};
- Statement* const merge_stmt{stmt_pool.Create(block, &parent)};
- parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt);
- return block;
+ return block_pool.Create(inst_pool);
}
ObjectPool<Statement>& stmt_pool;
ObjectPool<IR::Inst>& inst_pool;
ObjectPool<IR::Block>& block_pool;
Environment& env;
- IR::BlockList& block_list;
+ IR::AbstractSyntaxList& syntax_list;
+ // TODO: Make this constexpr when std::vector is constexpr
+ const Flow::Block dummy_flow_block;
};
} // Anonymous namespace
-IR::BlockList VisitAST(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
- Environment& env, Flow::CFG& cfg) {
+IR::AbstractSyntaxList BuildASL(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
+ Environment& env, Flow::CFG& cfg) {
ObjectPool<Statement> stmt_pool{64};
GotoPass goto_pass{cfg, inst_pool, block_pool, stmt_pool};
Statement& root{goto_pass.RootStatement()};
- IR::BlockList block_list;
- TranslatePass{inst_pool, block_pool, stmt_pool, env, root, block_list};
- return block_list;
+ IR::AbstractSyntaxList syntax_list;
+ TranslatePass{inst_pool, block_pool, stmt_pool, env, root, syntax_list};
+ return syntax_list;
}
} // namespace Shader::Maxwell