mirror of
https://github.com/open-goal/jak-project
synced 2026-08-04 01:04:11 -04:00
[decomp] Clean up - part 2 (#687)
* temp * temp2 * basic case support * working for or without else * support more cases * clean up to drawable headers * ocean * format json
This commit is contained in:
@@ -36,7 +36,7 @@ If the previous let variables appear in the definition of new one, make the let
|
||||
*/
|
||||
|
||||
namespace {
|
||||
std::vector<Form*> path_up_tree(Form* in, const Env& env) {
|
||||
std::vector<Form*> path_up_tree(Form* in, const Env&) {
|
||||
std::vector<Form*> path;
|
||||
|
||||
while (in) {
|
||||
@@ -357,6 +357,174 @@ FormElement* rewrite_empty_let(LetElement* in, const Env&, FormPool&) {
|
||||
return in->entries().at(0).src->try_as_single_element();
|
||||
}
|
||||
|
||||
Form* strip_truthy(Form* in) {
|
||||
auto as_ge = in->try_as_element<GenericElement>();
|
||||
if (as_ge) {
|
||||
if (as_ge->op().kind() == GenericOperator::Kind::CONDITION_OPERATOR &&
|
||||
as_ge->op().condition_kind() == IR2_Condition::Kind::TRUTHY) {
|
||||
in = as_ge->elts().at(0);
|
||||
}
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
ShortCircuitElement* get_or(Form* in) {
|
||||
// strip off truthy
|
||||
in = strip_truthy(in);
|
||||
|
||||
return in->try_as_element<ShortCircuitElement>();
|
||||
}
|
||||
|
||||
FormElement* rewrite_as_case_no_else(LetElement* in, const Env& env, FormPool& pool) {
|
||||
if (in->entries().size() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* cond = in->body()->try_as_element<CondNoElseElement>();
|
||||
if (!cond) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto case_var = in->entries().at(0).dest;
|
||||
auto& case_var_uses = env.get_use_def_info(case_var);
|
||||
int found_uses = 0;
|
||||
if (case_var_uses.def_count() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
auto case_var_name = env.get_variable_name(case_var);
|
||||
|
||||
std::vector<CaseElement::Entry> entries;
|
||||
|
||||
for (auto& e : cond->entries) {
|
||||
// first, lets see if its just (= case_var <expr>)
|
||||
auto single_matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::EQ),
|
||||
{Matcher::any_reg(0), Matcher::any(1)});
|
||||
|
||||
auto single_matcher_result = match(single_matcher, e.condition);
|
||||
|
||||
Form* single_value = nullptr;
|
||||
if (single_matcher_result.matched) {
|
||||
auto var_name = env.get_variable_name(*single_matcher_result.maps.regs.at(0));
|
||||
if (var_name == case_var_name) {
|
||||
single_value = single_matcher_result.maps.forms.at(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (single_value) {
|
||||
entries.push_back({{single_value}, e.body});
|
||||
found_uses++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// try as an or (or (= case_var <expr>) ...)
|
||||
auto* as_or = get_or(e.condition);
|
||||
if (!as_or) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CaseElement::Entry current_entry;
|
||||
for (auto& or_case : as_or->entries) {
|
||||
auto or_single_matcher_result = match(single_matcher, strip_truthy(or_case.condition));
|
||||
if (!or_single_matcher_result.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
auto var_name = env.get_variable_name(*or_single_matcher_result.maps.regs.at(0));
|
||||
if (var_name != case_var_name) {
|
||||
return nullptr;
|
||||
}
|
||||
found_uses++;
|
||||
current_entry.vals.push_back(or_single_matcher_result.maps.forms.at(1));
|
||||
}
|
||||
current_entry.body = e.body;
|
||||
entries.push_back(current_entry);
|
||||
|
||||
// no match
|
||||
// return nullptr;
|
||||
}
|
||||
|
||||
if (found_uses != case_var_uses.use_count()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pool.alloc_element<CaseElement>(in->entries().at(0).src, entries, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FormElement* rewrite_as_case_with_else(LetElement* in, const Env& env, FormPool& pool) {
|
||||
if (in->entries().size() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* cond = in->body()->try_as_element<CondWithElseElement>();
|
||||
if (!cond) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto case_var = in->entries().at(0).dest;
|
||||
auto& case_var_uses = env.get_use_def_info(case_var);
|
||||
int found_uses = 0;
|
||||
if (case_var_uses.def_count() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
auto case_var_name = env.get_variable_name(case_var);
|
||||
|
||||
std::vector<CaseElement::Entry> entries;
|
||||
|
||||
for (auto& e : cond->entries) {
|
||||
// first, lets see if its just (= case_var <expr>)
|
||||
auto single_matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::EQ),
|
||||
{Matcher::any_reg(0), Matcher::any(1)});
|
||||
|
||||
auto single_matcher_result = match(single_matcher, e.condition);
|
||||
|
||||
Form* single_value = nullptr;
|
||||
if (single_matcher_result.matched) {
|
||||
auto var_name = env.get_variable_name(*single_matcher_result.maps.regs.at(0));
|
||||
if (var_name == case_var_name) {
|
||||
single_value = single_matcher_result.maps.forms.at(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (single_value) {
|
||||
entries.push_back({{single_value}, e.body});
|
||||
found_uses++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// try as an or (or (= case_var <expr>) ...)
|
||||
auto* as_or = get_or(e.condition);
|
||||
if (!as_or) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CaseElement::Entry current_entry;
|
||||
for (auto& or_case : as_or->entries) {
|
||||
auto or_single_matcher_result = match(single_matcher, strip_truthy(or_case.condition));
|
||||
if (!or_single_matcher_result.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
auto var_name = env.get_variable_name(*or_single_matcher_result.maps.regs.at(0));
|
||||
if (var_name != case_var_name) {
|
||||
return nullptr;
|
||||
}
|
||||
found_uses++;
|
||||
current_entry.vals.push_back(or_single_matcher_result.maps.forms.at(1));
|
||||
}
|
||||
current_entry.body = e.body;
|
||||
entries.push_back(current_entry);
|
||||
|
||||
// no match
|
||||
// return nullptr;
|
||||
}
|
||||
|
||||
if (found_uses != case_var_uses.use_count()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pool.alloc_element<CaseElement>(in->entries().at(0).src, entries, cond->else_ir);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Attempt to rewrite a let as another form. If it cannot be rewritten, this will return nullptr.
|
||||
*/
|
||||
@@ -386,6 +554,16 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool) {
|
||||
return as_unused;
|
||||
}
|
||||
|
||||
auto as_case_no_else = rewrite_as_case_no_else(in, env, pool);
|
||||
if (as_case_no_else) {
|
||||
return as_case_no_else;
|
||||
}
|
||||
|
||||
auto as_case_with_else = rewrite_as_case_with_else(in, env, pool);
|
||||
if (as_case_with_else) {
|
||||
return as_case_with_else;
|
||||
}
|
||||
|
||||
// nothing matched.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user