diff options
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell')
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | 67 |
1 files changed, 36 insertions, 31 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index ebe5c2654..c1e0646e6 100644 --- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | |||
| @@ -101,22 +101,24 @@ struct Statement : ListBaseHook { | |||
| 101 | : children{std::move(children_)}, cond{cond_}, up{up_}, type{StatementType::Loop} {} | 101 | : children{std::move(children_)}, cond{cond_}, up{up_}, type{StatementType::Loop} {} |
| 102 | Statement(Break, Statement* cond_, Statement* up_) | 102 | Statement(Break, Statement* cond_, Statement* up_) |
| 103 | : cond{cond_}, up{up_}, type{StatementType::Break} {} | 103 | : cond{cond_}, up{up_}, type{StatementType::Break} {} |
| 104 | Statement(Return) : type{StatementType::Return} {} | 104 | Statement(Return, Statement* up_) : up{up_}, type{StatementType::Return} {} |
| 105 | Statement(Kill) : type{StatementType::Kill} {} | 105 | Statement(Kill, Statement* up_) : up{up_}, type{StatementType::Kill} {} |
| 106 | Statement(Unreachable) : type{StatementType::Unreachable} {} | 106 | Statement(Unreachable, Statement* up_) : up{up_}, type{StatementType::Unreachable} {} |
| 107 | Statement(FunctionTag) : children{}, type{StatementType::Function} {} | 107 | Statement(FunctionTag) : children{}, type{StatementType::Function} {} |
| 108 | Statement(Identity, IR::Condition cond_) : guest_cond{cond_}, type{StatementType::Identity} {} | 108 | Statement(Identity, IR::Condition cond_, Statement* up_) |
| 109 | Statement(Not, Statement* op_) : op{op_}, type{StatementType::Not} {} | 109 | : guest_cond{cond_}, up{up_}, type{StatementType::Identity} {} |
| 110 | Statement(Or, Statement* op_a_, Statement* op_b_) | 110 | Statement(Not, Statement* op_, Statement* up_) : op{op_}, up{up_}, type{StatementType::Not} {} |
| 111 | : op_a{op_a_}, op_b{op_b_}, type{StatementType::Or} {} | 111 | Statement(Or, Statement* op_a_, Statement* op_b_, Statement* up_) |
| 112 | : op_a{op_a_}, op_b{op_b_}, up{up_}, type{StatementType::Or} {} | ||
| 112 | Statement(SetVariable, u32 id_, Statement* op_, Statement* up_) | 113 | Statement(SetVariable, u32 id_, Statement* op_, Statement* up_) |
| 113 | : op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {} | 114 | : op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {} |
| 114 | Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_) | 115 | Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_, Statement* up_) |
| 115 | : branch_offset{branch_offset_}, | 116 | : branch_offset{branch_offset_}, |
| 116 | branch_reg{branch_reg_}, type{StatementType::SetIndirectBranchVariable} {} | 117 | branch_reg{branch_reg_}, up{up_}, type{StatementType::SetIndirectBranchVariable} {} |
| 117 | Statement(Variable, u32 id_) : id{id_}, type{StatementType::Variable} {} | 118 | Statement(Variable, u32 id_, Statement* up_) |
| 118 | Statement(IndirectBranchCond, u32 location_) | 119 | : id{id_}, up{up_}, type{StatementType::Variable} {} |
| 119 | : location{location_}, type{StatementType::IndirectBranchCond} {} | 120 | Statement(IndirectBranchCond, u32 location_, Statement* up_) |
| 121 | : location{location_}, up{up_}, type{StatementType::IndirectBranchCond} {} | ||
| 120 | 122 | ||
| 121 | ~Statement() { | 123 | ~Statement() { |
| 122 | if (HasChildren(type)) { | 124 | if (HasChildren(type)) { |
| @@ -385,7 +387,7 @@ private: | |||
| 385 | void BuildTree(Flow::CFG& cfg, Flow::Function& function, u32& label_id, | 387 | void BuildTree(Flow::CFG& cfg, Flow::Function& function, u32& label_id, |
| 386 | std::vector<Node>& gotos, Node function_insert_point, | 388 | std::vector<Node>& gotos, Node function_insert_point, |
| 387 | std::optional<Node> return_label) { | 389 | std::optional<Node> return_label) { |
| 388 | Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false})}; | 390 | Statement* const false_stmt{pool.Create(Identity{}, IR::Condition{false}, &root_stmt)}; |
| 389 | Tree& root{root_stmt.children}; | 391 | Tree& root{root_stmt.children}; |
| 390 | std::unordered_map<Flow::Block*, Node> local_labels; | 392 | std::unordered_map<Flow::Block*, Node> local_labels; |
| 391 | local_labels.reserve(function.blocks.size()); | 393 | local_labels.reserve(function.blocks.size()); |
| @@ -411,7 +413,8 @@ private: | |||
| 411 | 413 | ||
| 412 | switch (block.end_class) { | 414 | switch (block.end_class) { |
| 413 | case Flow::EndClass::Branch: { | 415 | case Flow::EndClass::Branch: { |
| 414 | Statement* const always_cond{pool.Create(Identity{}, IR::Condition{true})}; | 416 | Statement* const always_cond{ |
| 417 | pool.Create(Identity{}, IR::Condition{true}, &root_stmt)}; | ||
| 415 | if (block.cond == IR::Condition{true}) { | 418 | if (block.cond == IR::Condition{true}) { |
| 416 | const Node true_label{local_labels.at(block.branch_true)}; | 419 | const Node true_label{local_labels.at(block.branch_true)}; |
| 417 | gotos.push_back( | 420 | gotos.push_back( |
| @@ -423,7 +426,7 @@ private: | |||
| 423 | } else { | 426 | } else { |
| 424 | const Node true_label{local_labels.at(block.branch_true)}; | 427 | const Node true_label{local_labels.at(block.branch_true)}; |
| 425 | const Node false_label{local_labels.at(block.branch_false)}; | 428 | const Node false_label{local_labels.at(block.branch_false)}; |
| 426 | Statement* const true_cond{pool.Create(Identity{}, block.cond)}; | 429 | Statement* const true_cond{pool.Create(Identity{}, block.cond, &root_stmt)}; |
| 427 | gotos.push_back( | 430 | gotos.push_back( |
| 428 | root.insert(ip, *pool.Create(Goto{}, true_cond, true_label, &root_stmt))); | 431 | root.insert(ip, *pool.Create(Goto{}, true_cond, true_label, &root_stmt))); |
| 429 | gotos.push_back(root.insert( | 432 | gotos.push_back(root.insert( |
| @@ -433,14 +436,15 @@ private: | |||
| 433 | } | 436 | } |
| 434 | case Flow::EndClass::IndirectBranch: | 437 | case Flow::EndClass::IndirectBranch: |
| 435 | root.insert(ip, *pool.Create(SetIndirectBranchVariable{}, block.branch_reg, | 438 | root.insert(ip, *pool.Create(SetIndirectBranchVariable{}, block.branch_reg, |
| 436 | block.branch_offset)); | 439 | block.branch_offset, &root_stmt)); |
| 437 | for (const Flow::IndirectBranch& indirect : block.indirect_branches) { | 440 | for (const Flow::IndirectBranch& indirect : block.indirect_branches) { |
| 438 | const Node indirect_label{local_labels.at(indirect.block)}; | 441 | const Node indirect_label{local_labels.at(indirect.block)}; |
| 439 | Statement* cond{pool.Create(IndirectBranchCond{}, indirect.address)}; | 442 | Statement* cond{ |
| 443 | pool.Create(IndirectBranchCond{}, indirect.address, &root_stmt)}; | ||
| 440 | Statement* goto_stmt{pool.Create(Goto{}, cond, indirect_label, &root_stmt)}; | 444 | Statement* goto_stmt{pool.Create(Goto{}, cond, indirect_label, &root_stmt)}; |
| 441 | gotos.push_back(root.insert(ip, *goto_stmt)); | 445 | gotos.push_back(root.insert(ip, *goto_stmt)); |
| 442 | } | 446 | } |
| 443 | root.insert(ip, *pool.Create(Unreachable{})); | 447 | root.insert(ip, *pool.Create(Unreachable{}, &root_stmt)); |
| 444 | break; | 448 | break; |
| 445 | case Flow::EndClass::Call: { | 449 | case Flow::EndClass::Call: { |
| 446 | Flow::Function& call{cfg.Functions()[block.function_call]}; | 450 | Flow::Function& call{cfg.Functions()[block.function_call]}; |
| @@ -449,16 +453,16 @@ private: | |||
| 449 | break; | 453 | break; |
| 450 | } | 454 | } |
| 451 | case Flow::EndClass::Exit: | 455 | case Flow::EndClass::Exit: |
| 452 | root.insert(ip, *pool.Create(Return{})); | 456 | root.insert(ip, *pool.Create(Return{}, &root_stmt)); |
| 453 | break; | 457 | break; |
| 454 | case Flow::EndClass::Return: { | 458 | case Flow::EndClass::Return: { |
| 455 | Statement* const always_cond{pool.Create(Identity{}, block.cond)}; | 459 | Statement* const always_cond{pool.Create(Identity{}, block.cond, &root_stmt)}; |
| 456 | auto goto_stmt{pool.Create(Goto{}, always_cond, return_label.value(), &root_stmt)}; | 460 | auto goto_stmt{pool.Create(Goto{}, always_cond, return_label.value(), &root_stmt)}; |
| 457 | gotos.push_back(root.insert(ip, *goto_stmt)); | 461 | gotos.push_back(root.insert(ip, *goto_stmt)); |
| 458 | break; | 462 | break; |
| 459 | } | 463 | } |
| 460 | case Flow::EndClass::Kill: | 464 | case Flow::EndClass::Kill: |
| 461 | root.insert(ip, *pool.Create(Kill{})); | 465 | root.insert(ip, *pool.Create(Kill{}, &root_stmt)); |
| 462 | break; | 466 | break; |
| 463 | } | 467 | } |
| 464 | } | 468 | } |
| @@ -474,7 +478,7 @@ private: | |||
| 474 | Tree& body{goto_stmt->up->children}; | 478 | Tree& body{goto_stmt->up->children}; |
| 475 | Tree if_body; | 479 | Tree if_body; |
| 476 | if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_stmt); | 480 | if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_stmt); |
| 477 | Statement* const cond{pool.Create(Not{}, goto_stmt->cond)}; | 481 | Statement* const cond{pool.Create(Not{}, goto_stmt->cond, &root_stmt)}; |
| 478 | Statement* const if_stmt{pool.Create(If{}, cond, std::move(if_body), goto_stmt->up)}; | 482 | Statement* const if_stmt{pool.Create(If{}, cond, std::move(if_body), goto_stmt->up)}; |
| 479 | UpdateTreeUp(if_stmt); | 483 | UpdateTreeUp(if_stmt); |
| 480 | body.insert(goto_stmt, *if_stmt); | 484 | body.insert(goto_stmt, *if_stmt); |
| @@ -516,8 +520,8 @@ private: | |||
| 516 | 520 | ||
| 517 | Tree if_body; | 521 | Tree if_body; |
| 518 | if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_nested_stmt); | 522 | if_body.splice(if_body.begin(), body, std::next(goto_stmt), label_nested_stmt); |
| 519 | Statement* const variable{pool.Create(Variable{}, label_id)}; | 523 | Statement* const variable{pool.Create(Variable{}, label_id, &root_stmt)}; |
| 520 | Statement* const neg_var{pool.Create(Not{}, variable)}; | 524 | Statement* const neg_var{pool.Create(Not{}, variable, &root_stmt)}; |
| 521 | if (!if_body.empty()) { | 525 | if (!if_body.empty()) { |
| 522 | Statement* const if_stmt{pool.Create(If{}, neg_var, std::move(if_body), parent)}; | 526 | Statement* const if_stmt{pool.Create(If{}, neg_var, std::move(if_body), parent)}; |
| 523 | UpdateTreeUp(if_stmt); | 527 | UpdateTreeUp(if_stmt); |
| @@ -528,7 +532,8 @@ private: | |||
| 528 | switch (label_nested_stmt->type) { | 532 | switch (label_nested_stmt->type) { |
| 529 | case StatementType::If: | 533 | case StatementType::If: |
| 530 | // Update nested if condition | 534 | // Update nested if condition |
| 531 | label_nested_stmt->cond = pool.Create(Or{}, variable, label_nested_stmt->cond); | 535 | label_nested_stmt->cond = |
| 536 | pool.Create(Or{}, variable, label_nested_stmt->cond, &root_stmt); | ||
| 532 | break; | 537 | break; |
| 533 | case StatementType::Loop: | 538 | case StatementType::Loop: |
| 534 | break; | 539 | break; |
| @@ -550,7 +555,7 @@ private: | |||
| 550 | Tree loop_body; | 555 | Tree loop_body; |
| 551 | loop_body.splice(loop_body.begin(), body, label_nested_stmt, goto_stmt); | 556 | loop_body.splice(loop_body.begin(), body, label_nested_stmt, goto_stmt); |
| 552 | SanitizeNoBreaks(loop_body); | 557 | SanitizeNoBreaks(loop_body); |
| 553 | Statement* const variable{pool.Create(Variable{}, label_id)}; | 558 | Statement* const variable{pool.Create(Variable{}, label_id, &root_stmt)}; |
| 554 | Statement* const loop_stmt{pool.Create(Loop{}, variable, std::move(loop_body), parent)}; | 559 | Statement* const loop_stmt{pool.Create(Loop{}, variable, std::move(loop_body), parent)}; |
| 555 | UpdateTreeUp(loop_stmt); | 560 | UpdateTreeUp(loop_stmt); |
| 556 | body.insert(goto_stmt, *loop_stmt); | 561 | body.insert(goto_stmt, *loop_stmt); |
| @@ -577,15 +582,15 @@ private: | |||
| 577 | Tree if_body; | 582 | Tree if_body; |
| 578 | if_body.splice(if_body.begin(), body, std::next(goto_stmt), body.end()); | 583 | if_body.splice(if_body.begin(), body, std::next(goto_stmt), body.end()); |
| 579 | if_body.pop_front(); | 584 | if_body.pop_front(); |
| 580 | Statement* const cond{pool.Create(Variable{}, label_id)}; | 585 | Statement* const cond{pool.Create(Variable{}, label_id, &root_stmt)}; |
| 581 | Statement* const neg_cond{pool.Create(Not{}, cond)}; | 586 | Statement* const neg_cond{pool.Create(Not{}, cond, &root_stmt)}; |
| 582 | Statement* const if_stmt{pool.Create(If{}, neg_cond, std::move(if_body), &*parent)}; | 587 | Statement* const if_stmt{pool.Create(If{}, neg_cond, std::move(if_body), &*parent)}; |
| 583 | UpdateTreeUp(if_stmt); | 588 | UpdateTreeUp(if_stmt); |
| 584 | body.insert(goto_stmt, *if_stmt); | 589 | body.insert(goto_stmt, *if_stmt); |
| 585 | 590 | ||
| 586 | body.erase(goto_stmt); | 591 | body.erase(goto_stmt); |
| 587 | 592 | ||
| 588 | Statement* const new_cond{pool.Create(Variable{}, label_id)}; | 593 | Statement* const new_cond{pool.Create(Variable{}, label_id, &root_stmt)}; |
| 589 | Statement* const new_goto{pool.Create(Goto{}, new_cond, goto_stmt->label, parent->up)}; | 594 | Statement* const new_goto{pool.Create(Goto{}, new_cond, goto_stmt->label, parent->up)}; |
| 590 | Tree& parent_tree{parent->up->children}; | 595 | Tree& parent_tree{parent->up->children}; |
| 591 | return parent_tree.insert(std::next(parent), *new_goto); | 596 | return parent_tree.insert(std::next(parent), *new_goto); |
| @@ -597,14 +602,14 @@ private: | |||
| 597 | const u32 label_id{goto_stmt->label->id}; | 602 | const u32 label_id{goto_stmt->label->id}; |
| 598 | Statement* const goto_cond{goto_stmt->cond}; | 603 | Statement* const goto_cond{goto_stmt->cond}; |
| 599 | Statement* const set_goto_var{pool.Create(SetVariable{}, label_id, goto_cond, parent)}; | 604 | Statement* const set_goto_var{pool.Create(SetVariable{}, label_id, goto_cond, parent)}; |
| 600 | Statement* const cond{pool.Create(Variable{}, label_id)}; | 605 | Statement* const cond{pool.Create(Variable{}, label_id, &root_stmt)}; |
| 601 | Statement* const break_stmt{pool.Create(Break{}, cond, parent)}; | 606 | Statement* const break_stmt{pool.Create(Break{}, cond, parent)}; |
| 602 | body.insert(goto_stmt, *set_goto_var); | 607 | body.insert(goto_stmt, *set_goto_var); |
| 603 | body.insert(goto_stmt, *break_stmt); | 608 | body.insert(goto_stmt, *break_stmt); |
| 604 | body.erase(goto_stmt); | 609 | body.erase(goto_stmt); |
| 605 | 610 | ||
| 606 | const Node loop{Tree::s_iterator_to(*goto_stmt->up)}; | 611 | const Node loop{Tree::s_iterator_to(*goto_stmt->up)}; |
| 607 | Statement* const new_goto_cond{pool.Create(Variable{}, label_id)}; | 612 | Statement* const new_goto_cond{pool.Create(Variable{}, label_id, &root_stmt)}; |
| 608 | Statement* const new_goto{pool.Create(Goto{}, new_goto_cond, goto_stmt->label, loop->up)}; | 613 | Statement* const new_goto{pool.Create(Goto{}, new_goto_cond, goto_stmt->label, loop->up)}; |
| 609 | Tree& parent_tree{loop->up->children}; | 614 | Tree& parent_tree{loop->up->children}; |
| 610 | return parent_tree.insert(std::next(loop), *new_goto); | 615 | return parent_tree.insert(std::next(loop), *new_goto); |