summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp67
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);