| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  | // Copyright 2019 yuzu Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <string>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "common/assert.h"
 | 
					
						
							|  |  |  | #include "common/common_types.h"
 | 
					
						
							|  |  |  | #include "video_core/shader/ast.h"
 | 
					
						
							|  |  |  | #include "video_core/shader/expr.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace VideoCommon::Shader { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | ASTZipper::ASTZipper() = default; | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::Init(const ASTNode new_first, const ASTNode parent) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     ASSERT(new_first->manager == nullptr); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     first = new_first; | 
					
						
							|  |  |  |     last = new_first; | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     ASTNode current = first; | 
					
						
							|  |  |  |     while (current) { | 
					
						
							|  |  |  |         current->manager = this; | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         current->parent = parent; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         last = current; | 
					
						
							|  |  |  |         current = current->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::PushBack(const ASTNode new_node) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     ASSERT(new_node->manager == nullptr); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     new_node->previous = last; | 
					
						
							|  |  |  |     if (last) { | 
					
						
							|  |  |  |         last->next = new_node; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     new_node->next.reset(); | 
					
						
							|  |  |  |     last = new_node; | 
					
						
							|  |  |  |     if (!first) { | 
					
						
							|  |  |  |         first = new_node; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     new_node->manager = this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::PushFront(const ASTNode new_node) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     ASSERT(new_node->manager == nullptr); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     new_node->previous.reset(); | 
					
						
							|  |  |  |     new_node->next = first; | 
					
						
							|  |  |  |     if (first) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         first->previous = new_node; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     if (last == first) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         last = new_node; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     first = new_node; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     new_node->manager = this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::InsertAfter(const ASTNode new_node, const ASTNode at_node) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     ASSERT(new_node->manager == nullptr); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     if (!at_node) { | 
					
						
							|  |  |  |         PushFront(new_node); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode next = at_node->next; | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     if (next) { | 
					
						
							|  |  |  |         next->previous = new_node; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     new_node->previous = at_node; | 
					
						
							|  |  |  |     if (at_node == last) { | 
					
						
							|  |  |  |         last = new_node; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     new_node->next = next; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     at_node->next = new_node; | 
					
						
							|  |  |  |     new_node->manager = this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::InsertBefore(const ASTNode new_node, const ASTNode at_node) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     ASSERT(new_node->manager == nullptr); | 
					
						
							|  |  |  |     if (!at_node) { | 
					
						
							|  |  |  |         PushBack(new_node); | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode previous = at_node->previous; | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     if (previous) { | 
					
						
							|  |  |  |         previous->next = new_node; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     new_node->next = at_node; | 
					
						
							|  |  |  |     if (at_node == first) { | 
					
						
							|  |  |  |         first = new_node; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     new_node->previous = previous; | 
					
						
							|  |  |  |     at_node->previous = new_node; | 
					
						
							|  |  |  |     new_node->manager = this; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  | void ASTZipper::DetachTail(ASTNode node) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     ASSERT(node->manager == this); | 
					
						
							|  |  |  |     if (node == first) { | 
					
						
							|  |  |  |         first.reset(); | 
					
						
							|  |  |  |         last.reset(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     last = node->previous; | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     last->next.reset(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     node->previous.reset(); | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ASTNode current = std::move(node); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     while (current) { | 
					
						
							|  |  |  |         current->manager = nullptr; | 
					
						
							|  |  |  |         current->parent.reset(); | 
					
						
							|  |  |  |         current = current->next; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::DetachSegment(const ASTNode start, const ASTNode end) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     ASSERT(start->manager == this && end->manager == this); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     if (start == end) { | 
					
						
							|  |  |  |         DetachSingle(start); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode prev = start->previous; | 
					
						
							|  |  |  |     const ASTNode post = end->next; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     if (!prev) { | 
					
						
							|  |  |  |         first = post; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         prev->next = post; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!post) { | 
					
						
							|  |  |  |         last = prev; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         post->previous = prev; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     start->previous.reset(); | 
					
						
							|  |  |  |     end->next.reset(); | 
					
						
							|  |  |  |     ASTNode current = start; | 
					
						
							|  |  |  |     bool found = false; | 
					
						
							|  |  |  |     while (current) { | 
					
						
							|  |  |  |         current->manager = nullptr; | 
					
						
							|  |  |  |         current->parent.reset(); | 
					
						
							|  |  |  |         found |= current == end; | 
					
						
							|  |  |  |         current = current->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ASSERT(found); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::DetachSingle(const ASTNode node) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     ASSERT(node->manager == this); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode prev = node->previous; | 
					
						
							|  |  |  |     const ASTNode post = node->next; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     node->previous.reset(); | 
					
						
							|  |  |  |     node->next.reset(); | 
					
						
							|  |  |  |     if (!prev) { | 
					
						
							|  |  |  |         first = post; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         prev->next = post; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!post) { | 
					
						
							|  |  |  |         last = prev; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         post->previous = prev; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     node->manager = nullptr; | 
					
						
							|  |  |  |     node->parent.reset(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  | void ASTZipper::Remove(const ASTNode node) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     ASSERT(node->manager == this); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode next = node->next; | 
					
						
							|  |  |  |     const ASTNode previous = node->previous; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     if (previous) { | 
					
						
							|  |  |  |         previous->next = next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (next) { | 
					
						
							|  |  |  |         next->previous = previous; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     node->parent.reset(); | 
					
						
							|  |  |  |     node->manager = nullptr; | 
					
						
							|  |  |  |     if (node == last) { | 
					
						
							|  |  |  |         last = previous; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (node == first) { | 
					
						
							|  |  |  |         first = next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  | class ExprPrinter final { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ExprAnd& expr) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         inner += "( "; | 
					
						
							|  |  |  |         std::visit(*this, *expr.operand1); | 
					
						
							|  |  |  |         inner += " && "; | 
					
						
							|  |  |  |         std::visit(*this, *expr.operand2); | 
					
						
							|  |  |  |         inner += ')'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ExprOr& expr) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         inner += "( "; | 
					
						
							|  |  |  |         std::visit(*this, *expr.operand1); | 
					
						
							|  |  |  |         inner += " || "; | 
					
						
							|  |  |  |         std::visit(*this, *expr.operand2); | 
					
						
							|  |  |  |         inner += ')'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ExprNot& expr) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         inner += "!"; | 
					
						
							|  |  |  |         std::visit(*this, *expr.operand1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ExprPredicate& expr) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         inner += "P" + std::to_string(expr.predicate); | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ExprCondCode& expr) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         u32 cc = static_cast<u32>(expr.cc); | 
					
						
							|  |  |  |         inner += "CC" + std::to_string(cc); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ExprVar& expr) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         inner += "V" + std::to_string(expr.var_index); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ExprBoolean& expr) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         inner += expr.value ? "true" : "false"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     const std::string& GetResult() const { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         return inner; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::string inner{}; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ASTPrinter { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTProgram& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         scope++; | 
					
						
							|  |  |  |         inner += "program {\n"; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |         inner += "}\n"; | 
					
						
							|  |  |  |         scope--; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTIfThen& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         ExprPrinter expr_parser{}; | 
					
						
							|  |  |  |         std::visit(expr_parser, *ast.condition); | 
					
						
							|  |  |  |         inner += Ident() + "if (" + expr_parser.GetResult() + ") {\n"; | 
					
						
							|  |  |  |         scope++; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |         scope--; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         inner += Ident() + "}\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTIfElse& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         inner += Ident() + "else {\n"; | 
					
						
							|  |  |  |         scope++; | 
					
						
							|  |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         scope--; | 
					
						
							|  |  |  |         inner += Ident() + "}\n"; | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTBlockEncoded& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         inner += Ident() + "Block(" + std::to_string(ast.start) + ", " + std::to_string(ast.end) + | 
					
						
							|  |  |  |                  ");\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTBlockDecoded& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         inner += Ident() + "Block;\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTVarSet& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         ExprPrinter expr_parser{}; | 
					
						
							|  |  |  |         std::visit(expr_parser, *ast.condition); | 
					
						
							|  |  |  |         inner += | 
					
						
							|  |  |  |             Ident() + "V" + std::to_string(ast.index) + " := " + expr_parser.GetResult() + ";\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTLabel& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         inner += "Label_" + std::to_string(ast.index) + ":\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTGoto& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         ExprPrinter expr_parser{}; | 
					
						
							|  |  |  |         std::visit(expr_parser, *ast.condition); | 
					
						
							|  |  |  |         inner += Ident() + "(" + expr_parser.GetResult() + ") -> goto Label_" + | 
					
						
							|  |  |  |                  std::to_string(ast.label) + ";\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTDoWhile& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         ExprPrinter expr_parser{}; | 
					
						
							|  |  |  |         std::visit(expr_parser, *ast.condition); | 
					
						
							|  |  |  |         inner += Ident() + "do {\n"; | 
					
						
							|  |  |  |         scope++; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |         scope--; | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         inner += Ident() + "} while (" + expr_parser.GetResult() + ");\n"; | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTReturn& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         ExprPrinter expr_parser{}; | 
					
						
							|  |  |  |         std::visit(expr_parser, *ast.condition); | 
					
						
							|  |  |  |         inner += Ident() + "(" + expr_parser.GetResult() + ") -> " + | 
					
						
							|  |  |  |                  (ast.kills ? "discard" : "exit") + ";\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTBreak& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         ExprPrinter expr_parser{}; | 
					
						
							|  |  |  |         std::visit(expr_parser, *ast.condition); | 
					
						
							|  |  |  |         inner += Ident() + "(" + expr_parser.GetResult() + ") -> break;\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |     std::string& Ident() { | 
					
						
							|  |  |  |         if (memo_scope == scope) { | 
					
						
							|  |  |  |             return tabs_memo; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         tabs_memo = tabs.substr(0, scope * 2); | 
					
						
							|  |  |  |         memo_scope = scope; | 
					
						
							|  |  |  |         return tabs_memo; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void Visit(ASTNode& node) { | 
					
						
							|  |  |  |         std::visit(*this, *node->GetInnerData()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     const std::string& GetResult() const { | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  |         return inner; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     std::string inner{}; | 
					
						
							|  |  |  |     u32 scope{}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::string tabs_memo{}; | 
					
						
							|  |  |  |     u32 memo_scope{}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:45:28 -04:00
										 |  |  |     static constexpr std::string_view tabs{"                                    "}; | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string ASTManager::Print() { | 
					
						
							|  |  |  |     ASTPrinter printer{}; | 
					
						
							|  |  |  |     printer.Visit(main_node); | 
					
						
							|  |  |  |     return printer.GetResult(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-20 21:12:06 -04:00
										 |  |  | ASTManager::ASTManager(bool full_decompile, bool disable_else_derivation) | 
					
						
							|  |  |  |     : full_decompile{full_decompile}, disable_else_derivation{disable_else_derivation} {}; | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | ASTManager::~ASTManager() { | 
					
						
							|  |  |  |     Clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::Init() { | 
					
						
							|  |  |  |     main_node = ASTBase::Make<ASTProgram>(ASTNode{}); | 
					
						
							|  |  |  |     program = std::get_if<ASTProgram>(main_node->GetInnerData()); | 
					
						
							| 
									
										
										
										
											2019-06-29 01:44:07 -04:00
										 |  |  |     false_condition = MakeExpr<ExprBoolean>(false); | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::DeclareLabel(u32 address) { | 
					
						
							|  |  |  |     const auto pair = labels_map.emplace(address, labels_count); | 
					
						
							|  |  |  |     if (pair.second) { | 
					
						
							|  |  |  |         labels_count++; | 
					
						
							|  |  |  |         labels.resize(labels_count); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::InsertLabel(u32 address) { | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const u32 index = labels_map[address]; | 
					
						
							|  |  |  |     const ASTNode label = ASTBase::Make<ASTLabel>(main_node, index); | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  |     labels[index] = label; | 
					
						
							|  |  |  |     program->nodes.PushBack(label); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::InsertGoto(Expr condition, u32 address) { | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const u32 index = labels_map[address]; | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  |     const ASTNode goto_node = ASTBase::Make<ASTGoto>(main_node, std::move(condition), index); | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  |     gotos.push_back(goto_node); | 
					
						
							|  |  |  |     program->nodes.PushBack(goto_node); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::InsertBlock(u32 start_address, u32 end_address) { | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  |     ASTNode block = ASTBase::Make<ASTBlockEncoded>(main_node, start_address, end_address); | 
					
						
							|  |  |  |     program->nodes.PushBack(std::move(block)); | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::InsertReturn(Expr condition, bool kills) { | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  |     ASTNode node = ASTBase::Make<ASTReturn>(main_node, std::move(condition), kills); | 
					
						
							|  |  |  |     program->nodes.PushBack(std::move(node)); | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-23 08:15:31 -04:00
										 |  |  | // The decompile algorithm is based on
 | 
					
						
							|  |  |  | // "Taming control flow: A structured approach to eliminating goto statements"
 | 
					
						
							|  |  |  | // by AM Erosa, LJ Hendren 1994. In general, the idea is to get gotos to be
 | 
					
						
							|  |  |  | // on the same structured level as the label which they jump to. This is done,
 | 
					
						
							|  |  |  | // through outward/inward movements and lifting. Once they are at the same
 | 
					
						
							|  |  |  | // level, you can enclose them in an "if" structure or a "do-while" structure.
 | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | void ASTManager::Decompile() { | 
					
						
							|  |  |  |     auto it = gotos.begin(); | 
					
						
							|  |  |  |     while (it != gotos.end()) { | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |         const ASTNode goto_node = *it; | 
					
						
							| 
									
										
										
										
											2019-09-28 15:16:19 -04:00
										 |  |  |         const auto label_index = goto_node->GetGotoLabel(); | 
					
						
							|  |  |  |         if (!label_index) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const ASTNode label = labels[*label_index]; | 
					
						
							| 
									
										
										
										
											2019-08-16 16:25:02 -04:00
										 |  |  |         if (!full_decompile) { | 
					
						
							|  |  |  |             // We only decompile backward jumps
 | 
					
						
							|  |  |  |             if (!IsBackwardsJump(goto_node, label)) { | 
					
						
							|  |  |  |                 it++; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         if (IndirectlyRelated(goto_node, label)) { | 
					
						
							|  |  |  |             while (!DirectlyRelated(goto_node, label)) { | 
					
						
							|  |  |  |                 MoveOutward(goto_node); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (DirectlyRelated(goto_node, label)) { | 
					
						
							|  |  |  |             u32 goto_level = goto_node->GetLevel(); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |             const u32 label_level = label->GetLevel(); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |             while (label_level < goto_level) { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |                 MoveOutward(goto_node); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |                 goto_level--; | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |             // TODO(Blinkhawk): Implement Lifting and Inward Movements
 | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (label->GetParent() == goto_node->GetParent()) { | 
					
						
							|  |  |  |             bool is_loop = false; | 
					
						
							|  |  |  |             ASTNode current = goto_node->GetPrevious(); | 
					
						
							|  |  |  |             while (current) { | 
					
						
							|  |  |  |                 if (current == label) { | 
					
						
							|  |  |  |                     is_loop = true; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 current = current->GetPrevious(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (is_loop) { | 
					
						
							|  |  |  |                 EncloseDoWhile(goto_node, label); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 EncloseIfThen(goto_node, label); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             it = gotos.erase(it); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         it++; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-16 16:25:02 -04:00
										 |  |  |     if (full_decompile) { | 
					
						
							| 
									
										
										
										
											2019-10-04 17:23:16 -04:00
										 |  |  |         for (const ASTNode& label : labels) { | 
					
						
							| 
									
										
										
										
											2019-08-16 16:25:02 -04:00
										 |  |  |             auto& manager = label->GetManager(); | 
					
						
							|  |  |  |             manager.Remove(label); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         labels.clear(); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-10-05 08:46:54 -04:00
										 |  |  |         auto label_it = labels.begin(); | 
					
						
							|  |  |  |         while (label_it != labels.end()) { | 
					
						
							| 
									
										
										
										
											2019-08-16 16:25:02 -04:00
										 |  |  |             bool can_remove = true; | 
					
						
							| 
									
										
										
										
											2019-10-05 08:46:54 -04:00
										 |  |  |             ASTNode label = *label_it; | 
					
						
							| 
									
										
										
										
											2019-10-04 17:23:16 -04:00
										 |  |  |             for (const ASTNode& goto_node : gotos) { | 
					
						
							| 
									
										
										
										
											2019-09-28 15:16:19 -04:00
										 |  |  |                 const auto label_index = goto_node->GetGotoLabel(); | 
					
						
							|  |  |  |                 if (!label_index) { | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2019-10-04 17:23:16 -04:00
										 |  |  |                 ASTNode& glabel = labels[*label_index]; | 
					
						
							| 
									
										
										
										
											2019-08-16 16:25:02 -04:00
										 |  |  |                 if (glabel == label) { | 
					
						
							|  |  |  |                     can_remove = false; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (can_remove) { | 
					
						
							| 
									
										
										
										
											2019-08-21 11:54:47 -04:00
										 |  |  |                 label->MarkLabelUnused(); | 
					
						
							| 
									
										
										
										
											2019-08-16 16:25:02 -04:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ASTManager::IsBackwardsJump(ASTNode goto_node, ASTNode label_node) const { | 
					
						
							|  |  |  |     u32 goto_level = goto_node->GetLevel(); | 
					
						
							|  |  |  |     u32 label_level = label_node->GetLevel(); | 
					
						
							|  |  |  |     while (goto_level > label_level) { | 
					
						
							|  |  |  |         goto_level--; | 
					
						
							|  |  |  |         goto_node = goto_node->GetParent(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     while (label_level > goto_level) { | 
					
						
							|  |  |  |         label_level--; | 
					
						
							|  |  |  |         label_node = label_node->GetParent(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     while (goto_node->GetParent() != label_node->GetParent()) { | 
					
						
							|  |  |  |         goto_node = goto_node->GetParent(); | 
					
						
							|  |  |  |         label_node = label_node->GetParent(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ASTNode current = goto_node->GetPrevious(); | 
					
						
							|  |  |  |     while (current) { | 
					
						
							|  |  |  |         if (current == label_node) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         current = current->GetPrevious(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  | bool ASTManager::IndirectlyRelated(const ASTNode& first, const ASTNode& second) const { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     return !(first->GetParent() == second->GetParent() || DirectlyRelated(first, second)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:17:32 -04:00
										 |  |  | bool ASTManager::DirectlyRelated(const ASTNode& first, const ASTNode& second) const { | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     if (first->GetParent() == second->GetParent()) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const u32 first_level = first->GetLevel(); | 
					
						
							|  |  |  |     const u32 second_level = second->GetLevel(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     u32 min_level; | 
					
						
							|  |  |  |     u32 max_level; | 
					
						
							|  |  |  |     ASTNode max; | 
					
						
							|  |  |  |     ASTNode min; | 
					
						
							|  |  |  |     if (first_level > second_level) { | 
					
						
							|  |  |  |         min_level = second_level; | 
					
						
							|  |  |  |         min = second; | 
					
						
							|  |  |  |         max_level = first_level; | 
					
						
							|  |  |  |         max = first; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         min_level = first_level; | 
					
						
							|  |  |  |         min = first; | 
					
						
							|  |  |  |         max_level = second_level; | 
					
						
							|  |  |  |         max = second; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     while (max_level > min_level) { | 
					
						
							|  |  |  |         max_level--; | 
					
						
							|  |  |  |         max = max->GetParent(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-04 17:23:16 -04:00
										 |  |  |     return min->GetParent() == max->GetParent(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  | void ASTManager::ShowCurrentState(std::string state) { | 
					
						
							|  |  |  |     LOG_CRITICAL(HW_GPU, "\nState {}:\n\n{}\n", state, Print()); | 
					
						
							|  |  |  |     SanityCheck(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::SanityCheck() { | 
					
						
							| 
									
										
										
										
											2019-10-04 17:23:16 -04:00
										 |  |  |     for (auto& label : labels) { | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         if (!label->GetParent()) { | 
					
						
							|  |  |  |             LOG_CRITICAL(HW_GPU, "Sanity Check Failed"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) { | 
					
						
							|  |  |  |     ASTZipper& zipper = goto_node->GetManager(); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode loop_start = label->GetNext(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     if (loop_start == goto_node) { | 
					
						
							|  |  |  |         zipper.Remove(goto_node); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode parent = label->GetParent(); | 
					
						
							|  |  |  |     const Expr condition = goto_node->GetGotoCondition(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     zipper.DetachSegment(loop_start, goto_node); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode do_while_node = ASTBase::Make<ASTDoWhile>(parent, condition); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     ASTZipper* sub_zipper = do_while_node->GetSubNodes(); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     sub_zipper->Init(loop_start, do_while_node); | 
					
						
							|  |  |  |     zipper.InsertAfter(do_while_node, label); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     sub_zipper->Remove(goto_node); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) { | 
					
						
							|  |  |  |     ASTZipper& zipper = goto_node->GetManager(); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode if_end = label->GetPrevious(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     if (if_end == goto_node) { | 
					
						
							|  |  |  |         zipper.Remove(goto_node); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode prev = goto_node->GetPrevious(); | 
					
						
							|  |  |  |     const Expr condition = goto_node->GetGotoCondition(); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     bool do_else = false; | 
					
						
							| 
									
										
										
										
											2019-09-20 21:12:06 -04:00
										 |  |  |     if (!disable_else_derivation && prev->IsIfThen()) { | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |         const Expr if_condition = prev->GetIfCondition(); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         do_else = ExprAreEqual(if_condition, condition); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode parent = label->GetParent(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     zipper.DetachSegment(goto_node, if_end); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     ASTNode if_node; | 
					
						
							|  |  |  |     if (do_else) { | 
					
						
							|  |  |  |         if_node = ASTBase::Make<ASTIfElse>(parent); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         Expr neg_condition = MakeExprNot(condition); | 
					
						
							|  |  |  |         if_node = ASTBase::Make<ASTIfThen>(parent, neg_condition); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     ASTZipper* sub_zipper = if_node->GetSubNodes(); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     sub_zipper->Init(goto_node, if_node); | 
					
						
							|  |  |  |     zipper.InsertAfter(if_node, prev); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     sub_zipper->Remove(goto_node); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::MoveOutward(ASTNode goto_node) { | 
					
						
							|  |  |  |     ASTZipper& zipper = goto_node->GetManager(); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode parent = goto_node->GetParent(); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     ASTZipper& zipper2 = parent->GetManager(); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode grandpa = parent->GetParent(); | 
					
						
							|  |  |  |     const bool is_loop = parent->IsLoop(); | 
					
						
							|  |  |  |     const bool is_else = parent->IsIfElse(); | 
					
						
							|  |  |  |     const bool is_if = parent->IsIfThen(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode prev = goto_node->GetPrevious(); | 
					
						
							|  |  |  |     const ASTNode post = goto_node->GetNext(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const Expr condition = goto_node->GetGotoCondition(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     zipper.DetachSingle(goto_node); | 
					
						
							|  |  |  |     if (is_loop) { | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |         const u32 var_index = NewVariable(); | 
					
						
							|  |  |  |         const Expr var_condition = MakeExpr<ExprVar>(var_index); | 
					
						
							|  |  |  |         const ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); | 
					
						
							|  |  |  |         const ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         zipper2.InsertBefore(var_node_init, parent); | 
					
						
							|  |  |  |         zipper.InsertAfter(var_node, prev); | 
					
						
							|  |  |  |         goto_node->SetGotoCondition(var_condition); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |         const ASTNode break_node = ASTBase::Make<ASTBreak>(parent, var_condition); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         zipper.InsertAfter(break_node, var_node); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     } else if (is_if || is_else) { | 
					
						
							| 
									
										
										
										
											2019-09-23 08:10:29 -04:00
										 |  |  |         const u32 var_index = NewVariable(); | 
					
						
							|  |  |  |         const Expr var_condition = MakeExpr<ExprVar>(var_index); | 
					
						
							|  |  |  |         const ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); | 
					
						
							|  |  |  |         const ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition); | 
					
						
							|  |  |  |         if (is_if) { | 
					
						
							|  |  |  |             zipper2.InsertBefore(var_node_init, parent); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             zipper2.InsertBefore(var_node_init, parent->GetPrevious()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         zipper.InsertAfter(var_node, prev); | 
					
						
							|  |  |  |         goto_node->SetGotoCondition(var_condition); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         if (post) { | 
					
						
							|  |  |  |             zipper.DetachTail(post); | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |             const ASTNode if_node = ASTBase::Make<ASTIfThen>(parent, MakeExprNot(var_condition)); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |             ASTZipper* sub_zipper = if_node->GetSubNodes(); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |             sub_zipper->Init(post, if_node); | 
					
						
							|  |  |  |             zipper.InsertAfter(if_node, var_node); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         UNREACHABLE(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-21 13:07:02 -04:00
										 |  |  |     const ASTNode next = parent->GetNext(); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |     if (is_if && next && next->IsIfElse()) { | 
					
						
							|  |  |  |         zipper2.InsertAfter(goto_node, next); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |         goto_node->SetParent(grandpa); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     zipper2.InsertAfter(goto_node, parent); | 
					
						
							| 
									
										
										
										
											2019-06-28 20:54:21 -04:00
										 |  |  |     goto_node->SetParent(grandpa); | 
					
						
							| 
									
										
										
										
											2019-06-27 18:57:47 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | class ASTClearer { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     ASTClearer() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTProgram& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTIfThen& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTIfElse& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()([[maybe_unused]] const ASTBlockEncoded& ast) {} | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     void operator()(ASTBlockDecoded& ast) { | 
					
						
							|  |  |  |         ast.nodes.clear(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()([[maybe_unused]] const ASTVarSet& ast) {} | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()([[maybe_unused]] const ASTLabel& ast) {} | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()([[maybe_unused]] const ASTGoto& ast) {} | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()(const ASTDoWhile& ast) { | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  |         ASTNode current = ast.nodes.GetFirst(); | 
					
						
							|  |  |  |         while (current) { | 
					
						
							|  |  |  |             Visit(current); | 
					
						
							|  |  |  |             current = current->GetNext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()([[maybe_unused]] const ASTReturn& ast) {} | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void operator()([[maybe_unused]] const ASTBreak& ast) {} | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 08:06:44 -04:00
										 |  |  |     void Visit(const ASTNode& node) { | 
					
						
							| 
									
										
										
										
											2019-06-28 22:59:43 -04:00
										 |  |  |         std::visit(*this, *node->GetInnerData()); | 
					
						
							|  |  |  |         node->Clear(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ASTManager::Clear() { | 
					
						
							|  |  |  |     if (!main_node) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ASTClearer clearer{}; | 
					
						
							|  |  |  |     clearer.Visit(main_node); | 
					
						
							|  |  |  |     main_node.reset(); | 
					
						
							|  |  |  |     program = nullptr; | 
					
						
							|  |  |  |     labels_map.clear(); | 
					
						
							|  |  |  |     labels.clear(); | 
					
						
							|  |  |  |     gotos.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-27 00:39:40 -04:00
										 |  |  | } // namespace VideoCommon::Shader
 |