mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
[Decompiler] Decompile let
(#309)
* test * fix bug * fix tests for let * missing formatting fix
This commit is contained in:
parent
9168f03289
commit
65ffe83468
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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...");
|
||||
|
|
342
decompiler/analysis/insert_lets.cpp
Normal file
342
decompiler/analysis/insert_lets.cpp
Normal 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
decompiler/analysis/insert_lets.h
Normal file
21
decompiler/analysis/insert_lets.h
Normal 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
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "decompiler/analysis/cfg_builder.h"
|
||||
#include "decompiler/analysis/expression_build.h"
|
||||
#include "decompiler/analysis/final_output.h"
|
||||
#include "decompiler/analysis/insert_lets.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "third-party/json.hpp"
|
||||
|
@ -129,7 +130,7 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
|||
// for now, just test that this can at least be called.
|
||||
if (test->func.ir2.top_form) {
|
||||
RegAccessSet vars;
|
||||
test->func.ir2.top_form->collect_vars(vars);
|
||||
test->func.ir2.top_form->collect_vars(vars, true);
|
||||
|
||||
if (do_expressions) {
|
||||
bool success = convert_to_expressions(test->func.ir2.top_form, *test->func.ir2.form_pool,
|
||||
|
@ -139,6 +140,8 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
|||
if (!success) {
|
||||
return nullptr;
|
||||
}
|
||||
insert_lets(test->func, test->func.ir2.env, *test->func.ir2.form_pool,
|
||||
test->func.ir2.top_form);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -266,7 +266,7 @@ TEST_F(FormRegressionTest, ExprAbs) {
|
|||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int)";
|
||||
std::string expected = "(begin (set! v0-0 arg0) (abs v0-0))";
|
||||
std::string expected = "(let ((v0-0 arg0)) (abs v0-0))";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
|
@ -454,14 +454,11 @@ TEST_F(FormRegressionTest, ExprBasicTypeP) {
|
|||
std::string type = "(function basic type symbol)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 (-> arg0 type))\n"
|
||||
" (set! a0-1 object)\n"
|
||||
" (until\n"
|
||||
" (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n" // likely using set! as value. we
|
||||
// don't plan on supporting this.
|
||||
" (if\n"
|
||||
" (= v1-0 arg1)\n"
|
||||
" (return #t)\n"
|
||||
" (let\n"
|
||||
" ((v1-0 (-> arg0 type)) (a0-1 object))\n"
|
||||
" (until\n"
|
||||
" (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n"
|
||||
" (if (= v1-0 arg1) (return #t))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
|
@ -497,17 +494,14 @@ TEST_F(FormRegressionTest, FinalBasicTypeP) {
|
|||
std::string type = "(function basic type symbol)";
|
||||
std::string expected =
|
||||
"(defun test-function ((arg0 basic) (arg1 type))\n"
|
||||
" (local-vars\n"
|
||||
" (v1-0 type)\n"
|
||||
" (a0-1 type)\n"
|
||||
" )\n"
|
||||
" (set! v1-0 (-> arg0 type))\n"
|
||||
" (set! a0-1 object)\n"
|
||||
" (let\n"
|
||||
" ((v1-0 (-> arg0 type)) (a0-1 object))\n"
|
||||
" (until\n"
|
||||
" (begin (set! v1-0 (-> v1-0 parent)) (= v1-0 a0-1))\n"
|
||||
" (if (= v1-0 arg1) (return #t))\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )";
|
||||
test_final_function(func, type, expected);
|
||||
}
|
||||
|
@ -553,13 +547,12 @@ TEST_F(FormRegressionTest, ExprTypeTypep) {
|
|||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 object)\n"
|
||||
" (until\n"
|
||||
" (begin\n"
|
||||
" (set! arg0 (-> arg0 parent))\n"
|
||||
" (or (= arg0 v1-0) (zero? arg0))\n"
|
||||
" (let\n"
|
||||
" ((v1-0 object))\n"
|
||||
" (until\n"
|
||||
" (begin (set! arg0 (-> arg0 parent)) (or (= arg0 v1-0) (zero? arg0)))\n"
|
||||
" (if (= arg0 arg1) (return #t))\n"
|
||||
" )\n"
|
||||
" (if (= arg0 arg1) (return #t))\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )";
|
||||
|
@ -615,13 +608,15 @@ TEST_F(FormRegressionTest, ExprFindParentMethod) {
|
|||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-2 (-> arg0 method-table arg1))\n"
|
||||
" (until\n"
|
||||
" (!= v0-0 v1-2)\n"
|
||||
" (if (= arg0 object) (return nothing))\n"
|
||||
" (set! arg0 (-> arg0 parent))\n"
|
||||
" (set! v0-0 (-> arg0 method-table arg1))\n"
|
||||
" (if (zero? v0-0) (return nothing))\n"
|
||||
" (let\n"
|
||||
" ((v1-2 (-> arg0 method-table arg1)))\n"
|
||||
" (until\n"
|
||||
" (!= v0-0 v1-2)\n"
|
||||
" (if (= arg0 object) (return nothing))\n"
|
||||
" (set! arg0 (-> arg0 parent))\n"
|
||||
" (set! v0-0 (-> arg0 method-table arg1))\n"
|
||||
" (if (zero? v0-0) (return nothing))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" v0-0\n"
|
||||
" )";
|
||||
|
@ -656,13 +651,9 @@ TEST_F(FormRegressionTest, ExprRef) {
|
|||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 0)\n"
|
||||
" (while\n"
|
||||
" (< v1-0 arg1)\n"
|
||||
" (nop!)\n"
|
||||
" (nop!)\n"
|
||||
" (set! arg0 (cdr arg0))\n"
|
||||
" (+! v1-0 1)\n"
|
||||
" (let\n"
|
||||
" ((v1-0 0))\n"
|
||||
" (while (< v1-0 arg1) (nop!) (nop!) (set! arg0 (cdr arg0)) (+! v1-0 1))\n"
|
||||
" )\n"
|
||||
" (car arg0)\n"
|
||||
" )";
|
||||
|
@ -715,19 +706,20 @@ TEST_F(FormRegressionTest, ExprPairMethod4) {
|
|||
" daddu sp, sp, r0\n";
|
||||
std::string type = "(function pair int)";
|
||||
|
||||
// multiple return paths merged variable issue.
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (cond\n"
|
||||
" ((= arg0 '()) (set! v0-0 0))\n"
|
||||
" ((= arg0 (quote ())) (set! v0-0 0))\n"
|
||||
" (else\n"
|
||||
" (set! v1-1 (cdr arg0))\n"
|
||||
" (set! v0-0 1)\n"
|
||||
" (while\n"
|
||||
" (and (!= v1-1 '()) "
|
||||
" (< (shl (the-as int v1-1) 62) 0)\n"
|
||||
" (let\n"
|
||||
" ((v1-1 (cdr arg0)))\n"
|
||||
" (set! v0-0 1)\n"
|
||||
" (while\n"
|
||||
" (and (!= v1-1 (quote ())) (< (shl (the-as int v1-1) 62) 0))\n"
|
||||
" (+! v0-0 1)\n"
|
||||
" (set! v1-1 (cdr v1-1))\n"
|
||||
" )\n"
|
||||
" (+! v0-0 1)\n"
|
||||
" (set! v1-1 (cdr v1-1))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -774,12 +766,9 @@ TEST_F(FormRegressionTest, ExprLast) {
|
|||
std::string type = "(function object object)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v0-0 arg0)\n"
|
||||
" (while (!= (cdr v0-0) '())"
|
||||
" (nop!)\n"
|
||||
" (nop!)\n"
|
||||
" (set! v0-0 (cdr v0-0)))\n"
|
||||
"(let\n"
|
||||
" ((v0-0 arg0))\n"
|
||||
" (while (!= (cdr v0-0) (quote ())) (nop!) (nop!) (set! v0-0 (cdr v0-0)))\n"
|
||||
" v0-0\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, true, "");
|
||||
|
@ -826,13 +815,13 @@ TEST_F(FormRegressionTest, ExprMember) {
|
|||
std::string type = "(function object object object)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 arg1)\n"
|
||||
"(let\n"
|
||||
" ((v1-0 arg1))\n"
|
||||
" (while\n"
|
||||
" (not (or (= v1-0 '()) (= (car v1-0) arg0)))\n"
|
||||
" (not (or (= v1-0 (quote ())) (= (car v1-0) arg0)))\n"
|
||||
" (set! v1-0 (cdr v1-0))\n"
|
||||
" )\n"
|
||||
" (if (!= v1-0 '()) v1-0)\n"
|
||||
" (if (!= v1-0 (quote ())) v1-0)\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, true, "");
|
||||
}
|
||||
|
@ -939,13 +928,13 @@ TEST_F(FormRegressionTest, ExprAssoc) {
|
|||
std::string type = "(function object object object)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 arg1)\n"
|
||||
"(let\n"
|
||||
" ((v1-0 arg1))\n"
|
||||
" (while\n"
|
||||
" (not (or (= v1-0 '()) (= (car (car v1-0)) arg0)))\n"
|
||||
" (not (or (= v1-0 (quote ())) (= (car (car v1-0)) arg0)))\n"
|
||||
" (set! v1-0 (cdr v1-0))\n"
|
||||
" )\n"
|
||||
" (if (!= v1-0 '()) (car v1-0))\n"
|
||||
" (if (!= v1-0 (quote ())) (car v1-0))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, true, "");
|
||||
}
|
||||
|
@ -1001,19 +990,19 @@ TEST_F(FormRegressionTest, ExprAssoce) {
|
|||
std::string type = "(function object object object)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 arg1)\n"
|
||||
"(let\n"
|
||||
" ((v1-0 arg1))\n"
|
||||
" (while\n"
|
||||
" (not\n"
|
||||
" (or\n"
|
||||
" (= v1-0 '())\n"
|
||||
" (= v1-0 (quote ()))\n"
|
||||
" (= (car (car v1-0)) arg0)\n"
|
||||
" (= (car (car v1-0)) 'else)\n"
|
||||
" (= (car (car v1-0)) (quote else))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! v1-0 (cdr v1-0))\n"
|
||||
" )\n"
|
||||
" (if (!= v1-0 '()) (car v1-0))\n"
|
||||
" (if (!= v1-0 (quote ())) (car v1-0))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, true, "");
|
||||
}
|
||||
|
@ -1092,13 +1081,13 @@ TEST_F(FormRegressionTest, ExprNassoc) {
|
|||
" (not\n"
|
||||
" (or\n"
|
||||
" (= arg1 (quote ()))\n"
|
||||
" (begin\n"
|
||||
" (set! a1-1 (car (car arg1)))\n"
|
||||
" (if "
|
||||
" (let\n"
|
||||
" ((a1-1 (car (car arg1))))\n"
|
||||
" (if\n"
|
||||
" (pair? a1-1)\n"
|
||||
" (nmember (the-as basic arg0) a1-1)\n"
|
||||
" (name= (the-as basic a1-1) (the-as basic arg0))"
|
||||
" )\n"
|
||||
" (name= (the-as basic a1-1) (the-as basic arg0))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -1194,8 +1183,8 @@ TEST_F(FormRegressionTest, ExprNassoce) {
|
|||
" (not\n"
|
||||
" (or\n"
|
||||
" (= arg1 (quote ()))\n"
|
||||
" (begin\n"
|
||||
" (set! s4-0 (car (car arg1)))\n"
|
||||
" (let\n"
|
||||
" ((s4-0 (car (car arg1))))\n"
|
||||
" (if\n"
|
||||
" (pair? s4-0)\n"
|
||||
" (nmember (the-as basic arg0) s4-0)\n"
|
||||
|
@ -1260,11 +1249,13 @@ TEST_F(FormRegressionTest, ExprAppend) {
|
|||
|
||||
std::string expected =
|
||||
"(cond\n"
|
||||
" ((= arg0 '()) arg1)\n"
|
||||
" ((= arg0 (quote ())) arg1)\n"
|
||||
" (else\n"
|
||||
" (set! v1-1 arg0)\n"
|
||||
" (while (!= (cdr v1-1) '()) (nop!) (nop!) (set! v1-1 (cdr v1-1)))\n"
|
||||
" (if (!= v1-1 '()) (set! (cdr v1-1) arg1))\n"
|
||||
" (let\n"
|
||||
" ((v1-1 arg0))\n"
|
||||
" (while (!= (cdr v1-1) (quote ())) (nop!) (nop!) (set! v1-1 (cdr v1-1)))\n"
|
||||
" (if (!= v1-1 (quote ())) (set! (cdr v1-1) arg1))\n"
|
||||
" )\n"
|
||||
" arg0\n"
|
||||
" )\n"
|
||||
" )";
|
||||
|
@ -1332,14 +1323,15 @@ TEST_F(FormRegressionTest, ExprDelete) {
|
|||
" (cond\n"
|
||||
" ((= arg0 (car arg1)) (cdr arg1))\n"
|
||||
" (else\n"
|
||||
" (set! v1-1 arg1)\n"
|
||||
" (set! a2-0 (cdr arg1))\n"
|
||||
" (while\n"
|
||||
" (not (or (= a2-0 (quote ())) (= (car a2-0) arg0)))\n"
|
||||
" (set! v1-1 a2-0)\n"
|
||||
" (set! a2-0 (cdr a2-0))\n"
|
||||
" (let\n"
|
||||
" ((v1-1 arg1) (a2-0 (cdr arg1)))\n"
|
||||
" (while\n"
|
||||
" (not (or (= a2-0 (quote ())) (= (car a2-0) arg0)))\n"
|
||||
" (set! v1-1 a2-0)\n"
|
||||
" (set! a2-0 (cdr a2-0))\n"
|
||||
" )\n"
|
||||
" (if (!= a2-0 (quote ())) (set! (cdr v1-1) (cdr a2-0)))\n"
|
||||
" )\n"
|
||||
" (if (!= a2-0 (quote ())) (set! (cdr v1-1) (cdr a2-0)))\n"
|
||||
" arg1\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -1410,14 +1402,15 @@ TEST_F(FormRegressionTest, ExprDeleteCar) {
|
|||
" (cond\n"
|
||||
" ((= arg0 (car (car arg1))) (cdr arg1))\n"
|
||||
" (else\n"
|
||||
" (set! v1-2 arg1)\n"
|
||||
" (set! a2-0 (cdr arg1))\n"
|
||||
" (while\n"
|
||||
" (not (or (= a2-0 (quote ())) (= (car (car a2-0)) arg0)))\n"
|
||||
" (set! v1-2 a2-0)\n"
|
||||
" (set! a2-0 (cdr a2-0))\n"
|
||||
" (let\n"
|
||||
" ((v1-2 arg1) (a2-0 (cdr arg1)))\n"
|
||||
" (while\n"
|
||||
" (not (or (= a2-0 (quote ())) (= (car (car a2-0)) arg0)))\n"
|
||||
" (set! v1-2 a2-0)\n"
|
||||
" (set! a2-0 (cdr a2-0))\n"
|
||||
" )\n"
|
||||
" (if (!= a2-0 (quote ())) (set! (cdr v1-2) (cdr a2-0)))\n"
|
||||
" )\n"
|
||||
" (if (!= a2-0 (quote ())) (set! (cdr v1-2) (cdr a2-0)))\n"
|
||||
" arg1\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -1454,11 +1447,7 @@ TEST_F(FormRegressionTest, ExprInsertCons) {
|
|||
std::string type = "(function object object pair)";
|
||||
|
||||
// NOTE - this appears to _not_ be a nested call.
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! a3-0 (delete-car! (car arg0) arg1))\n"
|
||||
" (cons arg0 a3-0)\n"
|
||||
" )";
|
||||
std::string expected = "(let ((a3-0 (delete-car! (car arg0) arg1))) (cons arg0 a3-0))";
|
||||
test_with_expr(func, type, expected, true, "");
|
||||
}
|
||||
|
||||
|
@ -1568,25 +1557,29 @@ TEST_F(FormRegressionTest, ExprSort) {
|
|||
// TODO - this should probably be tested.
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s4-0 -1)\n"
|
||||
" (while\n"
|
||||
" (nonzero? s4-0)\n"
|
||||
" (set! s4-0 0)\n"
|
||||
" (set! s3-0 arg0)\n"
|
||||
" (let\n"
|
||||
" ((s4-0 -1))\n"
|
||||
" (while\n"
|
||||
" (not\n"
|
||||
" (or (= (cdr s3-0) (quote ())) (>= (shl (the-as int (cdr s3-0)) 62) 0))\n"
|
||||
" (nonzero? s4-0)\n"
|
||||
" (set! s4-0 0)\n"
|
||||
" (let\n"
|
||||
" ((s3-0 arg0))\n"
|
||||
" (while\n"
|
||||
" (not\n"
|
||||
" (or (= (cdr s3-0) (quote ())) (>= (shl (the-as int (cdr s3-0)) 62) 0))\n"
|
||||
" )\n"
|
||||
" (let*\n"
|
||||
" ((s2-0 (car s3-0)) (s1-0 (car (cdr s3-0))) (v1-1 (arg1 s2-0 s1-0)))\n"
|
||||
" (when\n"
|
||||
" (and (or (not v1-1) (> (the-as int v1-1) 0)) (!= v1-1 #t))\n"
|
||||
" (+! s4-0 1)\n"
|
||||
" (set! (car s3-0) s1-0)\n"
|
||||
" (set! (car (cdr s3-0)) s2-0)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! s3-0 (cdr s3-0))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! s2-0 (car s3-0))\n"
|
||||
" (set! s1-0 (car (cdr s3-0)))\n"
|
||||
" (set! v1-1 (arg1 s2-0 s1-0))\n"
|
||||
" (when\n"
|
||||
" (and (or (not v1-1) (> (the-as int v1-1) 0)) (!= v1-1 #t))\n"
|
||||
" (+! s4-0 1)\n"
|
||||
" (set! (car s3-0) s1-0)\n"
|
||||
" (set! (car (cdr s3-0)) s2-0)\n"
|
||||
" )\n"
|
||||
" (set! s3-0 (cdr s3-0))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" arg0\n"
|
||||
|
@ -1627,13 +1620,13 @@ TEST_F(FormRegressionTest, ExprInlineArrayMethod0) {
|
|||
std::string type = "(function symbol type int inline-array-class)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set!\n"
|
||||
" v0-0\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
" (the-as int (+ (-> arg1 size) (* (the-as uint arg2) (-> arg1 heap-base))))\n"
|
||||
"(let\n"
|
||||
" ((v0-0\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
" (the-as int (+ (-> arg1 size) (* (the-as uint arg2) (-> arg1 heap-base))))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (when\n"
|
||||
|
@ -1743,17 +1736,17 @@ TEST_F(FormRegressionTest, ExprArrayMethod0) {
|
|||
std::string type = "(function symbol type type int array)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set!\n"
|
||||
" v0-1\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
" (the-as\n"
|
||||
" int\n"
|
||||
" (+\n"
|
||||
" (-> arg1 size)\n"
|
||||
" (the-as uint (* arg3 (if (type-type? arg2 number) (-> arg2 size) 4)))\n"
|
||||
"(let\n"
|
||||
" ((v0-1\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
" (the-as\n"
|
||||
" int\n"
|
||||
" (+\n"
|
||||
" (-> arg1 size)\n"
|
||||
" (the-as uint (* arg3 (if (type-type? arg2 number) (-> arg2 size) 4)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -1867,15 +1860,17 @@ TEST_F(FormRegressionTest, ExprMemCopy) {
|
|||
std::string type = "(function pointer pointer int pointer)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v0-0 arg0)\n"
|
||||
" (set! v1-0 0)\n"
|
||||
" (while\n"
|
||||
" (< v1-0 arg2)\n"
|
||||
" (set! (-> (the-as (pointer int8) arg0)) (-> (the-as (pointer uint8) arg1)))\n"
|
||||
" (&+! arg0 1)\n"
|
||||
" (&+! arg1 1)\n"
|
||||
" (+! v1-0 1)\n"
|
||||
"(let\n"
|
||||
" ((v0-0 arg0))\n"
|
||||
" (let\n"
|
||||
" ((v1-0 0))\n"
|
||||
" (while\n"
|
||||
" (< v1-0 arg2)\n"
|
||||
" (set! (-> (the-as (pointer int8) arg0)) (-> (the-as (pointer uint8) arg1)))\n"
|
||||
" (&+! arg0 1)\n"
|
||||
" (&+! arg1 1)\n"
|
||||
" (+! v1-0 1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" v0-0\n"
|
||||
" )";
|
||||
|
@ -1908,15 +1903,17 @@ TEST_F(FormRegressionTest, ExprMemSet32) {
|
|||
std::string type = "(function pointer int int pointer)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v0-0 arg0)\n"
|
||||
" (set! v1-0 0)\n"
|
||||
" (while\n"
|
||||
" (< v1-0 arg1)\n"
|
||||
" (set! (-> (the-as (pointer int32) arg0)) arg2)\n"
|
||||
" (&+! arg0 4)\n"
|
||||
" (nop!)\n"
|
||||
" (+! v1-0 1)\n"
|
||||
"(let\n"
|
||||
" ((v0-0 arg0))\n"
|
||||
" (let\n"
|
||||
" ((v1-0 0))\n"
|
||||
" (while\n"
|
||||
" (< v1-0 arg1)\n"
|
||||
" (set! (-> (the-as (pointer int32) arg0)) arg2)\n"
|
||||
" (&+! arg0 4)\n"
|
||||
" (nop!)\n"
|
||||
" (+! v1-0 1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" v0-0\n"
|
||||
" )";
|
||||
|
@ -1952,21 +1949,23 @@ TEST_F(FormRegressionTest, ExprMemOr) {
|
|||
std::string type = "(function pointer pointer int pointer)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v0-0 arg0)\n"
|
||||
" (set! v1-0 0)\n"
|
||||
" (while\n"
|
||||
" (< v1-0 arg2)\n"
|
||||
" (set!\n"
|
||||
" (-> (the-as (pointer int8) arg0))\n"
|
||||
" (logior\n"
|
||||
" (-> (the-as (pointer uint8) arg0))\n"
|
||||
" (-> (the-as (pointer uint8) arg1))\n"
|
||||
"(let\n"
|
||||
" ((v0-0 arg0))\n"
|
||||
" (let\n"
|
||||
" ((v1-0 0))\n"
|
||||
" (while\n"
|
||||
" (< v1-0 arg2)\n"
|
||||
" (set!\n"
|
||||
" (-> (the-as (pointer int8) arg0))\n"
|
||||
" (logior\n"
|
||||
" (-> (the-as (pointer uint8) arg0))\n"
|
||||
" (-> (the-as (pointer uint8) arg1))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (&+! arg0 1)\n"
|
||||
" (&+! arg1 1)\n"
|
||||
" (+! v1-0 1)\n"
|
||||
" )\n"
|
||||
" (&+! arg0 1)\n"
|
||||
" (&+! arg1 1)\n"
|
||||
" (+! v1-0 1)\n"
|
||||
" )\n"
|
||||
" v0-0\n"
|
||||
" )";
|
||||
|
@ -2076,8 +2075,7 @@ TEST_F(FormRegressionTest, ExprPrintl) {
|
|||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! a0-1 arg0)\n"
|
||||
" ((method-of-type (rtype-of a0-1) print) a0-1)\n"
|
||||
" (let ((a0-1 arg0)) ((method-of-type (rtype-of a0-1) print) a0-1))\n"
|
||||
" (format #t \"~%\")\n"
|
||||
" arg0\n"
|
||||
" )";
|
||||
|
@ -2173,16 +2171,14 @@ TEST_F(FormRegressionTest, ExprPrintTreeBitmask) {
|
|||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s4-0 0)\n"
|
||||
" (while\n"
|
||||
" (< s4-0 arg1)\n"
|
||||
" (if\n"
|
||||
" (zero? (logand arg0 1))\n"
|
||||
" (format #t \" \")\n"
|
||||
" (format #t \"| \")\n"
|
||||
" (let\n"
|
||||
" ((s4-0 0))\n"
|
||||
" (while\n"
|
||||
" (< s4-0 arg1)\n"
|
||||
" (if (zero? (logand arg0 1)) (format #t \" \") (format #t \"| \"))\n"
|
||||
" (set! arg0 (shr arg0 1))\n"
|
||||
" (+! s4-0 1)\n"
|
||||
" )\n"
|
||||
" (set! arg0 (shr arg0 1))\n"
|
||||
" (+! s4-0 1)\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )";
|
||||
|
@ -2351,7 +2347,7 @@ TEST_F(FormRegressionTest, ExprStopwatchElapsedSeconds) {
|
|||
" daddiu sp, sp, 16";
|
||||
std::string type = "(function int float)";
|
||||
|
||||
std::string expected = "(begin (set! v1-0 (abs arg0)) (* (l.f L20) (the float v1-0)))";
|
||||
std::string expected = "(let ((v1-0 (abs arg0))) (* (l.f L20) (the float v1-0)))";
|
||||
test_with_expr(func, type, expected, false, "");
|
||||
}
|
||||
|
||||
|
@ -2381,17 +2377,23 @@ TEST_F(FormRegressionTest, ExprCopyStringString) {
|
|||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function string string string)";
|
||||
// this is correct, but an example of where let's might look better if nested,
|
||||
// even if it means making the scope a little bit larger...
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 (-> arg0 data))\n"
|
||||
" (set! a1-1 (-> arg1 data))\n"
|
||||
" (while\n"
|
||||
" (nonzero? (-> a1-1 0))\n"
|
||||
" (set! (-> v1-0 0) (-> a1-1 0))\n"
|
||||
" (set! v1-0 (&-> v1-0 1))\n"
|
||||
" (set! a1-1 (&-> a1-1 1))\n"
|
||||
" (let\n"
|
||||
" ((v1-0 (-> arg0 data)))\n"
|
||||
" (let\n"
|
||||
" ((a1-1 (-> arg1 data)))\n"
|
||||
" (while\n"
|
||||
" (nonzero? (-> a1-1 0))\n"
|
||||
" (set! (-> v1-0 0) (-> a1-1 0))\n"
|
||||
" (set! v1-0 (&-> v1-0 1))\n"
|
||||
" (set! a1-1 (&-> a1-1 1))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> v1-0 0) 0)\n"
|
||||
" )\n"
|
||||
" (set! (-> v1-0 0) 0)\n"
|
||||
" arg0\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "");
|
||||
|
@ -2485,21 +2487,23 @@ TEST_F(FormRegressionTest, StringLt) {
|
|||
std::string type = "(function string string symbol)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set!\n"
|
||||
" s4-1\n"
|
||||
" (min\n"
|
||||
" ((method-of-type string length) arg0)\n"
|
||||
" ((method-of-type string length) arg1)\n"
|
||||
" (let\n"
|
||||
" ((s4-1\n"
|
||||
" (min\n"
|
||||
" ((method-of-type string length) arg0)\n"
|
||||
" ((method-of-type string length) arg1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (v1-4 0)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! v1-4 0)\n"
|
||||
" (while\n"
|
||||
" (< v1-4 s4-1)\n"
|
||||
" (cond\n"
|
||||
" ((< (-> arg0 data v1-4) (-> arg1 data v1-4)) (return #t))\n"
|
||||
" ((< (-> arg1 data v1-4) (-> arg0 data v1-4)) (return #f))\n"
|
||||
" (while\n"
|
||||
" (< v1-4 s4-1)\n"
|
||||
" (cond\n"
|
||||
" ((< (-> arg0 data v1-4) (-> arg1 data v1-4)) (return #t))\n"
|
||||
" ((< (-> arg1 data v1-4) (-> arg0 data v1-4)) (return #f))\n"
|
||||
" )\n"
|
||||
" (+! v1-4 1)\n"
|
||||
" )\n"
|
||||
" (+! v1-4 1)\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )";
|
||||
|
@ -2567,8 +2571,8 @@ TEST_F(FormRegressionTest, ExprTerminal2) {
|
|||
std::string type = "(function float float float float float)";
|
||||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! f0-4 (sqrt (/ (- (* 0.000000 arg0) arg1) arg2)))\n"
|
||||
"(let\n"
|
||||
" ((f0-4 (sqrt (/ (- (* 0.0 arg0) arg1) arg2))))\n"
|
||||
" (- f0-4 (+ arg1 (* arg2 (* f0-4 f0-4))))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {{"L17", "A ~A"}});
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -62,10 +62,12 @@ TEST_F(FormRegressionTest, ExprLoadPackage) {
|
|||
std::string expected =
|
||||
"(when\n"
|
||||
" (not (nmember arg0 *kernel-packages*))\n"
|
||||
" (dgo-load arg0 arg1 15 2097152)\n"
|
||||
" (set! v0-1 (cons arg0 *kernel-packages*))\n"
|
||||
" (set! *kernel-packages* v0-1)\n"
|
||||
" v0-1\n"
|
||||
" (dgo-load arg0 arg1 15 #x200000)\n"
|
||||
" (let\n"
|
||||
" ((v0-1 (cons arg0 *kernel-packages*)))\n"
|
||||
" (set! *kernel-packages* v0-1)\n"
|
||||
" v0-1\n"
|
||||
" )\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
@ -100,8 +102,10 @@ TEST_F(FormRegressionTest, ExprUnloadPackage) {
|
|||
std::string type = "(function string pair)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 (nmember arg0 *kernel-packages*))\n"
|
||||
" (if v1-0 (set! *kernel-packages* (delete! (car v1-0) *kernel-packages*)))\n"
|
||||
" (let\n"
|
||||
" ((v1-0 (nmember arg0 *kernel-packages*)))\n"
|
||||
" (if v1-0 (set! *kernel-packages* (delete! (car v1-0) *kernel-packages*)))\n"
|
||||
" )\n"
|
||||
" *kernel-packages*\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, true);
|
||||
|
@ -128,7 +132,7 @@ TEST_F(FormRegressionTest, ExprMethod1Thread) {
|
|||
std::string type = "(function thread none)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (when (= arg0 (-> arg0 process main-thread)) (break!) (set! v1-3 0))\n"
|
||||
" (when (= arg0 (-> arg0 process main-thread)) (break!) (let ((v1-3 0))))\n"
|
||||
" (set! (-> arg0 process top-thread) (-> arg0 previous))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false);
|
||||
|
@ -253,26 +257,28 @@ TEST_F(FormRegressionTest, ExprMethod9Thread) {
|
|||
std::string type = "(function thread int none)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! a2-0 (-> arg0 process))\n"
|
||||
" (cond\n"
|
||||
" ((!= arg0 (-> a2-0 main-thread)) (format 0 \"1 ~A ~%\" a2-0))\n"
|
||||
" ((= (-> arg0 stack-size) arg1))\n"
|
||||
" ((=\n"
|
||||
" (-> a2-0 heap-cur)\n"
|
||||
" (+\n"
|
||||
" (+ (+ (-> arg0 stack-size) -4) (the-as int (-> arg0 type size)))\n"
|
||||
" (the-as int arg0)\n"
|
||||
" (let\n"
|
||||
" ((a2-0 (-> arg0 process)))\n"
|
||||
" (cond\n"
|
||||
" ((!= arg0 (-> a2-0 main-thread)) (format 0 \"1 ~A ~%\" a2-0))\n"
|
||||
" ((= (-> arg0 stack-size) arg1))\n"
|
||||
" ((=\n"
|
||||
" (-> a2-0 heap-cur)\n"
|
||||
" (+\n"
|
||||
" (+ (+ (-> arg0 stack-size) -4) (the-as int (-> arg0 type size)))\n"
|
||||
" (the-as int arg0)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set!\n"
|
||||
" (-> a2-0 heap-cur)\n"
|
||||
" (+ (+ (+ arg1 -4) (the-as int (-> arg0 type size))) (the-as int arg0))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 stack-size) arg1)\n"
|
||||
" )\n"
|
||||
" (set!\n"
|
||||
" (-> a2-0 heap-cur)\n"
|
||||
" (+ (+ (+ arg1 -4) (the-as int (-> arg0 type size))) (the-as int arg0))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 stack-size) arg1)\n"
|
||||
" (else (format 0 \"2 ~A ~%\" a2-0))\n"
|
||||
" )\n"
|
||||
" (else (format 0 \"2 ~A ~%\" a2-0))\n"
|
||||
" )\n"
|
||||
" (set! v0-2 0)\n"
|
||||
" (let ((v0-2 0)))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {{"L342", "1 ~A ~%"}, {"L341", "2 ~A ~%"}});
|
||||
}
|
||||
|
@ -319,18 +325,16 @@ TEST_F(FormRegressionTest, ExprMethod0Thread) {
|
|||
" daddu sp, sp, r0";
|
||||
std::string type = "(function symbol type process symbol int pointer thread)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set!\n"
|
||||
" v0-0\n"
|
||||
" (cond\n"
|
||||
" ((-> arg2 top-thread) (&+ arg5 -7164))\n"
|
||||
" (else\n"
|
||||
" (set!\n"
|
||||
" v1-2\n"
|
||||
" (logand -16 (the-as int (&+ (-> arg2 heap-cur) 15)))\n"
|
||||
"(let\n"
|
||||
" ((v0-0\n"
|
||||
" (if\n"
|
||||
" (-> arg2 top-thread)\n"
|
||||
" (&+ arg5 -7164)\n"
|
||||
" (let\n"
|
||||
" ((v1-2 (logand -16 (the-as int (&+ (-> arg2 heap-cur) 15)))))\n"
|
||||
" (set! (-> arg2 heap-cur) (+ (+ v1-2 (the-as int (-> arg1 size))) arg4))\n"
|
||||
" (+ v1-2 4)\n"
|
||||
" )\n"
|
||||
" (set! (-> arg2 heap-cur) (+ (+ v1-2 (the-as int (-> arg1 size))) arg4))\n"
|
||||
" (+ v1-2 4)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -341,7 +345,6 @@ TEST_F(FormRegressionTest, ExprMethod0Thread) {
|
|||
" (set! (-> v0-0 stack-top) arg5)\n"
|
||||
" (set! (-> v0-0 previous) (-> arg2 top-thread))\n"
|
||||
" (set! (-> arg2 top-thread) v0-0)\n"
|
||||
// TODO - we could make this method access nicer.
|
||||
" (set! (-> v0-0 suspend-hook) (method-of-object v0-0 thread-suspend))\n"
|
||||
" (set! (-> v0-0 resume-hook) (method-of-object v0-0 thread-resume))\n"
|
||||
" (set! (-> v0-0 stack-size) arg4)\n"
|
||||
|
@ -383,11 +386,13 @@ TEST_F(FormRegressionTest, RemoveExit) {
|
|||
" daddu sp, sp, r0";
|
||||
std::string type = "(function stack-frame)";
|
||||
std::string expected =
|
||||
"(when\n"
|
||||
"(if\n"
|
||||
" (-> pp stack-frame-top)\n"
|
||||
" (set! v0-0 (-> pp stack-frame-top next))\n"
|
||||
" (set! (-> pp stack-frame-top) v0-0)\n"
|
||||
" v0-0\n"
|
||||
" (let\n"
|
||||
" ((v0-0 (-> pp stack-frame-top next)))\n"
|
||||
" (set! (-> pp stack-frame-top) v0-0)\n"
|
||||
" v0-0\n"
|
||||
" )\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false);
|
||||
}
|
||||
|
@ -423,8 +428,8 @@ TEST_F(FormRegressionTest, RemoveMethod0ProcessTree) {
|
|||
" daddiu sp, sp, 32";
|
||||
std::string type = "(function symbol type basic process-tree)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v0-0 (object-new arg0 arg1 (the-as int (-> arg1 size))))\n"
|
||||
"(let\n"
|
||||
" ((v0-0 (object-new arg0 arg1 (the-as int (-> arg1 size)))))\n"
|
||||
" (set! (-> v0-0 name) arg2)\n"
|
||||
" (set! (-> v0-0 mask) 256)\n"
|
||||
" (set! (-> v0-0 parent) #f)\n"
|
||||
|
@ -525,21 +530,18 @@ TEST_F(FormRegressionTest, RemoveMethod3ProcessTree) {
|
|||
" (format #t \"[~8x] ~A~%\" arg0 (-> arg0 type))\n"
|
||||
" (format #t \"~Tname: ~S~%\" (-> arg0 name))\n"
|
||||
" (format #t \"~Tmask: #x~X~%\" (-> arg0 mask))\n"
|
||||
" (set! t9-3 format)\n"
|
||||
" (set! a0-4 #t)\n"
|
||||
" (set! a1-3 \"~Tparent: ~A~%\")\n"
|
||||
" (set! v1-0 (-> arg0 parent))\n"
|
||||
" (t9-3 a0-4 a1-3 (if v1-0 (-> v1-0 0 self)))\n"
|
||||
" (set! t9-4 format)\n"
|
||||
" (set! a0-5 #t)\n"
|
||||
" (set! a1-4 \"~Tbrother: ~A~%\")\n"
|
||||
" (set! v1-2 (-> arg0 brother))\n"
|
||||
" (t9-4 a0-5 a1-4 (if v1-2 (-> v1-2 0 self)))\n"
|
||||
" (set! t9-5 format)\n"
|
||||
" (set! a0-6 #t)\n"
|
||||
" (set! a1-5 \"~Tchild: ~A~%\")\n"
|
||||
" (set! v1-4 (-> arg0 child))\n"
|
||||
" (t9-5 a0-6 a1-5 (if v1-4 (-> v1-4 0 self)))\n"
|
||||
" (let\n"
|
||||
" ((t9-3 format) (a0-4 #t) (a1-3 \"~Tparent: ~A~%\") (v1-0 (-> arg0 parent)))\n"
|
||||
" (t9-3 a0-4 a1-3 (if v1-0 (-> v1-0 0 self)))\n"
|
||||
" )\n"
|
||||
" (let\n"
|
||||
" ((t9-4 format) (a0-5 #t) (a1-4 \"~Tbrother: ~A~%\") (v1-2 (-> arg0 brother)))\n"
|
||||
" (t9-4 a0-5 a1-4 (if v1-2 (-> v1-2 0 self)))\n"
|
||||
" )\n"
|
||||
" (let\n"
|
||||
" ((t9-5 format) (a0-6 #t) (a1-5 \"~Tchild: ~A~%\") (v1-4 (-> arg0 child)))\n"
|
||||
" (t9-5 a0-6 a1-5 (if v1-4 (-> v1-4 0 self)))\n"
|
||||
" )\n"
|
||||
" arg0\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "process-tree",
|
||||
|
@ -619,13 +621,17 @@ TEST_F(FormRegressionTest, ExprMethod0Process) {
|
|||
" daddiu sp, sp, 48";
|
||||
std::string type = "(function symbol type basic int process)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set!\n"
|
||||
" v0-0\n"
|
||||
" (if\n"
|
||||
" (= (-> arg0 type) symbol)\n"
|
||||
" (object-new arg0 arg1 (the-as int (+ (-> process size) (the-as uint arg3))))\n"
|
||||
" (+ (the-as int arg0) 4)\n"
|
||||
"(let\n"
|
||||
" ((v0-0\n"
|
||||
" (if\n"
|
||||
" (= (-> arg0 type) symbol)\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
" (the-as int (+ (-> process size) (the-as uint arg3)))\n"
|
||||
" )\n"
|
||||
" (+ (the-as int arg0) 4)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> (the-as process v0-0) name) arg2)\n"
|
||||
|
@ -635,9 +641,11 @@ TEST_F(FormRegressionTest, ExprMethod0Process) {
|
|||
" (set! (-> v0-0 allocated-length) arg3)\n"
|
||||
" (set! (-> v0-0 top-thread) #f)\n"
|
||||
" (set! (-> v0-0 main-thread) #f)\n"
|
||||
" (set! v1-5 (-> v0-0 stack))\n"
|
||||
" (set! (-> v0-0 heap-cur) v1-5)\n"
|
||||
" (set! (-> v0-0 heap-base) v1-5)\n"
|
||||
" (let\n"
|
||||
" ((v1-5 (-> v0-0 stack)))\n"
|
||||
" (set! (-> v0-0 heap-cur) v1-5)\n"
|
||||
" (set! (-> v0-0 heap-base) v1-5)\n"
|
||||
" )\n"
|
||||
" (set! (-> v0-0 heap-top) (&-> v0-0 stack (-> v0-0 allocated-length)))\n"
|
||||
" (set! (-> v0-0 stack-frame-top) (-> v0-0 heap-top))\n"
|
||||
" (set! (-> v0-0 stack-frame-top) #f)\n"
|
||||
|
@ -711,15 +719,16 @@ TEST_F(FormRegressionTest, ExprInspectProcessHeap) {
|
|||
std::string type = "(function process symbol)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s5-0 (&+ (-> arg0 heap-base) 4))\n"
|
||||
" (while\n"
|
||||
" (< (the-as int s5-0) (the-as int (-> arg0 heap-cur)))\n"
|
||||
" (inspect (the-as basic s5-0))\n"
|
||||
" (+! (the-as int s5-0) (logand -16 (+ (asize-of s5-0) 15)))\n"
|
||||
" (let\n"
|
||||
" ((s5-0 (&+ (-> arg0 heap-base) 4)))\n"
|
||||
" (while\n"
|
||||
" (< (the-as int s5-0) (the-as int (-> arg0 heap-cur)))\n"
|
||||
" (inspect (the-as basic s5-0))\n"
|
||||
" (+! (the-as int s5-0) (logand -16 (+ (asize-of s5-0) 15)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" #f\n"
|
||||
" )\n"
|
||||
"";
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {},
|
||||
parse_hint_json("[\t\t[4, [\"s5\", \"basic\"]],\n"
|
||||
"\t\t[17, [\"s5\", \"int\"]]]"));
|
||||
|
@ -914,8 +923,8 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPool) {
|
|||
" daddiu sp, sp, 112";
|
||||
std::string type = "(function symbol type int int basic dead-pool)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s3-0 (object-new arg0 arg1 (the-as int (-> arg1 size))))\n"
|
||||
"(let\n"
|
||||
" ((s3-0 (object-new arg0 arg1 (the-as int (-> arg1 size)))))\n"
|
||||
" (set! (-> s3-0 name) arg4)\n"
|
||||
" (set! (-> s3-0 mask) 256)\n"
|
||||
" (set! (-> s3-0 parent) #f)\n"
|
||||
|
@ -923,18 +932,21 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPool) {
|
|||
" (set! (-> s3-0 child) #f)\n"
|
||||
" (set! (-> s3-0 self) s3-0)\n"
|
||||
" (set! (-> s3-0 ppointer) (&-> s3-0 self))\n"
|
||||
" (set! s2-1 0)\n"
|
||||
" (while\n"
|
||||
" (< s2-1 arg2)\n"
|
||||
" (set! s1-0 (-> s3-0 child))\n"
|
||||
" (set! v1-5 ((method-of-type process new) arg0 process (quote dead) arg3))\n"
|
||||
" (set! a0-3 v1-5)\n"
|
||||
" (set! (-> s3-0 child) (if a0-3 (-> a0-3 ppointer)))\n"
|
||||
" (set! a0-4 s3-0)\n"
|
||||
" (set! (-> v1-5 parent) (if a0-4 (-> a0-4 ppointer)))\n"
|
||||
" (set! (-> v1-5 pool) s3-0)\n"
|
||||
" (set! (-> v1-5 brother) s1-0)\n"
|
||||
" (+! s2-1 1)\n"
|
||||
" (let\n"
|
||||
" ((s2-1 0))\n"
|
||||
" (while\n"
|
||||
" (< s2-1 arg2)\n"
|
||||
" (let\n"
|
||||
" ((s1-0 (-> s3-0 child))\n"
|
||||
" (v1-5 ((method-of-type process new) arg0 process (quote dead) arg3))\n"
|
||||
" )\n"
|
||||
" (let ((a0-3 v1-5)) (set! (-> s3-0 child) (if a0-3 (-> a0-3 ppointer))))\n"
|
||||
" (let ((a0-4 s3-0)) (set! (-> v1-5 parent) (if a0-4 (-> a0-4 ppointer))))\n"
|
||||
" (set! (-> v1-5 pool) s3-0)\n"
|
||||
" (set! (-> v1-5 brother) s1-0)\n"
|
||||
" )\n"
|
||||
" (+! s2-1 1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" s3-0\n"
|
||||
" )";
|
||||
|
@ -1039,28 +1051,31 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPool) {
|
|||
" jr ra\n"
|
||||
" daddiu sp, sp, 64";
|
||||
std::string type = "(function dead-pool type int process)";
|
||||
// todo - why does one work but not the other??
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s4-0 (-> arg0 child))\n"
|
||||
"(let\n"
|
||||
" ((s4-0 (-> arg0 child)))\n"
|
||||
" (when\n"
|
||||
" (and (not s4-0) *debug-segment* (!= arg0 *debug-dead-pool*))\n"
|
||||
" (set! s4-0 (get-process *debug-dead-pool* arg1 arg2))\n"
|
||||
" (when\n"
|
||||
" (if\n"
|
||||
" s4-0\n"
|
||||
" (set! t9-1 format)\n"
|
||||
" (set! a0-2 0)\n"
|
||||
" (set!\n"
|
||||
" a1-2\n"
|
||||
" \"WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%\"\n"
|
||||
" )\n"
|
||||
" (set! a2-1 arg1)\n"
|
||||
" (set! v1-6 s4-0)\n"
|
||||
" (t9-1\n"
|
||||
" a0-2\n"
|
||||
" a1-2\n"
|
||||
" a2-1\n"
|
||||
" (if v1-6 (-> (the-as (pointer process-tree) v1-6) 0 self))\n"
|
||||
" (-> arg0 name)\n"
|
||||
" (let\n"
|
||||
" ((t9-1 format)\n"
|
||||
" (a0-2 0)\n"
|
||||
" (a1-2\n"
|
||||
" \"WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%\"\n"
|
||||
" )\n"
|
||||
" (a2-1 arg1)\n"
|
||||
" (v1-6 s4-0)\n"
|
||||
" )\n"
|
||||
" (t9-1\n"
|
||||
" a0-2\n"
|
||||
" a1-2\n"
|
||||
" a2-1\n"
|
||||
" (if v1-6 (-> (the-as (pointer process-tree) v1-6) 0 self))\n"
|
||||
" (-> arg0 name)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -1214,17 +1229,17 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) {
|
|||
" daddiu sp, sp, 64";
|
||||
std::string type = "(function symbol type basic int int dead-pool-heap)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set!\n"
|
||||
" v0-0\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
" (the-as\n"
|
||||
" int\n"
|
||||
" (+\n"
|
||||
" (+ (-> arg1 size) (the-as uint (logand -16 (+ (* 12 arg3) 15))))\n"
|
||||
" (the-as uint arg4)\n"
|
||||
"(let\n"
|
||||
" ((v0-0\n"
|
||||
" (object-new\n"
|
||||
" arg0\n"
|
||||
" arg1\n"
|
||||
" (the-as\n"
|
||||
" int\n"
|
||||
" (+\n"
|
||||
" (+ (-> arg1 size) (the-as uint (logand -16 (+ (* 12 arg3) 15))))\n"
|
||||
" (the-as uint arg4)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -1237,13 +1252,17 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) {
|
|||
" (set! (-> v0-0 child) #f)\n"
|
||||
" (set! (-> v0-0 self) v0-0)\n"
|
||||
" (set! (-> v0-0 ppointer) (&-> v0-0 self))\n"
|
||||
" (set! v1-4 arg3)\n"
|
||||
" (while\n"
|
||||
" (nonzero? v1-4)\n"
|
||||
" (+! v1-4 -1)\n"
|
||||
" (set! a0-4 (-> v0-0 process-list v1-4))\n"
|
||||
" (set! (-> a0-4 process) *null-process*)\n"
|
||||
" (set! (-> a0-4 next) (-> v0-0 process-list (+ v1-4 1)))\n"
|
||||
" (let\n"
|
||||
" ((v1-4 arg3))\n"
|
||||
" (while\n"
|
||||
" (nonzero? v1-4)\n"
|
||||
" (+! v1-4 -1)\n"
|
||||
" (let\n"
|
||||
" ((a0-4 (-> v0-0 process-list v1-4)))\n"
|
||||
" (set! (-> a0-4 process) *null-process*)\n"
|
||||
" (set! (-> a0-4 next) (-> v0-0 process-list (+ v1-4 1)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> v0-0 dead-list next) (-> v0-0 process-list))\n"
|
||||
" (set! (-> v0-0 alive-list process) #f)\n"
|
||||
|
@ -1255,10 +1274,7 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) {
|
|||
" (set! (-> v0-0 first-shrink) #f)\n"
|
||||
" (set!\n"
|
||||
" (-> v0-0 heap base)\n"
|
||||
" (logand\n"
|
||||
" -16\n"
|
||||
" (the-as int (&+ (+ (the-as int v0-0) 115) (* 12 arg3)))\n"
|
||||
" )\n"
|
||||
" (logand -16 (the-as int (&+ (+ (the-as int v0-0) 115) (* 12 arg3))))\n"
|
||||
" )\n"
|
||||
" (set! (-> v0-0 heap current) (-> v0-0 heap base))\n"
|
||||
" (set! (-> v0-0 heap top) (&+ (-> v0-0 heap base) arg4))\n"
|
||||
|
@ -1364,13 +1380,14 @@ TEST_F(FormRegressionTest, ExprMethod21DeadPoolHeap) {
|
|||
" daddu sp, sp, r0";
|
||||
std::string type = "(function dead-pool-heap dead-pool-heap-rec int)";
|
||||
std::string expected =
|
||||
"(cond\n"
|
||||
" ((-> arg1 process)\n"
|
||||
" (set!\n"
|
||||
" v1-3\n"
|
||||
" (&+\n"
|
||||
" (&+ (-> arg1 process) (-> process size))\n"
|
||||
" (-> arg1 process allocated-length)\n"
|
||||
"(if\n"
|
||||
" (-> arg1 process)\n"
|
||||
" (let\n"
|
||||
" ((v1-3\n"
|
||||
" (&+\n"
|
||||
" (&+ (-> arg1 process) (-> process size))\n"
|
||||
" (-> arg1 process allocated-length)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (if\n"
|
||||
|
@ -1379,15 +1396,10 @@ TEST_F(FormRegressionTest, ExprMethod21DeadPoolHeap) {
|
|||
" (- (-> arg0 heap top) (the-as uint (&+ v1-3 4)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (if\n"
|
||||
" (-> arg1 next)\n"
|
||||
" (-\n"
|
||||
" (-> arg1 next process)\n"
|
||||
" (the-as uint (&+ (-> arg0 heap base) 4))\n"
|
||||
" )\n"
|
||||
" (- (-> arg0 heap top) (the-as uint (-> arg0 heap base)))\n"
|
||||
" )\n"
|
||||
" (if\n"
|
||||
" (-> arg1 next)\n"
|
||||
" (- (-> arg1 next process) (the-as uint (&+ (-> arg0 heap base) 4)))\n"
|
||||
" (- (-> arg0 heap top) (the-as uint (-> arg0 heap base)))\n"
|
||||
" )\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {},
|
||||
|
@ -1524,44 +1536,48 @@ TEST_F(FormRegressionTest, ExprMethod3DeadPoolHeap) {
|
|||
std::string type = "(function dead-pool-heap dead-pool-heap)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s5-0 (- (-> arg0 heap top) (the-as uint (-> arg0 heap base))))\n"
|
||||
" (set!\n"
|
||||
" v1-3\n"
|
||||
" (if (-> arg0 alive-list prev) (gap-size arg0 (-> arg0 alive-list prev)) s5-0)\n"
|
||||
" (let*\n"
|
||||
" ((s5-0 (- (-> arg0 heap top) (the-as uint (-> arg0 heap base))))\n"
|
||||
" (v1-3\n"
|
||||
" (if\n"
|
||||
" (-> arg0 alive-list prev)\n"
|
||||
" (gap-size arg0 (-> arg0 alive-list prev))\n"
|
||||
" s5-0\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (format\n"
|
||||
" #t\n"
|
||||
" \"~Tprocess-list[0] @ #x~X ~D/~D bytes used~%\"\n"
|
||||
" (-> arg0 process-list)\n"
|
||||
" (- s5-0 v1-3)\n"
|
||||
" s5-0\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (format\n"
|
||||
" #t\n"
|
||||
" \"~Tprocess-list[0] @ #x~X ~D/~D bytes used~%\"\n"
|
||||
" (-> arg0 process-list)\n"
|
||||
" (- s5-0 v1-3)\n"
|
||||
" s5-0\n"
|
||||
" )\n"
|
||||
" (set! s5-1 (-> arg0 alive-list))\n"
|
||||
" (set! s4-0 0)\n"
|
||||
" (while\n"
|
||||
" s5-1\n"
|
||||
" (if\n"
|
||||
" (-> s5-1 process)\n"
|
||||
" (format\n"
|
||||
" #t\n"
|
||||
" \"~T [~3D] #<dead-pool-heap-rec @ #x~X> ~A~%\"\n"
|
||||
" s4-0\n"
|
||||
" s5-1\n"
|
||||
" (let\n"
|
||||
" ((s5-1 (-> arg0 alive-list)) (s4-0 0))\n"
|
||||
" (while\n"
|
||||
" s5-1\n"
|
||||
" (if\n"
|
||||
" (-> s5-1 process)\n"
|
||||
" (format\n"
|
||||
" #t\n"
|
||||
" \"~T [~3D] #<dead-pool-heap-rec @ #x~X> ~A~%\"\n"
|
||||
" s4-0\n"
|
||||
" s5-1\n"
|
||||
" (-> s5-1 process)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! s3-0 (gap-size arg0 s5-1))\n"
|
||||
" (if\n"
|
||||
" (nonzero? s3-0)\n"
|
||||
" (format\n"
|
||||
" #t\n"
|
||||
" \"~T gap: ~D bytes @ #x~X~%\"\n"
|
||||
" s3-0\n"
|
||||
" (gap-location arg0 s5-1)\n"
|
||||
" (let\n"
|
||||
" ((s3-0 (gap-size arg0 s5-1)))\n"
|
||||
" (if\n"
|
||||
" (nonzero? s3-0)\n"
|
||||
" (format #t \"~T gap: ~D bytes @ #x~X~%\" s3-0 (gap-location arg0 s5-1))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! s5-1 (-> s5-1 next))\n"
|
||||
" (+! s4-0 1)\n"
|
||||
" )\n"
|
||||
" (set! s5-1 (-> s5-1 next))\n"
|
||||
" (+! s4-0 1)\n"
|
||||
" )\n"
|
||||
" arg0\n"
|
||||
" )";
|
||||
|
@ -1683,8 +1699,8 @@ TEST_F(FormRegressionTest, ExprMethod25DeadPoolHeap) {
|
|||
" daddiu sp, sp, 16";
|
||||
std::string type = "(function dead-pool-heap int)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! v1-0 (-> arg0 heap top))\n"
|
||||
"(let\n"
|
||||
" ((v1-0 (-> arg0 heap top)))\n"
|
||||
" (if\n"
|
||||
" (-> arg0 alive-list prev)\n"
|
||||
" (gap-size arg0 (-> arg0 alive-list prev))\n"
|
||||
|
@ -1754,8 +1770,8 @@ TEST_F(FormRegressionTest, ExprMethod24DeadPoolHeap) {
|
|||
" daddiu sp, sp, 64";
|
||||
std::string type = "(function dead-pool-heap int dead-pool-heap-rec)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! gp-0 (-> arg0 first-gap))\n"
|
||||
"(let\n"
|
||||
" ((gp-0 (-> arg0 first-gap)))\n"
|
||||
" (while (and gp-0 (< (gap-size arg0 gp-0) arg1)) (set! gp-0 (-> gp-0 next)))\n"
|
||||
" gp-0\n"
|
||||
" )";
|
||||
|
@ -1966,63 +1982,69 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPoolHeap) {
|
|||
" daddiu sp, sp, 112";
|
||||
std::string type = "(function dead-pool-heap type int process)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s4-0 (-> arg0 dead-list next))\n"
|
||||
" (set! s3-0 #f)\n"
|
||||
" (set! s1-0 (find-gap-by-size arg0 (+ (-> process size) (the-as uint arg2))))\n"
|
||||
" (cond\n"
|
||||
" ((and s4-0 s1-0)\n"
|
||||
" (set! (-> arg0 dead-list next) (-> s4-0 next))\n"
|
||||
" (set! v1-5 (-> s1-0 next))\n"
|
||||
" (set! (-> s1-0 next) s4-0)\n"
|
||||
" (set! (-> s4-0 next) v1-5)\n"
|
||||
" (when v1-5 (set! (-> v1-5 prev) s4-0) (set! v1-6 s4-0))\n"
|
||||
" (set! (-> s4-0 prev) s1-0)\n"
|
||||
" (when\n"
|
||||
" (= s1-0 (-> arg0 alive-list prev))\n"
|
||||
" (set! (-> arg0 alive-list prev) s4-0)\n"
|
||||
" (set! v1-9 s4-0)\n"
|
||||
" )\n"
|
||||
" (set! a0-4 (gap-location arg0 s1-0))\n"
|
||||
" (set!\n"
|
||||
" s3-0\n"
|
||||
" ((method-of-type process new)\n"
|
||||
" (the-as symbol a0-4)\n"
|
||||
" process\n"
|
||||
" (quote process)\n"
|
||||
" arg2\n"
|
||||
"(let\n"
|
||||
" ((s4-0 (-> arg0 dead-list next)) (s3-0 #f))\n"
|
||||
" (let\n"
|
||||
" ((s1-0 (find-gap-by-size arg0 (+ (-> process size) (the-as uint arg2)))))\n"
|
||||
" (cond\n"
|
||||
" ((and s4-0 s1-0)\n"
|
||||
" (set! (-> arg0 dead-list next) (-> s4-0 next))\n"
|
||||
" (let\n"
|
||||
" ((v1-5 (-> s1-0 next)))\n"
|
||||
" (set! (-> s1-0 next) s4-0)\n"
|
||||
" (set! (-> s4-0 next) v1-5)\n"
|
||||
" (when v1-5 (set! (-> v1-5 prev) s4-0) (let ((v1-6 s4-0))))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> s4-0 process) s3-0)\n"
|
||||
" (set! (-> s3-0 ppointer) (&-> s4-0 process))\n"
|
||||
" (if\n"
|
||||
" (= (-> arg0 first-gap) s1-0)\n"
|
||||
" (set! (-> arg0 first-gap) (find-gap arg0 s4-0))\n"
|
||||
" )\n"
|
||||
" (when\n"
|
||||
" (or\n"
|
||||
" (not (-> arg0 first-shrink))\n"
|
||||
" (< (the-as int s3-0) (the-as int (-> arg0 first-shrink process)))\n"
|
||||
" (set! (-> s4-0 prev) s1-0)\n"
|
||||
" (when\n"
|
||||
" (= s1-0 (-> arg0 alive-list prev))\n"
|
||||
" (set! (-> arg0 alive-list prev) s4-0)\n"
|
||||
" (let ((v1-9 s4-0)))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 first-shrink) s4-0)\n"
|
||||
" (set! v1-22 s4-0)\n"
|
||||
" )\n"
|
||||
" (set! (-> s3-0 parent) (-> arg0 ppointer))\n"
|
||||
" (set! (-> s3-0 pool) arg0)\n"
|
||||
" (set! (-> arg0 child) (&-> s4-0 process))\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (when\n"
|
||||
" (and *debug-segment* (!= arg0 *debug-dead-pool*))\n"
|
||||
" (set! s3-0 (get-process *debug-dead-pool* arg1 arg2))\n"
|
||||
" (if\n"
|
||||
" (and s3-0 *vis-boot*)\n"
|
||||
" (format\n"
|
||||
" 0\n"
|
||||
" \"WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%\"\n"
|
||||
" arg1\n"
|
||||
" (let\n"
|
||||
" ((a0-4 (gap-location arg0 s1-0)))\n"
|
||||
" (set!\n"
|
||||
" s3-0\n"
|
||||
" (-> arg0 name)\n"
|
||||
" ((method-of-type process new)\n"
|
||||
" (the-as symbol a0-4)\n"
|
||||
" process\n"
|
||||
" (quote process)\n"
|
||||
" arg2\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> s4-0 process) s3-0)\n"
|
||||
" (set! (-> s3-0 ppointer) (&-> s4-0 process))\n"
|
||||
" (if\n"
|
||||
" (= (-> arg0 first-gap) s1-0)\n"
|
||||
" (set! (-> arg0 first-gap) (find-gap arg0 s4-0))\n"
|
||||
" )\n"
|
||||
" (when\n"
|
||||
" (or\n"
|
||||
" (not (-> arg0 first-shrink))\n"
|
||||
" (< (the-as int s3-0) (the-as int (-> arg0 first-shrink process)))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 first-shrink) s4-0)\n"
|
||||
" (let ((v1-22 s4-0)))\n"
|
||||
" )\n"
|
||||
" (set! (-> s3-0 parent) (-> arg0 ppointer))\n"
|
||||
" (set! (-> s3-0 pool) arg0)\n"
|
||||
" (set! (-> arg0 child) (&-> s4-0 process))\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (when\n"
|
||||
" (and *debug-segment* (!= arg0 *debug-dead-pool*))\n"
|
||||
" (set! s3-0 (get-process *debug-dead-pool* arg1 arg2))\n"
|
||||
" (if\n"
|
||||
" (and s3-0 *vis-boot*)\n"
|
||||
" (format\n"
|
||||
" 0\n"
|
||||
" \"WARNING: ~A ~A had to be allocated from the debug pool, because ~A was "
|
||||
"empty.~%\"\n"
|
||||
" arg1\n"
|
||||
" s3-0\n"
|
||||
" (-> arg0 name)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -2180,35 +2202,34 @@ TEST_F(FormRegressionTest, ExprMethod15DeadPoolHeap) {
|
|||
" )\n"
|
||||
" (change-parent arg1 arg0)\n"
|
||||
" (set! (-> arg0 child) #f)\n"
|
||||
" (set! s5-1 (-> arg1 ppointer))\n"
|
||||
" (if\n"
|
||||
" (or\n"
|
||||
" (= (-> arg0 first-gap) s5-1)\n"
|
||||
" (<\n"
|
||||
" (the-as int (gap-location arg0 s5-1))\n"
|
||||
" (the-as int (gap-location arg0 (-> arg0 first-gap)))\n"
|
||||
" (let\n"
|
||||
" ((s5-1 (-> arg1 ppointer)))\n"
|
||||
" (if\n"
|
||||
" (or\n"
|
||||
" (= (-> arg0 first-gap) s5-1)\n"
|
||||
" (<\n"
|
||||
" (the-as int (gap-location arg0 s5-1))\n"
|
||||
" (the-as int (gap-location arg0 (-> arg0 first-gap)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 first-gap) (-> s5-1 1))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 first-gap) (-> s5-1 1))\n"
|
||||
" )\n"
|
||||
" (when\n"
|
||||
" (= (-> arg0 first-shrink) s5-1)\n"
|
||||
" (set! (-> arg0 first-shrink) (-> s5-1 1))\n"
|
||||
" (when\n"
|
||||
" (not (-> arg0 first-shrink process))\n"
|
||||
" (set! (-> arg0 first-shrink) #f)\n"
|
||||
" (= (-> arg0 first-shrink) s5-1)\n"
|
||||
" (set! (-> arg0 first-shrink) (-> s5-1 1))\n"
|
||||
" (when (not (-> arg0 first-shrink process)) (set! (-> arg0 first-shrink) #f))\n"
|
||||
" )\n"
|
||||
" (set! (-> s5-1 1 parent) (-> s5-1 2))\n"
|
||||
" (if\n"
|
||||
" (-> s5-1 2)\n"
|
||||
" (set! (-> s5-1 2 mask) (-> s5-1 1))\n"
|
||||
" (set! (-> arg0 alive-list prev) (-> s5-1 1))\n"
|
||||
" )\n"
|
||||
" (set! (-> s5-1 2) (-> arg0 dead-list next))\n"
|
||||
" (set! (-> arg0 dead-list next) s5-1)\n"
|
||||
" (set! (-> s5-1 0) *null-process*)\n"
|
||||
" )\n"
|
||||
" (set! (-> s5-1 1 parent) (-> s5-1 2))\n"
|
||||
" (if\n"
|
||||
" (-> s5-1 2)\n"
|
||||
" (set! (-> s5-1 2 mask) (-> s5-1 1))\n"
|
||||
" (set! (-> arg0 alive-list prev) (-> s5-1 1))\n"
|
||||
" )\n"
|
||||
" (set! (-> s5-1 2) (-> arg0 dead-list next))\n"
|
||||
" (set! (-> arg0 dead-list next) s5-1)\n"
|
||||
" (set! (-> s5-1 0) *null-process*)\n"
|
||||
" (set! v0-4 0)\n"
|
||||
" (let ((v0-4 0)))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "",
|
||||
{{"L297", "ERROR: process ~A does not belong to dead-pool-heap ~A.~%"}});
|
||||
|
@ -2305,30 +2326,32 @@ TEST_F(FormRegressionTest, ExprMethod17DeadPoolHeap) {
|
|||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (when\n"
|
||||
" (if\n"
|
||||
" arg1\n"
|
||||
" (set! s5-0 (-> arg1 ppointer))\n"
|
||||
" (when\n"
|
||||
" (not\n"
|
||||
" (or\n"
|
||||
" (nonzero? (logand (-> arg1 mask) 512))\n"
|
||||
" (and (not (-> arg1 next-state)) (not (-> arg1 state)))\n"
|
||||
" (let\n"
|
||||
" ((s5-0 (-> arg1 ppointer)))\n"
|
||||
" (when\n"
|
||||
" (not\n"
|
||||
" (or\n"
|
||||
" (nonzero? (logand (-> arg1 mask) 512))\n"
|
||||
" (and (not (-> arg1 next-state)) (not (-> arg1 state)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set!\n"
|
||||
" (-> arg1 allocated-length)\n"
|
||||
" (- (-> arg1 heap-cur) (the-as uint (-> arg1 stack)))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg1 heap-top) (&-> arg1 stack (-> arg1 allocated-length)))\n"
|
||||
" (if\n"
|
||||
" (< (the-as int arg1) (the-as int (gap-location arg0 (-> arg0 first-gap))))\n"
|
||||
" (set! (-> arg0 first-gap) (find-gap arg0 s5-0))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg1 mask) (logior (-> arg1 mask) 512))\n"
|
||||
" )\n"
|
||||
" (set!\n"
|
||||
" (-> arg1 allocated-length)\n"
|
||||
" (- (-> arg1 heap-cur) (the-as uint (-> arg1 stack)))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg1 heap-top) (&-> arg1 stack (-> arg1 allocated-length)))\n"
|
||||
" (if\n"
|
||||
" (< (the-as int arg1) (the-as int (gap-location arg0 (-> arg0 first-gap))))\n"
|
||||
" (set! (-> arg0 first-gap) (find-gap arg0 s5-0))\n"
|
||||
" (= (-> arg0 first-shrink) s5-0)\n"
|
||||
" (set! (-> arg0 first-shrink) (-> s5-0 2))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg1 mask) (logior (-> arg1 mask) 512))\n"
|
||||
" )\n"
|
||||
" (if\n"
|
||||
" (= (-> arg0 first-shrink) s5-0)\n"
|
||||
" (set! (-> arg0 first-shrink) (-> s5-0 2))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" arg0\n"
|
||||
|
@ -2528,49 +2551,57 @@ TEST_F(FormRegressionTest, ExprMethod16DeadPoolHeap) {
|
|||
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! s4-0 (memory-free arg0))\n"
|
||||
" (set! v1-2 (memory-total arg0))\n"
|
||||
" (set! f0-2 (/ (the float s4-0) (the float v1-2)))"
|
||||
" (cond\n"
|
||||
" ((< f0-2 (l.f L346))\n"
|
||||
" (set! arg1 1000)\n"
|
||||
" (if\n"
|
||||
" (and *debug-segment* (-> *kernel-context* low-memory-message))\n"
|
||||
" (format *stdcon* \"~3LLow Actor Memory~%~0L\" a2-0)\n" // ~3L tricks it.
|
||||
" )\n"
|
||||
" (let*\n"
|
||||
" ((s4-0 (memory-free arg0))\n"
|
||||
" (v1-2 (memory-total arg0))\n"
|
||||
" (f0-2 (/ (the float s4-0) (the float v1-2)))\n"
|
||||
" )\n"
|
||||
" (cond\n"
|
||||
" ((< f0-2 (l.f L346))\n"
|
||||
" (set! arg1 1000)\n"
|
||||
" (if\n"
|
||||
" (and *debug-segment* (-> *kernel-context* low-memory-message))\n"
|
||||
" (format *stdcon* \"~3LLow Actor Memory~%~0L\" a2-0)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" ((< f0-2 (l.f L347)) (set! arg1 (shl arg1 2)) (let ((v1-10 arg1))))\n"
|
||||
" ((< f0-2 (l.f L348)) (set! arg1 (shl arg1 1)) (let ((v1-12 arg1))))\n"
|
||||
" )\n"
|
||||
" ((< f0-2 (l.f L347)) (set! arg1 (shl arg1 2)) (set! v1-10 arg1))\n"
|
||||
" ((< f0-2 (l.f L348)) (set! arg1 (shl arg1 1)) (set! v1-12 arg1))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 compact-count-targ) arg1)\n"
|
||||
" (set! (-> arg0 compact-count) 0)\n"
|
||||
" (while\n"
|
||||
" (nonzero? arg1)\n"
|
||||
" (+! arg1 -1)\n"
|
||||
" (set! v1-13 (-> arg0 first-shrink))\n"
|
||||
" (when\n"
|
||||
" (not v1-13)\n"
|
||||
" (set! v1-13 (-> arg0 alive-list next))\n"
|
||||
" (set! (-> arg0 first-shrink) v1-13)\n"
|
||||
" (set! a0-5 v1-13)\n"
|
||||
" )\n"
|
||||
" (if v1-13 (shrink-heap arg0 (-> v1-13 process)))\n"
|
||||
" (set! s4-1 (-> arg0 first-gap))\n"
|
||||
" (when\n"
|
||||
" (-> s4-1 next)\n"
|
||||
" (set! s3-0 (-> s4-1 next process))\n"
|
||||
" (set! s2-0 (gap-size arg0 s4-1))\n"
|
||||
" (let\n"
|
||||
" ((v1-13 (-> arg0 first-shrink)))\n"
|
||||
" (when\n"
|
||||
" (nonzero? s2-0)\n"
|
||||
" (when (< s2-0 0) (break!) (set! v1-20 0))\n"
|
||||
" (shrink-heap arg0 s3-0)\n"
|
||||
" (relocate s3-0 (- s2-0))\n"
|
||||
" (set! (-> arg0 first-gap) (find-gap arg0 s4-1))\n"
|
||||
" (set! (-> arg0 compact-count) (+ (-> arg0 compact-count) 1))\n"
|
||||
" (not v1-13)\n"
|
||||
" (set! v1-13 (-> arg0 alive-list next))\n"
|
||||
" (set! (-> arg0 first-shrink) v1-13)\n"
|
||||
" (let ((a0-5 v1-13)))\n"
|
||||
" )\n"
|
||||
" (if v1-13 (shrink-heap arg0 (-> v1-13 process)))\n"
|
||||
" )\n"
|
||||
" (let\n"
|
||||
" ((s4-1 (-> arg0 first-gap)))\n"
|
||||
" (if\n"
|
||||
" (-> s4-1 next)\n"
|
||||
" (let\n"
|
||||
" ((s3-0 (-> s4-1 next process)) (s2-0 (gap-size arg0 s4-1)))\n"
|
||||
" (when\n"
|
||||
" (nonzero? s2-0)\n"
|
||||
" (when (< s2-0 0) (break!) (let ((v1-20 0))))\n"
|
||||
" (shrink-heap arg0 s3-0)\n"
|
||||
" (relocate s3-0 (- s2-0))\n"
|
||||
" (set! (-> arg0 first-gap) (find-gap arg0 s4-1))\n"
|
||||
" (set! (-> arg0 compact-count) (+ (-> arg0 compact-count) 1))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! v0-8 0)\n"
|
||||
" (let ((v0-8 0)))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {{"L296", "~3LLow Actor Memory~%~0L"}});
|
||||
}
|
||||
|
@ -2723,50 +2754,56 @@ TEST_F(FormRegressionTest, ExprMethod18DeadPoolHeap) {
|
|||
" (while\n"
|
||||
" (nonzero? arg1)\n"
|
||||
" (+! arg1 -1)\n"
|
||||
" (set! s4-0 (-> arg0 alive-list next))\n"
|
||||
" (when\n"
|
||||
" s4-0\n"
|
||||
" (if\n"
|
||||
" (or\n"
|
||||
" (= (-> arg0 first-gap) s4-0)\n"
|
||||
" (<\n"
|
||||
" (the-as int (gap-location arg0 s4-0))\n"
|
||||
" (the-as int (gap-location arg0 (-> arg0 first-gap)))\n"
|
||||
" (let\n"
|
||||
" ((s4-0 (-> arg0 alive-list next)))\n"
|
||||
" (when\n"
|
||||
" s4-0\n"
|
||||
" (if\n"
|
||||
" (or\n"
|
||||
" (= (-> arg0 first-gap) s4-0)\n"
|
||||
" (<\n"
|
||||
" (the-as int (gap-location arg0 s4-0))\n"
|
||||
" (the-as int (gap-location arg0 (-> arg0 first-gap)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 first-gap) (-> s4-0 prev))\n"
|
||||
" )\n"
|
||||
" (when\n"
|
||||
" (= (-> arg0 first-shrink) s4-0)\n"
|
||||
" (set! (-> arg0 first-shrink) (-> s4-0 prev))\n"
|
||||
" (when\n"
|
||||
" (not (-> arg0 first-shrink process))\n"
|
||||
" (set! (-> arg0 first-shrink) #f)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> arg0 first-gap) (-> s4-0 prev))\n"
|
||||
" )\n"
|
||||
" (when\n"
|
||||
" (= (-> arg0 first-shrink) s4-0)\n"
|
||||
" (set! (-> arg0 first-shrink) (-> s4-0 prev))\n"
|
||||
" (when\n"
|
||||
" (not (-> arg0 first-shrink process))\n"
|
||||
" (set! (-> arg0 first-shrink) #f)\n"
|
||||
" (set! (-> s4-0 prev next) (-> s4-0 next))\n"
|
||||
" (if\n"
|
||||
" (-> s4-0 next)\n"
|
||||
" (set! (-> s4-0 next prev) (-> s4-0 prev))\n"
|
||||
" (set! (-> arg0 alive-list prev) (-> s4-0 prev))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> s4-0 prev next) (-> s4-0 next))\n"
|
||||
" (if\n"
|
||||
" (-> s4-0 next)\n"
|
||||
" (set! (-> s4-0 next prev) (-> s4-0 prev))\n"
|
||||
" (set! (-> arg0 alive-list prev) (-> s4-0 prev))\n"
|
||||
" )\n"
|
||||
" (set! a1-3 (-> arg0 alive-list prev))\n"
|
||||
" (set! v1-19 (-> a1-3 next))\n"
|
||||
" (set! (-> a1-3 next) s4-0)\n"
|
||||
" (set! (-> s4-0 next) v1-19)\n"
|
||||
" (when v1-19 (set! (-> v1-19 prev) s4-0) (set! v1-20 s4-0))\n"
|
||||
" (set! (-> s4-0 prev) a1-3)\n"
|
||||
" (set! (-> arg0 alive-list prev) s4-0)\n"
|
||||
" (set!\n"
|
||||
" (-> s4-0 process)\n"
|
||||
" (relocate\n"
|
||||
" (-> s4-0 process)\n"
|
||||
" (- (gap-location arg0 a1-3) (the-as uint (&-> (-> s4-0 process) type)))\n"
|
||||
" (let\n"
|
||||
" ((a1-3 (-> arg0 alive-list prev)))\n"
|
||||
" (let\n"
|
||||
" ((v1-19 (-> a1-3 next)))\n"
|
||||
" (set! (-> a1-3 next) s4-0)\n"
|
||||
" (set! (-> s4-0 next) v1-19)\n"
|
||||
" (when v1-19 (set! (-> v1-19 prev) s4-0) (let ((v1-20 s4-0))))\n"
|
||||
" )\n"
|
||||
" (set! (-> s4-0 prev) a1-3)\n"
|
||||
" (set! (-> arg0 alive-list prev) s4-0)\n"
|
||||
" (set!\n"
|
||||
" (-> s4-0 process)\n"
|
||||
" (relocate\n"
|
||||
" (-> s4-0 process)\n"
|
||||
" (- (gap-location arg0 a1-3) (the-as uint (&-> (-> s4-0 process) type)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" (set! v0-4 0)\n"
|
||||
" (let ((v0-4 0)))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
|
@ -94,11 +94,11 @@ TEST_F(FormRegressionTest, ExprSeek) {
|
|||
" daddu sp, sp, r0";
|
||||
std::string type = "(function float float float float)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set! f2-0 (- arg1 arg0))\n"
|
||||
"(let\n"
|
||||
" ((f2-0 (- arg1 arg0)))\n"
|
||||
" (cond\n"
|
||||
" ((>= arg2 (fabs f2-0)) arg1)\n"
|
||||
" ((>= f2-0 0.000000) (+ arg0 arg2))\n"
|
||||
" ((>= f2-0 0.0) (+ arg0 arg2))\n"
|
||||
" (else (- arg0 arg2))\n"
|
||||
" )\n"
|
||||
" )";
|
||||
|
|
|
@ -40,7 +40,20 @@ const std::unordered_set<std::string> expected_skip_in_decompiler = {
|
|||
|
||||
const std::unordered_set<std::string> skip_in_compiling = {
|
||||
// these functions are not implemented by the compiler in OpenGOAL, but are in GOAL.
|
||||
"abs", "ash", "min", "max", "lognor", "(method 3 vec4s)", "(method 2 vec4s)"};
|
||||
"abs", "ash", "min", "max", "lognor",
|
||||
// these require 128-bit integers. We want these eventually, but disabling for now to focus
|
||||
// on more important issues.
|
||||
"(method 3 vec4s)", "(method 2 vec4s)",
|
||||
// these should pass eventually
|
||||
"(method 2 array)", "(method 3 array)", "valid?", "mem-copy!", "qmem-copy<-!", "qmem-copy->!",
|
||||
"mem-or!", "breakpoint-range-set!", "print", "printl", "inspect"};
|
||||
|
||||
// The decompiler does not attempt to insert forward definitions, as this would be part of an
|
||||
// unimplemented full-program type analysis pass. For now, we manually specify all functions
|
||||
// that should have a forward definition here.
|
||||
const std::string g_forward_type_defs =
|
||||
"(define-extern name= (function basic basic symbol))\n"
|
||||
"(define-extern fact (function int int))";
|
||||
|
||||
// default location for the data. It can be changed with a command line argument.
|
||||
std::string g_iso_data_path = "";
|
||||
|
@ -321,6 +334,8 @@ TEST_F(OfflineDecompilation, Reference) {
|
|||
TEST_F(OfflineDecompilation, Compile) {
|
||||
Compiler compiler;
|
||||
|
||||
compiler.run_front_end_on_string(g_forward_type_defs);
|
||||
|
||||
for (auto& file : g_object_files_to_check_against_reference) {
|
||||
auto& obj_l = db->obj_files_by_name.at(file);
|
||||
ASSERT_EQ(obj_l.size(), 1);
|
||||
|
|
Loading…
Reference in a new issue