diff options
| author | 2019-06-28 20:54:21 -0400 | |
|---|---|---|
| committer | 2019-10-04 18:52:48 -0400 | |
| commit | 8be6e1c5221066a49b6ad27efbd20a999a7c16b3 (patch) | |
| tree | a00263eb962503bec08ec4bc870a9546c3b80d22 | |
| parent | shader_ir: Add basic goto elimination (diff) | |
| download | yuzu-8be6e1c5221066a49b6ad27efbd20a999a7c16b3.tar.gz yuzu-8be6e1c5221066a49b6ad27efbd20a999a7c16b3.tar.xz yuzu-8be6e1c5221066a49b6ad27efbd20a999a7c16b3.zip | |
shader_ir: Corrections to outward movements and misc stuffs
| -rw-r--r-- | CMakeModules/GenerateSCMRev.cmake | 4 | ||||
| -rw-r--r-- | src/common/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/video_core/shader/ast.cpp | 185 | ||||
| -rw-r--r-- | src/video_core/shader/ast.h | 53 | ||||
| -rw-r--r-- | src/video_core/shader/control_flow.cpp | 14 | ||||
| -rw-r--r-- | src/video_core/shader/expr.cpp | 75 | ||||
| -rw-r--r-- | src/video_core/shader/expr.h | 36 |
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 @@ | |||
| 12 | namespace VideoCommon::Shader { | 12 | namespace VideoCommon::Shader { |
| 13 | 13 | ||
| 14 | ASTZipper::ASTZipper() = default; | 14 | ASTZipper::ASTZipper() = default; |
| 15 | ASTZipper::ASTZipper(ASTNode new_first) : first{}, last{} { | 15 | |
| 16 | void 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 | ||
| 26 | void ASTZipper::PushBack(ASTNode new_node) { | 29 | void 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 | ||
| 39 | void ASTZipper::PushFront(ASTNode new_node) { | 43 | void 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 | ||
| 52 | void ASTZipper::InsertAfter(ASTNode new_node, ASTNode at_node) { | 57 | void 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 | ||
| 66 | void ASTZipper::SetParent(ASTNode new_parent) { | 76 | void 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 | ||
| 74 | void ASTZipper::DetachTail(ASTNode node) { | 95 | void 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 | ||
| 86 | void ASTZipper::DetachSegment(ASTNode start, ASTNode end) { | 114 | void 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 | |||
| 135 | void ASTZipper::Remove(ASTNode node) { | 166 | void 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 | |||
| 338 | void ASTManager::Decompile() { | 366 | void 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 | ||
| 387 | bool ASTManager::IndirectlyRelated(ASTNode first, ASTNode second) { | 414 | bool 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 | ||
| 448 | void ASTManager::ShowCurrentState(std::string state) { | ||
| 449 | LOG_CRITICAL(HW_GPU, "\nState {}:\n\n{}\n", state, Print()); | ||
| 450 | SanityCheck(); | ||
| 451 | } | ||
| 452 | |||
| 453 | void ASTManager::SanityCheck() { | ||
| 454 | for (auto label : labels) { | ||
| 455 | if (!label->GetParent()) { | ||
| 456 | LOG_CRITICAL(HW_GPU, "Sanity Check Failed"); | ||
| 457 | } | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 421 | void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) { | 461 | void 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 | ||
| 438 | void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) { | 482 | void 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 | ||
| 457 | void ASTManager::MoveOutward(ASTNode goto_node) { | 515 | void 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; | |||
| 21 | class ASTIfThen; | 22 | class ASTIfThen; |
| 22 | class ASTIfElse; | 23 | class ASTIfElse; |
| 23 | class ASTBlockEncoded; | 24 | class ASTBlockEncoded; |
| 25 | class ASTBlockDecoded; | ||
| 24 | class ASTVarSet; | 26 | class ASTVarSet; |
| 25 | class ASTGoto; | 27 | class ASTGoto; |
| 26 | class ASTLabel; | 28 | class ASTLabel; |
| @@ -28,7 +30,7 @@ class ASTDoWhile; | |||
| 28 | class ASTReturn; | 30 | class ASTReturn; |
| 29 | class ASTBreak; | 31 | class ASTBreak; |
| 30 | 32 | ||
| 31 | using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTVarSet, ASTGoto, | 33 | using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTBlockDecoded, ASTVarSet, ASTGoto, |
| 32 | ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>; | 34 | ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>; |
| 33 | 35 | ||
| 34 | using ASTNode = std::shared_ptr<ASTBase>; | 36 | using ASTNode = std::shared_ptr<ASTBase>; |
| @@ -43,7 +45,8 @@ enum class ASTZipperType : u32 { | |||
| 43 | class ASTZipper final { | 45 | class ASTZipper final { |
| 44 | public: | 46 | public: |
| 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 | ||
| 75 | class ASTIfThen { | 78 | class ASTIfThen { |
| 76 | public: | 79 | public: |
| 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 | ||
| 82 | class ASTIfElse { | 85 | class ASTIfElse { |
| 83 | public: | 86 | public: |
| 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 | ||
| 98 | class ASTBlockDecoded { | ||
| 99 | public: | ||
| 100 | ASTBlockDecoded(NodeBlock& new_nodes) : nodes(std::move(new_nodes)) {} | ||
| 101 | NodeBlock nodes; | ||
| 102 | }; | ||
| 103 | |||
| 95 | class ASTVarSet { | 104 | class ASTVarSet { |
| 96 | public: | 105 | public: |
| 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 | ||
| 115 | class ASTDoWhile { | 124 | class ASTDoWhile { |
| 116 | public: | 125 | public: |
| 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 | ||
| 144 | using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>; | ||
| 145 | |||
| 135 | class ASTBase { | 146 | class ASTBase { |
| 136 | public: | 147 | public: |
| 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 | ||
| 288 | private: | 326 | private: |
| 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 | ||
| 467 | std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, | 477 | std::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 | |||
| 12 | namespace VideoCommon::Shader { | ||
| 13 | |||
| 14 | bool ExprAnd::operator==(const ExprAnd& b) const { | ||
| 15 | return (*operand1 == *b.operand1) && (*operand2 == *b.operand2); | ||
| 16 | } | ||
| 17 | |||
| 18 | bool ExprOr::operator==(const ExprOr& b) const { | ||
| 19 | return (*operand1 == *b.operand1) && (*operand2 == *b.operand2); | ||
| 20 | } | ||
| 21 | |||
| 22 | bool ExprNot::operator==(const ExprNot& b) const { | ||
| 23 | return (*operand1 == *b.operand1); | ||
| 24 | } | ||
| 25 | |||
| 26 | bool ExprIsBoolean(Expr expr) { | ||
| 27 | return std::holds_alternative<ExprBoolean>(*expr); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool ExprBooleanGet(Expr expr) { | ||
| 31 | return std::get_if<ExprBoolean>(expr.get())->value; | ||
| 32 | } | ||
| 33 | |||
| 34 | Expr 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 | |||
| 41 | Expr 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 | |||
| 51 | Expr 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 | |||
| 61 | bool ExprAreEqual(Expr first, Expr second) { | ||
| 62 | return (*first) == (*second); | ||
| 63 | } | ||
| 64 | |||
| 65 | bool 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 { | |||
| 30 | public: | 30 | public: |
| 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 { | |||
| 38 | public: | 40 | public: |
| 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 { | |||
| 46 | public: | 50 | public: |
| 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 { | |||
| 53 | public: | 59 | public: |
| 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 | ||
| 59 | class ExprPredicate final { | 69 | class ExprPredicate final { |
| 60 | public: | 70 | public: |
| 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 | ||
| 66 | class ExprCondCode final { | 80 | class ExprCondCode final { |
| 67 | public: | 81 | public: |
| 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 { | |||
| 74 | public: | 92 | public: |
| 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 | ||
| 108 | bool ExprAreEqual(Expr first, Expr second); | ||
| 109 | |||
| 110 | bool ExprAreOpposite(Expr first, Expr second); | ||
| 111 | |||
| 112 | Expr MakeExprNot(Expr first); | ||
| 113 | |||
| 114 | Expr MakeExprAnd(Expr first, Expr second); | ||
| 115 | |||
| 116 | Expr MakeExprOr(Expr first, Expr second); | ||
| 117 | |||
| 86 | } // namespace VideoCommon::Shader | 118 | } // namespace VideoCommon::Shader |