diff options
| author | 2021-04-21 03:39:35 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:28 -0400 | |
| commit | cc0fcd1b8d3080ae83709874e1d66f9e4cf3f1be (patch) | |
| tree | b2fd497f28fb433741c8f3e73cb29e4853a47b99 /src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | |
| parent | shader: Use memset to reset instruction arguments (diff) | |
| download | yuzu-cc0fcd1b8d3080ae83709874e1d66f9e4cf3f1be.tar.gz yuzu-cc0fcd1b8d3080ae83709874e1d66f9e4cf3f1be.tar.xz yuzu-cc0fcd1b8d3080ae83709874e1d66f9e4cf3f1be.zip | |
shader: Improve goto removal algorithm complexity
Find sibling node containing a nephew searching from the nephew itself
instead of the uncle.
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp')
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | 77 |
1 files changed, 28 insertions, 49 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index 6021ac891..b85b613f3 100644 --- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp | |||
| @@ -222,27 +222,6 @@ std::string DumpTree(const Tree& tree, u32 indentation = 0) { | |||
| 222 | return ret; | 222 | return ret; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | bool HasNode(const Tree& tree, ConstNode stmt) { | ||
| 226 | const auto end{tree.end()}; | ||
| 227 | for (auto it = tree.begin(); it != end; ++it) { | ||
| 228 | if (it == stmt || (HasChildren(it->type) && HasNode(it->children, stmt))) { | ||
| 229 | return true; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | return false; | ||
| 233 | } | ||
| 234 | |||
| 235 | Node FindStatementWithLabel(Tree& tree, ConstNode goto_stmt) { | ||
| 236 | const ConstNode label_stmt{goto_stmt->label}; | ||
| 237 | const ConstNode end{tree.end()}; | ||
| 238 | for (auto it = tree.begin(); it != end; ++it) { | ||
| 239 | if (it == label_stmt || (HasChildren(it->type) && HasNode(it->children, label_stmt))) { | ||
| 240 | return it; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | throw LogicError("Lift label not in tree"); | ||
| 244 | } | ||
| 245 | |||
| 246 | void SanitizeNoBreaks(const Tree& tree) { | 225 | void SanitizeNoBreaks(const Tree& tree) { |
| 247 | if (std::ranges::find(tree, StatementType::Break, &Statement::type) != tree.end()) { | 226 | if (std::ranges::find(tree, StatementType::Break, &Statement::type) != tree.end()) { |
| 248 | throw NotImplementedException("Capturing statement with break nodes"); | 227 | throw NotImplementedException("Capturing statement with break nodes"); |
| @@ -288,22 +267,6 @@ bool IsIndirectlyRelated(Node goto_stmt, Node label_stmt) { | |||
| 288 | return goto_stmt->up != label_stmt->up && !IsDirectlyRelated(goto_stmt, label_stmt); | 267 | return goto_stmt->up != label_stmt->up && !IsDirectlyRelated(goto_stmt, label_stmt); |
| 289 | } | 268 | } |
| 290 | 269 | ||
| 291 | bool SearchNode(const Tree& tree, ConstNode stmt, size_t& offset) { | ||
| 292 | ++offset; | ||
| 293 | |||
| 294 | const auto end = tree.end(); | ||
| 295 | for (ConstNode it = tree.begin(); it != end; ++it) { | ||
| 296 | ++offset; | ||
| 297 | if (stmt == it) { | ||
| 298 | return true; | ||
| 299 | } | ||
| 300 | if (HasChildren(it->type) && SearchNode(it->children, stmt, offset)) { | ||
| 301 | return true; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | return false; | ||
| 305 | } | ||
| 306 | |||
| 307 | bool AreSiblings(Node goto_stmt, Node label_stmt) noexcept { | 270 | bool AreSiblings(Node goto_stmt, Node label_stmt) noexcept { |
| 308 | Node it{goto_stmt}; | 271 | Node it{goto_stmt}; |
| 309 | do { | 272 | do { |
| @@ -321,6 +284,30 @@ bool AreSiblings(Node goto_stmt, Node label_stmt) noexcept { | |||
| 321 | return false; | 284 | return false; |
| 322 | } | 285 | } |
| 323 | 286 | ||
| 287 | Node SiblingFromNephew(Node uncle, Node nephew) noexcept { | ||
| 288 | Statement* const parent{uncle->up}; | ||
| 289 | Statement* it{&*nephew}; | ||
| 290 | while (it->up != parent) { | ||
| 291 | it = it->up; | ||
| 292 | } | ||
| 293 | return Tree::s_iterator_to(*it); | ||
| 294 | } | ||
| 295 | |||
| 296 | bool AreOrdered(Node left_sibling, Node right_sibling) noexcept { | ||
| 297 | const Node end{right_sibling->up->children.end()}; | ||
| 298 | for (auto it = right_sibling; it != end; ++it) { | ||
| 299 | if (it == left_sibling) { | ||
| 300 | return false; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | return true; | ||
| 304 | } | ||
| 305 | |||
| 306 | bool NeedsLift(Node goto_stmt, Node label_stmt) noexcept { | ||
| 307 | const Node sibling{SiblingFromNephew(goto_stmt, label_stmt)}; | ||
| 308 | return AreOrdered(sibling, goto_stmt); | ||
| 309 | } | ||
| 310 | |||
| 324 | class GotoPass { | 311 | class GotoPass { |
| 325 | public: | 312 | public: |
| 326 | explicit GotoPass(Flow::CFG& cfg, ObjectPool<IR::Inst>& inst_pool_, | 313 | explicit GotoPass(Flow::CFG& cfg, ObjectPool<IR::Inst>& inst_pool_, |
| @@ -358,7 +345,7 @@ private: | |||
| 358 | --goto_level; | 345 | --goto_level; |
| 359 | } | 346 | } |
| 360 | } else { // Level(goto_stmt) < Level(label_stmt) | 347 | } else { // Level(goto_stmt) < Level(label_stmt) |
| 361 | if (Offset(goto_stmt) > Offset(label_stmt)) { | 348 | if (NeedsLift(goto_stmt, label_stmt)) { |
| 362 | // Lift goto_stmt to above stmt containing label_stmt using goto-lifting | 349 | // Lift goto_stmt to above stmt containing label_stmt using goto-lifting |
| 363 | // transformations | 350 | // transformations |
| 364 | goto_stmt = Lift(goto_stmt); | 351 | goto_stmt = Lift(goto_stmt); |
| @@ -378,7 +365,7 @@ private: | |||
| 378 | if (std::next(goto_stmt) == label_stmt) { | 365 | if (std::next(goto_stmt) == label_stmt) { |
| 379 | // Simply eliminate the goto if the label is next to it | 366 | // Simply eliminate the goto if the label is next to it |
| 380 | goto_stmt->up->children.erase(goto_stmt); | 367 | goto_stmt->up->children.erase(goto_stmt); |
| 381 | } else if (Offset(goto_stmt) < Offset(label_stmt)) { | 368 | } else if (AreOrdered(goto_stmt, label_stmt)) { |
| 382 | // Eliminate goto_stmt with a conditional | 369 | // Eliminate goto_stmt with a conditional |
| 383 | EliminateAsConditional(goto_stmt, label_stmt); | 370 | EliminateAsConditional(goto_stmt, label_stmt); |
| 384 | } else { | 371 | } else { |
| @@ -523,8 +510,8 @@ private: | |||
| 523 | [[nodiscard]] Node MoveInward(Node goto_stmt) { | 510 | [[nodiscard]] Node MoveInward(Node goto_stmt) { |
| 524 | Statement* const parent{goto_stmt->up}; | 511 | Statement* const parent{goto_stmt->up}; |
| 525 | Tree& body{parent->children}; | 512 | Tree& body{parent->children}; |
| 526 | const Node label_nested_stmt{FindStatementWithLabel(body, goto_stmt)}; | ||
| 527 | const Node label{goto_stmt->label}; | 513 | const Node label{goto_stmt->label}; |
| 514 | const Node label_nested_stmt{SiblingFromNephew(goto_stmt, label)}; | ||
| 528 | const u32 label_id{label->id}; | 515 | const u32 label_id{label->id}; |
| 529 | 516 | ||
| 530 | Statement* const goto_cond{goto_stmt->cond}; | 517 | Statement* const goto_cond{goto_stmt->cond}; |
| @@ -562,7 +549,7 @@ private: | |||
| 562 | Tree& body{parent->children}; | 549 | Tree& body{parent->children}; |
| 563 | const Node label{goto_stmt->label}; | 550 | const Node label{goto_stmt->label}; |
| 564 | const u32 label_id{label->id}; | 551 | const u32 label_id{label->id}; |
| 565 | const Node label_nested_stmt{FindStatementWithLabel(body, goto_stmt)}; | 552 | const Node label_nested_stmt{SiblingFromNephew(goto_stmt, label)}; |
| 566 | 553 | ||
| 567 | Tree loop_body; | 554 | Tree loop_body; |
| 568 | loop_body.splice(loop_body.begin(), body, label_nested_stmt, goto_stmt); | 555 | loop_body.splice(loop_body.begin(), body, label_nested_stmt, goto_stmt); |
| @@ -627,14 +614,6 @@ private: | |||
| 627 | return parent_tree.insert(std::next(loop), *new_goto); | 614 | return parent_tree.insert(std::next(loop), *new_goto); |
| 628 | } | 615 | } |
| 629 | 616 | ||
| 630 | size_t Offset(ConstNode stmt) const { | ||
| 631 | size_t offset{0}; | ||
| 632 | if (!SearchNode(root_stmt.children, stmt, offset)) { | ||
| 633 | throw LogicError("Node not found in tree"); | ||
| 634 | } | ||
| 635 | return offset; | ||
| 636 | } | ||
| 637 | |||
| 638 | ObjectPool<IR::Inst>& inst_pool; | 617 | ObjectPool<IR::Inst>& inst_pool; |
| 639 | ObjectPool<IR::Block>& block_pool; | 618 | ObjectPool<IR::Block>& block_pool; |
| 640 | ObjectPool<Statement>& pool; | 619 | ObjectPool<Statement>& pool; |