mirror of
https://gitlab.com/suyu-emu/suyu.git
synced 2024-03-15 23:15:44 +00:00
shader_ir: Corrections to outward movements and misc stuffs
This commit is contained in:
parent
4fde66e609
commit
8be6e1c522
|
@ -83,9 +83,13 @@ set(HASH_FILES
|
||||||
"${VIDEO_CORE}/shader/decode/video.cpp"
|
"${VIDEO_CORE}/shader/decode/video.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/warp.cpp"
|
"${VIDEO_CORE}/shader/decode/warp.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/xmad.cpp"
|
"${VIDEO_CORE}/shader/decode/xmad.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/ast.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/ast.h"
|
||||||
"${VIDEO_CORE}/shader/control_flow.cpp"
|
"${VIDEO_CORE}/shader/control_flow.cpp"
|
||||||
"${VIDEO_CORE}/shader/control_flow.h"
|
"${VIDEO_CORE}/shader/control_flow.h"
|
||||||
"${VIDEO_CORE}/shader/decode.cpp"
|
"${VIDEO_CORE}/shader/decode.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/expr.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/expr.h"
|
||||||
"${VIDEO_CORE}/shader/node.h"
|
"${VIDEO_CORE}/shader/node.h"
|
||||||
"${VIDEO_CORE}/shader/node_helper.cpp"
|
"${VIDEO_CORE}/shader/node_helper.cpp"
|
||||||
"${VIDEO_CORE}/shader/node_helper.h"
|
"${VIDEO_CORE}/shader/node_helper.h"
|
||||||
|
|
|
@ -60,9 +60,13 @@ add_custom_command(OUTPUT scm_rev.cpp
|
||||||
"${VIDEO_CORE}/shader/decode/video.cpp"
|
"${VIDEO_CORE}/shader/decode/video.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/warp.cpp"
|
"${VIDEO_CORE}/shader/decode/warp.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/xmad.cpp"
|
"${VIDEO_CORE}/shader/decode/xmad.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/ast.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/ast.h"
|
||||||
"${VIDEO_CORE}/shader/control_flow.cpp"
|
"${VIDEO_CORE}/shader/control_flow.cpp"
|
||||||
"${VIDEO_CORE}/shader/control_flow.h"
|
"${VIDEO_CORE}/shader/control_flow.h"
|
||||||
"${VIDEO_CORE}/shader/decode.cpp"
|
"${VIDEO_CORE}/shader/decode.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/expr.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/expr.h"
|
||||||
"${VIDEO_CORE}/shader/node.h"
|
"${VIDEO_CORE}/shader/node.h"
|
||||||
"${VIDEO_CORE}/shader/node_helper.cpp"
|
"${VIDEO_CORE}/shader/node_helper.cpp"
|
||||||
"${VIDEO_CORE}/shader/node_helper.h"
|
"${VIDEO_CORE}/shader/node_helper.h"
|
||||||
|
|
|
@ -110,6 +110,7 @@ add_library(video_core STATIC
|
||||||
shader/control_flow.cpp
|
shader/control_flow.cpp
|
||||||
shader/control_flow.h
|
shader/control_flow.h
|
||||||
shader/decode.cpp
|
shader/decode.cpp
|
||||||
|
shader/expr.cpp
|
||||||
shader/expr.h
|
shader/expr.h
|
||||||
shader/node_helper.cpp
|
shader/node_helper.cpp
|
||||||
shader/node_helper.h
|
shader/node_helper.h
|
||||||
|
|
|
@ -12,18 +12,22 @@
|
||||||
namespace VideoCommon::Shader {
|
namespace VideoCommon::Shader {
|
||||||
|
|
||||||
ASTZipper::ASTZipper() = default;
|
ASTZipper::ASTZipper() = default;
|
||||||
ASTZipper::ASTZipper(ASTNode new_first) : first{}, last{} {
|
|
||||||
|
void ASTZipper::Init(ASTNode new_first, ASTNode parent) {
|
||||||
|
ASSERT(new_first->manager == nullptr);
|
||||||
first = new_first;
|
first = new_first;
|
||||||
last = new_first;
|
last = new_first;
|
||||||
ASTNode current = first;
|
ASTNode current = first;
|
||||||
while (current) {
|
while (current) {
|
||||||
current->manager = this;
|
current->manager = this;
|
||||||
|
current->parent = parent;
|
||||||
last = current;
|
last = current;
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTZipper::PushBack(ASTNode new_node) {
|
void ASTZipper::PushBack(ASTNode new_node) {
|
||||||
|
ASSERT(new_node->manager == nullptr);
|
||||||
new_node->previous = last;
|
new_node->previous = last;
|
||||||
if (last) {
|
if (last) {
|
||||||
last->next = new_node;
|
last->next = new_node;
|
||||||
|
@ -37,38 +41,55 @@ void ASTZipper::PushBack(ASTNode new_node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTZipper::PushFront(ASTNode new_node) {
|
void ASTZipper::PushFront(ASTNode new_node) {
|
||||||
|
ASSERT(new_node->manager == nullptr);
|
||||||
new_node->previous.reset();
|
new_node->previous.reset();
|
||||||
new_node->next = first;
|
new_node->next = first;
|
||||||
if (first) {
|
if (first) {
|
||||||
first->previous = first;
|
first->previous = new_node;
|
||||||
}
|
}
|
||||||
first = new_node;
|
if (last == first) {
|
||||||
if (!last) {
|
|
||||||
last = new_node;
|
last = new_node;
|
||||||
}
|
}
|
||||||
|
first = new_node;
|
||||||
new_node->manager = this;
|
new_node->manager = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTZipper::InsertAfter(ASTNode new_node, ASTNode at_node) {
|
void ASTZipper::InsertAfter(ASTNode new_node, ASTNode at_node) {
|
||||||
|
ASSERT(new_node->manager == nullptr);
|
||||||
if (!at_node) {
|
if (!at_node) {
|
||||||
PushFront(new_node);
|
PushFront(new_node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ASTNode next = at_node->next;
|
||||||
|
if (next) {
|
||||||
|
next->previous = new_node;
|
||||||
|
}
|
||||||
new_node->previous = at_node;
|
new_node->previous = at_node;
|
||||||
if (at_node == last) {
|
if (at_node == last) {
|
||||||
last = new_node;
|
last = new_node;
|
||||||
}
|
}
|
||||||
new_node->next = at_node->next;
|
new_node->next = next;
|
||||||
at_node->next = new_node;
|
at_node->next = new_node;
|
||||||
new_node->manager = this;
|
new_node->manager = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTZipper::SetParent(ASTNode new_parent) {
|
void ASTZipper::InsertBefore(ASTNode new_node, ASTNode at_node) {
|
||||||
ASTNode current = first;
|
ASSERT(new_node->manager == nullptr);
|
||||||
while (current) {
|
if (!at_node) {
|
||||||
current->parent = new_parent;
|
PushBack(new_node);
|
||||||
current = current->next;
|
return;
|
||||||
}
|
}
|
||||||
|
ASTNode previous = at_node->previous;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTZipper::DetachTail(ASTNode node) {
|
void ASTZipper::DetachTail(ASTNode node) {
|
||||||
|
@ -80,11 +101,22 @@ void ASTZipper::DetachTail(ASTNode node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
last = node->previous;
|
last = node->previous;
|
||||||
|
last->next.reset();
|
||||||
node->previous.reset();
|
node->previous.reset();
|
||||||
|
ASTNode current = node;
|
||||||
|
while (current) {
|
||||||
|
current->manager = nullptr;
|
||||||
|
current->parent.reset();
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTZipper::DetachSegment(ASTNode start, ASTNode end) {
|
void ASTZipper::DetachSegment(ASTNode start, ASTNode end) {
|
||||||
ASSERT(start->manager == this && end->manager == this);
|
ASSERT(start->manager == this && end->manager == this);
|
||||||
|
if (start == end) {
|
||||||
|
DetachSingle(start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
ASTNode prev = start->previous;
|
ASTNode prev = start->previous;
|
||||||
ASTNode post = end->next;
|
ASTNode post = end->next;
|
||||||
if (!prev) {
|
if (!prev) {
|
||||||
|
@ -131,7 +163,6 @@ void ASTZipper::DetachSingle(ASTNode node) {
|
||||||
node->parent.reset();
|
node->parent.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ASTZipper::Remove(ASTNode node) {
|
void ASTZipper::Remove(ASTNode node) {
|
||||||
ASSERT(node->manager == this);
|
ASSERT(node->manager == this);
|
||||||
ASTNode next = node->next;
|
ASTNode next = node->next;
|
||||||
|
@ -178,12 +209,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(ExprPredicate const& expr) {
|
void operator()(ExprPredicate const& expr) {
|
||||||
u32 pred = static_cast<u32>(expr.predicate);
|
inner += "P" + std::to_string(expr.predicate);
|
||||||
if (pred > 7) {
|
|
||||||
inner += "!";
|
|
||||||
pred -= 8;
|
|
||||||
}
|
|
||||||
inner += "P" + std::to_string(pred);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(ExprCondCode const& expr) {
|
void operator()(ExprCondCode const& expr) {
|
||||||
|
@ -253,6 +279,10 @@ public:
|
||||||
");\n";
|
");\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator()(ASTBlockDecoded& ast) {
|
||||||
|
inner += Ident() + "Block;\n";
|
||||||
|
}
|
||||||
|
|
||||||
void operator()(ASTVarSet& ast) {
|
void operator()(ASTVarSet& ast) {
|
||||||
ExprPrinter expr_parser{};
|
ExprPrinter expr_parser{};
|
||||||
std::visit(expr_parser, *ast.condition);
|
std::visit(expr_parser, *ast.condition);
|
||||||
|
@ -282,7 +312,7 @@ public:
|
||||||
current = current->GetNext();
|
current = current->GetNext();
|
||||||
}
|
}
|
||||||
scope--;
|
scope--;
|
||||||
inner += Ident() + "} while (" + expr_parser.GetResult() + ")\n";
|
inner += Ident() + "} while (" + expr_parser.GetResult() + ");\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(ASTReturn& ast) {
|
void operator()(ASTReturn& ast) {
|
||||||
|
@ -333,8 +363,6 @@ std::string ASTManager::Print() {
|
||||||
return printer.GetResult();
|
return printer.GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma optimize("", off)
|
|
||||||
|
|
||||||
void ASTManager::Decompile() {
|
void ASTManager::Decompile() {
|
||||||
auto it = gotos.begin();
|
auto it = gotos.begin();
|
||||||
while (it != gotos.end()) {
|
while (it != gotos.end()) {
|
||||||
|
@ -348,11 +376,12 @@ void ASTManager::Decompile() {
|
||||||
}
|
}
|
||||||
if (DirectlyRelated(goto_node, label)) {
|
if (DirectlyRelated(goto_node, label)) {
|
||||||
u32 goto_level = goto_node->GetLevel();
|
u32 goto_level = goto_node->GetLevel();
|
||||||
u32 label_level = goto_node->GetLevel();
|
u32 label_level = label->GetLevel();
|
||||||
while (label_level > goto_level) {
|
while (label_level < goto_level) {
|
||||||
MoveOutward(goto_node);
|
MoveOutward(goto_node);
|
||||||
goto_level++;
|
goto_level--;
|
||||||
}
|
}
|
||||||
|
// TODO(Blinkhawk): Implement Lifting and Inward Movements
|
||||||
}
|
}
|
||||||
if (label->GetParent() == goto_node->GetParent()) {
|
if (label->GetParent() == goto_node->GetParent()) {
|
||||||
bool is_loop = false;
|
bool is_loop = false;
|
||||||
|
@ -375,13 +404,11 @@ void ASTManager::Decompile() {
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
for (ASTNode label : labels) {
|
for (ASTNode label : labels) {
|
||||||
auto& manager = label->GetManager();
|
auto& manager = label->GetManager();
|
||||||
manager.Remove(label);
|
manager.Remove(label);
|
||||||
}
|
}
|
||||||
labels.clear();
|
labels.clear();
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTManager::IndirectlyRelated(ASTNode first, ASTNode second) {
|
bool ASTManager::IndirectlyRelated(ASTNode first, ASTNode second) {
|
||||||
|
@ -410,87 +437,149 @@ bool ASTManager::DirectlyRelated(ASTNode first, ASTNode second) {
|
||||||
max = second;
|
max = second;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (min_level < max_level) {
|
while (max_level > min_level) {
|
||||||
min_level++;
|
max_level--;
|
||||||
min = min->GetParent();
|
max = max->GetParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (min->GetParent() == max->GetParent());
|
return (min->GetParent() == max->GetParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTManager::ShowCurrentState(std::string state) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "\nState {}:\n\n{}\n", state, Print());
|
||||||
|
SanityCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASTManager::SanityCheck() {
|
||||||
|
for (auto label : labels) {
|
||||||
|
if (!label->GetParent()) {
|
||||||
|
LOG_CRITICAL(HW_GPU, "Sanity Check Failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) {
|
void ASTManager::EncloseDoWhile(ASTNode goto_node, ASTNode label) {
|
||||||
|
// ShowCurrentState("Before DoWhile Enclose");
|
||||||
|
enclose_count++;
|
||||||
ASTZipper& zipper = goto_node->GetManager();
|
ASTZipper& zipper = goto_node->GetManager();
|
||||||
ASTNode loop_start = label->GetNext();
|
ASTNode loop_start = label->GetNext();
|
||||||
if (loop_start == goto_node) {
|
if (loop_start == goto_node) {
|
||||||
zipper.Remove(goto_node);
|
zipper.Remove(goto_node);
|
||||||
|
// ShowCurrentState("Ignore DoWhile Enclose");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASTNode parent = label->GetParent();
|
ASTNode parent = label->GetParent();
|
||||||
Expr condition = goto_node->GetGotoCondition();
|
Expr condition = goto_node->GetGotoCondition();
|
||||||
zipper.DetachSegment(loop_start, goto_node);
|
zipper.DetachSegment(loop_start, goto_node);
|
||||||
ASTNode do_while_node = ASTBase::Make<ASTDoWhile>(parent, condition, ASTZipper(loop_start));
|
ASTNode do_while_node = ASTBase::Make<ASTDoWhile>(parent, condition);
|
||||||
zipper.InsertAfter(do_while_node, label);
|
|
||||||
ASTZipper* sub_zipper = do_while_node->GetSubNodes();
|
ASTZipper* sub_zipper = do_while_node->GetSubNodes();
|
||||||
sub_zipper->SetParent(do_while_node);
|
sub_zipper->Init(loop_start, do_while_node);
|
||||||
|
zipper.InsertAfter(do_while_node, label);
|
||||||
sub_zipper->Remove(goto_node);
|
sub_zipper->Remove(goto_node);
|
||||||
|
// ShowCurrentState("After DoWhile Enclose");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) {
|
void ASTManager::EncloseIfThen(ASTNode goto_node, ASTNode label) {
|
||||||
|
// ShowCurrentState("Before IfThen Enclose");
|
||||||
|
enclose_count++;
|
||||||
ASTZipper& zipper = goto_node->GetManager();
|
ASTZipper& zipper = goto_node->GetManager();
|
||||||
ASTNode if_end = label->GetPrevious();
|
ASTNode if_end = label->GetPrevious();
|
||||||
if (if_end == goto_node) {
|
if (if_end == goto_node) {
|
||||||
zipper.Remove(goto_node);
|
zipper.Remove(goto_node);
|
||||||
|
// ShowCurrentState("Ignore IfThen Enclose");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASTNode prev = goto_node->GetPrevious();
|
ASTNode prev = goto_node->GetPrevious();
|
||||||
ASTNode parent = label->GetParent();
|
|
||||||
Expr condition = goto_node->GetGotoCondition();
|
Expr condition = goto_node->GetGotoCondition();
|
||||||
Expr neg_condition = MakeExpr<ExprNot>(condition);
|
bool do_else = false;
|
||||||
|
if (prev->IsIfThen()) {
|
||||||
|
Expr if_condition = prev->GetIfCondition();
|
||||||
|
do_else = ExprAreEqual(if_condition, condition);
|
||||||
|
}
|
||||||
|
ASTNode parent = label->GetParent();
|
||||||
zipper.DetachSegment(goto_node, if_end);
|
zipper.DetachSegment(goto_node, if_end);
|
||||||
ASTNode if_node = ASTBase::Make<ASTIfThen>(parent, condition, ASTZipper(goto_node));
|
ASTNode if_node;
|
||||||
zipper.InsertAfter(if_node, prev);
|
if (do_else) {
|
||||||
|
if_node = ASTBase::Make<ASTIfElse>(parent);
|
||||||
|
} else {
|
||||||
|
Expr neg_condition = MakeExprNot(condition);
|
||||||
|
if_node = ASTBase::Make<ASTIfThen>(parent, neg_condition);
|
||||||
|
}
|
||||||
ASTZipper* sub_zipper = if_node->GetSubNodes();
|
ASTZipper* sub_zipper = if_node->GetSubNodes();
|
||||||
sub_zipper->SetParent(if_node);
|
sub_zipper->Init(goto_node, if_node);
|
||||||
|
zipper.InsertAfter(if_node, prev);
|
||||||
sub_zipper->Remove(goto_node);
|
sub_zipper->Remove(goto_node);
|
||||||
|
// ShowCurrentState("After IfThen Enclose");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTManager::MoveOutward(ASTNode goto_node) {
|
void ASTManager::MoveOutward(ASTNode goto_node) {
|
||||||
|
// ShowCurrentState("Before MoveOutward");
|
||||||
|
outward_count++;
|
||||||
ASTZipper& zipper = goto_node->GetManager();
|
ASTZipper& zipper = goto_node->GetManager();
|
||||||
ASTNode parent = goto_node->GetParent();
|
ASTNode parent = goto_node->GetParent();
|
||||||
|
ASTZipper& zipper2 = parent->GetManager();
|
||||||
|
ASTNode grandpa = parent->GetParent();
|
||||||
bool is_loop = parent->IsLoop();
|
bool is_loop = parent->IsLoop();
|
||||||
bool is_if = parent->IsIfThen() || parent->IsIfElse();
|
bool is_else = parent->IsIfElse();
|
||||||
|
bool is_if = parent->IsIfThen();
|
||||||
|
|
||||||
ASTNode prev = goto_node->GetPrevious();
|
ASTNode prev = goto_node->GetPrevious();
|
||||||
|
ASTNode post = goto_node->GetNext();
|
||||||
|
|
||||||
Expr condition = goto_node->GetGotoCondition();
|
Expr condition = goto_node->GetGotoCondition();
|
||||||
u32 var_index = NewVariable();
|
|
||||||
Expr var_condition = MakeExpr<ExprVar>(var_index);
|
|
||||||
ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
|
|
||||||
zipper.DetachSingle(goto_node);
|
zipper.DetachSingle(goto_node);
|
||||||
zipper.InsertAfter(var_node, prev);
|
|
||||||
goto_node->SetGotoCondition(var_condition);
|
|
||||||
if (is_loop) {
|
if (is_loop) {
|
||||||
|
u32 var_index = NewVariable();
|
||||||
|
Expr var_condition = MakeExpr<ExprVar>(var_index);
|
||||||
|
ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
|
||||||
|
ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition);
|
||||||
|
zipper2.InsertBefore(var_node_init, parent);
|
||||||
|
zipper.InsertAfter(var_node, prev);
|
||||||
|
goto_node->SetGotoCondition(var_condition);
|
||||||
ASTNode break_node = ASTBase::Make<ASTBreak>(parent, var_condition);
|
ASTNode break_node = ASTBase::Make<ASTBreak>(parent, var_condition);
|
||||||
zipper.InsertAfter(break_node, var_node);
|
zipper.InsertAfter(break_node, var_node);
|
||||||
} else if (is_if) {
|
} else if (is_if || is_else) {
|
||||||
ASTNode post = var_node->GetNext();
|
|
||||||
if (post) {
|
if (post) {
|
||||||
|
u32 var_index = NewVariable();
|
||||||
|
Expr var_condition = MakeExpr<ExprVar>(var_index);
|
||||||
|
ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
|
||||||
|
ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_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);
|
||||||
zipper.DetachTail(post);
|
zipper.DetachTail(post);
|
||||||
ASTNode if_node = ASTBase::Make<ASTIfThen>(parent, var_condition, ASTZipper(post));
|
ASTNode if_node = ASTBase::Make<ASTIfThen>(parent, MakeExprNot(var_condition));
|
||||||
zipper.InsertAfter(if_node, var_node);
|
|
||||||
ASTZipper* sub_zipper = if_node->GetSubNodes();
|
ASTZipper* sub_zipper = if_node->GetSubNodes();
|
||||||
sub_zipper->SetParent(if_node);
|
sub_zipper->Init(post, if_node);
|
||||||
|
zipper.InsertAfter(if_node, var_node);
|
||||||
|
} else {
|
||||||
|
Expr if_condition;
|
||||||
|
if (is_if) {
|
||||||
|
if_condition = parent->GetIfCondition();
|
||||||
|
} else {
|
||||||
|
ASTNode if_node = parent->GetPrevious();
|
||||||
|
if_condition = MakeExprNot(if_node->GetIfCondition());
|
||||||
|
}
|
||||||
|
Expr new_condition = MakeExprAnd(if_condition, condition);
|
||||||
|
goto_node->SetGotoCondition(new_condition);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
ASTZipper& zipper2 = parent->GetManager();
|
|
||||||
ASTNode next = parent->GetNext();
|
ASTNode next = parent->GetNext();
|
||||||
if (is_if && next && next->IsIfElse()) {
|
if (is_if && next && next->IsIfElse()) {
|
||||||
zipper2.InsertAfter(goto_node, next);
|
zipper2.InsertAfter(goto_node, next);
|
||||||
|
goto_node->SetParent(grandpa);
|
||||||
|
// ShowCurrentState("After MoveOutward");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
zipper2.InsertAfter(goto_node, parent);
|
zipper2.InsertAfter(goto_node, parent);
|
||||||
|
goto_node->SetParent(grandpa);
|
||||||
|
// ShowCurrentState("After MoveOutward");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VideoCommon::Shader
|
} // namespace VideoCommon::Shader
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -21,6 +22,7 @@ class ASTProgram;
|
||||||
class ASTIfThen;
|
class ASTIfThen;
|
||||||
class ASTIfElse;
|
class ASTIfElse;
|
||||||
class ASTBlockEncoded;
|
class ASTBlockEncoded;
|
||||||
|
class ASTBlockDecoded;
|
||||||
class ASTVarSet;
|
class ASTVarSet;
|
||||||
class ASTGoto;
|
class ASTGoto;
|
||||||
class ASTLabel;
|
class ASTLabel;
|
||||||
|
@ -28,7 +30,7 @@ class ASTDoWhile;
|
||||||
class ASTReturn;
|
class ASTReturn;
|
||||||
class ASTBreak;
|
class ASTBreak;
|
||||||
|
|
||||||
using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTVarSet, ASTGoto,
|
using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTBlockDecoded, ASTVarSet, ASTGoto,
|
||||||
ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>;
|
ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>;
|
||||||
|
|
||||||
using ASTNode = std::shared_ptr<ASTBase>;
|
using ASTNode = std::shared_ptr<ASTBase>;
|
||||||
|
@ -43,7 +45,8 @@ enum class ASTZipperType : u32 {
|
||||||
class ASTZipper final {
|
class ASTZipper final {
|
||||||
public:
|
public:
|
||||||
ASTZipper();
|
ASTZipper();
|
||||||
ASTZipper(ASTNode first);
|
|
||||||
|
void Init(ASTNode first, ASTNode parent);
|
||||||
|
|
||||||
ASTNode GetFirst() {
|
ASTNode GetFirst() {
|
||||||
return first;
|
return first;
|
||||||
|
@ -56,7 +59,7 @@ public:
|
||||||
void PushBack(ASTNode new_node);
|
void PushBack(ASTNode new_node);
|
||||||
void PushFront(ASTNode new_node);
|
void PushFront(ASTNode new_node);
|
||||||
void InsertAfter(ASTNode new_node, ASTNode at_node);
|
void InsertAfter(ASTNode new_node, ASTNode at_node);
|
||||||
void SetParent(ASTNode new_parent);
|
void InsertBefore(ASTNode new_node, ASTNode at_node);
|
||||||
void DetachTail(ASTNode node);
|
void DetachTail(ASTNode node);
|
||||||
void DetachSingle(ASTNode node);
|
void DetachSingle(ASTNode node);
|
||||||
void DetachSegment(ASTNode start, ASTNode end);
|
void DetachSegment(ASTNode start, ASTNode end);
|
||||||
|
@ -74,14 +77,14 @@ public:
|
||||||
|
|
||||||
class ASTIfThen {
|
class ASTIfThen {
|
||||||
public:
|
public:
|
||||||
ASTIfThen(Expr condition, ASTZipper nodes) : condition(condition), nodes{nodes} {}
|
ASTIfThen(Expr condition) : condition(condition), nodes{} {}
|
||||||
Expr condition;
|
Expr condition;
|
||||||
ASTZipper nodes;
|
ASTZipper nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ASTIfElse {
|
class ASTIfElse {
|
||||||
public:
|
public:
|
||||||
ASTIfElse(ASTZipper nodes) : nodes{nodes} {}
|
ASTIfElse() : nodes{} {}
|
||||||
ASTZipper nodes;
|
ASTZipper nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,6 +95,12 @@ public:
|
||||||
u32 end;
|
u32 end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ASTBlockDecoded {
|
||||||
|
public:
|
||||||
|
ASTBlockDecoded(NodeBlock& new_nodes) : nodes(std::move(new_nodes)) {}
|
||||||
|
NodeBlock nodes;
|
||||||
|
};
|
||||||
|
|
||||||
class ASTVarSet {
|
class ASTVarSet {
|
||||||
public:
|
public:
|
||||||
ASTVarSet(u32 index, Expr condition) : index{index}, condition{condition} {}
|
ASTVarSet(u32 index, Expr condition) : index{index}, condition{condition} {}
|
||||||
|
@ -114,7 +123,7 @@ public:
|
||||||
|
|
||||||
class ASTDoWhile {
|
class ASTDoWhile {
|
||||||
public:
|
public:
|
||||||
ASTDoWhile(Expr condition, ASTZipper nodes) : condition(condition), nodes{nodes} {}
|
ASTDoWhile(Expr condition) : condition(condition), nodes{} {}
|
||||||
Expr condition;
|
Expr condition;
|
||||||
ASTZipper nodes;
|
ASTZipper nodes;
|
||||||
};
|
};
|
||||||
|
@ -132,6 +141,8 @@ public:
|
||||||
Expr condition;
|
Expr condition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>;
|
||||||
|
|
||||||
class ASTBase {
|
class ASTBase {
|
||||||
public:
|
public:
|
||||||
explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {}
|
explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {}
|
||||||
|
@ -195,6 +206,14 @@ public:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr GetIfCondition() const {
|
||||||
|
auto inner = std::get_if<ASTIfThen>(&data);
|
||||||
|
if (inner) {
|
||||||
|
return inner->condition;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void SetGotoCondition(Expr new_condition) {
|
void SetGotoCondition(Expr new_condition) {
|
||||||
auto inner = std::get_if<ASTGoto>(&data);
|
auto inner = std::get_if<ASTGoto>(&data);
|
||||||
if (inner) {
|
if (inner) {
|
||||||
|
@ -210,6 +229,18 @@ public:
|
||||||
return std::holds_alternative<ASTIfElse>(data);
|
return std::holds_alternative<ASTIfElse>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsBlockEncoded() const {
|
||||||
|
return std::holds_alternative<ASTBlockEncoded>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransformBlockEncoded(TransformCallback& callback) {
|
||||||
|
auto block = std::get_if<ASTBlockEncoded>(&data);
|
||||||
|
const u32 start = block->start;
|
||||||
|
const u32 end = block->end;
|
||||||
|
NodeBlock nodes = callback(start, end);
|
||||||
|
data = ASTBlockDecoded(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsLoop() const {
|
bool IsLoop() const {
|
||||||
return std::holds_alternative<ASTDoWhile>(data);
|
return std::holds_alternative<ASTDoWhile>(data);
|
||||||
}
|
}
|
||||||
|
@ -245,6 +276,7 @@ public:
|
||||||
explicit ASTManager() {
|
explicit ASTManager() {
|
||||||
main_node = ASTBase::Make<ASTProgram>(ASTNode{});
|
main_node = ASTBase::Make<ASTProgram>(ASTNode{});
|
||||||
program = std::get_if<ASTProgram>(main_node->GetInnerData());
|
program = std::get_if<ASTProgram>(main_node->GetInnerData());
|
||||||
|
true_condition = MakeExpr<ExprBoolean>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclareLabel(u32 address) {
|
void DeclareLabel(u32 address) {
|
||||||
|
@ -283,7 +315,13 @@ public:
|
||||||
|
|
||||||
void Decompile();
|
void Decompile();
|
||||||
|
|
||||||
|
void ShowCurrentState(std::string state);
|
||||||
|
|
||||||
|
void SanityCheck();
|
||||||
|
|
||||||
|
bool IsFullyDecompiled() {
|
||||||
|
return gotos.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IndirectlyRelated(ASTNode first, ASTNode second);
|
bool IndirectlyRelated(ASTNode first, ASTNode second);
|
||||||
|
@ -309,6 +347,9 @@ private:
|
||||||
u32 variables{};
|
u32 variables{};
|
||||||
ASTProgram* program;
|
ASTProgram* program;
|
||||||
ASTNode main_node;
|
ASTNode main_node;
|
||||||
|
Expr true_condition;
|
||||||
|
u32 outward_count{};
|
||||||
|
u32 enclose_count{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon::Shader
|
} // namespace VideoCommon::Shader
|
||||||
|
|
|
@ -423,7 +423,16 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) {
|
||||||
result = MakeExpr<ExprCondCode>(cond.cc);
|
result = MakeExpr<ExprCondCode>(cond.cc);
|
||||||
}
|
}
|
||||||
if (cond.predicate != Pred::UnusedIndex) {
|
if (cond.predicate != Pred::UnusedIndex) {
|
||||||
Expr extra = MakeExpr<ExprPredicate>(cond.predicate);
|
u32 pred = static_cast<u32>(cond.predicate);
|
||||||
|
bool negate;
|
||||||
|
if (pred > 7) {
|
||||||
|
negate = true;
|
||||||
|
pred -= 8;
|
||||||
|
}
|
||||||
|
Expr extra = MakeExpr<ExprPredicate>(pred);
|
||||||
|
if (negate) {
|
||||||
|
extra = MakeExpr<ExprNot>(extra);
|
||||||
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
return MakeExpr<ExprAnd>(extra, result);
|
return MakeExpr<ExprAnd>(extra, result);
|
||||||
}
|
}
|
||||||
|
@ -460,8 +469,9 @@ void DecompileShader(CFGRebuildState& state) {
|
||||||
InsertBranch(manager, block.branch);
|
InsertBranch(manager, block.branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//manager.ShowCurrentState("Before Decompiling");
|
||||||
manager.Decompile();
|
manager.Decompile();
|
||||||
LOG_CRITICAL(HW_GPU, "Decompiled Shader:\n{} \n", manager.Print());
|
//manager.ShowCurrentState("After Decompiling");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
|
std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
|
||||||
|
|
75
src/video_core/shader/expr.cpp
Normal file
75
src/video_core/shader/expr.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "video_core/shader/expr.h"
|
||||||
|
|
||||||
|
namespace VideoCommon::Shader {
|
||||||
|
|
||||||
|
bool ExprAnd::operator==(const ExprAnd& b) const {
|
||||||
|
return (*operand1 == *b.operand1) && (*operand2 == *b.operand2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExprOr::operator==(const ExprOr& b) const {
|
||||||
|
return (*operand1 == *b.operand1) && (*operand2 == *b.operand2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExprNot::operator==(const ExprNot& b) const {
|
||||||
|
return (*operand1 == *b.operand1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExprIsBoolean(Expr expr) {
|
||||||
|
return std::holds_alternative<ExprBoolean>(*expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExprBooleanGet(Expr expr) {
|
||||||
|
return std::get_if<ExprBoolean>(expr.get())->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr MakeExprNot(Expr first) {
|
||||||
|
if (std::holds_alternative<ExprNot>(*first)) {
|
||||||
|
return std::get_if<ExprNot>(first.get())->operand1;
|
||||||
|
}
|
||||||
|
return MakeExpr<ExprNot>(first);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr MakeExprAnd(Expr first, Expr second) {
|
||||||
|
if (ExprIsBoolean(first)) {
|
||||||
|
return ExprBooleanGet(first) ? second : first;
|
||||||
|
}
|
||||||
|
if (ExprIsBoolean(second)) {
|
||||||
|
return ExprBooleanGet(second) ? first : second;
|
||||||
|
}
|
||||||
|
return MakeExpr<ExprAnd>(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr MakeExprOr(Expr first, Expr second) {
|
||||||
|
if (ExprIsBoolean(first)) {
|
||||||
|
return ExprBooleanGet(first) ? first : second;
|
||||||
|
}
|
||||||
|
if (ExprIsBoolean(second)) {
|
||||||
|
return ExprBooleanGet(second) ? second : first;
|
||||||
|
}
|
||||||
|
return MakeExpr<ExprOr>(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExprAreEqual(Expr first, Expr second) {
|
||||||
|
return (*first) == (*second);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExprAreOpposite(Expr first, Expr second) {
|
||||||
|
if (std::holds_alternative<ExprNot>(*first)) {
|
||||||
|
return ExprAreEqual(std::get_if<ExprNot>(first.get())->operand1, second);
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<ExprNot>(*second)) {
|
||||||
|
return ExprAreEqual(std::get_if<ExprNot>(second.get())->operand1, first);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VideoCommon::Shader
|
|
@ -30,6 +30,8 @@ class ExprAnd final {
|
||||||
public:
|
public:
|
||||||
ExprAnd(Expr a, Expr b) : operand1{a}, operand2{b} {}
|
ExprAnd(Expr a, Expr b) : operand1{a}, operand2{b} {}
|
||||||
|
|
||||||
|
bool operator==(const ExprAnd& b) const;
|
||||||
|
|
||||||
Expr operand1;
|
Expr operand1;
|
||||||
Expr operand2;
|
Expr operand2;
|
||||||
};
|
};
|
||||||
|
@ -38,6 +40,8 @@ class ExprOr final {
|
||||||
public:
|
public:
|
||||||
ExprOr(Expr a, Expr b) : operand1{a}, operand2{b} {}
|
ExprOr(Expr a, Expr b) : operand1{a}, operand2{b} {}
|
||||||
|
|
||||||
|
bool operator==(const ExprOr& b) const;
|
||||||
|
|
||||||
Expr operand1;
|
Expr operand1;
|
||||||
Expr operand2;
|
Expr operand2;
|
||||||
};
|
};
|
||||||
|
@ -46,6 +50,8 @@ class ExprNot final {
|
||||||
public:
|
public:
|
||||||
ExprNot(Expr a) : operand1{a} {}
|
ExprNot(Expr a) : operand1{a} {}
|
||||||
|
|
||||||
|
bool operator==(const ExprNot& b) const;
|
||||||
|
|
||||||
Expr operand1;
|
Expr operand1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,20 +59,32 @@ class ExprVar final {
|
||||||
public:
|
public:
|
||||||
ExprVar(u32 index) : var_index{index} {}
|
ExprVar(u32 index) : var_index{index} {}
|
||||||
|
|
||||||
|
bool operator==(const ExprVar& b) const {
|
||||||
|
return var_index == b.var_index;
|
||||||
|
}
|
||||||
|
|
||||||
u32 var_index;
|
u32 var_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExprPredicate final {
|
class ExprPredicate final {
|
||||||
public:
|
public:
|
||||||
ExprPredicate(Pred predicate) : predicate{predicate} {}
|
ExprPredicate(u32 predicate) : predicate{predicate} {}
|
||||||
|
|
||||||
Pred predicate;
|
bool operator==(const ExprPredicate& b) const {
|
||||||
|
return predicate == b.predicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 predicate;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExprCondCode final {
|
class ExprCondCode final {
|
||||||
public:
|
public:
|
||||||
ExprCondCode(ConditionCode cc) : cc{cc} {}
|
ExprCondCode(ConditionCode cc) : cc{cc} {}
|
||||||
|
|
||||||
|
bool operator==(const ExprCondCode& b) const {
|
||||||
|
return cc == b.cc;
|
||||||
|
}
|
||||||
|
|
||||||
ConditionCode cc;
|
ConditionCode cc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,6 +92,10 @@ class ExprBoolean final {
|
||||||
public:
|
public:
|
||||||
ExprBoolean(bool val) : value{val} {}
|
ExprBoolean(bool val) : value{val} {}
|
||||||
|
|
||||||
|
bool operator==(const ExprBoolean& b) const {
|
||||||
|
return value == b.value;
|
||||||
|
}
|
||||||
|
|
||||||
bool value;
|
bool value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,4 +105,14 @@ Expr MakeExpr(Args&&... args) {
|
||||||
return std::make_shared<ExprData>(T(std::forward<Args>(args)...));
|
return std::make_shared<ExprData>(T(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExprAreEqual(Expr first, Expr second);
|
||||||
|
|
||||||
|
bool ExprAreOpposite(Expr first, Expr second);
|
||||||
|
|
||||||
|
Expr MakeExprNot(Expr first);
|
||||||
|
|
||||||
|
Expr MakeExprAnd(Expr first, Expr second);
|
||||||
|
|
||||||
|
Expr MakeExprOr(Expr first, Expr second);
|
||||||
|
|
||||||
} // namespace VideoCommon::Shader
|
} // namespace VideoCommon::Shader
|
||||||
|
|
Loading…
Reference in a new issue