mirror of
https://github.com/open-goal/jak-project
synced 2026-09-09 20:21:28 -04:00
[Decompiler] Decompile let (#309)
* test * fix bug * fix tests for let * missing formatting fix
This commit is contained in:
@@ -6,6 +6,7 @@ add_library(
|
||||
analysis/cfg_builder.cpp
|
||||
analysis/expression_build.cpp
|
||||
analysis/final_output.cpp
|
||||
analysis/insert_lets.cpp
|
||||
analysis/reg_usage.cpp
|
||||
analysis/variable_naming.cpp
|
||||
|
||||
|
||||
+22
-2
@@ -82,6 +82,7 @@ goos::Object Env::get_variable_name(Register reg, int atomic_idx, AccessMode mod
|
||||
if (type_kv != m_typehints.end()) {
|
||||
for (auto& x : type_kv->second) {
|
||||
if (x.reg == reg) {
|
||||
// TODO - redo this!
|
||||
return pretty_print::build_list("the-as", x.type_name, lookup_name);
|
||||
}
|
||||
}
|
||||
@@ -92,6 +93,19 @@ goos::Object Env::get_variable_name(Register reg, int atomic_idx, AccessMode mod
|
||||
}
|
||||
}
|
||||
|
||||
std::string Env::get_variable_name(const RegisterAccess& access) const {
|
||||
if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) {
|
||||
std::string lookup_name = m_var_names.lookup(access.reg(), access.idx(), access.mode()).name();
|
||||
auto remapped = m_var_remap.find(lookup_name);
|
||||
if (remapped != m_var_remap.end()) {
|
||||
lookup_name = remapped->second;
|
||||
}
|
||||
return lookup_name;
|
||||
} else {
|
||||
throw std::runtime_error("Cannot store a variable in this reg");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Update the Env with the result of the type analysis pass.
|
||||
*/
|
||||
@@ -167,7 +181,7 @@ std::vector<VariableNames::VarInfo> Env::extract_visible_variables(
|
||||
std::vector<VariableNames::VarInfo> entries;
|
||||
if (top_level_form) {
|
||||
RegAccessSet var_set;
|
||||
top_level_form->collect_vars(var_set);
|
||||
top_level_form->collect_vars(var_set, true);
|
||||
|
||||
// we want to sort them for easier reading:
|
||||
std::vector<std::pair<RegId, RegisterAccess>> vars;
|
||||
@@ -243,13 +257,19 @@ goos::Object Env::local_var_type_list(const Form* top_level_form,
|
||||
x.reg_id.reg.get_gpr() >= Reg::A0 && x.reg_id.id == 0) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
|
||||
std::string lookup_name = x.name();
|
||||
auto remapped = m_var_remap.find(lookup_name);
|
||||
if (remapped != m_var_remap.end()) {
|
||||
lookup_name = remapped->second;
|
||||
}
|
||||
|
||||
if (m_vars_defined_in_let.find(lookup_name) != m_vars_defined_in_let.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
elts.push_back(pretty_print::build_list(lookup_name, x.type.typespec().print()));
|
||||
}
|
||||
if (count_out) {
|
||||
|
||||
@@ -43,7 +43,9 @@ class Env {
|
||||
return m_reg_use;
|
||||
}
|
||||
|
||||
// TODO - remove this.
|
||||
goos::Object get_variable_name(Register reg, int atomic_idx, AccessMode mode) const;
|
||||
std::string get_variable_name(const RegisterAccess& access) const;
|
||||
|
||||
/*!
|
||||
* Get the types in registers _after_ the given operation has completed.
|
||||
@@ -126,6 +128,8 @@ class Env {
|
||||
}
|
||||
}
|
||||
|
||||
void set_defined_in_let(const std::string& var) { m_vars_defined_in_let.insert(var); }
|
||||
|
||||
LinkedObjectFile* file = nullptr;
|
||||
DecompilerTypeSystem* dts = nullptr;
|
||||
|
||||
@@ -148,5 +152,7 @@ class Env {
|
||||
std::unordered_map<int, std::vector<TypeHint>> m_typehints;
|
||||
std::unordered_map<std::string, std::string> m_var_remap;
|
||||
std::unordered_map<std::string, LabelType> m_label_types;
|
||||
|
||||
std::unordered_set<std::string> m_vars_defined_in_let;
|
||||
};
|
||||
} // namespace decompiler
|
||||
+257
-79
@@ -120,9 +120,9 @@ void Form::apply_form(const std::function<void(Form*)>& f) {
|
||||
}
|
||||
}
|
||||
|
||||
void Form::collect_vars(RegAccessSet& vars) const {
|
||||
void Form::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
for (auto e : m_elements) {
|
||||
e->collect_vars(vars);
|
||||
e->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ bool SimpleExpressionElement::is_sequence_point() const {
|
||||
throw std::runtime_error("Should not check if a SimpleExpressionElement is a sequence point");
|
||||
}
|
||||
|
||||
void SimpleExpressionElement::collect_vars(RegAccessSet& vars) const {
|
||||
void SimpleExpressionElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
m_expr.collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ void StoreElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void StoreElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void StoreElement::collect_vars(RegAccessSet& vars) const {
|
||||
void StoreElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
return m_op->collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -239,8 +239,10 @@ void LoadSourceElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
m_addr->apply_form(f);
|
||||
}
|
||||
|
||||
void LoadSourceElement::collect_vars(RegAccessSet& vars) const {
|
||||
m_addr->collect_vars(vars);
|
||||
void LoadSourceElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
m_addr->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadSourceElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -263,7 +265,7 @@ void SimpleAtomElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void SimpleAtomElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void SimpleAtomElement::collect_vars(RegAccessSet& vars) const {
|
||||
void SimpleAtomElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
return m_atom.collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -301,12 +303,14 @@ bool SetVarElement::is_sequence_point() const {
|
||||
return m_is_sequence_point;
|
||||
}
|
||||
|
||||
void SetVarElement::collect_vars(RegAccessSet& vars) const {
|
||||
void SetVarElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (m_var_info.is_dead_set || m_var_info.is_dead_false) {
|
||||
return;
|
||||
}
|
||||
vars.insert(m_dst);
|
||||
m_src->collect_vars(vars);
|
||||
if (recursive) {
|
||||
m_src->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void SetVarElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -350,7 +354,7 @@ void StoreInSymbolElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void StoreInSymbolElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void StoreInSymbolElement::collect_vars(RegAccessSet& vars) const {
|
||||
void StoreInSymbolElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
m_value.collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -374,7 +378,7 @@ void StoreInPairElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void StoreInPairElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void StoreInPairElement::collect_vars(RegAccessSet& vars) const {
|
||||
void StoreInPairElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
m_value.collect_vars(vars);
|
||||
vars.insert(m_pair);
|
||||
}
|
||||
@@ -438,9 +442,11 @@ bool SetFormFormElement::is_sequence_point() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetFormFormElement::collect_vars(RegAccessSet& vars) const {
|
||||
m_src->collect_vars(vars);
|
||||
m_dst->collect_vars(vars);
|
||||
void SetFormFormElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
m_src->collect_vars(vars, recursive);
|
||||
m_dst->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void SetFormFormElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -463,7 +469,7 @@ void AtomicOpElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void AtomicOpElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void AtomicOpElement::collect_vars(RegAccessSet& vars) const {
|
||||
void AtomicOpElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
m_op->collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -493,7 +499,7 @@ void AsmOpElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void AsmOpElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void AsmOpElement::collect_vars(RegAccessSet& vars) const {
|
||||
void AsmOpElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
m_op->collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -552,7 +558,7 @@ void ConditionElement::invert() {
|
||||
m_kind = get_condition_opposite(m_kind);
|
||||
}
|
||||
|
||||
void ConditionElement::collect_vars(RegAccessSet& vars) const {
|
||||
void ConditionElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
for (auto src : m_src) {
|
||||
if (src.has_value() && src->is_var()) {
|
||||
vars.insert(src->var());
|
||||
@@ -580,7 +586,7 @@ void FunctionCallElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void FunctionCallElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void FunctionCallElement::collect_vars(RegAccessSet& vars) const {
|
||||
void FunctionCallElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
return m_op->collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -610,7 +616,7 @@ void BranchElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void BranchElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void BranchElement::collect_vars(RegAccessSet& vars) const {
|
||||
void BranchElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
return m_op->collect_vars(vars);
|
||||
}
|
||||
|
||||
@@ -628,6 +634,14 @@ void BranchElement::get_modified_regs(RegSet& regs) const {
|
||||
// ReturnElement
|
||||
/////////////////////////////
|
||||
|
||||
ReturnElement::ReturnElement(Form* _return_code, Form* _dead_code)
|
||||
: return_code(_return_code), dead_code(_dead_code) {
|
||||
return_code->parent_element = this;
|
||||
if (dead_code) {
|
||||
dead_code->parent_element = this;
|
||||
}
|
||||
}
|
||||
|
||||
goos::Object ReturnElement::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> forms;
|
||||
forms.push_back(pretty_print::to_symbol("return"));
|
||||
@@ -653,10 +667,12 @@ void ReturnElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
}
|
||||
}
|
||||
|
||||
void ReturnElement::collect_vars(RegAccessSet& vars) const {
|
||||
return_code->collect_vars(vars);
|
||||
if (dead_code) {
|
||||
dead_code->collect_vars(vars);
|
||||
void ReturnElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
return_code->collect_vars(vars, recursive);
|
||||
if (dead_code) {
|
||||
dead_code->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,6 +687,12 @@ void ReturnElement::get_modified_regs(RegSet& regs) const {
|
||||
// BreakElement
|
||||
/////////////////////////////
|
||||
|
||||
BreakElement::BreakElement(Form* _return_code, Form* _dead_code)
|
||||
: return_code(_return_code), dead_code(_dead_code) {
|
||||
return_code->parent_element = this;
|
||||
dead_code->parent_element = this;
|
||||
}
|
||||
|
||||
goos::Object BreakElement::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> forms;
|
||||
forms.push_back(pretty_print::to_symbol("break"));
|
||||
@@ -690,9 +712,11 @@ void BreakElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
dead_code->apply_form(f);
|
||||
}
|
||||
|
||||
void BreakElement::collect_vars(RegAccessSet& vars) const {
|
||||
return_code->collect_vars(vars);
|
||||
dead_code->collect_vars(vars);
|
||||
void BreakElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
return_code->collect_vars(vars, recursive);
|
||||
dead_code->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -705,6 +729,15 @@ void BreakElement::get_modified_regs(RegSet& regs) const {
|
||||
// CondWithElseElement
|
||||
/////////////////////////////
|
||||
|
||||
CondWithElseElement::CondWithElseElement(std::vector<Entry> _entries, Form* _else_ir)
|
||||
: entries(std::move(_entries)), else_ir(_else_ir) {
|
||||
for (auto& e : entries) {
|
||||
e.condition->parent_element = this;
|
||||
e.body->parent_element = this;
|
||||
}
|
||||
else_ir->parent_element = this;
|
||||
}
|
||||
|
||||
goos::Object CondWithElseElement::to_form_internal(const Env& env) 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.
|
||||
@@ -750,12 +783,14 @@ void CondWithElseElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
else_ir->apply_form(f);
|
||||
}
|
||||
|
||||
void CondWithElseElement::collect_vars(RegAccessSet& vars) const {
|
||||
for (auto& entry : entries) {
|
||||
entry.condition->collect_vars(vars);
|
||||
entry.body->collect_vars(vars);
|
||||
void CondWithElseElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
for (auto& entry : entries) {
|
||||
entry.condition->collect_vars(vars, recursive);
|
||||
entry.body->collect_vars(vars, recursive);
|
||||
}
|
||||
else_ir->collect_vars(vars, recursive);
|
||||
}
|
||||
else_ir->collect_vars(vars);
|
||||
}
|
||||
|
||||
void CondWithElseElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -779,13 +814,18 @@ void EmptyElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
}
|
||||
|
||||
void EmptyElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void EmptyElement::collect_vars(RegAccessSet&) const {}
|
||||
void EmptyElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
void EmptyElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
/////////////////////////////
|
||||
// WhileElement
|
||||
/////////////////////////////
|
||||
|
||||
WhileElement::WhileElement(Form* _condition, Form* _body) : condition(_condition), body(_body) {
|
||||
condition->parent_element = this;
|
||||
body->parent_element = this;
|
||||
}
|
||||
|
||||
void WhileElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
// note - this is done in program order, rather than print order. Not sure if this makes sense.
|
||||
f(this);
|
||||
@@ -806,9 +846,11 @@ void WhileElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
condition->apply_form(f);
|
||||
}
|
||||
|
||||
void WhileElement::collect_vars(RegAccessSet& vars) const {
|
||||
body->collect_vars(vars);
|
||||
condition->collect_vars(vars);
|
||||
void WhileElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
body->collect_vars(vars, recursive);
|
||||
condition->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void WhileElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -820,6 +862,11 @@ void WhileElement::get_modified_regs(RegSet& regs) const {
|
||||
// UntilElement
|
||||
/////////////////////////////
|
||||
|
||||
UntilElement::UntilElement(Form* _condition, Form* _body) : condition(_condition), body(_body) {
|
||||
condition->parent_element = this;
|
||||
body->parent_element = this;
|
||||
}
|
||||
|
||||
void UntilElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
// note - this is done in program order, rather than print order. Not sure if this makes sense.
|
||||
f(this);
|
||||
@@ -840,9 +887,11 @@ void UntilElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
condition->apply_form(f);
|
||||
}
|
||||
|
||||
void UntilElement::collect_vars(RegAccessSet& vars) const {
|
||||
body->collect_vars(vars);
|
||||
condition->collect_vars(vars);
|
||||
void UntilElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
body->collect_vars(vars, recursive);
|
||||
condition->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void UntilElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -854,6 +903,13 @@ void UntilElement::get_modified_regs(RegSet& regs) const {
|
||||
// ShortCircuitElement
|
||||
/////////////////////////////
|
||||
|
||||
ShortCircuitElement::ShortCircuitElement(std::vector<Entry> _entries)
|
||||
: entries(std::move(_entries)) {
|
||||
for (auto& entry : entries) {
|
||||
entry.condition->parent_element = this;
|
||||
}
|
||||
}
|
||||
|
||||
void ShortCircuitElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
f(this);
|
||||
for (auto& x : entries) {
|
||||
@@ -896,10 +952,12 @@ goos::Object ShortCircuitElement::to_form_internal(const Env& env) const {
|
||||
return pretty_print::build_list(forms);
|
||||
}
|
||||
|
||||
void ShortCircuitElement::collect_vars(RegAccessSet& vars) const {
|
||||
void ShortCircuitElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
// vars.insert(final_result); // todo - this might be unused.
|
||||
for (auto& entry : entries) {
|
||||
entry.condition->collect_vars(vars);
|
||||
if (recursive) {
|
||||
for (auto& entry : entries) {
|
||||
entry.condition->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -913,6 +971,13 @@ void ShortCircuitElement::get_modified_regs(RegSet& regs) const {
|
||||
// CondNoElseElement
|
||||
/////////////////////////////
|
||||
|
||||
CondNoElseElement::CondNoElseElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {
|
||||
for (auto& entry : entries) {
|
||||
entry.condition->parent_element = this;
|
||||
entry.body->parent_element = this;
|
||||
}
|
||||
}
|
||||
|
||||
goos::Object CondNoElseElement::to_form_internal(const Env& env) const {
|
||||
if (entries.size() == 1 && entries.front().body->is_single_element()) {
|
||||
// print as an if statement if we can put the body in a single form.
|
||||
@@ -958,10 +1023,12 @@ void CondNoElseElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
}
|
||||
}
|
||||
|
||||
void CondNoElseElement::collect_vars(RegAccessSet& vars) const {
|
||||
for (auto& e : entries) {
|
||||
e.condition->collect_vars(vars);
|
||||
e.body->collect_vars(vars);
|
||||
void CondNoElseElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
for (auto& e : entries) {
|
||||
e.condition->collect_vars(vars, recursive);
|
||||
e.body->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,7 +1056,7 @@ void AbsElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void AbsElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void AbsElement::collect_vars(RegAccessSet& vars) const {
|
||||
void AbsElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
vars.insert(source);
|
||||
}
|
||||
|
||||
@@ -1021,7 +1088,7 @@ void AshElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void AshElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void AshElement::collect_vars(RegAccessSet& vars) const {
|
||||
void AshElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
vars.insert(value);
|
||||
vars.insert(shift_amount);
|
||||
}
|
||||
@@ -1050,8 +1117,10 @@ void TypeOfElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
value->apply_form(f);
|
||||
}
|
||||
|
||||
void TypeOfElement::collect_vars(RegAccessSet& vars) const {
|
||||
value->collect_vars(vars);
|
||||
void TypeOfElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
value->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeOfElement::get_modified_regs(RegSet&) const {}
|
||||
@@ -1077,7 +1146,7 @@ void ConditionalMoveFalseElement::apply(const std::function<void(FormElement*)>&
|
||||
|
||||
void ConditionalMoveFalseElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void ConditionalMoveFalseElement::collect_vars(RegAccessSet& vars) const {
|
||||
void ConditionalMoveFalseElement::collect_vars(RegAccessSet& vars, bool) const {
|
||||
vars.insert(dest);
|
||||
vars.insert(old_value);
|
||||
vars.insert(source);
|
||||
@@ -1112,13 +1181,15 @@ GenericOperator GenericOperator::make_compare(IR2_Condition::Kind kind) {
|
||||
return op;
|
||||
}
|
||||
|
||||
void GenericOperator::collect_vars(RegAccessSet& vars) const {
|
||||
void GenericOperator::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
switch (m_kind) {
|
||||
case Kind::FIXED_OPERATOR:
|
||||
case Kind::CONDITION_OPERATOR:
|
||||
return;
|
||||
case Kind::FUNCTION_EXPR:
|
||||
m_function->collect_vars(vars);
|
||||
if (recursive) {
|
||||
m_function->collect_vars(vars, recursive);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
assert(false);
|
||||
@@ -1324,6 +1395,7 @@ goos::Object GenericElement::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> result;
|
||||
result.push_back(m_head.to_form(env));
|
||||
for (auto x : m_elts) {
|
||||
assert(x->parent_element);
|
||||
result.push_back(x->to_form(env));
|
||||
}
|
||||
return pretty_print::build_list(result);
|
||||
@@ -1345,10 +1417,12 @@ void GenericElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
}
|
||||
}
|
||||
|
||||
void GenericElement::collect_vars(RegAccessSet& vars) const {
|
||||
m_head.collect_vars(vars);
|
||||
for (auto x : m_elts) {
|
||||
x->collect_vars(vars);
|
||||
void GenericElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
m_head.collect_vars(vars, recursive);
|
||||
for (auto x : m_elts) {
|
||||
x->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1382,8 +1456,10 @@ void CastElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
m_source->apply_form(f);
|
||||
}
|
||||
|
||||
void CastElement::collect_vars(RegAccessSet& vars) const {
|
||||
m_source->collect_vars(vars);
|
||||
void CastElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
m_source->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void CastElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -1421,14 +1497,16 @@ DerefToken DerefToken::make_expr_placeholder() {
|
||||
return x;
|
||||
}
|
||||
|
||||
void DerefToken::collect_vars(RegAccessSet& vars) const {
|
||||
void DerefToken::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
switch (m_kind) {
|
||||
case Kind::INTEGER_CONSTANT:
|
||||
case Kind::FIELD_NAME:
|
||||
case Kind::EXPRESSION_PLACEHOLDER:
|
||||
break;
|
||||
case Kind::INTEGER_EXPRESSION:
|
||||
m_expr->collect_vars(vars);
|
||||
if (recursive) {
|
||||
m_expr->collect_vars(vars, recursive);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
@@ -1527,6 +1605,7 @@ DerefElement::DerefElement(Form* base, bool is_addr_of, std::vector<DerefToken>
|
||||
}
|
||||
|
||||
goos::Object DerefElement::to_form_internal(const Env& env) const {
|
||||
assert(m_base->parent_element);
|
||||
std::vector<goos::Object> forms = {pretty_print::to_symbol(m_is_addr_of ? "&->" : "->"),
|
||||
m_base->to_form(env)};
|
||||
for (auto& tok : m_tokens) {
|
||||
@@ -1550,10 +1629,12 @@ void DerefElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
}
|
||||
}
|
||||
|
||||
void DerefElement::collect_vars(RegAccessSet& vars) const {
|
||||
m_base->collect_vars(vars);
|
||||
for (auto& tok : m_tokens) {
|
||||
tok.collect_vars(vars);
|
||||
void DerefElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
m_base->collect_vars(vars, recursive);
|
||||
for (auto& tok : m_tokens) {
|
||||
tok.collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1564,6 +1645,11 @@ void DerefElement::get_modified_regs(RegSet& regs) const {
|
||||
}
|
||||
}
|
||||
|
||||
void DerefElement::set_base(Form* new_base) {
|
||||
m_base = new_base;
|
||||
m_base->parent_element = this;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// DynamicMethodAccess
|
||||
/////////////////////////////
|
||||
@@ -1580,7 +1666,7 @@ void DynamicMethodAccess::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void DynamicMethodAccess::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void DynamicMethodAccess::collect_vars(RegAccessSet& vars) const {
|
||||
void DynamicMethodAccess::collect_vars(RegAccessSet& vars, bool) const {
|
||||
vars.insert(m_source);
|
||||
}
|
||||
|
||||
@@ -1596,7 +1682,13 @@ ArrayFieldAccess::ArrayFieldAccess(RegisterAccess source,
|
||||
: m_source(source),
|
||||
m_deref_tokens(deref_tokens),
|
||||
m_expected_stride(expected_stride),
|
||||
m_constant_offset(constant_offset) {}
|
||||
m_constant_offset(constant_offset) {
|
||||
for (auto& token : m_deref_tokens) {
|
||||
if (token.kind() == DerefToken::Kind::INTEGER_EXPRESSION) {
|
||||
token.expr()->parent_element = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goos::Object ArrayFieldAccess::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> elts;
|
||||
@@ -1621,10 +1713,12 @@ void ArrayFieldAccess::apply_form(const std::function<void(Form*)>& f) {
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayFieldAccess::collect_vars(RegAccessSet& vars) const {
|
||||
void ArrayFieldAccess::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
vars.insert(m_source);
|
||||
for (auto& tok : m_deref_tokens) {
|
||||
tok.collect_vars(vars);
|
||||
if (recursive) {
|
||||
for (auto& tok : m_deref_tokens) {
|
||||
tok.collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1657,8 +1751,10 @@ void GetMethodElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
m_in->apply_form(f);
|
||||
}
|
||||
|
||||
void GetMethodElement::collect_vars(RegAccessSet& vars) const {
|
||||
m_in->collect_vars(vars);
|
||||
void GetMethodElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
if (recursive) {
|
||||
m_in->collect_vars(vars, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
void GetMethodElement::get_modified_regs(RegSet& regs) const {
|
||||
@@ -1677,7 +1773,7 @@ goos::Object StringConstantElement::to_form_internal(const Env&) const {
|
||||
|
||||
void StringConstantElement::apply(const std::function<void(FormElement*)>&) {}
|
||||
void StringConstantElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void StringConstantElement::collect_vars(RegAccessSet&) const {}
|
||||
void StringConstantElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
void StringConstantElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
/////////////////////////////
|
||||
@@ -1691,7 +1787,7 @@ goos::Object ConstantTokenElement::to_form_internal(const Env&) const {
|
||||
|
||||
void ConstantTokenElement::apply(const std::function<void(FormElement*)>&) {}
|
||||
void ConstantTokenElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void ConstantTokenElement::collect_vars(RegAccessSet&) const {}
|
||||
void ConstantTokenElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
void ConstantTokenElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
/////////////////////////////
|
||||
@@ -1702,13 +1798,17 @@ ConstantFloatElement::ConstantFloatElement(float value) : m_value(value) {}
|
||||
|
||||
void ConstantFloatElement::apply(const std::function<void(FormElement*)>&) {}
|
||||
void ConstantFloatElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void ConstantFloatElement::collect_vars(RegAccessSet&) const {}
|
||||
void ConstantFloatElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
void ConstantFloatElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
goos::Object ConstantFloatElement::to_form_internal(const Env&) const {
|
||||
return pretty_print::float_representation(m_value);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// StorePlainDeref
|
||||
/////////////////////////////
|
||||
|
||||
StorePlainDeref::StorePlainDeref(DerefElement* dst,
|
||||
SimpleExpression expr,
|
||||
int my_idx,
|
||||
@@ -1736,15 +1836,19 @@ void StorePlainDeref::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void StorePlainDeref::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void StorePlainDeref::collect_vars(RegAccessSet& vars) const {
|
||||
void StorePlainDeref::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
m_expr.collect_vars(vars);
|
||||
m_dst->collect_vars(vars);
|
||||
m_dst->collect_vars(vars, recursive);
|
||||
}
|
||||
|
||||
void StorePlainDeref::get_modified_regs(RegSet& regs) const {
|
||||
m_dst->get_modified_regs(regs);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// StoreArrayAccess
|
||||
/////////////////////////////
|
||||
|
||||
StoreArrayAccess::StoreArrayAccess(ArrayFieldAccess* dst,
|
||||
SimpleExpression expr,
|
||||
int my_idx,
|
||||
@@ -1765,15 +1869,19 @@ void StoreArrayAccess::apply_form(const std::function<void(Form*)>& f) {
|
||||
m_dst->apply_form(f);
|
||||
}
|
||||
|
||||
void StoreArrayAccess::collect_vars(RegAccessSet& vars) const {
|
||||
void StoreArrayAccess::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
m_expr.collect_vars(vars);
|
||||
m_dst->collect_vars(vars);
|
||||
m_dst->collect_vars(vars, recursive);
|
||||
}
|
||||
|
||||
void StoreArrayAccess::get_modified_regs(RegSet& regs) const {
|
||||
m_dst->get_modified_regs(regs);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// DecompiledDataElement
|
||||
/////////////////////////////
|
||||
|
||||
DecompiledDataElement::DecompiledDataElement(goos::Object description)
|
||||
: m_description(std::move(description)) {}
|
||||
|
||||
@@ -1787,8 +1895,78 @@ void DecompiledDataElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
|
||||
void DecompiledDataElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
|
||||
void DecompiledDataElement::collect_vars(RegAccessSet&) const {}
|
||||
void DecompiledDataElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
|
||||
void DecompiledDataElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
/////////////////////////////
|
||||
// LetElement
|
||||
/////////////////////////////
|
||||
|
||||
LetElement::LetElement(Form* body, bool star) : m_body(body), m_star(star) {
|
||||
m_body->parent_element = this;
|
||||
}
|
||||
|
||||
void LetElement::add_def(RegisterAccess dst, Form* value) {
|
||||
value->parent_element = this;
|
||||
m_entries.push_back({dst, value});
|
||||
}
|
||||
|
||||
void LetElement::make_let_star() {
|
||||
m_star = true;
|
||||
}
|
||||
|
||||
goos::Object LetElement::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> outer = {pretty_print::to_symbol(m_star ? "let*" : "let")};
|
||||
|
||||
std::vector<goos::Object> def_list;
|
||||
|
||||
for (auto& entry : m_entries) {
|
||||
def_list.push_back(pretty_print::build_list(entry.dest.to_form(env), entry.src->to_form(env)));
|
||||
}
|
||||
|
||||
outer.push_back(pretty_print::build_list(def_list));
|
||||
m_body->inline_forms(outer, env);
|
||||
return pretty_print::build_list(outer);
|
||||
}
|
||||
|
||||
void LetElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
f(this);
|
||||
for (auto& entry : m_entries) {
|
||||
entry.src->apply(f);
|
||||
}
|
||||
m_body->apply(f);
|
||||
}
|
||||
|
||||
void LetElement::apply_form(const std::function<void(Form*)>& f) {
|
||||
for (auto& entry : m_entries) {
|
||||
entry.src->apply_form(f);
|
||||
}
|
||||
m_body->apply_form(f);
|
||||
}
|
||||
|
||||
void LetElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||
for (auto& entry : m_entries) {
|
||||
vars.insert(entry.dest);
|
||||
}
|
||||
m_body->collect_vars(vars, recursive);
|
||||
}
|
||||
|
||||
void LetElement::get_modified_regs(RegSet& regs) const {
|
||||
for (auto& entry : m_entries) {
|
||||
regs.insert(entry.dest.reg());
|
||||
}
|
||||
m_body->get_modified_regs(regs);
|
||||
}
|
||||
|
||||
void LetElement::add_entry(const Entry& e) {
|
||||
e.src->parent_element = this;
|
||||
m_entries.push_back(e);
|
||||
}
|
||||
|
||||
void LetElement::set_body(Form* new_body) {
|
||||
m_body = new_body;
|
||||
m_body->parent_element = this;
|
||||
}
|
||||
|
||||
} // namespace decompiler
|
||||
|
||||
+82
-52
@@ -29,7 +29,7 @@ class FormElement {
|
||||
virtual void apply(const std::function<void(FormElement*)>& f) = 0;
|
||||
virtual void apply_form(const std::function<void(Form*)>& f) = 0;
|
||||
virtual bool is_sequence_point() const { return true; }
|
||||
virtual void collect_vars(RegAccessSet& vars) const = 0;
|
||||
virtual void collect_vars(RegAccessSet& vars, bool recursive) const = 0;
|
||||
virtual void get_modified_regs(RegSet& regs) const = 0;
|
||||
virtual bool active() const;
|
||||
|
||||
@@ -67,7 +67,7 @@ class SimpleExpressionElement : public FormElement {
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
bool is_sequence_point() const override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -175,7 +175,7 @@ class StoreElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
|
||||
@@ -195,7 +195,7 @@ class LoadSourceElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
int size() const { return m_size; }
|
||||
LoadVarOp::Kind kind() const { return m_kind; }
|
||||
const Form* location() const { return m_addr; }
|
||||
@@ -222,7 +222,7 @@ class SimpleAtomElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
const SimpleAtom& atom() const { return m_atom; }
|
||||
void update_from_stack(const Env& env,
|
||||
@@ -248,7 +248,7 @@ class SetVarElement : public FormElement {
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
bool is_sequence_point() const override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
bool active() const override;
|
||||
@@ -285,7 +285,7 @@ class StoreInSymbolElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
@@ -303,7 +303,7 @@ class StoreInPairElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
@@ -330,7 +330,7 @@ class SetFormFormElement : public FormElement {
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
bool is_sequence_point() const override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
@@ -356,7 +356,7 @@ class AtomicOpElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
const AtomicOp* op() const { return m_op; }
|
||||
@@ -374,7 +374,7 @@ class AsmOpElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
const AsmOp* op() const { return m_op; }
|
||||
@@ -403,7 +403,7 @@ class ConditionElement : public FormElement {
|
||||
goos::Object to_form_as_condition_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -440,7 +440,7 @@ class FunctionCallElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -463,7 +463,7 @@ class BranchElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
const BranchOp* op() const { return m_op; }
|
||||
|
||||
@@ -481,12 +481,11 @@ class ReturnElement : public FormElement {
|
||||
public:
|
||||
Form* return_code = nullptr;
|
||||
Form* dead_code = nullptr;
|
||||
ReturnElement(Form* _return_code, Form* _dead_code)
|
||||
: return_code(_return_code), dead_code(_dead_code) {}
|
||||
ReturnElement(Form* _return_code, Form* _dead_code);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
};
|
||||
@@ -516,12 +515,11 @@ class BreakElement : public FormElement {
|
||||
public:
|
||||
Form* return_code = nullptr;
|
||||
Form* dead_code = nullptr;
|
||||
BreakElement(Form* _return_code, Form* _dead_code)
|
||||
: return_code(_return_code), dead_code(_dead_code) {}
|
||||
BreakElement(Form* _return_code, Form* _dead_code);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
};
|
||||
|
||||
@@ -550,12 +548,11 @@ class CondWithElseElement : public FormElement {
|
||||
std::vector<Entry> entries;
|
||||
Form* else_ir = nullptr;
|
||||
bool already_rewritten = false;
|
||||
CondWithElseElement(std::vector<Entry> _entries, Form* _else_ir)
|
||||
: entries(std::move(_entries)), else_ir(_else_ir) {}
|
||||
CondWithElseElement(std::vector<Entry> _entries, Form* _else_ir);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
};
|
||||
@@ -574,7 +571,7 @@ class EmptyElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
};
|
||||
@@ -586,11 +583,11 @@ class EmptyElement : public FormElement {
|
||||
*/
|
||||
class WhileElement : public FormElement {
|
||||
public:
|
||||
WhileElement(Form* _condition, Form* _body) : condition(_condition), body(_body) {}
|
||||
WhileElement(Form* _condition, Form* _body);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
Form* condition = nullptr;
|
||||
@@ -605,11 +602,11 @@ class WhileElement : public FormElement {
|
||||
*/
|
||||
class UntilElement : public FormElement {
|
||||
public:
|
||||
UntilElement(Form* _condition, Form* _body) : condition(_condition), body(_body) {}
|
||||
UntilElement(Form* _condition, Form* _body);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
Form* condition = nullptr;
|
||||
@@ -640,11 +637,11 @@ class ShortCircuitElement : public FormElement {
|
||||
std::optional<bool> used_as_value = std::nullopt;
|
||||
bool already_rewritten = false;
|
||||
|
||||
explicit ShortCircuitElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
|
||||
explicit ShortCircuitElement(std::vector<Entry> _entries);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -672,11 +669,11 @@ class CondNoElseElement : public FormElement {
|
||||
bool used_as_value = false;
|
||||
bool already_rewritten = false;
|
||||
std::vector<Entry> entries;
|
||||
explicit CondNoElseElement(std::vector<Entry> _entries) : entries(std::move(_entries)) {}
|
||||
explicit CondNoElseElement(std::vector<Entry> _entries);
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
@@ -695,7 +692,7 @@ class AbsElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -725,7 +722,7 @@ class AshElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -746,7 +743,7 @@ class TypeOfElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -786,7 +783,7 @@ class ConditionalMoveFalseElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
};
|
||||
@@ -804,7 +801,7 @@ class GenericOperator {
|
||||
static GenericOperator make_fixed(FixedOperatorKind kind);
|
||||
static GenericOperator make_function(Form* value);
|
||||
static GenericOperator make_compare(IR2_Condition::Kind kind);
|
||||
void collect_vars(RegAccessSet& vars) const;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const;
|
||||
goos::Object to_form(const Env& env) const;
|
||||
void apply(const std::function<void(FormElement*)>& f);
|
||||
void apply_form(const std::function<void(Form*)>& f);
|
||||
@@ -850,7 +847,7 @@ class GenericElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -873,7 +870,7 @@ class CastElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -904,7 +901,7 @@ class DerefToken {
|
||||
static DerefToken make_field_name(const std::string& name);
|
||||
static DerefToken make_expr_placeholder();
|
||||
|
||||
void collect_vars(RegAccessSet& vars) const;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const;
|
||||
goos::Object to_form(const Env& env) const;
|
||||
void apply(const std::function<void(FormElement*)>& f);
|
||||
void apply_form(const std::function<void(Form*)>& f);
|
||||
@@ -937,7 +934,7 @@ class DerefElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -951,7 +948,7 @@ class DerefElement : public FormElement {
|
||||
const Form* base() const { return m_base; }
|
||||
Form* base() { return m_base; }
|
||||
const std::vector<DerefToken>& tokens() const { return m_tokens; }
|
||||
void set_base(Form* new_base) { m_base = new_base; }
|
||||
void set_base(Form* new_base);
|
||||
|
||||
private:
|
||||
Form* m_base = nullptr;
|
||||
@@ -965,7 +962,7 @@ class DynamicMethodAccess : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -986,7 +983,7 @@ class ArrayFieldAccess : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
@@ -1013,7 +1010,7 @@ class GetMethodElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -1033,7 +1030,7 @@ class StringConstantElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -1051,7 +1048,7 @@ class ConstantTokenElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -1069,7 +1066,7 @@ class ConstantFloatElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
@@ -1092,7 +1089,7 @@ class StorePlainDeref : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
|
||||
@@ -1113,7 +1110,7 @@ class StoreArrayAccess : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override;
|
||||
|
||||
@@ -1130,13 +1127,41 @@ class DecompiledDataElement : public FormElement {
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars) const override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
private:
|
||||
goos::Object m_description;
|
||||
};
|
||||
|
||||
class LetElement : public FormElement {
|
||||
public:
|
||||
LetElement(Form* body, bool star = false);
|
||||
void add_def(RegisterAccess dst, Form* value);
|
||||
|
||||
void make_let_star();
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
Form* body() { return m_body; }
|
||||
void set_body(Form* new_body);
|
||||
|
||||
struct Entry {
|
||||
RegisterAccess dest;
|
||||
Form* src = nullptr;
|
||||
};
|
||||
std::vector<Entry> entries() { return m_entries; }
|
||||
void add_entry(const Entry& e);
|
||||
bool is_star() const { return m_star; }
|
||||
|
||||
private:
|
||||
Form* m_body = nullptr;
|
||||
std::vector<Entry> m_entries;
|
||||
bool m_star = false;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A Form is a wrapper around one or more FormElements.
|
||||
* This is done for two reasons:
|
||||
@@ -1186,6 +1211,11 @@ class Form {
|
||||
|
||||
const std::vector<FormElement*>& elts() const { return m_elements; }
|
||||
std::vector<FormElement*>& elts() { return m_elements; }
|
||||
void claim_all_children() {
|
||||
for (auto elt : elts()) {
|
||||
elt->parent_form = this;
|
||||
}
|
||||
}
|
||||
|
||||
void push_back(FormElement* elt) {
|
||||
elt->parent_form = this;
|
||||
@@ -1200,7 +1230,7 @@ class Form {
|
||||
void inline_forms(std::vector<goos::Object>& forms, const Env& env) const;
|
||||
void apply(const std::function<void(FormElement*)>& f);
|
||||
void apply_form(const std::function<void(Form*)>& f);
|
||||
void collect_vars(RegAccessSet& vars) const;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const;
|
||||
|
||||
void update_children_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
|
||||
@@ -1348,7 +1348,8 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
||||
throw std::runtime_error("Failed to resolve.");
|
||||
}
|
||||
|
||||
arg_forms.insert(arg_forms.begin(), unsafe);
|
||||
arg_forms.insert(arg_forms.begin(), mr.maps.forms.at(0));
|
||||
|
||||
new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_function(mr.maps.forms.at(1)), arg_forms);
|
||||
|
||||
@@ -1750,8 +1751,10 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
|
||||
if (rewrite_as_set && !set_unused) {
|
||||
for (auto& entry : entries) {
|
||||
rewrite_to_get_var(entry.body->elts(), pool, *last_var, env);
|
||||
entry.body->claim_all_children();
|
||||
}
|
||||
rewrite_to_get_var(else_ir->elts(), pool, *last_var, env);
|
||||
else_ir->claim_all_children();
|
||||
}
|
||||
|
||||
// update register info
|
||||
|
||||
@@ -75,6 +75,7 @@ class ObjectFileDB {
|
||||
void ir2_cfg_build_pass();
|
||||
void ir2_store_current_forms();
|
||||
void ir2_build_expressions();
|
||||
void ir2_insert_lets();
|
||||
void ir2_write_results(const std::string& output_dir);
|
||||
std::string ir2_to_file(ObjectFileData& data);
|
||||
std::string ir2_function_to_string(ObjectFileData& data, Function& function, int seg);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "decompiler/Function/TypeInspector.h"
|
||||
#include "decompiler/analysis/reg_usage.h"
|
||||
#include "decompiler/analysis/insert_lets.h"
|
||||
#include "decompiler/analysis/variable_naming.h"
|
||||
#include "decompiler/analysis/cfg_builder.h"
|
||||
#include "decompiler/analysis/final_output.h"
|
||||
@@ -45,6 +46,11 @@ void ObjectFileDB::analyze_functions_ir2(const std::string& output_dir) {
|
||||
ir2_store_current_forms();
|
||||
lg::info("Expression building...");
|
||||
ir2_build_expressions();
|
||||
|
||||
if (get_config().insert_lets) {
|
||||
lg::info("Inserting lets...");
|
||||
ir2_insert_lets();
|
||||
}
|
||||
}
|
||||
|
||||
if (!output_dir.empty()) {
|
||||
@@ -422,6 +428,22 @@ void ObjectFileDB::ir2_build_expressions() {
|
||||
lg::info("{}/{}/{} expression build in {:.2f} ms\n", successful, attempted, total, timer.getMs());
|
||||
}
|
||||
|
||||
void ObjectFileDB::ir2_insert_lets() {
|
||||
Timer timer;
|
||||
LetStats combined_stats;
|
||||
int attempted = 0;
|
||||
|
||||
for_each_function_def_order([&](Function& func, int, ObjectFileData&) {
|
||||
if (func.ir2.expressions_succeeded) {
|
||||
attempted++;
|
||||
combined_stats += insert_lets(func, func.ir2.env, *func.ir2.form_pool, func.ir2.top_form);
|
||||
}
|
||||
});
|
||||
|
||||
lg::info("Let pass on {} functions ({}/{} vars in lets) in {:.2f} ms\n", attempted,
|
||||
combined_stats.vars_in_lets, combined_stats.total_vars, timer.getMs());
|
||||
}
|
||||
|
||||
void ObjectFileDB::ir2_write_results(const std::string& output_dir) {
|
||||
Timer timer;
|
||||
lg::info("Writing IR2 results to file...");
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "insert_lets.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
/*
|
||||
Part 1:
|
||||
Create a std::unordered_map<ProgVar, std::vector<FormElement*>> which maps a program variable to the
|
||||
collection of FormElement* which reference it.
|
||||
|
||||
Part 2:
|
||||
For each ProgVar, find the lowest common ancestor Form* of the FormElement*'s in the above map.
|
||||
|
||||
Part 3:
|
||||
For each Form*, find the smallest range of FormElement*s which include all uses of the ProgVar
|
||||
|
||||
Part 4:
|
||||
Sort these from the largest to smaller range.
|
||||
|
||||
This makes sure that at a single level (in the original tree), we insert larger lets first, leaving
|
||||
us with only one nesting case to worry about in the next step.
|
||||
|
||||
Check the first FormElement* which uses the ProgVar.
|
||||
If it is a (set! var xxx), then we can insert a let.
|
||||
|
||||
If we are inserting directly inside of another let, at the beginning of that let's body, add to that
|
||||
let. This makes the scope larger than it needs to be, but this seems like it will lead to more
|
||||
readable code.
|
||||
|
||||
If the previous let variables appear in the definition of new one, make the let into a let*
|
||||
*/
|
||||
|
||||
namespace {
|
||||
std::vector<Form*> path_up_tree(Form* in) {
|
||||
std::vector<Form*> path;
|
||||
|
||||
while (in) {
|
||||
path.push_back(in);
|
||||
// lg::warn("In: {}", in->to_string(env));
|
||||
if (in->parent_element) {
|
||||
// lg::warn(" {}", in->parent_element->to_string(env));
|
||||
in = in->parent_element->parent_form;
|
||||
} else {
|
||||
in = nullptr;
|
||||
}
|
||||
}
|
||||
// lg::warn("DONE\n");
|
||||
return path;
|
||||
}
|
||||
|
||||
Form* lca_form(Form* a, Form* b, const Env& env) {
|
||||
(void)env;
|
||||
if (!a) {
|
||||
return b;
|
||||
}
|
||||
|
||||
// fmt::print("lca {} ({}) and {} ({})\n", a->to_string(env), (void*)a, b->to_string(env),
|
||||
// (void*)b);
|
||||
|
||||
auto a_up = path_up_tree(a);
|
||||
auto b_up = path_up_tree(b);
|
||||
|
||||
int ai = a_up.size() - 1;
|
||||
int bi = b_up.size() - 1;
|
||||
|
||||
Form* result = nullptr;
|
||||
while (ai >= 0 && bi >= 0) {
|
||||
if (a_up.at(ai) == b_up.at(bi)) {
|
||||
result = a_up.at(ai);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
ai--;
|
||||
bi--;
|
||||
}
|
||||
assert(result);
|
||||
|
||||
// fmt::print("{}\n\n", result->to_string(env));
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_level_form) {
|
||||
(void)func;
|
||||
// if (func.guessed_name.to_string() != "(method 4 pair)") {
|
||||
// return {};
|
||||
// }
|
||||
LetStats stats;
|
||||
|
||||
// Stored per variable.
|
||||
struct PerVarInfo {
|
||||
std::string var_name; // name used to uniquely identify
|
||||
RegisterAccess access;
|
||||
std::unordered_set<FormElement*> elts_using_var; // all FormElements using var
|
||||
Form* lca_form = nullptr; // the lowest common form that contains all the above elts
|
||||
int start_idx = -1; // in the above form, first FormElement using var's index
|
||||
int end_idx = -1; // in the above form, 1 + last FormElement using var's index
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, PerVarInfo> var_info;
|
||||
|
||||
// Part 1, figure out which forms reference each var
|
||||
top_level_form->apply([&](FormElement* elt) {
|
||||
// for each element, figure out what vars we reference:
|
||||
RegAccessSet reg_accesses;
|
||||
elt->collect_vars(reg_accesses, false);
|
||||
|
||||
// and add it.
|
||||
for (auto& access : reg_accesses) {
|
||||
if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) {
|
||||
auto name = env.get_variable_name(access);
|
||||
var_info[name].elts_using_var.insert(elt);
|
||||
var_info[name].var_name = name;
|
||||
var_info[name].access = access;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
stats.total_vars = var_info.size();
|
||||
|
||||
// Part 2, figure out the lca form which contains all uses of a var
|
||||
for (auto& kv : var_info) {
|
||||
// fmt::print("--------------------- {}\n", kv.first);
|
||||
Form* lca = nullptr;
|
||||
for (auto fe : kv.second.elts_using_var) {
|
||||
lca = lca_form(lca, fe->parent_form, env);
|
||||
}
|
||||
assert(lca);
|
||||
var_info[kv.first].lca_form = lca;
|
||||
}
|
||||
|
||||
// Part 3, find the minimum range of FormElement's within the lca form that contain
|
||||
// all uses. This is the minimum possible range for a set!
|
||||
for (auto& kv : var_info) {
|
||||
// fmt::print("Setting range for let {}\n", kv.first);
|
||||
kv.second.start_idx = std::numeric_limits<int>::max();
|
||||
kv.second.end_idx = std::numeric_limits<int>::min();
|
||||
|
||||
bool got_one = false;
|
||||
for (int i = 0; i < kv.second.lca_form->size(); i++) {
|
||||
RegAccessSet ras;
|
||||
kv.second.lca_form->at(i)->collect_vars(ras, true);
|
||||
bool uses = false;
|
||||
for (auto& ra : ras) {
|
||||
if (env.get_variable_name(ra) == kv.second.var_name) {
|
||||
uses = true;
|
||||
}
|
||||
}
|
||||
if (uses) {
|
||||
// if (kv.second.elts_using_var.find(kv.second.lca_form->at(i)) !=
|
||||
// kv.second.elts_using_var.end()) {
|
||||
got_one = true;
|
||||
kv.second.start_idx = std::min(kv.second.start_idx, i);
|
||||
kv.second.end_idx = std::max(kv.second.end_idx, i + 1);
|
||||
// fmt::print("update range {} to {} because of {}\n", kv.second.start_idx,
|
||||
// kv.second.end_idx, kv.second.lca_form->at(i)->to_string(env));
|
||||
}
|
||||
}
|
||||
assert(got_one);
|
||||
}
|
||||
|
||||
// fmt::print("\n");
|
||||
|
||||
// Part 4, sort the var infos in descending size.
|
||||
// this simplifies future passes.
|
||||
std::vector<PerVarInfo> sorted_info;
|
||||
for (auto& kv : var_info) {
|
||||
sorted_info.push_back(kv.second);
|
||||
}
|
||||
std::sort(sorted_info.begin(), sorted_info.end(), [](const PerVarInfo& a, const PerVarInfo& b) {
|
||||
return (a.end_idx - a.start_idx) > (b.end_idx - b.start_idx);
|
||||
});
|
||||
|
||||
// Part 5, find where we want to insert lets. But don't actually do any insertions.
|
||||
// Only variables that begin with a set! var value can be used in a let, so we may discard
|
||||
// some variables here. Though I suspect most reasonable functions will not discard any.
|
||||
struct LetInsertion {
|
||||
Form* form = nullptr;
|
||||
int start_elt = -1; // this is the set!
|
||||
SetVarElement* set_form = nullptr;
|
||||
int end_elt = -1;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// stored per containing form.
|
||||
std::unordered_map<Form*, std::vector<LetInsertion>> possible_insertions;
|
||||
for (auto& info : sorted_info) {
|
||||
auto first_form = info.lca_form->at(info.start_idx);
|
||||
auto first_form_as_set = dynamic_cast<SetVarElement*>(first_form);
|
||||
if (first_form_as_set &&
|
||||
env.get_variable_name(first_form_as_set->dst()) == env.get_variable_name(info.access) &&
|
||||
!first_form_as_set->info().is_eliminated_coloring_move) {
|
||||
// success!
|
||||
// fmt::print("Want let for {} range {} to {}\n",
|
||||
// env.get_variable_name(first_form_as_set->dst()), info.start_idx, info.end_idx);
|
||||
LetInsertion li;
|
||||
li.form = info.lca_form;
|
||||
li.start_elt = info.start_idx;
|
||||
li.end_elt = info.end_idx;
|
||||
li.set_form = first_form_as_set;
|
||||
li.name = info.var_name;
|
||||
possible_insertions[li.form].push_back(li);
|
||||
stats.vars_in_lets++;
|
||||
} else {
|
||||
// fmt::print("fail for {} : {}\n", info.var_name, first_form->to_string(env));
|
||||
}
|
||||
}
|
||||
|
||||
// Part 6, expand ends of intervals to prevent "tangled lets"
|
||||
for (auto& group : possible_insertions) {
|
||||
// Note : this algorithm is not efficient.
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (auto& let_a : group.second) {
|
||||
for (auto& let_b : group.second) {
|
||||
// If b starts within a and ends after a, expand a.
|
||||
if (let_b.start_elt > let_a.start_elt && let_b.start_elt < let_a.end_elt &&
|
||||
let_b.end_elt > let_a.end_elt) {
|
||||
changed = true;
|
||||
// fmt::print("Resized {}'s end to {}\n", let_a.set_form->dst().to_string(env),
|
||||
// let_b.end_elt);
|
||||
let_a.end_elt = let_b.end_elt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Part 7: insert lets!
|
||||
for (auto& group : possible_insertions) {
|
||||
// sort decreasing size.
|
||||
std::sort(group.second.begin(), group.second.end(),
|
||||
[](const LetInsertion& a, const LetInsertion& b) {
|
||||
return (a.end_elt - a.start_elt) > (b.end_elt - b.start_elt);
|
||||
});
|
||||
|
||||
// ownership[elt_idx] = the let which actually has this.
|
||||
std::vector<int> ownership;
|
||||
ownership.resize(group.first->size(), -1);
|
||||
for (int let_idx = 0; let_idx < int(group.second.size()); let_idx++) {
|
||||
for (int elt_idx = group.second.at(let_idx).start_elt;
|
||||
elt_idx < group.second.at(let_idx).end_elt; elt_idx++) {
|
||||
ownership.at(elt_idx) = let_idx;
|
||||
}
|
||||
}
|
||||
|
||||
// build lets
|
||||
std::vector<LetElement*> lets;
|
||||
lets.resize(group.first->size(), nullptr);
|
||||
// start at the smallest.
|
||||
for (size_t let_idx = group.second.size(); let_idx-- > 0;) {
|
||||
auto& let_desc = group.second.at(let_idx);
|
||||
std::vector<FormElement*> body;
|
||||
int elt_idx = let_desc.start_elt + 1; // plus one to skip the variable def.
|
||||
while (elt_idx < let_desc.end_elt) {
|
||||
if (ownership.at(elt_idx) == int(let_idx)) {
|
||||
body.push_back(let_desc.form->at(elt_idx));
|
||||
elt_idx++;
|
||||
} else {
|
||||
auto existing_let = lets.at(ownership[elt_idx]);
|
||||
assert(existing_let);
|
||||
auto& existing_let_info = group.second.at(ownership[elt_idx]);
|
||||
assert(existing_let_info.start_elt == elt_idx);
|
||||
body.push_back(existing_let);
|
||||
elt_idx = existing_let_info.end_elt;
|
||||
}
|
||||
}
|
||||
assert(elt_idx == let_desc.end_elt);
|
||||
auto new_let = pool.alloc_element<LetElement>(pool.alloc_sequence_form(nullptr, body));
|
||||
new_let->add_def(let_desc.set_form->dst(), let_desc.set_form->src());
|
||||
env.set_defined_in_let(let_desc.name);
|
||||
lets.at(let_idx) = new_let;
|
||||
}
|
||||
|
||||
// now rebuild form
|
||||
int elt_idx = 0;
|
||||
std::vector<FormElement*> new_body;
|
||||
while (elt_idx < group.first->size()) {
|
||||
if (ownership.at(elt_idx) == -1) {
|
||||
new_body.push_back(group.first->at(elt_idx));
|
||||
elt_idx++;
|
||||
} else {
|
||||
auto existing_let = lets.at(ownership[elt_idx]);
|
||||
assert(existing_let);
|
||||
auto& existing_let_info = group.second.at(ownership[elt_idx]);
|
||||
assert(existing_let_info.start_elt == elt_idx);
|
||||
new_body.push_back(existing_let);
|
||||
elt_idx = existing_let_info.end_elt;
|
||||
}
|
||||
}
|
||||
assert(elt_idx == group.first->size());
|
||||
|
||||
group.first->elts() = new_body;
|
||||
group.first->claim_all_children();
|
||||
}
|
||||
|
||||
// Part 8: (todo) recognize loops and stuff.
|
||||
|
||||
// Part 9: compact recursive lets:
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
top_level_form->apply([&](FormElement* f) {
|
||||
auto as_let = dynamic_cast<LetElement*>(f);
|
||||
if (!as_let) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto inner_let = dynamic_cast<LetElement*>(as_let->body()->try_as_single_element());
|
||||
if (!inner_let) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& e : inner_let->entries()) {
|
||||
if (!as_let->is_star()) {
|
||||
RegAccessSet used;
|
||||
e.src->collect_vars(used, true);
|
||||
std::unordered_set<std::string> used_by_name;
|
||||
for (auto used_var : used) {
|
||||
used_by_name.insert(env.get_variable_name(used_var));
|
||||
}
|
||||
for (auto& old_entry : as_let->entries()) {
|
||||
if (used_by_name.find(env.get_variable_name(old_entry.dest)) != used_by_name.end()) {
|
||||
as_let->make_let_star();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
as_let->add_entry(e);
|
||||
}
|
||||
|
||||
as_let->set_body(inner_let->body());
|
||||
changed = true;
|
||||
});
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
} // namespace decompiler
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "decompiler/IR2/Env.h"
|
||||
#include "decompiler/Function/Function.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
struct LetStats {
|
||||
int total_vars = 0;
|
||||
int vars_in_lets = 0;
|
||||
|
||||
void operator+=(const LetStats& other) {
|
||||
total_vars += other.total_vars;
|
||||
vars_in_lets += other.vars_in_lets;
|
||||
}
|
||||
};
|
||||
|
||||
LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_level_form);
|
||||
|
||||
} // namespace decompiler
|
||||
@@ -53,6 +53,7 @@ void set_config(const std::string& path_to_config_file) {
|
||||
gConfig.function_type_prop = cfg.at("function_type_prop").get<bool>();
|
||||
gConfig.analyze_expressions = cfg.at("analyze_expressions").get<bool>();
|
||||
gConfig.run_ir2 = cfg.at("run_ir2").get<bool>();
|
||||
gConfig.insert_lets = cfg.at("insert_lets").get<bool>();
|
||||
|
||||
std::vector<std::string> asm_functions_by_name =
|
||||
cfg.at("asm_functions_by_name").get<std::vector<std::string>>();
|
||||
|
||||
@@ -40,6 +40,7 @@ struct Config {
|
||||
bool write_func_json = false;
|
||||
bool function_type_prop = false;
|
||||
bool analyze_expressions = false;
|
||||
bool insert_lets = false;
|
||||
std::unordered_set<std::string> asm_functions_by_name;
|
||||
std::unordered_set<std::string> pair_functions_by_name;
|
||||
std::unordered_set<std::string> no_type_analysis_functions_by_name;
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"analyze_functions":true,
|
||||
"analyze_expressions":true,
|
||||
"function_type_prop":true,
|
||||
"insert_lets":true,
|
||||
"write_disassembly":true,
|
||||
"write_hex_near_instructions":false,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user