summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-06-28 20:54:21 -0400
committerGravatar FernandoS272019-10-04 18:52:48 -0400
commit8be6e1c5221066a49b6ad27efbd20a999a7c16b3 (patch)
treea00263eb962503bec08ec4bc870a9546c3b80d22
parentshader_ir: Add basic goto elimination (diff)
downloadyuzu-8be6e1c5221066a49b6ad27efbd20a999a7c16b3.tar.gz
yuzu-8be6e1c5221066a49b6ad27efbd20a999a7c16b3.tar.xz
yuzu-8be6e1c5221066a49b6ad27efbd20a999a7c16b3.zip
shader_ir: Corrections to outward movements and misc stuffs
-rw-r--r--CMakeModules/GenerateSCMRev.cmake4
-rw-r--r--src/common/CMakeLists.txt4
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/shader/ast.cpp185
-rw-r--r--src/video_core/shader/ast.h53
-rw-r--r--src/video_core/shader/control_flow.cpp14
-rw-r--r--src/video_core/shader/expr.cpp75
-rw-r--r--src/video_core/shader/expr.h36
8 files changed, 314 insertions, 58 deletions
diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake
index a1ace89cb..d3ab22c08 100644
--- a/CMakeModules/GenerateSCMRev.cmake
+++ b/CMakeModules/GenerateSCMRev.cmake
@@ -83,9 +83,13 @@ set(HASH_FILES
83 "${VIDEO_CORE}/shader/decode/video.cpp" 83 "${VIDEO_CORE}/shader/decode/video.cpp"
84 "${VIDEO_CORE}/shader/decode/warp.cpp" 84 "${VIDEO_CORE}/shader/decode/warp.cpp"
85 "${VIDEO_CORE}/shader/decode/xmad.cpp" 85 "${VIDEO_CORE}/shader/decode/xmad.cpp"
86 "${VIDEO_CORE}/shader/ast.cpp"
87 "${VIDEO_CORE}/shader/ast.h"
86 "${VIDEO_CORE}/shader/control_flow.cpp" 88 "${VIDEO_CORE}/shader/control_flow.cpp"
87 "${VIDEO_CORE}/shader/control_flow.h" 89 "${VIDEO_CORE}/shader/control_flow.h"
88 "${VIDEO_CORE}/shader/decode.cpp" 90 "${VIDEO_CORE}/shader/decode.cpp"
91 "${VIDEO_CORE}/shader/expr.cpp"
92 "${VIDEO_CORE}/shader/expr.h"
89 "${VIDEO_CORE}/shader/node.h" 93 "${VIDEO_CORE}/shader/node.h"
90 "${VIDEO_CORE}/shader/node_helper.cpp" 94 "${VIDEO_CORE}/shader/node_helper.cpp"
91 "${VIDEO_CORE}/shader/node_helper.h" 95 "${VIDEO_CORE}/shader/node_helper.h"
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index dfed8b51d..afc5ff736 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -60,9 +60,13 @@ add_custom_command(OUTPUT scm_rev.cpp
60 "${VIDEO_CORE}/shader/decode/video.cpp" 60 "${VIDEO_CORE}/shader/decode/video.cpp"
61 "${VIDEO_CORE}/shader/decode/warp.cpp" 61 "${VIDEO_CORE}/shader/decode/warp.cpp"
62 "${VIDEO_CORE}/shader/decode/xmad.cpp" 62 "${VIDEO_CORE}/shader/decode/xmad.cpp"
63 "${VIDEO_CORE}/shader/ast.cpp"
64 "${VIDEO_CORE}/shader/ast.h"
63 "${VIDEO_CORE}/shader/control_flow.cpp" 65 "${VIDEO_CORE}/shader/control_flow.cpp"
64 "${VIDEO_CORE}/shader/control_flow.h" 66 "${VIDEO_CORE}/shader/control_flow.h"
65 "${VIDEO_CORE}/shader/decode.cpp" 67 "${VIDEO_CORE}/shader/decode.cpp"
68 "${VIDEO_CORE}/shader/expr.cpp"
69 "${VIDEO_CORE}/shader/expr.h"
66 "${VIDEO_CORE}/shader/node.h" 70 "${VIDEO_CORE}/shader/node.h"
67 "${VIDEO_CORE}/shader/node_helper.cpp" 71 "${VIDEO_CORE}/shader/node_helper.cpp"
68 "${VIDEO_CORE}/shader/node_helper.h" 72 "${VIDEO_CORE}/shader/node_helper.h"
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 32049a2e7..33fa88762 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -110,6 +110,7 @@ add_library(video_core STATIC
110 shader/control_flow.cpp 110 shader/control_flow.cpp
111 shader/control_flow.h 111 shader/control_flow.h
112 shader/decode.cpp 112 shader/decode.cpp
113 shader/expr.cpp
113 shader/expr.h 114 shader/expr.h
114 shader/node_helper.cpp 115 shader/node_helper.cpp
115 shader/node_helper.h 116 shader/node_helper.h
diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp
index 56a1b29f3..d521a7b52 100644
--- a/src/video_core/shader/ast.cpp
+++ b/src/video_core/shader/ast.cpp
@@ -12,18 +12,22 @@
12namespace VideoCommon::Shader { 12namespace VideoCommon::Shader {
13 13
14ASTZipper::ASTZipper() = default; 14ASTZipper::ASTZipper() = default;
15ASTZipper::ASTZipper(ASTNode new_first) : first{}, last{} { 15
16void ASTZipper::Init(ASTNode new_first, ASTNode parent) {
17 ASSERT(new_first->manager == nullptr);
16 first = new_first; 18 first = new_first;
17 last = new_first; 19 last = new_first;
18 ASTNode current = first; 20 ASTNode current = first;
19 while (current) { 21 while (current) {
20 current->manager = this; 22 current->manager = this;
23 current->parent = parent;
21 last = current; 24 last = current;
22 current = current->next; 25 current = current->next;
23 } 26 }
24} 27}
25 28
26void ASTZipper::PushBack(ASTNode new_node) { 29void ASTZipper::PushBack(ASTNode new_node) {
30 ASSERT(new_node->manager == nullptr);
27 new_node->previous = last; 31 new_node->previous = last;
28 if (last) { 32 if (last) {
29 last->next = new_node; 33 last->next = new_node;
@@ -37,38 +41,55 @@ void ASTZipper::PushBack(ASTNode new_node) {
37} 41}
38 42
39void ASTZipper::PushFront(ASTNode new_node) { 43void ASTZipper::PushFront(ASTNode new_node) {
44 ASSERT(new_node->manager == nullptr);
40 new_node->previous.reset(); 45 new_node->previous.reset();
41 new_node->next = first; 46 new_node->next = first;
42 if (first) { 47 if (first) {
43 first->previous = first; 48 first->previous = new_node;
44 } 49 }
45 first = new_node; 50 if (last == first) {
46 if (!last) {
47 last = new_node; 51 last = new_node;
48 } 52 }
53 first = new_node;
49 new_node->manager = this; 54 new_node->manager = this;
50} 55}
51 56
52void ASTZipper::InsertAfter(ASTNode new_node, ASTNode at_node) { 57void ASTZipper::InsertAfter(ASTNode new_node, ASTNode at_node) {
58 ASSERT(new_node->manager == nullptr);
53 if (!at_node) { 59 if (!at_node) {
54 PushFront(new_node); 60 PushFront(new_node);
55 return; 61 return;
56 } 62 }
63 ASTNode next = at_node->next;
64 if (next) {
65 next->previous = new_node;
66 }
57 new_node->previous = at_node; 67 new_node->previous = at_node;
58 if (at_node == last) { 68 if (at_node == last) {
59 last = new_node; 69 last = new_node;
60 } 70 }
61 new_node->next = at_node->next; 71 new_node->next = next;
62 at_node->next = new_node; 72 at_node->next = new_node;
63 new_node->manager = this; 73 new_node->manager = this;
64} 74}
65 75
66void ASTZipper::SetParent(ASTNode new_parent) { 76void ASTZipper::InsertBefore(ASTNode new_node, ASTNode at_node) {
67 ASTNode current = first; 77 ASSERT(new_node->manager == nullptr);
68 while (current) { 78 if (!at_node) {
69 current->parent = new_parent; 79 PushBack(new_node);
70 current = current->next; 80 return;
71 } 81 }
82 ASTNode previous = at_node->previous;
83 if (previous) {
84 previous->next = new_node;
85 }
86 new_node->next = at_node;
87 if (at_node == first) {
88 first = new_node;
89 }
90 new_node->previous = previous;
91 at_node->previous = new_node;
92 new_node->manager = this;
72} 93}
73 94
74void ASTZipper::DetachTail(ASTNode node) { 95void ASTZipper::DetachTail(ASTNode node) {
@@ -80,11 +101,22 @@ void ASTZipper::DetachTail(ASTNode node) {
80 } 101 }
81 102
82 last = node->previous; 103 last = node->previous;
104 last->next.reset();
83 node->previous.reset(); 105 node->previous.reset();
106 ASTNode current = node;
107 while (current) {
108 current->manager = nullptr;
109 current->parent.reset();
110 current = current->next;
111 }
84} 112}
85 113
86void ASTZipper::DetachSegment(ASTNode start, ASTNode end) { 114void ASTZipper::DetachSegment(ASTNode start, ASTNode end) {
87 ASSERT(start->manager == this && end->manager == this); 115 ASSERT(start->manager == this && end->manager == this);
116 if (start == end) {
117 DetachSingle(start);
118 return;
119 }
88 ASTNode prev = start->previous; 120 ASTNode prev = start->previous;
89 ASTNode post = end->next; 121 ASTNode post = end->next;
90 if (!prev) { 122 if (!prev) {
@@ -131,7 +163,6 @@ void ASTZipper::DetachSingle(ASTNode node) {
131 node->parent.reset(); 163 node->parent.reset();
132} 164}
133 165
134
135void ASTZipper::Remove(ASTNode node) { 166void ASTZipper::Remove(ASTNode node) {
136 ASSERT(node->manager == this); 167 ASSERT(node->manager == this);
137 ASTNode next = node->next; 168 ASTNode next = node->next;
@@ -178,12 +209,7 @@ public:
178 } 209 }
179 210
180 void operator()(ExprPredicate const& expr) { 211 void operator()(ExprPredicate const& expr) {
181 u32 pred = static_cast<u32>(expr.predicate); 212 inner += "P" + std::to_string(expr.predicate);
182 if (pred > 7) {
183 inner += "!";
184 pred -= 8;
185 }
186 inner += "P" + std::to_string(pred);
187 } 213 }
188 214
189 void operator()(ExprCondCode const& expr) { 215 void operator()(ExprCondCode const& expr) {
@@ -253,6 +279,10 @@ public:
253 ");\n"; 279 ");\n";
254 } 280 }
255 281
282 void operator()(ASTBlockDecoded& ast) {
283 inner += Ident() + "Block;\n";
284 }
285
256 void operator()(ASTVarSet& ast) { 286 void operator()(ASTVarSet& ast) {
257 ExprPrinter expr_parser{}; 287 ExprPrinter expr_parser{};
258 std::visit(expr_parser, *ast.condition); 288 std::visit(expr_parser, *ast.condition);
@@ -282,7 +312,7 @@ public:
282 current = current->GetNext(); 312 current = current->GetNext();
283 } 313 }
284 scope--; 314 scope--;
285 inner += Ident() + "} while (" + expr_parser.GetResult() + ")\n"; 315 inner += Ident() + "} while (" + expr_parser.GetResult() + ");\n";
286 } 316 }
287 317
288 void operator()(ASTReturn& ast) { 318 void operator()(ASTReturn& ast) {
@@ -333,8 +363,6 @@ std::string ASTManager::Print() {
333 return printer.GetResult(); 363 return printer.GetResult();
334} 364}
335 365
336#pragma optimize("", off)
337
338void ASTManager::Decompile() { 366void ASTManager::Decompile() {
339 auto it = gotos.begin(); 367 auto it = gotos.begin();
340 while (it != gotos.end()) { 368 while (it != gotos.end()) {
@@ -348,11 +376,12 @@ void ASTManager::Decompile() {
348 } 376 }
349 if (DirectlyRelated(goto_node, label)) { 377 if (DirectlyRelated(goto_node, label)) {
350 u32 goto_level = goto_node->GetLevel(); 378 u32 goto_level = goto_node->GetLevel();
351 u32 label_level = goto_node->GetLevel(); 379 u32 label_level = label->GetLevel();
352 while (label_level > goto_level) { 380 while (label_level < goto_level) {
353 MoveOutward(goto_node); 381 MoveOutward(goto_node);
354 goto_level++; 382 goto_level--;
355 } 383 }
384 // TODO(Blinkhawk): Implement Lifting and Inward Movements
356 } 385 }
357 if (label->GetParent() == goto_node->GetParent()) { 386 if (label->GetParent() == goto_node->GetParent()) {
358 bool is_loop = false; 387 bool is_loop = false;
@@ -375,13 +404,11 @@ void ASTManager::Decompile() {
375 } 404 }
376 it++; 405 it++;
377 } 406 }
378 /*
379 for (ASTNode label : labels) { 407 for (ASTNode label : labels) {
380 auto& manager = label->GetManager(); 408 auto& manager = label->GetManager();
381 manager.Remove(label); 409 manager.Remove(label);
382 } 410 }
383 labels.clear(); 411 labels.clear();
384 */
385} 412}
386 413
387bool ASTManager::IndirectlyRelated(ASTNode first, ASTNode second) { 414bool ASTManager::IndirectlyRelated(ASTNode first, ASTNode second) {
@@ -410,87 +437,149 @@ bool ASTManager::DirectlyRelated(ASTNode first, ASTNode second) {
410 max = second; 437 max = second;
411 } 438 }
412 439
413 while (min_level < max_level) { 440 while (max_level > min_level) {
414 min_level++; 441 max_level--;
415 min = min->GetParent(); 442 max = max->GetParent();
416 } 443 }
417 444
418 return (min->GetParent() == max->GetParent()); 445 return (min->GetParent() == max->GetParent());
419} 446}
420 447
448void ASTManager::ShowCurrentState(std::string state) {
449 LOG_CRITICAL(HW_GPU, "\nState {}:\n\n{}\n", state, Print());
450 SanityCheck();
451}
452
453void ASTManager::SanityCheck() {
454 for (auto label : labels) {
455 if (!label->GetParent()) {
456 LOG_CRITICAL(HW_GPU, "Sanity Check Failed");
457 }
458 }
459}
460
421void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) { 461void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) {
462 // ShowCurrentState("Before DoWhile Enclose");
463 enclose_count++;
422 ASTZipper& zipper = goto_node->GetManager(); 464 ASTZipper& zipper = goto_node->GetManager();
423 ASTNode loop_start = label->GetNext(); 465 ASTNode loop_start = label->GetNext();
424 if (loop_start == goto_node) { 466 if (loop_start == goto_node) {
425 zipper.Remove(goto_node); 467 zipper.Remove(goto_node);
468 // ShowCurrentState("Ignore DoWhile Enclose");
426 return; 469 return;
427 } 470 }
428 ASTNode parent = label->GetParent(); 471 ASTNode parent = label->GetParent();
429 Expr condition = goto_node->GetGotoCondition(); 472 Expr condition = goto_node->GetGotoCondition();
430 zipper.DetachSegment(loop_start, goto_node); 473 zipper.DetachSegment(loop_start, goto_node);
431 ASTNode do_while_node = ASTBase::Make<ASTDoWhile>(parent, condition, ASTZipper(loop_start)); 474 ASTNode do_while_node = ASTBase::Make<ASTDoWhile>(parent, condition);
432 zipper.InsertAfter(do_while_node, label);
433 ASTZipper* sub_zipper = do_while_node->GetSubNodes(); 475 ASTZipper* sub_zipper = do_while_node->GetSubNodes();
434 sub_zipper->SetParent(do_while_node); 476 sub_zipper->Init(loop_start, do_while_node);
477 zipper.InsertAfter(do_while_node, label);
435 sub_zipper->Remove(goto_node); 478 sub_zipper->Remove(goto_node);
479 // ShowCurrentState("After DoWhile Enclose");
436} 480}
437 481
438void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) { 482void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) {
483 // ShowCurrentState("Before IfThen Enclose");
484 enclose_count++;
439 ASTZipper& zipper = goto_node->GetManager(); 485 ASTZipper& zipper = goto_node->GetManager();
440 ASTNode if_end = label->GetPrevious(); 486 ASTNode if_end = label->GetPrevious();
441 if (if_end == goto_node) { 487 if (if_end == goto_node) {
442 zipper.Remove(goto_node); 488 zipper.Remove(goto_node);
489 // ShowCurrentState("Ignore IfThen Enclose");
443 return; 490 return;
444 } 491 }
445 ASTNode prev = goto_node->GetPrevious(); 492 ASTNode prev = goto_node->GetPrevious();
446 ASTNode parent = label->GetParent();
447 Expr condition = goto_node->GetGotoCondition(); 493 Expr condition = goto_node->GetGotoCondition();
448 Expr neg_condition = MakeExpr<ExprNot>(condition); 494 bool do_else = false;
495 if (prev->IsIfThen()) {
496 Expr if_condition = prev->GetIfCondition();
497 do_else = ExprAreEqual(if_condition, condition);
498 }
499 ASTNode parent = label->GetParent();
449 zipper.DetachSegment(goto_node, if_end); 500 zipper.DetachSegment(goto_node, if_end);
450 ASTNode if_node = ASTBase::Make<ASTIfThen>(parent, condition, ASTZipper(goto_node)); 501 ASTNode if_node;
451 zipper.InsertAfter(if_node, prev); 502 if (do_else) {
503 if_node = ASTBase::Make<ASTIfElse>(parent);
504 } else {
505 Expr neg_condition = MakeExprNot(condition);
506 if_node = ASTBase::Make<ASTIfThen>(parent, neg_condition);
507 }
452 ASTZipper* sub_zipper = if_node->GetSubNodes(); 508 ASTZipper* sub_zipper = if_node->GetSubNodes();
453 sub_zipper->SetParent(if_node); 509 sub_zipper->Init(goto_node, if_node);
510 zipper.InsertAfter(if_node, prev);
454 sub_zipper->Remove(goto_node); 511 sub_zipper->Remove(goto_node);
512 // ShowCurrentState("After IfThen Enclose");
455} 513}
456 514
457void ASTManager::MoveOutward(ASTNode goto_node) { 515void ASTManager::MoveOutward(ASTNode goto_node) {
516 // ShowCurrentState("Before MoveOutward");
517 outward_count++;
458 ASTZipper& zipper = goto_node->GetManager(); 518 ASTZipper& zipper = goto_node->GetManager();
459 ASTNode parent = goto_node->GetParent(); 519 ASTNode parent = goto_node->GetParent();
520 ASTZipper& zipper2 = parent->GetManager();
521 ASTNode grandpa = parent->GetParent();
460 bool is_loop = parent->IsLoop(); 522 bool is_loop = parent->IsLoop();
461 bool is_if = parent->IsIfThen() || parent->IsIfElse(); 523 bool is_else = parent->IsIfElse();
524 bool is_if = parent->IsIfThen();
462 525
463 ASTNode prev = goto_node->GetPrevious(); 526 ASTNode prev = goto_node->GetPrevious();
527 ASTNode post = goto_node->GetNext();
464 528
465 Expr condition = goto_node->GetGotoCondition(); 529 Expr condition = goto_node->GetGotoCondition();
466 u32 var_index = NewVariable();
467 Expr var_condition = MakeExpr<ExprVar>(var_index);
468 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
469 zipper.DetachSingle(goto_node); 530 zipper.DetachSingle(goto_node);
470 zipper.InsertAfter(var_node, prev);
471 goto_node->SetGotoCondition(var_condition);
472 if (is_loop) { 531 if (is_loop) {
532 u32 var_index = NewVariable();
533 Expr var_condition = MakeExpr<ExprVar>(var_index);
534 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
535 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition);
536 zipper2.InsertBefore(var_node_init, parent);
537 zipper.InsertAfter(var_node, prev);
538 goto_node->SetGotoCondition(var_condition);
473 ASTNode break_node = ASTBase::Make<ASTBreak>(parent, var_condition); 539 ASTNode break_node = ASTBase::Make<ASTBreak>(parent, var_condition);
474 zipper.InsertAfter(break_node, var_node); 540 zipper.InsertAfter(break_node, var_node);
475 } else if (is_if) { 541 } else if (is_if || is_else) {
476 ASTNode post = var_node->GetNext();
477 if (post) { 542 if (post) {
543 u32 var_index = NewVariable();
544 Expr var_condition = MakeExpr<ExprVar>(var_index);
545 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
546 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition);
547 if (is_if) {
548 zipper2.InsertBefore(var_node_init, parent);
549 } else {
550 zipper2.InsertBefore(var_node_init, parent->GetPrevious());
551 }
552 zipper.InsertAfter(var_node, prev);
553 goto_node->SetGotoCondition(var_condition);
478 zipper.DetachTail(post); 554 zipper.DetachTail(post);
479 ASTNode if_node = ASTBase::Make<ASTIfThen>(parent, var_condition, ASTZipper(post)); 555 ASTNode if_node = ASTBase::Make<ASTIfThen>(parent, MakeExprNot(var_condition));
480 zipper.InsertAfter(if_node, var_node);
481 ASTZipper* sub_zipper = if_node->GetSubNodes(); 556 ASTZipper* sub_zipper = if_node->GetSubNodes();
482 sub_zipper->SetParent(if_node); 557 sub_zipper->Init(post, if_node);
558 zipper.InsertAfter(if_node, var_node);
559 } else {
560 Expr if_condition;
561 if (is_if) {
562 if_condition = parent->GetIfCondition();
563 } else {
564 ASTNode if_node = parent->GetPrevious();
565 if_condition = MakeExprNot(if_node->GetIfCondition());
566 }
567 Expr new_condition = MakeExprAnd(if_condition, condition);
568 goto_node->SetGotoCondition(new_condition);
483 } 569 }
484 } else { 570 } else {
485 UNREACHABLE(); 571 UNREACHABLE();
486 } 572 }
487 ASTZipper& zipper2 = parent->GetManager();
488 ASTNode next = parent->GetNext(); 573 ASTNode next = parent->GetNext();
489 if (is_if && next && next->IsIfElse()) { 574 if (is_if && next && next->IsIfElse()) {
490 zipper2.InsertAfter(goto_node, next); 575 zipper2.InsertAfter(goto_node, next);
576 goto_node->SetParent(grandpa);
577 // ShowCurrentState("After MoveOutward");
491 return; 578 return;
492 } 579 }
493 zipper2.InsertAfter(goto_node, parent); 580 zipper2.InsertAfter(goto_node, parent);
581 goto_node->SetParent(grandpa);
582 // ShowCurrentState("After MoveOutward");
494} 583}
495 584
496} // namespace VideoCommon::Shader 585} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h
index 22ac8884c..4276f66a9 100644
--- a/src/video_core/shader/ast.h
+++ b/src/video_core/shader/ast.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <functional>
7#include <list> 8#include <list>
8#include <memory> 9#include <memory>
9#include <optional> 10#include <optional>
@@ -21,6 +22,7 @@ class ASTProgram;
21class ASTIfThen; 22class ASTIfThen;
22class ASTIfElse; 23class ASTIfElse;
23class ASTBlockEncoded; 24class ASTBlockEncoded;
25class ASTBlockDecoded;
24class ASTVarSet; 26class ASTVarSet;
25class ASTGoto; 27class ASTGoto;
26class ASTLabel; 28class ASTLabel;
@@ -28,7 +30,7 @@ class ASTDoWhile;
28class ASTReturn; 30class ASTReturn;
29class ASTBreak; 31class ASTBreak;
30 32
31using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTVarSet, ASTGoto, 33using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTBlockDecoded, ASTVarSet, ASTGoto,
32 ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>; 34 ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>;
33 35
34using ASTNode = std::shared_ptr<ASTBase>; 36using ASTNode = std::shared_ptr<ASTBase>;
@@ -43,7 +45,8 @@ enum class ASTZipperType : u32 {
43class ASTZipper final { 45class ASTZipper final {
44public: 46public:
45 ASTZipper(); 47 ASTZipper();
46 ASTZipper(ASTNode first); 48
49 void Init(ASTNode first, ASTNode parent);
47 50
48 ASTNode GetFirst() { 51 ASTNode GetFirst() {
49 return first; 52 return first;
@@ -56,7 +59,7 @@ public:
56 void PushBack(ASTNode new_node); 59 void PushBack(ASTNode new_node);
57 void PushFront(ASTNode new_node); 60 void PushFront(ASTNode new_node);
58 void InsertAfter(ASTNode new_node, ASTNode at_node); 61 void InsertAfter(ASTNode new_node, ASTNode at_node);
59 void SetParent(ASTNode new_parent); 62 void InsertBefore(ASTNode new_node, ASTNode at_node);
60 void DetachTail(ASTNode node); 63 void DetachTail(ASTNode node);
61 void DetachSingle(ASTNode node); 64 void DetachSingle(ASTNode node);
62 void DetachSegment(ASTNode start, ASTNode end); 65 void DetachSegment(ASTNode start, ASTNode end);
@@ -74,14 +77,14 @@ public:
74 77
75class ASTIfThen { 78class ASTIfThen {
76public: 79public:
77 ASTIfThen(Expr condition, ASTZipper nodes) : condition(condition), nodes{nodes} {} 80 ASTIfThen(Expr condition) : condition(condition), nodes{} {}
78 Expr condition; 81 Expr condition;
79 ASTZipper nodes; 82 ASTZipper nodes;
80}; 83};
81 84
82class ASTIfElse { 85class ASTIfElse {
83public: 86public:
84 ASTIfElse(ASTZipper nodes) : nodes{nodes} {} 87 ASTIfElse() : nodes{} {}
85 ASTZipper nodes; 88 ASTZipper nodes;
86}; 89};
87 90
@@ -92,6 +95,12 @@ public:
92 u32 end; 95 u32 end;
93}; 96};
94 97
98class ASTBlockDecoded {
99public:
100 ASTBlockDecoded(NodeBlock& new_nodes) : nodes(std::move(new_nodes)) {}
101 NodeBlock nodes;
102};
103
95class ASTVarSet { 104class ASTVarSet {
96public: 105public:
97 ASTVarSet(u32 index, Expr condition) : index{index}, condition{condition} {} 106 ASTVarSet(u32 index, Expr condition) : index{index}, condition{condition} {}
@@ -114,7 +123,7 @@ public:
114 123
115class ASTDoWhile { 124class ASTDoWhile {
116public: 125public:
117 ASTDoWhile(Expr condition, ASTZipper nodes) : condition(condition), nodes{nodes} {} 126 ASTDoWhile(Expr condition) : condition(condition), nodes{} {}
118 Expr condition; 127 Expr condition;
119 ASTZipper nodes; 128 ASTZipper nodes;
120}; 129};
@@ -132,6 +141,8 @@ public:
132 Expr condition; 141 Expr condition;
133}; 142};
134 143
144using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>;
145
135class ASTBase { 146class ASTBase {
136public: 147public:
137 explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {} 148 explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {}
@@ -195,6 +206,14 @@ public:
195 return nullptr; 206 return nullptr;
196 } 207 }
197 208
209 Expr GetIfCondition() const {
210 auto inner = std::get_if<ASTIfThen>(&data);
211 if (inner) {
212 return inner->condition;
213 }
214 return nullptr;
215 }
216
198 void SetGotoCondition(Expr new_condition) { 217 void SetGotoCondition(Expr new_condition) {
199 auto inner = std::get_if<ASTGoto>(&data); 218 auto inner = std::get_if<ASTGoto>(&data);
200 if (inner) { 219 if (inner) {
@@ -210,6 +229,18 @@ public:
210 return std::holds_alternative<ASTIfElse>(data); 229 return std::holds_alternative<ASTIfElse>(data);
211 } 230 }
212 231
232 bool IsBlockEncoded() const {
233 return std::holds_alternative<ASTBlockEncoded>(data);
234 }
235
236 void TransformBlockEncoded(TransformCallback& callback) {
237 auto block = std::get_if<ASTBlockEncoded>(&data);
238 const u32 start = block->start;
239 const u32 end = block->end;
240 NodeBlock nodes = callback(start, end);
241 data = ASTBlockDecoded(nodes);
242 }
243
213 bool IsLoop() const { 244 bool IsLoop() const {
214 return std::holds_alternative<ASTDoWhile>(data); 245 return std::holds_alternative<ASTDoWhile>(data);
215 } 246 }
@@ -245,6 +276,7 @@ public:
245 explicit ASTManager() { 276 explicit ASTManager() {
246 main_node = ASTBase::Make<ASTProgram>(ASTNode{}); 277 main_node = ASTBase::Make<ASTProgram>(ASTNode{});
247 program = std::get_if<ASTProgram>(main_node->GetInnerData()); 278 program = std::get_if<ASTProgram>(main_node->GetInnerData());
279 true_condition = MakeExpr<ExprBoolean>(true);
248 } 280 }
249 281
250 void DeclareLabel(u32 address) { 282 void DeclareLabel(u32 address) {
@@ -283,7 +315,13 @@ public:
283 315
284 void Decompile(); 316 void Decompile();
285 317
318 void ShowCurrentState(std::string state);
286 319
320 void SanityCheck();
321
322 bool IsFullyDecompiled() {
323 return gotos.size() == 0;
324 }
287 325
288private: 326private:
289 bool IndirectlyRelated(ASTNode first, ASTNode second); 327 bool IndirectlyRelated(ASTNode first, ASTNode second);
@@ -309,6 +347,9 @@ private:
309 u32 variables{}; 347 u32 variables{};
310 ASTProgram* program; 348 ASTProgram* program;
311 ASTNode main_node; 349 ASTNode main_node;
350 Expr true_condition;
351 u32 outward_count{};
352 u32 enclose_count{};
312}; 353};
313 354
314} // namespace VideoCommon::Shader 355} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index bea7f767c..7a21d870f 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -423,7 +423,16 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) {
423 result = MakeExpr<ExprCondCode>(cond.cc); 423 result = MakeExpr<ExprCondCode>(cond.cc);
424 } 424 }
425 if (cond.predicate != Pred::UnusedIndex) { 425 if (cond.predicate != Pred::UnusedIndex) {
426 Expr extra = MakeExpr<ExprPredicate>(cond.predicate); 426 u32 pred = static_cast<u32>(cond.predicate);
427 bool negate;
428 if (pred > 7) {
429 negate = true;
430 pred -= 8;
431 }
432 Expr extra = MakeExpr<ExprPredicate>(pred);
433 if (negate) {
434 extra = MakeExpr<ExprNot>(extra);
435 }
427 if (result) { 436 if (result) {
428 return MakeExpr<ExprAnd>(extra, result); 437 return MakeExpr<ExprAnd>(extra, result);
429 } 438 }
@@ -460,8 +469,9 @@ void DecompileShader(CFGRebuildState& state) {
460 InsertBranch(manager, block.branch); 469 InsertBranch(manager, block.branch);
461 } 470 }
462 } 471 }
472 //manager.ShowCurrentState("Before Decompiling");
463 manager.Decompile(); 473 manager.Decompile();
464 LOG_CRITICAL(HW_GPU, "Decompiled Shader:\n{} \n", manager.Print()); 474 //manager.ShowCurrentState("After Decompiling");
465} 475}
466 476
467std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, 477std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
diff --git a/src/video_core/shader/expr.cpp b/src/video_core/shader/expr.cpp
new file mode 100644
index 000000000..ebce6339b
--- /dev/null
+++ b/src/video_core/shader/expr.cpp
@@ -0,0 +1,75 @@
1// Copyright 2019 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 <memory>
8#include <variant>
9
10#include "video_core/shader/expr.h"
11
12namespace VideoCommon::Shader {
13
14bool ExprAnd::operator==(const ExprAnd& b) const {
15 return (*operand1 == *b.operand1) && (*operand2 == *b.operand2);
16}
17
18bool ExprOr::operator==(const ExprOr& b) const {
19 return (*operand1 == *b.operand1) && (*operand2 == *b.operand2);
20}
21
22bool ExprNot::operator==(const ExprNot& b) const {
23 return (*operand1 == *b.operand1);
24}
25
26bool ExprIsBoolean(Expr expr) {
27 return std::holds_alternative<ExprBoolean>(*expr);
28}
29
30bool ExprBooleanGet(Expr expr) {
31 return std::get_if<ExprBoolean>(expr.get())->value;
32}
33
34Expr MakeExprNot(Expr first) {
35 if (std::holds_alternative<ExprNot>(*first)) {
36 return std::get_if<ExprNot>(first.get())->operand1;
37 }
38 return MakeExpr<ExprNot>(first);
39}
40
41Expr MakeExprAnd(Expr first, Expr second) {
42 if (ExprIsBoolean(first)) {
43 return ExprBooleanGet(first) ? second : first;
44 }
45 if (ExprIsBoolean(second)) {
46 return ExprBooleanGet(second) ? first : second;
47 }
48 return MakeExpr<ExprAnd>(first, second);
49}
50
51Expr MakeExprOr(Expr first, Expr second) {
52 if (ExprIsBoolean(first)) {
53 return ExprBooleanGet(first) ? first : second;
54 }
55 if (ExprIsBoolean(second)) {
56 return ExprBooleanGet(second) ? second : first;
57 }
58 return MakeExpr<ExprOr>(first, second);
59}
60
61bool ExprAreEqual(Expr first, Expr second) {
62 return (*first) == (*second);
63}
64
65bool ExprAreOpposite(Expr first, Expr second) {
66 if (std::holds_alternative<ExprNot>(*first)) {
67 return ExprAreEqual(std::get_if<ExprNot>(first.get())->operand1, second);
68 }
69 if (std::holds_alternative<ExprNot>(*second)) {
70 return ExprAreEqual(std::get_if<ExprNot>(second.get())->operand1, first);
71 }
72 return false;
73}
74
75} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/expr.h b/src/video_core/shader/expr.h
index 94678f09a..f012f6fcf 100644
--- a/src/video_core/shader/expr.h
+++ b/src/video_core/shader/expr.h
@@ -30,6 +30,8 @@ class ExprAnd final {
30public: 30public:
31 ExprAnd(Expr a, Expr b) : operand1{a}, operand2{b} {} 31 ExprAnd(Expr a, Expr b) : operand1{a}, operand2{b} {}
32 32
33 bool operator==(const ExprAnd& b) const;
34
33 Expr operand1; 35 Expr operand1;
34 Expr operand2; 36 Expr operand2;
35}; 37};
@@ -38,6 +40,8 @@ class ExprOr final {
38public: 40public:
39 ExprOr(Expr a, Expr b) : operand1{a}, operand2{b} {} 41 ExprOr(Expr a, Expr b) : operand1{a}, operand2{b} {}
40 42
43 bool operator==(const ExprOr& b) const;
44
41 Expr operand1; 45 Expr operand1;
42 Expr operand2; 46 Expr operand2;
43}; 47};
@@ -46,6 +50,8 @@ class ExprNot final {
46public: 50public:
47 ExprNot(Expr a) : operand1{a} {} 51 ExprNot(Expr a) : operand1{a} {}
48 52
53 bool operator==(const ExprNot& b) const;
54
49 Expr operand1; 55 Expr operand1;
50}; 56};
51 57
@@ -53,20 +59,32 @@ class ExprVar final {
53public: 59public:
54 ExprVar(u32 index) : var_index{index} {} 60 ExprVar(u32 index) : var_index{index} {}
55 61
62 bool operator==(const ExprVar& b) const {
63 return var_index == b.var_index;
64 }
65
56 u32 var_index; 66 u32 var_index;
57}; 67};
58 68
59class ExprPredicate final { 69class ExprPredicate final {
60public: 70public:
61 ExprPredicate(Pred predicate) : predicate{predicate} {} 71 ExprPredicate(u32 predicate) : predicate{predicate} {}
72
73 bool operator==(const ExprPredicate& b) const {
74 return predicate == b.predicate;
75 }
62 76
63 Pred predicate; 77 u32 predicate;
64}; 78};
65 79
66class ExprCondCode final { 80class ExprCondCode final {
67public: 81public:
68 ExprCondCode(ConditionCode cc) : cc{cc} {} 82 ExprCondCode(ConditionCode cc) : cc{cc} {}
69 83
84 bool operator==(const ExprCondCode& b) const {
85 return cc == b.cc;
86 }
87
70 ConditionCode cc; 88 ConditionCode cc;
71}; 89};
72 90
@@ -74,6 +92,10 @@ class ExprBoolean final {
74public: 92public:
75 ExprBoolean(bool val) : value{val} {} 93 ExprBoolean(bool val) : value{val} {}
76 94
95 bool operator==(const ExprBoolean& b) const {
96 return value == b.value;
97 }
98
77 bool value; 99 bool value;
78}; 100};
79 101
@@ -83,4 +105,14 @@ Expr MakeExpr(Args&&... args) {
83 return std::make_shared<ExprData>(T(std::forward<Args>(args)...)); 105 return std::make_shared<ExprData>(T(std::forward<Args>(args)...));
84} 106}
85 107
108bool ExprAreEqual(Expr first, Expr second);
109
110bool ExprAreOpposite(Expr first, Expr second);
111
112Expr MakeExprNot(Expr first);
113
114Expr MakeExprAnd(Expr first, Expr second);
115
116Expr MakeExprOr(Expr first, Expr second);
117
86} // namespace VideoCommon::Shader 118} // namespace VideoCommon::Shader