mirror of
https://github.com/open-goal/jak-project
synced 2026-08-11 03:26:33 -04:00
[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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user