diff options
Diffstat (limited to '')
| -rw-r--r-- | src/shader_recompiler/frontend/ir/function.cpp | 5 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/function.h | 18 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/program.cpp | 18 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/ir/program.h | 5 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp (renamed from src/shader_recompiler/frontend/ir/structured_control_flow.cpp) | 254 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/structured_control_flow.h (renamed from src/shader_recompiler/frontend/ir/structured_control_flow.h) | 12 |
6 files changed, 157 insertions, 155 deletions
diff --git a/src/shader_recompiler/frontend/ir/function.cpp b/src/shader_recompiler/frontend/ir/function.cpp deleted file mode 100644 index d1fc9461d..000000000 --- a/src/shader_recompiler/frontend/ir/function.cpp +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "shader_recompiler/frontend/ir/function.h" | ||
diff --git a/src/shader_recompiler/frontend/ir/function.h b/src/shader_recompiler/frontend/ir/function.h deleted file mode 100644 index d1f061146..000000000 --- a/src/shader_recompiler/frontend/ir/function.h +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <boost/container/small_vector.hpp> | ||
| 8 | |||
| 9 | #include "shader_recompiler/frontend/ir/basic_block.h" | ||
| 10 | |||
| 11 | namespace Shader::IR { | ||
| 12 | |||
| 13 | struct Function { | ||
| 14 | BlockList blocks; | ||
| 15 | BlockList post_order_blocks; | ||
| 16 | }; | ||
| 17 | |||
| 18 | } // namespace Shader::IR | ||
diff --git a/src/shader_recompiler/frontend/ir/program.cpp b/src/shader_recompiler/frontend/ir/program.cpp index 8c301c3a1..5f51aeb5f 100644 --- a/src/shader_recompiler/frontend/ir/program.cpp +++ b/src/shader_recompiler/frontend/ir/program.cpp | |||
| @@ -9,7 +9,8 @@ | |||
| 9 | 9 | ||
| 10 | #include <fmt/format.h> | 10 | #include <fmt/format.h> |
| 11 | 11 | ||
| 12 | #include "shader_recompiler/frontend/ir/function.h" | 12 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 13 | #include "shader_recompiler/frontend/ir/microinstruction.h" | ||
| 13 | #include "shader_recompiler/frontend/ir/program.h" | 14 | #include "shader_recompiler/frontend/ir/program.h" |
| 14 | 15 | ||
| 15 | namespace Shader::IR { | 16 | namespace Shader::IR { |
| @@ -19,18 +20,13 @@ std::string DumpProgram(const Program& program) { | |||
| 19 | std::map<const IR::Inst*, size_t> inst_to_index; | 20 | std::map<const IR::Inst*, size_t> inst_to_index; |
| 20 | std::map<const IR::Block*, size_t> block_to_index; | 21 | std::map<const IR::Block*, size_t> block_to_index; |
| 21 | 22 | ||
| 22 | for (const IR::Function& function : program.functions) { | 23 | for (const IR::Block* const block : program.blocks) { |
| 23 | for (const IR::Block* const block : function.blocks) { | 24 | block_to_index.emplace(block, index); |
| 24 | block_to_index.emplace(block, index); | 25 | ++index; |
| 25 | ++index; | ||
| 26 | } | ||
| 27 | } | 26 | } |
| 28 | std::string ret; | 27 | std::string ret; |
| 29 | for (const IR::Function& function : program.functions) { | 28 | for (const auto& block : program.blocks) { |
| 30 | ret += fmt::format("Function\n"); | 29 | ret += IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n'; |
| 31 | for (const auto& block : function.blocks) { | ||
| 32 | ret += IR::DumpBlock(*block, block_to_index, inst_to_index, index) + '\n'; | ||
| 33 | } | ||
| 34 | } | 30 | } |
| 35 | return ret; | 31 | return ret; |
| 36 | } | 32 | } |
diff --git a/src/shader_recompiler/frontend/ir/program.h b/src/shader_recompiler/frontend/ir/program.h index 98aab2dc6..bce8b19b3 100644 --- a/src/shader_recompiler/frontend/ir/program.h +++ b/src/shader_recompiler/frontend/ir/program.h | |||
| @@ -8,13 +8,14 @@ | |||
| 8 | 8 | ||
| 9 | #include <boost/container/small_vector.hpp> | 9 | #include <boost/container/small_vector.hpp> |
| 10 | 10 | ||
| 11 | #include "shader_recompiler/frontend/ir/function.h" | 11 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 12 | #include "shader_recompiler/shader_info.h" | 12 | #include "shader_recompiler/shader_info.h" |
| 13 | 13 | ||
| 14 | namespace Shader::IR { | 14 | namespace Shader::IR { |
| 15 | 15 | ||
| 16 | struct Program { | 16 | struct Program { |
| 17 | boost::container::small_vector<Function, 1> functions; | 17 | BlockList blocks; |
| 18 | BlockList post_order_blocks; | ||
| 18 | Info info; | 19 | Info info; |
| 19 | }; | 20 | }; |
| 20 | 21 | ||
diff --git a/src/shader_recompiler/frontend/ir/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index bfba55a7e..5f5d9cf17 100644 --- a/src/shader_recompiler/frontend/ir/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | |||
| @@ -14,11 +14,14 @@ | |||
| 14 | 14 | ||
| 15 | #include <boost/intrusive/list.hpp> | 15 | #include <boost/intrusive/list.hpp> |
| 16 | 16 | ||
| 17 | #include "shader_recompiler/environment.h" | ||
| 17 | #include "shader_recompiler/frontend/ir/basic_block.h" | 18 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 18 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | 19 | #include "shader_recompiler/frontend/ir/ir_emitter.h" |
| 20 | #include "shader_recompiler/frontend/maxwell/structured_control_flow.h" | ||
| 21 | #include "shader_recompiler/frontend/maxwell/translate/translate.h" | ||
| 19 | #include "shader_recompiler/object_pool.h" | 22 | #include "shader_recompiler/object_pool.h" |
| 20 | 23 | ||
| 21 | namespace Shader::IR { | 24 | namespace Shader::Maxwell { |
| 22 | namespace { | 25 | namespace { |
| 23 | struct Statement; | 26 | struct Statement; |
| 24 | 27 | ||
| @@ -79,7 +82,7 @@ struct Variable {}; | |||
| 79 | #pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement | 82 | #pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement |
| 80 | #endif | 83 | #endif |
| 81 | struct Statement : ListBaseHook { | 84 | struct Statement : ListBaseHook { |
| 82 | Statement(Block* code_, Statement* up_) : code{code_}, up{up_}, type{StatementType::Code} {} | 85 | Statement(IR::Block* code_, Statement* up_) : code{code_}, up{up_}, type{StatementType::Code} {} |
| 83 | Statement(Goto, Statement* cond_, Node label_, Statement* up_) | 86 | Statement(Goto, Statement* cond_, Node label_, Statement* up_) |
| 84 | : label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {} | 87 | : label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {} |
| 85 | Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {} | 88 | Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {} |
| @@ -91,7 +94,7 @@ struct Statement : ListBaseHook { | |||
| 91 | : cond{cond_}, up{up_}, type{StatementType::Break} {} | 94 | : cond{cond_}, up{up_}, type{StatementType::Break} {} |
| 92 | Statement(Return) : type{StatementType::Return} {} | 95 | Statement(Return) : type{StatementType::Return} {} |
| 93 | Statement(FunctionTag) : children{}, type{StatementType::Function} {} | 96 | Statement(FunctionTag) : children{}, type{StatementType::Function} {} |
| 94 | Statement(Identity, Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {} | 97 | Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {} |
| 95 | Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {} | 98 | Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {} |
| 96 | Statement(Or, Statement* op_a_, Statement* op_b_) | 99 | Statement(Or, Statement* op_a_, Statement* op_b_) |
| 97 | : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {} | 100 | : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {} |
| @@ -106,10 +109,10 @@ struct Statement : ListBaseHook { | |||
| 106 | } | 109 | } |
| 107 | 110 | ||
| 108 | union { | 111 | union { |
| 109 | Block* code; | 112 | IR::Block* code; |
| 110 | Node label; | 113 | Node label; |
| 111 | Tree children; | 114 | Tree children; |
| 112 | Condition guest_cond; | 115 | IR::Condition guest_cond; |
| 113 | Statement* op; | 116 | Statement* op; |
| 114 | Statement* op_a; | 117 | Statement* op_a; |
| 115 | }; | 118 | }; |
| @@ -269,9 +272,10 @@ bool SearchNode(const Tree& tree, ConstNode stmt, size_t& offset) { | |||
| 269 | 272 | ||
| 270 | class GotoPass { | 273 | class GotoPass { |
| 271 | public: | 274 | public: |
| 272 | explicit GotoPass(std::span<Block* const> blocks, ObjectPool<Statement>& stmt_pool) | 275 | explicit GotoPass(Flow::CFG& cfg, ObjectPool<IR::Inst>& inst_pool_, |
| 273 | : pool{stmt_pool} { | 276 | ObjectPool<IR::Block>& block_pool_, ObjectPool<Statement>& stmt_pool) |
| 274 | std::vector gotos{BuildUnorderedTreeGetGotos(blocks)}; | 277 | : inst_pool{inst_pool_}, block_pool{block_pool_}, pool{stmt_pool} { |
| 278 | std::vector gotos{BuildTree(cfg)}; | ||
| 275 | for (const Node& goto_stmt : gotos | std::views::reverse) { | 279 | for (const Node& goto_stmt : gotos | std::views::reverse) { |
| 276 | RemoveGoto(goto_stmt); | 280 | RemoveGoto(goto_stmt); |
| 277 | } | 281 | } |
| @@ -316,18 +320,20 @@ private: | |||
| 316 | } | 320 | } |
| 317 | } | 321 | } |
| 318 | // TODO: Remove this | 322 | // TODO: Remove this |
| 319 | Node it{goto_stmt}; | 323 | { |
| 320 | bool sibling{false}; | 324 | Node it{goto_stmt}; |
| 321 | do { | 325 | bool sibling{false}; |
| 322 | sibling |= it == label_stmt; | 326 | do { |
| 323 | --it; | 327 | sibling |= it == label_stmt; |
| 324 | } while (it != goto_stmt->up->children.begin()); | 328 | --it; |
| 325 | while (it != goto_stmt->up->children.end()) { | 329 | } while (it != goto_stmt->up->children.begin()); |
| 326 | sibling |= it == label_stmt; | 330 | while (it != goto_stmt->up->children.end()) { |
| 327 | ++it; | 331 | sibling |= it == label_stmt; |
| 328 | } | 332 | ++it; |
| 329 | if (!sibling) { | 333 | } |
| 330 | throw LogicError("Not siblings"); | 334 | if (!sibling) { |
| 335 | throw LogicError("Not siblings"); | ||
| 336 | } | ||
| 331 | } | 337 | } |
| 332 | // goto_stmt and label_stmt are guaranteed to be siblings, eliminate | 338 | // goto_stmt and label_stmt are guaranteed to be siblings, eliminate |
| 333 | if (std::next(goto_stmt) == label_stmt) { | 339 | if (std::next(goto_stmt) == label_stmt) { |
| @@ -342,63 +348,84 @@ private: | |||
| 342 | } | 348 | } |
| 343 | } | 349 | } |
| 344 | 350 | ||
| 345 | std::vector<Node> BuildUnorderedTreeGetGotos(std::span<Block* const> blocks) { | 351 | std::vector<Node> BuildTree(Flow::CFG& cfg) { |
| 346 | // Assume all blocks have two branches | 352 | u32 label_id{0}; |
| 347 | std::vector<Node> gotos; | 353 | std::vector<Node> gotos; |
| 348 | gotos.reserve(blocks.size() * 2); | 354 | Flow::Function& first_function{cfg.Functions().front()}; |
| 349 | 355 | BuildTree(cfg, first_function, label_id, gotos, root_stmt.children.end(), std::nullopt); | |
| 350 | const std::unordered_map labels_map{BuildLabels(blocks)}; | ||
| 351 | Tree& root{root_stmt.children}; | ||
| 352 | auto insert_point{root.begin()}; | ||
| 353 | // Skip all goto variables zero-initialization | ||
| 354 | std::advance(insert_point, labels_map.size()); | ||
| 355 | |||
| 356 | for (Block* const block : blocks) { | ||
| 357 | // Skip label | ||
| 358 | ++insert_point; | ||
| 359 | // Skip set variable | ||
| 360 | ++insert_point; | ||
| 361 | root.insert(insert_point, *pool.Create(block, &root_stmt)); | ||
| 362 | |||
| 363 | if (block->IsTerminationBlock()) { | ||
| 364 | root.insert(insert_point, *pool.Create(Return{})); | ||
| 365 | continue; | ||
| 366 | } | ||
| 367 | const Condition cond{block->BranchCondition()}; | ||
| 368 | Statement* const true_cond{pool.Create(Identity{}, Condition{true})}; | ||
| 369 | if (cond == Condition{true} || cond == Condition{false}) { | ||
| 370 | const bool is_true{cond == Condition{true}}; | ||
| 371 | const Block* const branch{is_true ? block->TrueBranch() : block->FalseBranch()}; | ||
| 372 | const Node label{labels_map.at(branch)}; | ||
| 373 | Statement* const goto_stmt{pool.Create(Goto{}, true_cond, label, &root_stmt)}; | ||
| 374 | gotos.push_back(root.insert(insert_point, *goto_stmt)); | ||
| 375 | } else { | ||
| 376 | Statement* const ident_cond{pool.Create(Identity{}, cond)}; | ||
| 377 | const Node true_label{labels_map.at(block->TrueBranch())}; | ||
| 378 | const Node false_label{labels_map.at(block->FalseBranch())}; | ||
| 379 | Statement* goto_true{pool.Create(Goto{}, ident_cond, true_label, &root_stmt)}; | ||
| 380 | Statement* goto_false{pool.Create(Goto{}, true_cond, false_label, &root_stmt)}; | ||
| 381 | gotos.push_back(root.insert(insert_point, *goto_true)); | ||
| 382 | gotos.push_back(root.insert(insert_point, *goto_false)); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | return gotos; | 356 | return gotos; |
| 386 | } | 357 | } |
| 387 | 358 | ||
| 388 | std::unordered_map<const Block*, Node> BuildLabels(std::span<Block* const> blocks) { | 359 | void BuildTree(Flow::CFG& cfg, Flow::Function& function, u32& label_id, |
| 389 | // TODO: Consider storing labels intrusively inside the block | 360 | std::vector<Node>& gotos, Node function_insert_point, |
| 390 | std::unordered_map<const Block*, Node> labels_map; | 361 | std::optional<Node> return_label) { |
| 362 | Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false})}; | ||
| 391 | Tree& root{root_stmt.children}; | 363 | Tree& root{root_stmt.children}; |
| 392 | u32 label_id{0}; | 364 | std::unordered_map<Flow::Block*, Node> local_labels; |
| 393 | for (const Block* const block : blocks) { | 365 | local_labels.reserve(function.blocks.size()); |
| 366 | |||
| 367 | for (Flow::Block& block : function.blocks) { | ||
| 394 | Statement* const label{pool.Create(Label{}, label_id, &root_stmt)}; | 368 | Statement* const label{pool.Create(Label{}, label_id, &root_stmt)}; |
| 395 | labels_map.emplace(block, root.insert(root.end(), *label)); | 369 | const Node label_it{root.insert(function_insert_point, *label)}; |
| 396 | Statement* const false_stmt{pool.Create(Identity{}, Condition{false})}; | 370 | local_labels.emplace(&block, label_it); |
| 397 | root.push_back(*pool.Create(SetVariable{}, label_id, false_stmt, &root_stmt)); | ||
| 398 | root.push_front(*pool.Create(SetVariable{}, label_id, false_stmt, &root_stmt)); | ||
| 399 | ++label_id; | 371 | ++label_id; |
| 400 | } | 372 | } |
| 401 | return labels_map; | 373 | for (Flow::Block& block : function.blocks) { |
| 374 | const Node label{local_labels.at(&block)}; | ||
| 375 | // Insertion point | ||
| 376 | const Node ip{std::next(label)}; | ||
| 377 | |||
| 378 | // Reset goto variables before the first block and after its respective label | ||
| 379 | const auto make_reset_variable{[&]() -> Statement& { | ||
| 380 | return *pool.Create(SetVariable{}, label->id, false_stmt, &root_stmt); | ||
| 381 | }}; | ||
| 382 | root.push_front(make_reset_variable()); | ||
| 383 | root.insert(ip, make_reset_variable()); | ||
| 384 | |||
| 385 | const u32 begin_offset{block.begin.Offset()}; | ||
| 386 | const u32 end_offset{block.end.Offset()}; | ||
| 387 | IR::Block* const ir_block{block_pool.Create(inst_pool, begin_offset, end_offset)}; | ||
| 388 | root.insert(ip, *pool.Create(ir_block, &root_stmt)); | ||
| 389 | |||
| 390 | switch (block.end_class) { | ||
| 391 | case Flow::EndClass::Branch: { | ||
| 392 | Statement* const always_cond{pool.Create(Identity{}, IR::Condition{true})}; | ||
| 393 | if (block.cond == IR::Condition{true}) { | ||
| 394 | const Node true_label{local_labels.at(block.branch_true)}; | ||
| 395 | gotos.push_back( | ||
| 396 | root.insert(ip, *pool.Create(Goto{}, always_cond, true_label, &root_stmt))); | ||
| 397 | } else if (block.cond == IR::Condition{false}) { | ||
| 398 | const Node false_label{local_labels.at(block.branch_false)}; | ||
| 399 | gotos.push_back(root.insert( | ||
| 400 | ip, *pool.Create(Goto{}, always_cond, false_label, &root_stmt))); | ||
| 401 | } else { | ||
| 402 | const Node true_label{local_labels.at(block.branch_true)}; | ||
| 403 | const Node false_label{local_labels.at(block.branch_false)}; | ||
| 404 | Statement* const true_cond{pool.Create(Identity{}, block.cond)}; | ||
| 405 | gotos.push_back( | ||
| 406 | root.insert(ip, *pool.Create(Goto{}, true_cond, true_label, &root_stmt))); | ||
| 407 | gotos.push_back(root.insert( | ||
| 408 | ip, *pool.Create(Goto{}, always_cond, false_label, &root_stmt))); | ||
| 409 | } | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | case Flow::EndClass::Call: { | ||
| 413 | Flow::Function& call{cfg.Functions()[block.function_call]}; | ||
| 414 | const Node call_return_label{local_labels.at(block.return_block)}; | ||
| 415 | BuildTree(cfg, call, label_id, gotos, ip, call_return_label); | ||
| 416 | break; | ||
| 417 | } | ||
| 418 | case Flow::EndClass::Exit: | ||
| 419 | root.insert(ip, *pool.Create(Return{})); | ||
| 420 | break; | ||
| 421 | case Flow::EndClass::Return: { | ||
| 422 | Statement* const always_cond{pool.Create(Identity{}, block.cond)}; | ||
| 423 | auto goto_stmt{pool.Create(Goto{}, always_cond, return_label.value(), &root_stmt)}; | ||
| 424 | gotos.push_back(root.insert(ip, *goto_stmt)); | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | } | ||
| 402 | } | 429 | } |
| 403 | 430 | ||
| 404 | void UpdateTreeUp(Statement* tree) { | 431 | void UpdateTreeUp(Statement* tree) { |
| @@ -556,11 +583,13 @@ private: | |||
| 556 | return offset; | 583 | return offset; |
| 557 | } | 584 | } |
| 558 | 585 | ||
| 586 | ObjectPool<IR::Inst>& inst_pool; | ||
| 587 | ObjectPool<IR::Block>& block_pool; | ||
| 559 | ObjectPool<Statement>& pool; | 588 | ObjectPool<Statement>& pool; |
| 560 | Statement root_stmt{FunctionTag{}}; | 589 | Statement root_stmt{FunctionTag{}}; |
| 561 | }; | 590 | }; |
| 562 | 591 | ||
| 563 | Block* TryFindForwardBlock(const Statement& stmt) { | 592 | IR::Block* TryFindForwardBlock(const Statement& stmt) { |
| 564 | const Tree& tree{stmt.up->children}; | 593 | const Tree& tree{stmt.up->children}; |
| 565 | const ConstNode end{tree.cend()}; | 594 | const ConstNode end{tree.cend()}; |
| 566 | ConstNode forward_node{std::next(Tree::s_iterator_to(stmt))}; | 595 | ConstNode forward_node{std::next(Tree::s_iterator_to(stmt))}; |
| @@ -573,12 +602,12 @@ Block* TryFindForwardBlock(const Statement& stmt) { | |||
| 573 | return nullptr; | 602 | return nullptr; |
| 574 | } | 603 | } |
| 575 | 604 | ||
| 576 | [[nodiscard]] U1 VisitExpr(IREmitter& ir, const Statement& stmt) { | 605 | [[nodiscard]] IR::U1 VisitExpr(IR::IREmitter& ir, const Statement& stmt) { |
| 577 | switch (stmt.type) { | 606 | switch (stmt.type) { |
| 578 | case StatementType::Identity: | 607 | case StatementType::Identity: |
| 579 | return ir.Condition(stmt.guest_cond); | 608 | return ir.Condition(stmt.guest_cond); |
| 580 | case StatementType::Not: | 609 | case StatementType::Not: |
| 581 | return ir.LogicalNot(U1{VisitExpr(ir, *stmt.op)}); | 610 | return ir.LogicalNot(IR::U1{VisitExpr(ir, *stmt.op)}); |
| 582 | case StatementType::Or: | 611 | case StatementType::Or: |
| 583 | return ir.LogicalOr(VisitExpr(ir, *stmt.op_a), VisitExpr(ir, *stmt.op_b)); | 612 | return ir.LogicalOr(VisitExpr(ir, *stmt.op_a), VisitExpr(ir, *stmt.op_b)); |
| 584 | case StatementType::Variable: | 613 | case StatementType::Variable: |
| @@ -590,18 +619,18 @@ Block* TryFindForwardBlock(const Statement& stmt) { | |||
| 590 | 619 | ||
| 591 | class TranslatePass { | 620 | class TranslatePass { |
| 592 | public: | 621 | public: |
| 593 | TranslatePass(ObjectPool<Inst>& inst_pool_, ObjectPool<Block>& block_pool_, | 622 | TranslatePass(ObjectPool<IR::Inst>& inst_pool_, ObjectPool<IR::Block>& block_pool_, |
| 594 | ObjectPool<Statement>& stmt_pool_, Statement& root_stmt, | 623 | ObjectPool<Statement>& stmt_pool_, Environment& env_, Statement& root_stmt, |
| 595 | const std::function<void(IR::Block*)>& func_, BlockList& block_list_) | 624 | IR::BlockList& block_list_) |
| 596 | : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, func{func_}, | 625 | : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_}, |
| 597 | block_list{block_list_} { | 626 | block_list{block_list_} { |
| 598 | Visit(root_stmt, nullptr, nullptr); | 627 | Visit(root_stmt, nullptr, nullptr); |
| 599 | } | 628 | } |
| 600 | 629 | ||
| 601 | private: | 630 | private: |
| 602 | void Visit(Statement& parent, Block* continue_block, Block* break_block) { | 631 | void Visit(Statement& parent, IR::Block* continue_block, IR::Block* break_block) { |
| 603 | Tree& tree{parent.children}; | 632 | Tree& tree{parent.children}; |
| 604 | Block* current_block{nullptr}; | 633 | IR::Block* current_block{nullptr}; |
| 605 | 634 | ||
| 606 | for (auto it = tree.begin(); it != tree.end(); ++it) { | 635 | for (auto it = tree.begin(); it != tree.end(); ++it) { |
| 607 | Statement& stmt{*it}; | 636 | Statement& stmt{*it}; |
| @@ -611,11 +640,10 @@ private: | |||
| 611 | break; | 640 | break; |
| 612 | case StatementType::Code: { | 641 | case StatementType::Code: { |
| 613 | if (current_block && current_block != stmt.code) { | 642 | if (current_block && current_block != stmt.code) { |
| 614 | IREmitter ir{*current_block}; | 643 | IR::IREmitter{*current_block}.Branch(stmt.code); |
| 615 | ir.Branch(stmt.code); | ||
| 616 | } | 644 | } |
| 617 | current_block = stmt.code; | 645 | current_block = stmt.code; |
| 618 | func(stmt.code); | 646 | Translate(env, stmt.code); |
| 619 | block_list.push_back(stmt.code); | 647 | block_list.push_back(stmt.code); |
| 620 | break; | 648 | break; |
| 621 | } | 649 | } |
| @@ -623,7 +651,7 @@ private: | |||
| 623 | if (!current_block) { | 651 | if (!current_block) { |
| 624 | current_block = MergeBlock(parent, stmt); | 652 | current_block = MergeBlock(parent, stmt); |
| 625 | } | 653 | } |
| 626 | IREmitter ir{*current_block}; | 654 | IR::IREmitter ir{*current_block}; |
| 627 | ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op)); | 655 | ir.SetGotoVariable(stmt.id, VisitExpr(ir, *stmt.op)); |
| 628 | break; | 656 | break; |
| 629 | } | 657 | } |
| @@ -632,16 +660,16 @@ private: | |||
| 632 | current_block = block_pool.Create(inst_pool); | 660 | current_block = block_pool.Create(inst_pool); |
| 633 | block_list.push_back(current_block); | 661 | block_list.push_back(current_block); |
| 634 | } | 662 | } |
| 635 | Block* const merge_block{MergeBlock(parent, stmt)}; | 663 | IR::Block* const merge_block{MergeBlock(parent, stmt)}; |
| 636 | 664 | ||
| 637 | // Visit children | 665 | // Visit children |
| 638 | const size_t first_block_index{block_list.size()}; | 666 | const size_t first_block_index{block_list.size()}; |
| 639 | Visit(stmt, merge_block, break_block); | 667 | Visit(stmt, merge_block, break_block); |
| 640 | 668 | ||
| 641 | // Implement if header block | 669 | // Implement if header block |
| 642 | Block* const first_if_block{block_list.at(first_block_index)}; | 670 | IR::Block* const first_if_block{block_list.at(first_block_index)}; |
| 643 | IREmitter ir{*current_block}; | 671 | IR::IREmitter ir{*current_block}; |
| 644 | const U1 cond{VisitExpr(ir, *stmt.cond)}; | 672 | const IR::U1 cond{VisitExpr(ir, *stmt.cond)}; |
| 645 | ir.SelectionMerge(merge_block); | 673 | ir.SelectionMerge(merge_block); |
| 646 | ir.BranchConditional(cond, first_if_block, merge_block); | 674 | ir.BranchConditional(cond, first_if_block, merge_block); |
| 647 | 675 | ||
| @@ -649,14 +677,14 @@ private: | |||
| 649 | break; | 677 | break; |
| 650 | } | 678 | } |
| 651 | case StatementType::Loop: { | 679 | case StatementType::Loop: { |
| 652 | Block* const loop_header_block{block_pool.Create(inst_pool)}; | 680 | IR::Block* const loop_header_block{block_pool.Create(inst_pool)}; |
| 653 | if (current_block) { | 681 | if (current_block) { |
| 654 | IREmitter{*current_block}.Branch(loop_header_block); | 682 | IR::IREmitter{*current_block}.Branch(loop_header_block); |
| 655 | } | 683 | } |
| 656 | block_list.push_back(loop_header_block); | 684 | block_list.push_back(loop_header_block); |
| 657 | 685 | ||
| 658 | Block* const new_continue_block{block_pool.Create(inst_pool)}; | 686 | IR::Block* const new_continue_block{block_pool.Create(inst_pool)}; |
| 659 | Block* const merge_block{MergeBlock(parent, stmt)}; | 687 | IR::Block* const merge_block{MergeBlock(parent, stmt)}; |
| 660 | 688 | ||
| 661 | // Visit children | 689 | // Visit children |
| 662 | const size_t first_block_index{block_list.size()}; | 690 | const size_t first_block_index{block_list.size()}; |
| @@ -666,14 +694,14 @@ private: | |||
| 666 | block_list.push_back(new_continue_block); | 694 | block_list.push_back(new_continue_block); |
| 667 | 695 | ||
| 668 | // Implement loop header block | 696 | // Implement loop header block |
| 669 | Block* const first_loop_block{block_list.at(first_block_index)}; | 697 | IR::Block* const first_loop_block{block_list.at(first_block_index)}; |
| 670 | IREmitter ir{*loop_header_block}; | 698 | IR::IREmitter ir{*loop_header_block}; |
| 671 | ir.LoopMerge(merge_block, new_continue_block); | 699 | ir.LoopMerge(merge_block, new_continue_block); |
| 672 | ir.Branch(first_loop_block); | 700 | ir.Branch(first_loop_block); |
| 673 | 701 | ||
| 674 | // Implement continue block | 702 | // Implement continue block |
| 675 | IREmitter continue_ir{*new_continue_block}; | 703 | IR::IREmitter continue_ir{*new_continue_block}; |
| 676 | const U1 continue_cond{VisitExpr(continue_ir, *stmt.cond)}; | 704 | const IR::U1 continue_cond{VisitExpr(continue_ir, *stmt.cond)}; |
| 677 | continue_ir.BranchConditional(continue_cond, ir.block, merge_block); | 705 | continue_ir.BranchConditional(continue_cond, ir.block, merge_block); |
| 678 | 706 | ||
| 679 | current_block = merge_block; | 707 | current_block = merge_block; |
| @@ -684,9 +712,9 @@ private: | |||
| 684 | current_block = block_pool.Create(inst_pool); | 712 | current_block = block_pool.Create(inst_pool); |
| 685 | block_list.push_back(current_block); | 713 | block_list.push_back(current_block); |
| 686 | } | 714 | } |
| 687 | Block* const skip_block{MergeBlock(parent, stmt)}; | 715 | IR::Block* const skip_block{MergeBlock(parent, stmt)}; |
| 688 | 716 | ||
| 689 | IREmitter ir{*current_block}; | 717 | IR::IREmitter ir{*current_block}; |
| 690 | ir.BranchConditional(VisitExpr(ir, *stmt.cond), break_block, skip_block); | 718 | ir.BranchConditional(VisitExpr(ir, *stmt.cond), break_block, skip_block); |
| 691 | 719 | ||
| 692 | current_block = skip_block; | 720 | current_block = skip_block; |
| @@ -697,7 +725,7 @@ private: | |||
| 697 | current_block = block_pool.Create(inst_pool); | 725 | current_block = block_pool.Create(inst_pool); |
| 698 | block_list.push_back(current_block); | 726 | block_list.push_back(current_block); |
| 699 | } | 727 | } |
| 700 | IREmitter{*current_block}.Return(); | 728 | IR::IREmitter{*current_block}.Return(); |
| 701 | current_block = nullptr; | 729 | current_block = nullptr; |
| 702 | break; | 730 | break; |
| 703 | } | 731 | } |
| @@ -706,39 +734,37 @@ private: | |||
| 706 | } | 734 | } |
| 707 | } | 735 | } |
| 708 | if (current_block && continue_block) { | 736 | if (current_block && continue_block) { |
| 709 | IREmitter ir{*current_block}; | 737 | IR::IREmitter{*current_block}.Branch(continue_block); |
| 710 | ir.Branch(continue_block); | ||
| 711 | } | 738 | } |
| 712 | } | 739 | } |
| 713 | 740 | ||
| 714 | Block* MergeBlock(Statement& parent, Statement& stmt) { | 741 | IR::Block* MergeBlock(Statement& parent, Statement& stmt) { |
| 715 | if (Block* const block{TryFindForwardBlock(stmt)}) { | 742 | if (IR::Block* const block{TryFindForwardBlock(stmt)}) { |
| 716 | return block; | 743 | return block; |
| 717 | } | 744 | } |
| 718 | // Create a merge block we can visit later | 745 | // Create a merge block we can visit later |
| 719 | Block* const block{block_pool.Create(inst_pool)}; | 746 | IR::Block* const block{block_pool.Create(inst_pool)}; |
| 720 | Statement* const merge_stmt{stmt_pool.Create(block, &parent)}; | 747 | Statement* const merge_stmt{stmt_pool.Create(block, &parent)}; |
| 721 | parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt); | 748 | parent.children.insert(std::next(Tree::s_iterator_to(stmt)), *merge_stmt); |
| 722 | return block; | 749 | return block; |
| 723 | } | 750 | } |
| 724 | 751 | ||
| 725 | ObjectPool<Statement>& stmt_pool; | 752 | ObjectPool<Statement>& stmt_pool; |
| 726 | ObjectPool<Inst>& inst_pool; | 753 | ObjectPool<IR::Inst>& inst_pool; |
| 727 | ObjectPool<Block>& block_pool; | 754 | ObjectPool<IR::Block>& block_pool; |
| 728 | const std::function<void(IR::Block*)>& func; | 755 | Environment& env; |
| 729 | BlockList& block_list; | 756 | IR::BlockList& block_list; |
| 730 | }; | 757 | }; |
| 731 | } // Anonymous namespace | 758 | } // Anonymous namespace |
| 732 | 759 | ||
| 733 | BlockList VisitAST(ObjectPool<Inst>& inst_pool, ObjectPool<Block>& block_pool, | 760 | IR::BlockList VisitAST(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, |
| 734 | std::span<Block* const> unordered_blocks, | 761 | Environment& env, Flow::CFG& cfg) { |
| 735 | const std::function<void(Block*)>& func) { | ||
| 736 | ObjectPool<Statement> stmt_pool{64}; | 762 | ObjectPool<Statement> stmt_pool{64}; |
| 737 | GotoPass goto_pass{unordered_blocks, stmt_pool}; | 763 | GotoPass goto_pass{cfg, inst_pool, block_pool, stmt_pool}; |
| 738 | BlockList block_list; | 764 | Statement& root{goto_pass.RootStatement()}; |
| 739 | TranslatePass translate_pass{inst_pool, block_pool, stmt_pool, goto_pass.RootStatement(), | 765 | IR::BlockList block_list; |
| 740 | func, block_list}; | 766 | TranslatePass{inst_pool, block_pool, stmt_pool, env, root, block_list}; |
| 741 | return block_list; | 767 | return block_list; |
| 742 | } | 768 | } |
| 743 | 769 | ||
| 744 | } // namespace Shader::IR | 770 | } // namespace Shader::Maxwell |
diff --git a/src/shader_recompiler/frontend/ir/structured_control_flow.h b/src/shader_recompiler/frontend/maxwell/structured_control_flow.h index a574c24f7..e4797291e 100644 --- a/src/shader_recompiler/frontend/ir/structured_control_flow.h +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.h | |||
| @@ -9,14 +9,16 @@ | |||
| 9 | 9 | ||
| 10 | #include <boost/intrusive/list.hpp> | 10 | #include <boost/intrusive/list.hpp> |
| 11 | 11 | ||
| 12 | #include "shader_recompiler/environment.h" | ||
| 12 | #include "shader_recompiler/frontend/ir/basic_block.h" | 13 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 13 | #include "shader_recompiler/frontend/ir/microinstruction.h" | 14 | #include "shader_recompiler/frontend/ir/microinstruction.h" |
| 15 | #include "shader_recompiler/frontend/maxwell/control_flow.h" | ||
| 14 | #include "shader_recompiler/object_pool.h" | 16 | #include "shader_recompiler/object_pool.h" |
| 15 | 17 | ||
| 16 | namespace Shader::IR { | 18 | namespace Shader::Maxwell { |
| 17 | 19 | ||
| 18 | [[nodiscard]] BlockList VisitAST(ObjectPool<Inst>& inst_pool, ObjectPool<Block>& block_pool, | 20 | [[nodiscard]] IR::BlockList VisitAST(ObjectPool<IR::Inst>& inst_pool, |
| 19 | std::span<Block* const> unordered_blocks, | 21 | ObjectPool<IR::Block>& block_pool, Environment& env, |
| 20 | const std::function<void(Block*)>& func); | 22 | Flow::CFG& cfg); |
| 21 | 23 | ||
| 22 | } // namespace Shader::IR | 24 | } // namespace Shader::Maxwell |