[Decompiler] Expression Building (#211)

* up to ash

* add more expressions

* fix some return variable usage nonsense

* bfloat print working

* basic-type working

* type working, fix decompiler on all files

* clang format
This commit is contained in:
water111
2021-01-24 16:39:15 -05:00
committed by GitHub
parent 27f0a7ca44
commit 2f722e6379
28 changed files with 1440 additions and 247 deletions
+47 -26
View File
@@ -5,6 +5,8 @@
#include "cfg_builder.h"
#include "decompiler/util/MatchParam.h"
#include "decompiler/Function/Function.h"
#include "decompiler/IR2/Form.h"
namespace decompiler {
namespace {
@@ -60,7 +62,7 @@ std::pair<BranchElement*, FormElement**> get_condition_branch(Form* in) {
* compare IR instead of a branch.
* Doesn't "rebalance" the leading condition because this runs way before expression compaction.
*/
void clean_up_cond_with_else(FormPool& pool, FormElement* ir) {
void clean_up_cond_with_else(FormPool& pool, FormElement* ir, const Env& env) {
auto cwe = dynamic_cast<CondWithElseElement*>(ir);
assert(cwe);
for (auto& e : cwe->entries) {
@@ -72,7 +74,7 @@ void clean_up_cond_with_else(FormPool& pool, FormElement* ir) {
assert(jump_to_next.first);
assert(jump_to_next.first->op()->branch_delay().kind() == IR2_BranchDelay::Kind::NOP);
// patch the branch to next with a condition.
auto replacement = jump_to_next.first->op()->get_condition_as_form(pool);
auto replacement = jump_to_next.first->op()->get_condition_as_form(pool, env);
replacement->invert();
*(jump_to_next.second) = replacement;
@@ -102,11 +104,11 @@ void clean_up_cond_with_else(FormPool& pool, FormElement* ir) {
/*!
* Replace the branch at the end of an until loop's condition with a condition.
*/
void clean_up_until_loop(FormPool& pool, UntilElement* ir) {
void clean_up_until_loop(FormPool& pool, UntilElement* ir, const Env& env) {
auto condition_branch = get_condition_branch(ir->condition);
assert(condition_branch.first);
assert(condition_branch.first->op()->branch_delay().kind() == IR2_BranchDelay::Kind::NOP);
auto replacement = condition_branch.first->op()->get_condition_as_form(pool);
auto replacement = condition_branch.first->op()->get_condition_as_form(pool, env);
replacement->invert();
*(condition_branch.second) = replacement;
}
@@ -261,7 +263,7 @@ bool try_clean_up_sc_as_and(FormPool& pool, const Function& func, ShortCircuitEl
}
}
auto replacement = branch.first->op()->get_condition_as_form(pool);
auto replacement = branch.first->op()->get_condition_as_form(pool, func.ir2.env);
replacement->invert();
*(branch.second) = replacement;
}
@@ -317,7 +319,7 @@ bool try_clean_up_sc_as_or(FormPool& pool, const Function& func, ShortCircuitEle
}
}
auto replacement = branch.first->op()->get_condition_as_form(pool);
auto replacement = branch.first->op()->get_condition_as_form(pool, func.ir2.env);
*(branch.second) = replacement;
}
@@ -442,7 +444,7 @@ void convert_cond_no_else_to_compare(FormPool& pool,
auto condition_as_single =
dynamic_cast<BranchElement*>(cne->entries.front().condition->try_as_single_element());
auto condition_replacement = condition.first->op()->get_condition_as_form(pool);
auto condition_replacement = condition.first->op()->get_condition_as_form(pool, f.ir2.env);
auto crf = pool.alloc_single_form(nullptr, condition_replacement);
auto replacement = pool.alloc_element<SetVarElement>(dst, crf, true);
replacement->parent_form = cne->parent_form;
@@ -552,7 +554,7 @@ void clean_up_cond_no_else(FormPool& pool,
e.original_condition_branch = *jump_to_next.second;
auto replacement = jump_to_next.first->op()->get_condition_as_form(pool);
auto replacement = jump_to_next.first->op()->get_condition_as_form(pool, f.ir2.env);
replacement->invert();
*(jump_to_next.second) = replacement;
e.cleaned = true;
@@ -709,8 +711,15 @@ Form* try_sc_as_abs(FormPool& pool, const Function& f, const ShortCircuit* vtx)
// remove the branch
b0_ptr->pop_back();
// add the ash
auto src_var = pool.alloc_single_element_form<SimpleAtomElement>(nullptr, input);
auto src_abs = pool.alloc_single_element_form<AbsElement>(nullptr, src_var);
auto& info = f.ir2.env.reg_use();
auto final_op_idx = input.var().idx();
RegSet consumed = info.op.at(final_op_idx).consumes;
if (output.reg() == input.var().reg()) {
consumed.insert(output.reg());
}
auto src_abs = pool.alloc_single_element_form<AbsElement>(nullptr, input.var(), consumed);
auto replacement = pool.alloc_element<SetVarElement>(output, src_abs, true);
b0_ptr->push_back(replacement);
@@ -799,11 +808,21 @@ Form* try_sc_as_ash(FormPool& pool, const Function& f, const ShortCircuit* vtx)
// remove the branch
b0_ptr->pop_back();
auto& info = f.ir2.env.reg_use();
auto final_op_idx = value_ir.var().idx();
RegSet consumed = info.op.at(final_op_idx).consumes;
for (auto var : {shift_ir.var(), value_ir.var()}) {
if (var.reg() == clobber) {
consumed.insert(var.reg());
}
if (var.reg() == dest_ir.reg()) {
consumed.insert(var.reg());
}
}
// setup
auto value_form = pool.alloc_single_element_form<SimpleAtomElement>(nullptr, value_ir);
auto shift_form = pool.alloc_single_element_form<SimpleAtomElement>(nullptr, shift_ir);
auto ash_form = pool.alloc_single_element_form<AshElement>(nullptr, shift_form, value_form,
clobber_ir, is_arith);
auto ash_form = pool.alloc_single_element_form<AshElement>(
nullptr, shift_ir.var(), value_ir.var(), clobber_ir, is_arith, consumed);
auto set_form = pool.alloc_element<SetVarElement>(dest_ir, ash_form, true);
b0_ptr->push_back(set_form);
@@ -993,7 +1012,7 @@ void insert_cfg_into_list(FormPool& pool,
auto start_op = f.ir2.atomic_ops->block_id_to_first_atomic_op.at(as_block->block_id);
auto end_op = f.ir2.atomic_ops->block_id_to_end_atomic_op.at(as_block->block_id);
for (auto i = start_op; i < end_op; i++) {
output->push_back(f.ir2.atomic_ops->ops.at(i)->get_as_form(pool));
output->push_back(f.ir2.atomic_ops->ops.at(i)->get_as_form(pool, f.ir2.env));
}
} else {
auto ir = cfg_to_ir(pool, f, vtx);
@@ -1011,7 +1030,7 @@ Form* cfg_to_ir(FormPool& pool, const Function& f, const CfgVtx* vtx) {
auto start_op = f.ir2.atomic_ops->block_id_to_first_atomic_op.at(bv->block_id);
auto end_op = f.ir2.atomic_ops->block_id_to_end_atomic_op.at(bv->block_id);
for (auto i = start_op; i < end_op; i++) {
output->push_back(f.ir2.atomic_ops->ops.at(i)->get_as_form(pool));
output->push_back(f.ir2.atomic_ops->ops.at(i)->get_as_form(pool, f.ir2.env));
}
return output;
@@ -1031,19 +1050,21 @@ Form* cfg_to_ir(FormPool& pool, const Function& f, const CfgVtx* vtx) {
auto wvtx = dynamic_cast<const UntilLoop*>(vtx);
auto result = pool.alloc_single_element_form<UntilElement>(
nullptr, cfg_to_ir(pool, f, wvtx->condition), cfg_to_ir(pool, f, wvtx->body));
clean_up_until_loop(pool, dynamic_cast<UntilElement*>(result->try_as_single_element()));
clean_up_until_loop(pool, dynamic_cast<UntilElement*>(result->try_as_single_element()),
f.ir2.env);
return result;
} else if (dynamic_cast<const UntilLoop_single*>(vtx)) {
auto wvtx = dynamic_cast<const UntilLoop_single*>(vtx);
auto empty = pool.alloc_single_element_form<EmptyElement>(nullptr);
auto result = pool.alloc_single_element_form<UntilElement>(
nullptr, cfg_to_ir(pool, f, wvtx->block), empty);
clean_up_until_loop(pool, dynamic_cast<UntilElement*>(result->try_as_single_element()));
clean_up_until_loop(pool, dynamic_cast<UntilElement*>(result->try_as_single_element()),
f.ir2.env);
return result;
} else if (dynamic_cast<const InfiniteLoopBlock*>(vtx)) {
auto wvtx = dynamic_cast<const InfiniteLoopBlock*>(vtx);
auto condition = pool.alloc_single_element_form<ConditionElement>(
nullptr, IR2_Condition::Kind::ALWAYS, nullptr, nullptr);
nullptr, IR2_Condition::Kind::ALWAYS, std::nullopt, std::nullopt, RegSet());
auto result = pool.alloc_single_element_form<WhileElement>(nullptr, condition,
cfg_to_ir(pool, f, wvtx->block));
clean_up_infinite_while_loop(pool,
@@ -1089,8 +1110,8 @@ Form* cfg_to_ir(FormPool& pool, const Function& f, const CfgVtx* vtx) {
entries.push_back(std::move(e));
}
auto result = pool.alloc_single_element_form<CondWithElseElement>(nullptr, entries, else_ir);
clean_up_cond_with_else(pool,
dynamic_cast<CondWithElseElement*>(result->try_as_single_element()));
clean_up_cond_with_else(
pool, dynamic_cast<CondWithElseElement*>(result->try_as_single_element()), f.ir2.env);
return result;
}
} else if (dynamic_cast<const ShortCircuit*>(vtx)) {
@@ -1159,7 +1180,7 @@ Form* cfg_to_ir(FormPool& pool, const Function& f, const CfgVtx* vtx) {
* has a jump to the condition branch that we need to remove. This currently happens after all
* conversion but this may need to be revisited depending on the final order of simplifications.
*/
void clean_up_while_loops(FormPool& pool, Form* sequence) {
void clean_up_while_loops(FormPool& pool, Form* sequence, const Env& env) {
std::vector<size_t> to_remove; // the list of branches to remove by index in this sequence
for (int i = 0; i < sequence->size(); i++) {
auto* form_as_while = dynamic_cast<WhileElement*>(sequence->at(i));
@@ -1181,7 +1202,7 @@ void clean_up_while_loops(FormPool& pool, Form* sequence) {
assert(condition_branch.first);
assert(condition_branch.first->op()->branch_delay().kind() == IR2_BranchDelay::Kind::NOP);
// printf("got while condition branch %s\n", condition_branch.first->print(file).c_str());
auto replacement = condition_branch.first->op()->get_condition_as_form(pool);
auto replacement = condition_branch.first->op()->get_condition_as_form(pool, env);
*(condition_branch.second) = replacement;
}
@@ -1206,10 +1227,10 @@ void build_initial_forms(Function& function) {
auto& pool = function.ir2.form_pool;
auto top_level = function.cfg->get_single_top_level();
std::vector<FormElement*> top_level_elts;
insert_cfg_into_list(pool, function, top_level, &top_level_elts);
auto result = pool.alloc_sequence_form(nullptr, top_level_elts);
insert_cfg_into_list(*pool, function, top_level, &top_level_elts);
auto result = pool->alloc_sequence_form(nullptr, top_level_elts);
result->apply_form([&](Form* form) { clean_up_while_loops(pool, form); });
result->apply_form([&](Form* form) { clean_up_while_loops(*pool, form, function.ir2.env); });
result->apply([&](FormElement* form) {
auto as_cne = dynamic_cast<CondNoElseElement*>(form);