Make decompiler more successful (#66)

* w/early-return-and-break

* more edge cases

* all instructions in non asm functions now convert to ir

* cleanup

* implement rarely used control flow in IR

* clang format
This commit is contained in:
water111
2020-10-11 18:27:44 -04:00
committed by GitHub
parent 30e0e4204b
commit 1e1b5e7c00
11 changed files with 970 additions and 22 deletions
+104
View File
@@ -256,6 +256,12 @@ goos::Object IR_IntMath2::to_form(const LinkedObjectFile& file) const {
case RIGHT_SHIFT_LOGIC:
math_operator = "shr";
break;
case MIN_SIGNED:
math_operator = "min.si";
break;
case MAX_SIGNED:
math_operator = "max.si";
break;
default:
assert(false);
}
@@ -399,6 +405,8 @@ int Condition::num_args() const {
case FLOAT_NOT_EQUAL:
case FLOAT_LESS_THAN:
case FLOAT_GEQ:
case FLOAT_GREATER_THAN:
case FLOAT_LEQ:
return 2;
case ZERO:
case NONZERO:
@@ -501,6 +509,12 @@ void Condition::invert() {
case FLOAT_GEQ:
kind = FLOAT_LESS_THAN;
break;
case FLOAT_GREATER_THAN:
kind = FLOAT_LEQ;
break;
case FLOAT_LEQ:
kind = FLOAT_GREATER_THAN;
break;
default:
assert(false);
}
@@ -570,6 +584,12 @@ goos::Object Condition::to_form(const LinkedObjectFile& file) const {
case FLOAT_GEQ:
condtion_operator = ">=.f";
break;
case FLOAT_GREATER_THAN:
condtion_operator = ">.f";
break;
case FLOAT_LEQ:
condtion_operator = "<=.f";
break;
case GREATER_THAN_ZERO_SIGNED:
condtion_operator = ">0.si";
break;
@@ -680,6 +700,19 @@ void IR_WhileLoop::get_children(std::vector<std::shared_ptr<IR>>* output) const
output->push_back(body);
}
goos::Object IR_UntilLoop::to_form(const LinkedObjectFile& file) const {
std::vector<goos::Object> list;
list.push_back(pretty_print::to_symbol("until"));
list.push_back(condition->to_form(file));
print_inlining_begin(&list, body.get(), file);
return pretty_print::build_list(list);
}
void IR_UntilLoop::get_children(std::vector<std::shared_ptr<IR>>* output) const {
output->push_back(condition);
output->push_back(body);
}
goos::Object IR_CondWithElse::to_form(const LinkedObjectFile& file) const {
// for now we only turn it into an if statement if both cases won't require a begin at the top
// level. I think it is more common to write these as a two-case cond instead of an if with begin.
@@ -801,3 +834,74 @@ void IR_Ash::get_children(std::vector<std::shared_ptr<IR>>* output) const {
output->push_back(value);
output->push_back(shift_amount);
}
goos::Object IR_AsmOp::to_form(const LinkedObjectFile& file) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol(name));
for (auto& x : {dst, src0, src1, src2}) {
if (x) {
forms.push_back(x->to_form(file));
}
}
return pretty_print::build_list(forms);
}
void IR_AsmOp::get_children(std::vector<std::shared_ptr<IR>>* output) const {
for (auto& x : {dst, src0, src1}) {
if (x) {
output->push_back(x);
}
}
}
goos::Object IR_CMoveF::to_form(const LinkedObjectFile& file) const {
return pretty_print::build_list(
pretty_print::to_symbol(on_zero ? "cmove-false-on-zero" : "cmove-false-on-nonzero"),
src->to_form(file));
}
void IR_CMoveF::get_children(std::vector<std::shared_ptr<IR>>* output) const {
output->push_back(src);
}
goos::Object IR_AsmReg::to_form(const LinkedObjectFile& file) const {
(void)file;
switch (kind) {
case VU_Q:
return pretty_print::to_symbol("Q");
case VU_ACC:
return pretty_print::to_symbol("ACC");
default:
assert(false);
}
}
void IR_AsmReg::get_children(std::vector<std::shared_ptr<IR>>* output) const {
(void)output;
}
goos::Object IR_Return::to_form(const LinkedObjectFile& file) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("return"));
forms.push_back(pretty_print::build_list(return_code->to_form(file)));
forms.push_back(pretty_print::build_list(dead_code->to_form(file)));
return pretty_print::build_list(forms);
}
void IR_Return::get_children(std::vector<std::shared_ptr<IR>>* output) const {
output->push_back(return_code);
output->push_back(dead_code);
}
goos::Object IR_Break::to_form(const LinkedObjectFile& file) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("break")); // todo break destination...
forms.push_back(pretty_print::build_list(return_code->to_form(file)));
forms.push_back(pretty_print::build_list(dead_code->to_form(file)));
return pretty_print::build_list(forms);
}
void IR_Break::get_children(std::vector<std::shared_ptr<IR>>* output) const {
output->push_back(return_code);
output->push_back(dead_code);
}