[Decompiler] Decompile let (#309)

* test

* fix bug

* fix tests for let

* missing formatting fix
This commit is contained in:
water111
2021-03-05 18:48:01 -05:00
committed by GitHub
parent 9168f03289
commit 65ffe83468
20 changed files with 2312 additions and 1655 deletions
+1
View File
@@ -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
View File
@@ -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) {
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+4 -1
View File
@@ -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
+1
View File
@@ -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...");
+342
View 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
+21
View File
@@ -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
+1
View File
@@ -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>>();
+1
View File
@@ -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,