From 65ffe83468dc979ac080f3951e49620fa8d561cd Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Fri, 5 Mar 2021 18:48:01 -0500 Subject: [PATCH] [Decompiler] Decompile `let` (#309) * test * fix bug * fix tests for let * missing formatting fix --- decompiler/CMakeLists.txt | 1 + decompiler/IR2/Env.cpp | 24 +- decompiler/IR2/Env.h | 6 + decompiler/IR2/Form.cpp | 336 +++-- decompiler/IR2/Form.h | 134 +- decompiler/IR2/FormExpressionAnalysis.cpp | 5 +- decompiler/ObjectFile/ObjectFileDB.h | 1 + decompiler/ObjectFile/ObjectFileDB_IR2.cpp | 22 + decompiler/analysis/insert_lets.cpp | 342 +++++ decompiler/analysis/insert_lets.h | 21 + decompiler/config.cpp | 1 + decompiler/config.h | 1 + decompiler/config/jak1_ntsc_black_label.jsonc | 1 + test/decompiler/FormRegressionTest.cpp | 5 +- test/decompiler/reference/gcommon_REF.gc | 1129 ++++++++--------- test/decompiler/test_FormExpressionBuild.cpp | 392 +++--- .../test_FormExpressionBuildLong.cpp | 796 ++++++------ test/decompiler/test_gkernel_decomp.cpp | 727 ++++++----- test/decompiler/test_math_decomp.cpp | 6 +- test/offline/offline_test_main.cpp | 17 +- 20 files changed, 2312 insertions(+), 1655 deletions(-) create mode 100644 decompiler/analysis/insert_lets.cpp create mode 100644 decompiler/analysis/insert_lets.h diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index f1b1253a1..c30f88629 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -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 diff --git a/decompiler/IR2/Env.cpp b/decompiler/IR2/Env.cpp index dbd052f03..51353bbc4 100644 --- a/decompiler/IR2/Env.cpp +++ b/decompiler/IR2/Env.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 Env::extract_visible_variables( std::vector 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> 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) { diff --git a/decompiler/IR2/Env.h b/decompiler/IR2/Env.h index 00993bc7b..2d20b8dce 100644 --- a/decompiler/IR2/Env.h +++ b/decompiler/IR2/Env.h @@ -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> m_typehints; std::unordered_map m_var_remap; std::unordered_map m_label_types; + + std::unordered_set m_vars_defined_in_let; }; } // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index 6e9fd1246..e1377d860 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -120,9 +120,9 @@ void Form::apply_form(const std::function& 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& f) { void StoreElement::apply_form(const std::function&) {} -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& 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& f) { void SimpleAtomElement::apply_form(const std::function&) {} -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& f) { void StoreInSymbolElement::apply_form(const std::function&) {} -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& f) { void StoreInPairElement::apply_form(const std::function&) {} -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& f) { void AtomicOpElement::apply_form(const std::function&) {} -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& f) { void AsmOpElement::apply_form(const std::function&) {} -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& f) { void FunctionCallElement::apply_form(const std::function&) {} -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& f) { void BranchElement::apply_form(const std::function&) {} -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 forms; forms.push_back(pretty_print::to_symbol("return")); @@ -653,10 +667,12 @@ void ReturnElement::apply_form(const std::function& 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 forms; forms.push_back(pretty_print::to_symbol("break")); @@ -690,9 +712,11 @@ void BreakElement::apply_form(const std::function& 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 _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& 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& f) { } void EmptyElement::apply_form(const std::function&) {} -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& 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& 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& 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& 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 _entries) + : entries(std::move(_entries)) { + for (auto& entry : entries) { + entry.condition->parent_element = this; + } +} + void ShortCircuitElement::apply(const std::function& 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 _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& 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& f) { void AbsElement::apply_form(const std::function&) {} -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& f) { void AshElement::apply_form(const std::function&) {} -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& 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 ConditionalMoveFalseElement::apply_form(const std::function&) {} -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 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& 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& 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 } goos::Object DerefElement::to_form_internal(const Env& env) const { + assert(m_base->parent_element); std::vector 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& 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& f) { void DynamicMethodAccess::apply_form(const std::function&) {} -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 elts; @@ -1621,10 +1713,12 @@ void ArrayFieldAccess::apply_form(const std::function& 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& 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 StringConstantElement::apply_form(const std::function&) {} -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 ConstantTokenElement::apply_form(const std::function&) {} -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 ConstantFloatElement::apply_form(const std::function&) {} -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& f) { void StorePlainDeref::apply_form(const std::function&) {} -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& 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& f) { void DecompiledDataElement::apply_form(const std::function&) {} -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 outer = {pretty_print::to_symbol(m_star ? "let*" : "let")}; + + std::vector 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& f) { + f(this); + for (auto& entry : m_entries) { + entry.src->apply(f); + } + m_body->apply(f); +} + +void LetElement::apply_form(const std::function& 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 diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 0526f3e29..92a20ea6a 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -29,7 +29,7 @@ class FormElement { virtual void apply(const std::function& f) = 0; virtual void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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 entries; Form* else_ir = nullptr; bool already_rewritten = false; - CondWithElseElement(std::vector _entries, Form* _else_ir) - : entries(std::move(_entries)), else_ir(_else_ir) {} + CondWithElseElement(std::vector _entries, Form* _else_ir); goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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 used_as_value = std::nullopt; bool already_rewritten = false; - explicit ShortCircuitElement(std::vector _entries) : entries(std::move(_entries)) {} + explicit ShortCircuitElement(std::vector _entries); goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& 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 entries; - explicit CondNoElseElement(std::vector _entries) : entries(std::move(_entries)) {} + explicit CondNoElseElement(std::vector _entries); goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f); void apply_form(const std::function& f); @@ -850,7 +847,7 @@ class GenericElement : public FormElement { goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f); void apply_form(const std::function& f); @@ -937,7 +934,7 @@ class DerefElement : public FormElement { goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& 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& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; void apply_form(const std::function& 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& f) override; + void apply_form(const std::function& 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 entries() { return m_entries; } + void add_entry(const Entry& e); + bool is_star() const { return m_star; } + + private: + Form* m_body = nullptr; + std::vector 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& elts() const { return m_elements; } std::vector& 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& forms, const Env& env) const; void apply(const std::function& f); void apply_form(const std::function& 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, diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 229b72dfa..6312966cc 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -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( 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 diff --git a/decompiler/ObjectFile/ObjectFileDB.h b/decompiler/ObjectFile/ObjectFileDB.h index 562db9506..220550da3 100644 --- a/decompiler/ObjectFile/ObjectFileDB.h +++ b/decompiler/ObjectFile/ObjectFileDB.h @@ -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); diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index 7f1c40c3d..633320de8 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -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..."); diff --git a/decompiler/analysis/insert_lets.cpp b/decompiler/analysis/insert_lets.cpp new file mode 100644 index 000000000..e82e79905 --- /dev/null +++ b/decompiler/analysis/insert_lets.cpp @@ -0,0 +1,342 @@ +#include + +#include "insert_lets.h" + +namespace decompiler { + +/* +Part 1: +Create a std::unordered_map> 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 path_up_tree(Form* in) { + std::vector 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 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 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::max(); + kv.second.end_idx = std::numeric_limits::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 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> possible_insertions; + for (auto& info : sorted_info) { + auto first_form = info.lca_form->at(info.start_idx); + auto first_form_as_set = dynamic_cast(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 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 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 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(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 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(f); + if (!as_let) { + return; + } + + auto inner_let = dynamic_cast(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 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 \ No newline at end of file diff --git a/decompiler/analysis/insert_lets.h b/decompiler/analysis/insert_lets.h new file mode 100644 index 000000000..64e636771 --- /dev/null +++ b/decompiler/analysis/insert_lets.h @@ -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 \ No newline at end of file diff --git a/decompiler/config.cpp b/decompiler/config.cpp index 33169920b..2b04e5bd6 100644 --- a/decompiler/config.cpp +++ b/decompiler/config.cpp @@ -53,6 +53,7 @@ void set_config(const std::string& path_to_config_file) { gConfig.function_type_prop = cfg.at("function_type_prop").get(); gConfig.analyze_expressions = cfg.at("analyze_expressions").get(); gConfig.run_ir2 = cfg.at("run_ir2").get(); + gConfig.insert_lets = cfg.at("insert_lets").get(); std::vector asm_functions_by_name = cfg.at("asm_functions_by_name").get>(); diff --git a/decompiler/config.h b/decompiler/config.h index d0c63751c..01186ba1d 100644 --- a/decompiler/config.h +++ b/decompiler/config.h @@ -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 asm_functions_by_name; std::unordered_set pair_functions_by_name; std::unordered_set no_type_analysis_functions_by_name; diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index 6d60967c2..efd13c97a 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -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, diff --git a/test/decompiler/FormRegressionTest.cpp b/test/decompiler/FormRegressionTest.cpp index b71b336e6..99a4130e5 100644 --- a/test/decompiler/FormRegressionTest.cpp +++ b/test/decompiler/FormRegressionTest.cpp @@ -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::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::make_function( if (!success) { return nullptr; } + insert_lets(test->func, test->func.ir2.env, *test->func.ir2.form_pool, + test->func.ir2.top_form); } } diff --git a/test/decompiler/reference/gcommon_REF.gc b/test/decompiler/reference/gcommon_REF.gc index 3fa637b57..7a29eb6be 100644 --- a/test/decompiler/reference/gcommon_REF.gc +++ b/test/decompiler/reference/gcommon_REF.gc @@ -48,9 +48,7 @@ ;; definition for function abs (defun abs ((x int)) - (local-vars (v0-0 int)) - (set! v0-0 x) - (abs v0-0) + (let ((v0-0 x)) (abs v0-0)) ) ;; definition for function min @@ -118,46 +116,34 @@ (v0-5 int) (v1-0 int) (v1-1 int) - (a0-1 symbol) - (a0-2 symbol) - (a0-4 symbol) - (a0-5 symbol) - (a1-0 string) - (a1-1 string) - (a1-3 string) - (a1-4 string) (a2-0 int) (a2-1 int) (a2-3 int) - (t9-0 (function _varargs_ object)) - (t9-1 (function _varargs_ object)) - (t9-3 (function _varargs_ object)) - (t9-4 (function _varargs_ object)) (gp-0 int) ) (.por gp-0 obj r0-0) - (set! t9-0 format) - (set! a0-1 #t) - (set! a1-0 "[~8x] ~A~%") - (.por a2-0 gp-0 r0-0) - (t9-0 a0-1 a1-0 a2-0 'vec4s) - (set! t9-1 format) - (set! a0-2 #t) - (set! a1-1 "~Tx: ~f~%") - (.sllv a2-1 gp-0 r0-0) - (t9-1 a0-2 a1-1 a2-1) + (let + ((t9-0 format) (a0-1 #t) (a1-0 "[~8x] ~A~%")) + (.por a2-0 gp-0 r0-0) + (t9-0 a0-1 a1-0 a2-0 'vec4s) + ) + (let + ((t9-1 format) (a0-2 #t) (a1-1 "~Tx: ~f~%")) + (.sllv a2-1 gp-0 r0-0) + (t9-1 a0-2 a1-1 a2-1) + ) (format #t "~Ty: ~f~%" (sar gp-0 32)) - (set! t9-3 format) - (set! a0-4 #t) - (set! a1-3 "~Tz: ~f~%") - (.pcpyud v1-0 gp-0 r0-0) - (.sllv a2-3 v1-0 r0-0) - (t9-3 a0-4 a1-3 a2-3) - (set! t9-4 format) - (set! a0-5 #t) - (set! a1-4 "~Tw: ~f~%") - (.pcpyud v1-1 gp-0 r0-0) - (t9-4 a0-5 a1-4 (sar v1-1 32)) + (let + ((t9-3 format) (a0-4 #t) (a1-3 "~Tz: ~f~%")) + (.pcpyud v1-0 gp-0 r0-0) + (.sllv a2-3 v1-0 r0-0) + (t9-3 a0-4 a1-3 a2-3) + ) + (let + ((t9-4 format) (a0-5 #t) (a1-4 "~Tw: ~f~%")) + (.pcpyud v1-1 gp-0 r0-0) + (t9-4 a0-5 a1-4 (sar v1-1 32)) + ) (.por v0-5 gp-0 r0-0) (the-as vec4s v0-5) ) @@ -170,28 +156,27 @@ (v0-1 int) (v1-0 int) (v1-1 int) - (a0-1 symbol) - (a1-0 string) (a2-0 int) - (a3-0 int) (t0-0 int) - (t1-0 int) (t2-0 int) - (t9-0 (function _varargs_ object)) (gp-0 int) ) (.por gp-0 obj r0-0) - (set! t9-0 format) - (set! a0-1 #t) - (set! a1-0 "#") - (.sllv a2-0 gp-0 r0-0) - (set! a3-0 (sar gp-0 32)) - (.pcpyud v1-0 gp-0 r0-0) - (.sllv t0-0 v1-0 r0-0) - (.pcpyud v1-1 gp-0 r0-0) - (set! t1-0 (sar v1-1 32)) - (.por t2-0 gp-0 r0-0) - (t9-0 a0-1 a1-0 a2-0 a3-0 t0-0 t1-0 t2-0) + (let + ((t9-0 format) (a0-1 #t) (a1-0 "#")) + (.sllv a2-0 gp-0 r0-0) + (let + ((a3-0 (sar gp-0 32))) + (.pcpyud v1-0 gp-0 r0-0) + (.sllv t0-0 v1-0 r0-0) + (.pcpyud v1-1 gp-0 r0-0) + (let + ((t1-0 (sar v1-1 32))) + (.por t2-0 gp-0 r0-0) + (t9-0 a0-1 a1-0 a2-0 a3-0 t0-0 t1-0 t2-0) + ) + ) + ) (.por v0-1 gp-0 r0-0) (the-as vec4s v0-1) ) @@ -227,64 +212,70 @@ ;; definition for function basic-type? (defun basic-type? ((obj basic) (parent-type type)) - (local-vars (obj-type type) (end-type type)) - (set! obj-type (-> obj type)) - (set! end-type object) - (until - (begin (set! obj-type (-> obj-type parent)) (= obj-type end-type)) - (if (= obj-type parent-type) (return #t)) + (let + ((obj-type (-> obj type)) (end-type object)) + (until + (begin (set! obj-type (-> obj-type parent)) (= obj-type end-type)) + (if (= obj-type parent-type) (return #t)) + ) ) #f ) ;; definition for function type-type? (defun type-type? ((child-type type) (parent-type type)) - (local-vars (end-type type)) - (set! end-type object) - (until - (begin - (set! child-type (-> child-type parent)) - (or (= child-type end-type) (zero? child-type)) + (let + ((end-type object)) + (until + (begin + (set! child-type (-> child-type parent)) + (or (= child-type end-type) (zero? child-type)) + ) + (if (= child-type parent-type) (return #t)) ) - (if (= child-type parent-type) (return #t)) ) #f ) ;; definition for function find-parent-method (defun find-parent-method ((child-type type) (method-id int)) - (local-vars (current-method function) (original-method function)) - (set! original-method (-> child-type method-table method-id)) - (until - (!= current-method original-method) - (if (= child-type object) (return nothing)) - (set! child-type (-> child-type parent)) - (set! current-method (-> child-type method-table method-id)) - (if (zero? current-method) (return nothing)) + (local-vars (current-method function)) + (let + ((original-method (-> child-type method-table method-id))) + (until + (!= current-method original-method) + (if (= child-type object) (return nothing)) + (set! child-type (-> child-type parent)) + (set! current-method (-> child-type method-table method-id)) + (if (zero? current-method) (return nothing)) + ) ) current-method ) ;; definition for function ref (defun ref ((lst object) (index int)) - (local-vars (count int)) - (set! count 0) - (while (< count index) (nop!) (nop!) (set! lst (cdr lst)) (+! count 1)) + (let + ((count 0)) + (while (< count index) (nop!) (nop!) (set! lst (cdr lst)) (+! count 1)) + ) (car lst) ) ;; definition for method of type pair (defmethod length pair ((obj pair)) - (local-vars (result int) (iter object)) + (local-vars (result int)) (cond ((= obj '()) (set! result 0)) (else - (set! iter (cdr obj)) - (set! result 1) - (while - (and (!= iter '()) (< (shl (the-as int iter) 62) 0)) - (+! result 1) - (set! iter (cdr iter)) + (let + ((iter (cdr obj))) + (set! result 1) + (while + (and (!= iter '()) (< (shl (the-as int iter) 62) 0)) + (+! result 1) + (set! iter (cdr iter)) + ) ) ) ) @@ -299,18 +290,20 @@ ;; definition for function last (defun last ((lst object)) - (local-vars (iter object)) - (set! iter lst) - (while (!= (cdr iter) '()) (nop!) (nop!) (set! iter (cdr iter))) - iter + (let + ((iter lst)) + (while (!= (cdr iter) '()) (nop!) (nop!) (set! iter (cdr iter))) + iter + ) ) ;; definition for function member (defun member ((obj object) (lst object)) - (local-vars (iter object)) - (set! iter lst) - (while (not (or (= iter '()) (= (car iter) obj))) (set! iter (cdr iter))) - (if (!= iter '()) iter) + (let + ((iter lst)) + (while (not (or (= iter '()) (= (car iter) obj))) (set! iter (cdr iter))) + (if (!= iter '()) iter) + ) ) ;; definition for function nmember @@ -324,35 +317,36 @@ ;; definition for function assoc (defun assoc ((item object) (alist object)) - (local-vars (iter object)) - (set! iter alist) - (while - (not (or (= iter '()) (= (car (car iter)) item))) - (set! iter (cdr iter)) + (let + ((iter alist)) + (while + (not (or (= iter '()) (= (car (car iter)) item))) + (set! iter (cdr iter)) + ) + (if (!= iter '()) (car iter)) ) - (if (!= iter '()) (car iter)) ) ;; definition for function assoce (defun assoce ((item object) (alist object)) - (local-vars (iter object)) - (set! iter alist) - (while - (not (or (= iter '()) (= (car (car iter)) item) (= (car (car iter)) 'else))) - (set! iter (cdr iter)) + (let + ((iter alist)) + (while + (not (or (= iter '()) (= (car (car iter)) item) (= (car (car iter)) 'else))) + (set! iter (cdr iter)) + ) + (if (!= iter '()) (car iter)) ) - (if (!= iter '()) (car iter)) ) ;; definition for function nassoc (defun nassoc ((item-name string) (alist object)) - (local-vars (key object)) (while (not (or (= alist '()) - (begin - (set! key (car (car alist))) + (let + ((key (car (car alist)))) (if (pair? key) (nmember item-name key) @@ -368,13 +362,12 @@ ;; definition for function nassoce (defun nassoce ((item-name string) (alist object)) - (local-vars (key object)) (while (not (or (= alist '()) - (begin - (set! key (car (car alist))) + (let + ((key (car (car alist)))) (if (pair? key) (nmember item-name key) @@ -390,13 +383,14 @@ ;; definition for function append! (defun append! ((front object) (back object)) - (local-vars (iter object)) (cond ((= front '()) back) (else - (set! iter front) - (while (!= (cdr iter) '()) (nop!) (nop!) (set! iter (cdr iter))) - (if (!= iter '()) (set! (cdr iter) back)) + (let + ((iter front)) + (while (!= (cdr iter) '()) (nop!) (nop!) (set! iter (cdr iter))) + (if (!= iter '()) (set! (cdr iter) back)) + ) front ) ) @@ -405,20 +399,20 @@ ;; definition for function delete! ;; INFO: Return type mismatch object vs pair. (defun delete! ((item object) (lst object)) - (local-vars (iter-prev object) (iter object)) (the-as pair (cond ((= item (car lst)) (cdr lst)) (else - (set! iter-prev lst) - (set! iter (cdr lst)) - (while - (not (or (= iter '()) (= (car iter) item))) - (set! iter-prev iter) - (set! iter (cdr iter)) + (let + ((iter-prev lst) (iter (cdr lst))) + (while + (not (or (= iter '()) (= (car iter) item))) + (set! iter-prev iter) + (set! iter (cdr iter)) + ) + (if (!= iter '()) (set! (cdr iter-prev) (cdr iter))) ) - (if (!= iter '()) (set! (cdr iter-prev) (cdr iter))) lst ) ) @@ -427,18 +421,18 @@ ;; definition for function delete-car! (defun delete-car! ((item object) (lst object)) - (local-vars (iter-prev object) (iter object)) (cond ((= item (car (car lst))) (cdr lst)) (else - (set! iter-prev lst) - (set! iter (cdr lst)) - (while - (not (or (= iter '()) (= (car (car iter)) item))) - (set! iter-prev iter) - (set! iter (cdr iter)) + (let + ((iter-prev lst) (iter (cdr lst))) + (while + (not (or (= iter '()) (= (car (car iter)) item))) + (set! iter-prev iter) + (set! iter (cdr iter)) + ) + (if (!= iter '()) (set! (cdr iter-prev) (cdr iter))) ) - (if (!= iter '()) (set! (cdr iter-prev) (cdr iter))) lst ) ) @@ -446,40 +440,38 @@ ;; definition for function insert-cons! (defun insert-cons! ((kv object) (alist object)) - (local-vars (updated-list object)) - (set! updated-list (delete-car! (car kv) alist)) - (cons kv updated-list) + (let ((updated-list (delete-car! (car kv) alist))) (cons kv updated-list)) ) ;; definition for function sort (defun sort ((lst object) (compare-func (function object object object))) - (local-vars - (compare-result object) - (seoncd-elt object) - (first-elt object) - (iter object) - (unsorted-count int) - ) - (set! unsorted-count -1) - (while - (nonzero? unsorted-count) - (set! unsorted-count 0) - (set! iter lst) + (let + ((unsorted-count -1)) (while - (not (or (= (cdr iter) '()) (>= (shl (the-as int (cdr iter)) 62) 0))) - (set! first-elt (car iter)) - (set! seoncd-elt (car (cdr iter))) - (set! compare-result (compare-func first-elt seoncd-elt)) - (when - (and - (or (not compare-result) (> (the-as int compare-result) 0)) - (!= compare-result #t) + (nonzero? unsorted-count) + (set! unsorted-count 0) + (let + ((iter lst)) + (while + (not (or (= (cdr iter) '()) (>= (shl (the-as int (cdr iter)) 62) 0))) + (let* + ((first-elt (car iter)) + (seoncd-elt (car (cdr iter))) + (compare-result (compare-func first-elt seoncd-elt)) + ) + (when + (and + (or (not compare-result) (> (the-as int compare-result) 0)) + (!= compare-result #t) + ) + (+! unsorted-count 1) + (set! (car iter) seoncd-elt) + (set! (car (cdr iter)) first-elt) + ) + ) + (set! iter (cdr iter)) ) - (+! unsorted-count 1) - (set! (car iter) seoncd-elt) - (set! (car (cdr iter)) first-elt) ) - (set! iter (cdr iter)) ) ) lst @@ -514,27 +506,28 @@ new inline-array-class ((allocation symbol) (type-to-make type) (size int)) - (local-vars (obj inline-array-class)) - (set! - obj - (object-new - allocation - type-to-make - (the-as - int - (+ - (-> type-to-make size) - (* (the-as uint size) (-> type-to-make heap-base)) + (let + ((obj + (object-new + allocation + type-to-make + (the-as + int + (+ + (-> type-to-make size) + (* (the-as uint size) (-> type-to-make heap-base)) + ) + ) ) ) ) + (when + (nonzero? obj) + (set! (-> obj length) size) + (set! (-> obj allocated-length) size) + ) + obj ) - (when - (nonzero? obj) - (set! (-> obj length) size) - (set! (-> obj allocated-length) size) - ) - obj ) ;; definition for method of type inline-array-class @@ -562,37 +555,34 @@ new array ((allocation symbol) (type-to-make type) (content-type type) (len int)) - (local-vars (obj array)) - (set! - obj - (object-new - allocation - type-to-make - (the-as - int - (+ - (-> type-to-make size) + (let + ((obj + (object-new + allocation + type-to-make (the-as - uint - (* len (if (type-type? content-type number) (-> content-type size) 4)) + int + (+ + (-> type-to-make size) + (the-as + uint + (* len (if (type-type? content-type number) (-> content-type size) 4)) + ) + ) ) ) ) ) + (set! (-> obj allocated-length) len) + (set! (-> obj length) len) + (set! (-> obj content-type) content-type) + obj ) - (set! (-> obj allocated-length) len) - (set! (-> obj length) len) - (set! (-> obj content-type) content-type) - obj ) ;; definition for method of type array (defmethod print array ((obj array)) (local-vars - (content-type-sym symbol) - (v1-42 pointer) - (a0-21 symbol) - (a1-11 string) (a2-8 int) (i int) (i int) @@ -606,12 +596,12 @@ (i int) (i int) (i int) - (t9-10 (function _varargs_ object)) ) (format #t "#(") - (cond - ((type-type? (-> obj content-type) integer) - (set! content-type-sym (-> obj content-type symbol)) + (if + (type-type? (-> obj content-type) integer) + (let + ((content-type-sym (-> obj content-type symbol))) (cond ((= content-type-sym 'int32) (set! i 0) @@ -687,12 +677,14 @@ (set! i 0) (while (< i (-> obj length)) - (set! t9-10 format) - (set! a0-21 #t) - (set! a1-11 (if (zero? i) "#x~X" " #x~X")) - (set! v1-42 (+ (shl i 4) (the-as int (the-as (array uint128) obj)))) - (.lq a2-8 12 v1-42) - (t9-10 a0-21 a1-11 a2-8) + (let + ((t9-10 format) (a0-21 #t) (a1-11 (if (zero? i) "#x~X" " #x~X"))) + (let + ((v1-42 (+ (shl i 4) (the-as int (the-as (array uint128) obj))))) + (.lq a2-8 12 v1-42) + ) + (t9-10 a0-21 a1-11 a2-8) + ) (+! i 1) ) ) @@ -708,31 +700,29 @@ ) ) ) - (else - (cond - ((= (-> obj content-type) float) - (set! i 0) - (while - (< i (-> obj length)) - (if - (zero? i) - (format #t "~f" (-> (the-as (array float) obj) i)) - (format #t " ~f" (-> (the-as (array float) obj) i)) - ) - (+! i 1) + (cond + ((= (-> obj content-type) float) + (set! i 0) + (while + (< i (-> obj length)) + (if + (zero? i) + (format #t "~f" (-> (the-as (array float) obj) i)) + (format #t " ~f" (-> (the-as (array float) obj) i)) ) + (+! i 1) ) - (else - (set! i 0) - (while - (< i (-> obj length)) - (if - (zero? i) - (format #t "~A" (-> (the-as (array basic) obj) i)) - (format #t " ~A" (-> (the-as (array basic) obj) i)) - ) - (+! i 1) + ) + (else + (set! i 0) + (while + (< i (-> obj length)) + (if + (zero? i) + (format #t "~A" (-> (the-as (array basic) obj) i)) + (format #t " ~A" (-> (the-as (array basic) obj) i)) ) + (+! i 1) ) ) ) @@ -744,11 +734,6 @@ ;; definition for method of type array (defmethod inspect array ((obj array)) (local-vars - (content-type-sym symbol) - (v1-42 pointer) - (a0-25 symbol) - (a1-15 string) - (a2-13 int) (a3-10 int) (i int) (i int) @@ -762,16 +747,16 @@ (i int) (i int) (i int) - (t9-14 (function _varargs_ object)) ) (format #t "[~8x] ~A~%" obj (-> obj type)) (format #t "~Tallocated-length: ~D~%" (-> obj allocated-length)) (format #t "~Tlength: ~D~%" (-> obj length)) (format #t "~Tcontent-type: ~A~%" (-> obj content-type)) (format #t "~Tdata[~D]: @ #x~X~%" (-> obj allocated-length) (-> obj data)) - (cond - ((type-type? (-> obj content-type) integer) - (set! content-type-sym (-> obj content-type symbol)) + (if + (type-type? (-> obj content-type) integer) + (let + ((content-type-sym (-> obj content-type symbol))) (cond ((= content-type-sym 'int32) (set! i 0) @@ -843,13 +828,11 @@ (set! i 0) (while (< i (-> obj length)) - (set! t9-14 format) - (set! a0-25 #t) - (set! a1-15 "~T [~D] #x~X~%") - (set! a2-13 i) - (set! v1-42 (+ (shl i 4) (the-as int obj))) - (.lq a3-10 12 v1-42) - (t9-14 a0-25 a1-15 a2-13 a3-10) + (let + ((t9-14 format) (a0-25 #t) (a1-15 "~T [~D] #x~X~%") (a2-13 i)) + (let ((v1-42 (+ (shl i 4) (the-as int obj)))) (.lq a3-10 12 v1-42)) + (t9-14 a0-25 a1-15 a2-13 a3-10) + ) (+! i 1) ) ) @@ -865,23 +848,21 @@ ) ) ) - (else - (cond - ((= (-> obj content-type) float) - (set! i 0) - (while - (< i (-> obj length)) - (format #t "~T [~D] ~f~%" i (-> obj i)) - (+! i 1) - ) + (cond + ((= (-> obj content-type) float) + (set! i 0) + (while + (< i (-> obj length)) + (format #t "~T [~D] ~f~%" i (-> obj i)) + (+! i 1) ) - (else - (set! i 0) - (while - (< i (-> obj length)) - (format #t "~T [~D] ~A~%" i (-> obj i)) - (+! i 1) - ) + ) + (else + (set! i 0) + (while + (< i (-> obj length)) + (format #t "~T [~D] ~A~%" i (-> obj i)) + (+! i 1) ) ) ) @@ -918,90 +899,104 @@ ;; definition for function mem-copy! (defun mem-copy! ((dst pointer) (src pointer) (size int)) - (local-vars (result pointer) (i int)) - (set! result dst) - (set! i 0) - (while - (< i size) - (set! (-> (the-as (pointer int8) dst)) (-> (the-as (pointer uint8) src))) - (&+! dst 1) - (&+! src 1) - (+! i 1) + (let + ((result dst)) + (let + ((i 0)) + (while + (< i size) + (set! (-> (the-as (pointer int8) dst)) (-> (the-as (pointer uint8) src))) + (&+! dst 1) + (&+! src 1) + (+! i 1) + ) + ) + result ) - result ) ;; definition for function qmem-copy<-! (defun qmem-copy<-! ((dst pointer) (src pointer) (size int)) - (local-vars (result pointer) (qwc int) (value int)) - (set! result dst) - (set! qwc (sar (+ size 15) 4)) - (while - (nonzero? qwc) - (+! qwc -1) - (.lq value 0 src) - (.sq value 0 dst) - (&+! dst 16) - (&+! src 16) + (local-vars (value int)) + (let + ((result dst)) + (let + ((qwc (sar (+ size 15) 4))) + (while + (nonzero? qwc) + (+! qwc -1) + (.lq value 0 src) + (.sq value 0 dst) + (&+! dst 16) + (&+! src 16) + ) + ) + result ) - result ) ;; definition for function qmem-copy->! (defun qmem-copy->! ((dst pointer) (src pointer) (size int)) - (local-vars - (result pointer) - (qwc int) - (src-ptr pointer) - (dst-ptr pointer) - (value int) + (local-vars (src-ptr pointer) (dst-ptr pointer) (value int)) + (let + ((result dst)) + (let + ((qwc (sar (+ size 15) 4))) + (&+! dst (shl qwc 4)) + (&+! src (shl qwc 4)) + (while + (nonzero? qwc) + (+! qwc -1) + (&+! src-ptr -16) + (&+! dst-ptr -16) + (.lq value 0 dst-ptr) + (.sq value 0 src-ptr) + ) + ) + result ) - (set! result dst) - (set! qwc (sar (+ size 15) 4)) - (&+! dst (shl qwc 4)) - (&+! src (shl qwc 4)) - (while - (nonzero? qwc) - (+! qwc -1) - (&+! src-ptr -16) - (&+! dst-ptr -16) - (.lq value 0 dst-ptr) - (.sq value 0 src-ptr) - ) - result ) ;; definition for function mem-set32! (defun mem-set32! ((dst pointer) (size int) (value int)) - (local-vars (result pointer) (i int)) - (set! result dst) - (set! i 0) - (while - (< i size) - (set! (-> (the-as (pointer int32) dst)) value) - (&+! dst 4) - (nop!) - (+! i 1) + (let + ((result dst)) + (let + ((i 0)) + (while + (< i size) + (set! (-> (the-as (pointer int32) dst)) value) + (&+! dst 4) + (nop!) + (+! i 1) + ) + ) + result ) - result ) ;; definition for function mem-or! (defun mem-or! ((dst pointer) (src pointer) (size int)) - (local-vars (result pointer) (i int)) - (set! result dst) - (set! i 0) - (while - (< i size) - (set! - (-> (the-as (pointer int8) dst)) - (logior (-> (the-as (pointer uint8) dst)) (-> (the-as (pointer uint8) src))) + (let + ((result dst)) + (let + ((i 0)) + (while + (< i size) + (set! + (-> (the-as (pointer int8) dst)) + (logior + (-> (the-as (pointer uint8) dst)) + (-> (the-as (pointer uint8) src)) + ) + ) + (&+! dst 1) + (&+! src 1) + (+! i 1) + ) ) - (&+! dst 1) - (&+! src 1) - (+! i 1) + result ) - result ) ;; definition for function quad-copy! @@ -1022,9 +1017,7 @@ ;; definition for function printl (defun printl ((arg0 object)) - (local-vars (a0-1 object)) - (set! a0-1 arg0) - ((method-of-type (rtype-of a0-1) print) a0-1) + (let ((a0-1 arg0)) ((method-of-type (rtype-of a0-1) print) a0-1)) (format #t "~%") arg0 ) @@ -1036,20 +1029,21 @@ ;; definition (debug) for function mem-print (defun-debug mem-print ((data (pointer uint32)) (word-count int)) - (local-vars (current-qword int)) - (set! current-qword 0) - (while - (< current-qword (sar word-count 2)) - (format - 0 - "~X: ~X ~X ~X ~X~%" - (&-> data (shl current-qword 2)) - (-> data (shl current-qword 2)) - (-> data (+ (shl current-qword 2) 1)) - (-> data (+ (shl current-qword 2) 2)) - (-> data (+ (shl current-qword 2) 3)) + (let + ((current-qword 0)) + (while + (< current-qword (sar word-count 2)) + (format + 0 + "~X: ~X ~X ~X ~X~%" + (&-> data (shl current-qword 2)) + (-> data (shl current-qword 2)) + (-> data (+ (shl current-qword 2) 1)) + (-> data (+ (shl current-qword 2) 2)) + (-> data (+ (shl current-qword 2) 3)) + ) + (+! current-qword 1) ) - (+! current-qword 1) ) #f ) @@ -1059,13 +1053,14 @@ ;; definition for function print-tree-bitmask (defun print-tree-bitmask ((bits int) (count int)) - (local-vars (i int)) - (set! i 0) - (while - (< i count) - (if (zero? (logand bits 1)) (format #t " ") (format #t "| ")) - (set! bits (shr bits 1)) - (+! i 1) + (let + ((i 0)) + (while + (< i count) + (if (zero? (logand bits 1)) (format #t " ") (format #t "| ")) + (set! bits (shr bits 1)) + (+! i 1) + ) ) #f ) @@ -1087,251 +1082,244 @@ (allow-false basic) (print-dest object) ) - (local-vars - (in-goal-mem symbol) - (v1-10 int) - (v1-11 int) - (v1-43 int) - (v1-44 int) - (v1-47 int) - (v1-48 int) - (s7-0 none) - ) - (set! - in-goal-mem - (and - (>= (the-as uint obj) (the-as uint __START-OF-TABLE__)) - (< (the-as uint obj) (the-as uint #x8000000)) - ) - ) - (cond - ((not expected-type) - (cond - ((nonzero? (logand (the-as int obj) 3)) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object (misaligned)~%" - obj - name - ) - ) - #f + (local-vars (v1-11 int) (v1-44 int) (v1-48 int) (s7-0 none)) + (let + ((in-goal-mem + (and + (>= (the-as uint obj) (the-as uint __START-OF-TABLE__)) + (< (the-as uint obj) (the-as uint #x8000000)) ) - ((not in-goal-mem) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object (bad address)~%" - obj - name - ) - ) - #f - ) - (else #t) ) ) - ((and allow-false (not obj)) #t) - (else - (cond - ((= expected-type structure) - (cond - ((nonzero? (logand (the-as int obj) 15)) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" - obj - name - expected-type - ) - ) - #f - ) - ((or - (not in-goal-mem) - (begin - (set! v1-10 #x8000) - (.daddu v1-11 v1-10 s7-0) - (< (the-as uint obj) (the-as uint v1-11)) - ) - ) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" - obj - name - expected-type - ) - ) - #f - ) - (else #t) - ) - ) - ((= expected-type pair) - (cond - ((!= (logand (the-as int obj) 7) 2) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" - obj - name - expected-type - ) - ) - #f - ) - ((not in-goal-mem) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" - obj - name - expected-type - ) - ) - #f - ) - (else #t) - ) - ) - ((= expected-type binteger) - (cond - ((zero? (logand (the-as int obj) 7)) #t) - (else - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" - obj - name - expected-type - ) - ) - #f - ) - ) - ) - ((!= (logand (the-as int obj) 7) 4) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" - obj + (cond + ((not expected-type) + (cond + ((nonzero? (logand (the-as int obj) 3)) + (if name - expected-type - ) - ) - #f - ) - ((not in-goal-mem) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" - obj - name - expected-type - ) - ) - #f - ) - ((and (= expected-type type) (!= (rtype-of obj) type)) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" - obj - name - expected-type - (rtype-of obj) - ) - ) - #f - ) - (else - (cond - ((and (!= expected-type type) (not (valid? (rtype-of obj) type #f #t 0))) - (if + (format + print-dest + "ERROR: object #x~X ~S is not a valid object (misaligned)~%" + obj name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" - obj - name - expected-type - (rtype-of obj) - ) ) - #f ) - ((not (type-type? (rtype-of obj) expected-type)) - (if + #f + ) + ((not in-goal-mem) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object (bad address)~%" + obj name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' instead)~%" - obj - name - expected-type - (rtype-of obj) - ) ) - #f ) - ((= expected-type symbol) - (set! v1-43 #x8000) - (.daddu v1-44 v1-43 s7-0) - (cond - ((>= (the-as uint obj) (the-as uint v1-44)) - (if + #f + ) + (else #t) + ) + ) + ((and allow-false (not obj)) #t) + (else + (cond + ((= expected-type structure) + (cond + ((nonzero? (logand (the-as int obj) 15)) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol table)~%" - obj - name - expected-type - ) + expected-type ) - #f ) - (else #t) + #f ) - ) - ((begin - (set! v1-47 #x8000) - (.daddu v1-48 v1-47 s7-0) - (< (the-as uint obj) (the-as uint v1-48)) - ) - (if - name - (format - print-dest - "ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol table)~%" - obj + ((or + (not in-goal-mem) + (begin + (let ((v1-10 #x8000)) (.daddu v1-11 v1-10 s7-0)) + (< (the-as uint obj) (the-as uint v1-11)) + ) + ) + (if name - expected-type + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + name + expected-type + ) + ) + #f + ) + (else #t) + ) + ) + ((= expected-type pair) + (cond + ((!= (logand (the-as int obj) 7) 2) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + name + expected-type + ) + ) + #f + ) + ((not in-goal-mem) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + name + expected-type + ) + ) + #f + ) + (else #t) + ) + ) + ((= expected-type binteger) + (cond + ((zero? (logand (the-as int obj) 7)) #t) + (else + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + name + expected-type + ) + ) + #f + ) + ) + ) + ((!= (logand (the-as int obj) 7) 4) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" + obj + name + expected-type + ) + ) + #f + ) + ((not in-goal-mem) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" + obj + name + expected-type + ) + ) + #f + ) + ((and (= expected-type type) (!= (rtype-of obj) type)) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" + obj + name + expected-type + (rtype-of obj) + ) + ) + #f + ) + (else + (cond + ((and + (!= expected-type type) + (not (valid? (rtype-of obj) type #f #t 0)) + ) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%" + obj + name + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((not (type-type? (rtype-of obj) expected-type)) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' instead)~%" + obj + name + expected-type + (rtype-of obj) + ) + ) + #f + ) + ((= expected-type symbol) + (let ((v1-43 #x8000)) (.daddu v1-44 v1-43 s7-0)) + (cond + ((>= (the-as uint obj) (the-as uint v1-44)) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol table)~%" + obj + name + expected-type + ) + ) + #f + ) + (else #t) ) ) - #f + ((begin + (let ((v1-47 #x8000)) (.daddu v1-48 v1-47 s7-0)) + (< (the-as uint obj) (the-as uint v1-48)) + ) + (if + name + (format + print-dest + "ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol table)~%" + obj + name + expected-type + ) + ) + #f + ) + (else #t) ) - (else #t) ) ) ) @@ -1340,5 +1328,4 @@ ) ;; failed to figure out what this is: -(set! v0-3 0) - +(let ((v0-3 0))) diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp index aa33cfcb6..4a0da8109 100644 --- a/test/decompiler/test_FormExpressionBuild.cpp +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -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"}}); diff --git a/test/decompiler/test_FormExpressionBuildLong.cpp b/test/decompiler/test_FormExpressionBuildLong.cpp index b248c821d..2be3e3c4a 100644 --- a/test/decompiler/test_FormExpressionBuildLong.cpp +++ b/test/decompiler/test_FormExpressionBuildLong.cpp @@ -539,144 +539,165 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { std::string expected = "(begin\n" " (format #t \"#(\")\n" - " (cond\n" - " ((type-type? (-> arg0 content-type) integer)\n" - " (set! v1-1 (-> arg0 content-type symbol))\n" + " (if\n" + " (type-type? (-> arg0 content-type) integer)\n" + " (let\n" + " ((v1-1 (-> arg0 content-type symbol)))\n" " (cond\n" " ((= v1-1 (quote int32))\n" - " (set! s5-0 0)\n" - " (while\n" - " (< s5-0 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-0) \"~D\" \" ~D\")\n" - " (-> (the-as (array int32) arg0) s5-0)\n" + " (let\n" + " ((s5-0 0))\n" + " (while\n" + " (< s5-0 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-0) \"~D\" \" ~D\")\n" + " (-> (the-as (array int32) arg0) s5-0)\n" + " )\n" + " (+! s5-0 1)\n" " )\n" - " (+! s5-0 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint32))\n" - " (set! s5-1 0)\n" - " (while\n" - " (< s5-1 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-1) \"~D\" \" ~D\")\n" - " (-> (the-as (array uint32) arg0) s5-1)\n" + " (let\n" + " ((s5-1 0))\n" + " (while\n" + " (< s5-1 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-1) \"~D\" \" ~D\")\n" + " (-> (the-as (array uint32) arg0) s5-1)\n" + " )\n" + " (+! s5-1 1)\n" " )\n" - " (+! s5-1 1)\n" " )\n" " )\n" " ((= v1-1 (quote int64))\n" - " (set! s5-2 0)\n" - " (while\n" - " (< s5-2 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-2) \"~D\" \" ~D\")\n" - " (-> (the-as (array int64) arg0) s5-2)\n" + " (let\n" + " ((s5-2 0))\n" + " (while\n" + " (< s5-2 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-2) \"~D\" \" ~D\")\n" + " (-> (the-as (array int64) arg0) s5-2)\n" + " )\n" + " (+! s5-2 1)\n" " )\n" - " (+! s5-2 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint64))\n" - " (set! s5-3 0)\n" - " (while\n" - " (< s5-3 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-3) \"#x~X\" \" #x~X\")\n" - " (-> (the-as (array uint64) arg0) s5-3)\n" + " (let\n" + " ((s5-3 0))\n" + " (while\n" + " (< s5-3 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-3) \"#x~X\" \" #x~X\")\n" + " (-> (the-as (array uint64) arg0) s5-3)\n" + " )\n" + " (+! s5-3 1)\n" " )\n" - " (+! s5-3 1)\n" " )\n" " )\n" " ((= v1-1 (quote int8))\n" - " (set! s5-4 0)\n" - " (while\n" - " (< s5-4 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-4) \"~D\" \" ~D\")\n" - " (-> (the-as (array int8) arg0) s5-4)\n" + " (let\n" + " ((s5-4 0))\n" + " (while\n" + " (< s5-4 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-4) \"~D\" \" ~D\")\n" + " (-> (the-as (array int8) arg0) s5-4)\n" + " )\n" + " (+! s5-4 1)\n" " )\n" - " (+! s5-4 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint8))\n" - " (set! s5-5 0)\n" - " (while\n" - " (< s5-5 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-5) \"~D\" \" ~D\")\n" - " (-> (the-as (array uint8) arg0) s5-5)\n" + " (let\n" + " ((s5-5 0))\n" + " (while\n" + " (< s5-5 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-5) \"~D\" \" ~D\")\n" + " (-> (the-as (array uint8) arg0) s5-5)\n" + " )\n" + " (+! s5-5 1)\n" " )\n" - " (+! s5-5 1)\n" " )\n" " )\n" " ((= v1-1 (quote int16))\n" - " (set! s5-6 0)\n" - " (while\n" - " (< s5-6 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-6) \"~D\" \" ~D\")\n" - " (-> (the-as (array int16) arg0) s5-6)\n" + " (let\n" + " ((s5-6 0))\n" + " (while\n" + " (< s5-6 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-6) \"~D\" \" ~D\")\n" + " (-> (the-as (array int16) arg0) s5-6)\n" + " )\n" + " (+! s5-6 1)\n" " )\n" - " (+! s5-6 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint16))\n" - " (set! s5-7 0)\n" - " (while\n" - " (< s5-7 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-7) \"~D\" \" ~D\")\n" - " (-> (the-as (array uint16) arg0) s5-7)\n" + " (let\n" + " ((s5-7 0))\n" + " (while\n" + " (< s5-7 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-7) \"~D\" \" ~D\")\n" + " (-> (the-as (array uint16) arg0) s5-7)\n" + " )\n" + " (+! s5-7 1)\n" " )\n" - " (+! s5-7 1)\n" " )\n" " )\n" " (else\n" " (cond\n" " ((or (= v1-1 (quote uint128)) (= v1-1 (quote int128)))\n" - " (set! s5-8 0)\n" - " (while\n" - " (< s5-8 (-> arg0 length))\n" - " (set! t9-10 format)\n" - " (set! a0-21 #t)\n" - " (set! a1-11 (if (zero? s5-8) \"#x~X\" \" #x~X\"))\n" - " (set!\n" - " v1-42\n" - " (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0)))\n" + " (let\n" + " ((s5-8 0))\n" + " (while\n" + " (< s5-8 (-> arg0 length))\n" + " (let\n" + " ((t9-10 format) (a0-21 #t) (a1-11 (if (zero? s5-8) \"#x~X\" \" #x~X\")))\n" + " (let\n" + " ((v1-42 (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0))))\n" + " )\n" + " (.lq a2-8 12 v1-42)\n" + " )\n" + " (t9-10 a0-21 a1-11 a2-8)\n" + " )\n" + " (+! s5-8 1)\n" " )\n" - " (.lq a2-8 12 v1-42)\n" - " (t9-10 a0-21 a1-11 a2-8)\n" - " (+! s5-8 1)\n" " )\n" " )\n" " (else\n" - " (set! s5-9 0)\n" - " (while\n" - " (< s5-9 (-> arg0 length))\n" - " (format\n" - " #t\n" - " (if (zero? s5-9) \"~D\" \" ~D\")\n" - " (-> (the-as (array int32) arg0) s5-9)\n" + " (let\n" + " ((s5-9 0))\n" + " (while\n" + " (< s5-9 (-> arg0 length))\n" + " (format\n" + " #t\n" + " (if (zero? s5-9) \"~D\" \" ~D\")\n" + " (-> (the-as (array int32) arg0) s5-9)\n" + " )\n" + " (+! s5-9 1)\n" " )\n" - " (+! s5-9 1)\n" " )\n" " )\n" " )\n" " )\n" " )\n" " )\n" - " (else\n" - " (cond\n" - " ((= (-> arg0 content-type) float)\n" - " (set! s5-10 0)\n" + " (cond\n" + " ((= (-> arg0 content-type) float)\n" + " (let\n" + " ((s5-10 0))\n" " (while\n" " (< s5-10 (-> arg0 length))\n" " (if\n" @@ -687,8 +708,10 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " (+! s5-10 1)\n" " )\n" " )\n" - " (else\n" - " (set! s5-11 0)\n" + " )\n" + " (else\n" + " (let\n" + " ((s5-11 0))\n" " (while\n" " (< s5-11 (-> arg0 length))\n" " (if\n" @@ -1192,176 +1215,148 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " (format #t \"~Tallocated-length: ~D~%\" (-> arg0 allocated-length))\n" " (format #t \"~Tlength: ~D~%\" (-> arg0 length))\n" " (format #t \" ~Tcontent-type: ~A~%\" (-> arg0 content-type))\n" - " (format\n" - " #t\n" - " \"~Tdata[~D]: @ #x~X~%\"\n" - " (-> arg0 allocated-length)\n" - " (-> arg0 data)\n" - " )\n" - " (cond\n" - " ((type-type? (-> arg0 content-type) integer)\n" - " (set! v1-1 (-> arg0 content-type symbol))\n" + " (format #t \"~Tdata[~D]: @ #x~X~%\" (-> arg0 allocated-length) (-> arg0 data))\n" + " (if\n" + " (type-type? (-> arg0 content-type) integer)\n" + " (let\n" + " ((v1-1 (-> arg0 content-type symbol)))\n" " (cond\n" " ((= v1-1 (quote int32))\n" - " (set! s5-0 0)\n" - " (while\n" - " (< s5-0 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~D~%\"\n" - " s5-0\n" - " (-> (the-as (array int32) arg0) s5-0)\n" + " (let\n" + " ((s5-0 0))\n" + " (while\n" + " (< s5-0 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-0 (-> (the-as (array int32) arg0) s5-0))\n" + " (+! s5-0 1)\n" " )\n" - " (+! s5-0 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint32))\n" - " (set! s5-1 0)\n" - " (while\n" - " (< s5-1 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~D~%\"\n" - " s5-1\n" - " (-> (the-as (array uint32) arg0) s5-1)\n" + " (let\n" + " ((s5-1 0))\n" + " (while\n" + " (< s5-1 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-1 (-> (the-as (array uint32) arg0) s5-1))\n" + " (+! s5-1 1)\n" " )\n" - " (+! s5-1 1)\n" " )\n" " )\n" " ((= v1-1 (quote int64))\n" - " (set! s5-2 0)\n" - " (while\n" - " (< s5-2 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~D~%\"\n" - " s5-2\n" - " (-> (the-as (array int64) arg0) s5-2)\n" + " (let\n" + " ((s5-2 0))\n" + " (while\n" + " (< s5-2 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-2 (-> (the-as (array int64) arg0) s5-2))\n" + " (+! s5-2 1)\n" " )\n" - " (+! s5-2 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint64))\n" - " (set! s5-3 0)\n" - " (while\n" - " (< s5-3 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] #x~X~%\"\n" - " s5-3\n" - " (-> (the-as (array uint64) arg0) s5-3)\n" + " (let\n" + " ((s5-3 0))\n" + " (while\n" + " (< s5-3 (-> arg0 length))\n" + " (format\n" + " #t\n" + " \"~T [~D] #x~X~%\"\n" + " s5-3\n" + " (-> (the-as (array uint64) arg0) s5-3)\n" + " )\n" + " (+! s5-3 1)\n" " )\n" - " (+! s5-3 1)\n" " )\n" " )\n" " ((= v1-1 (quote int8))\n" - " (set! s5-4 0)\n" - " (while\n" - " (< s5-4 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~D~%\"\n" - " s5-4\n" - " (-> (the-as (array int8) arg0) s5-4)\n" + " (let\n" + " ((s5-4 0))\n" + " (while\n" + " (< s5-4 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-4 (-> (the-as (array int8) arg0) s5-4))\n" + " (+! s5-4 1)\n" " )\n" - " (+! s5-4 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint8))\n" - " (set! s5-5 0)\n" - " (while\n" - " (< s5-5 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~D~%\"\n" - " s5-5\n" - " (-> (the-as (array int8) arg0) s5-5)\n" + " (let\n" + " ((s5-5 0))\n" + " (while\n" + " (< s5-5 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-5 (-> (the-as (array int8) arg0) s5-5))\n" + " (+! s5-5 1)\n" " )\n" - " (+! s5-5 1)\n" " )\n" " )\n" " ((= v1-1 (quote int16))\n" - " (set! s5-6 0)\n" - " (while\n" - " (< s5-6 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~D~%\"\n" - " s5-6\n" - " (-> (the-as (array int16) arg0) s5-6)\n" + " (let\n" + " ((s5-6 0))\n" + " (while\n" + " (< s5-6 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-6 (-> (the-as (array int16) arg0) s5-6))\n" + " (+! s5-6 1)\n" " )\n" - " (+! s5-6 1)\n" " )\n" " )\n" " ((= v1-1 (quote uint16))\n" - " (set! s5-7 0)\n" - " (while\n" - " (< s5-7 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~D~%\"\n" - " s5-7\n" - " (-> (the-as (array uint16) arg0) s5-7)\n" + " (let\n" + " ((s5-7 0))\n" + " (while\n" + " (< s5-7 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-7 (-> (the-as (array uint16) arg0) s5-7))\n" + " (+! s5-7 1)\n" " )\n" - " (+! s5-7 1)\n" " )\n" " )\n" " (else\n" " (cond\n" " ((or (= v1-1 (quote int128)) (= v1-1 (quote uint128)))\n" - " (set! s5-8 0)\n" - " (while\n" - " (< s5-8 (-> arg0 length))\n" - " (set! t9-14 format)\n" - " (set! a0-25 #t)\n" - " (set! a1-15 \"~T [~D] #x~X~%\")\n" - " (set! a2-13 s5-8)\n" - " (set!\n" - " v1-42\n" - " (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0)))\n" + " (let\n" + " ((s5-8 0))\n" + " (while\n" + " (< s5-8 (-> arg0 length))\n" + " (let\n" + " ((t9-14 format) (a0-25 #t) (a1-15 \"~T [~D] #x~X~%\") (a2-13 s5-8))\n" + " (let\n" + " ((v1-42 (+ (shl s5-8 4) (the-as int (the-as (array uint128) arg0))))\n" + " )\n" + " (.lq a3-10 12 v1-42)\n" + " )\n" + " (t9-14 a0-25 a1-15 a2-13 a3-10)\n" + " )\n" + " (+! s5-8 1)\n" " )\n" - " (.lq a3-10 12 v1-42)\n" - " (t9-14 a0-25 a1-15 a2-13 a3-10)\n" - " (+! s5-8 1)\n" " )\n" " )\n" " (else\n" - " (set! s5-9 0)\n" - " (while\n" - " (< s5-9 (-> arg0 length))\n" - " (format #t \"~T [~D] ~D~%\" s5-9 (-> arg0 s5-9))\n" - " (+! s5-9 1)\n" + " (let\n" + " ((s5-9 0))\n" + " (while\n" + " (< s5-9 (-> arg0 length))\n" + " (format #t \"~T [~D] ~D~%\" s5-9 (-> arg0 s5-9))\n" + " (+! s5-9 1)\n" + " )\n" " )\n" " )\n" " )\n" " )\n" " )\n" " )\n" - " (else\n" - " (cond\n" - " ((= (-> arg0 content-type) float)\n" - " (set! s5-10 0)\n" + " (cond\n" + " ((= (-> arg0 content-type) float)\n" + " (let\n" + " ((s5-10 0))\n" " (while\n" " (< s5-10 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~f~%\"\n" - " s5-10\n" - " (-> (the-as (array float) arg0) s5-10)\n" - " )\n" + " (format #t \"~T [~D] ~f~%\" s5-10 (-> (the-as (array float) arg0) s5-10))\n" " (+! s5-10 1)\n" " )\n" " )\n" - " (else\n" - " (set! s5-11 0)\n" + " )\n" + " (else\n" + " (let\n" + " ((s5-11 0))\n" " (while\n" " (< s5-11 (-> arg0 length))\n" - " (format\n" - " #t\n" - " \"~T [~D] ~A~%\"\n" - " s5-11\n" - " (-> (the-as (array basic) arg0) s5-11)\n" - " )\n" + " (format #t \"~T [~D] ~A~%\" s5-11 (-> (the-as (array basic) arg0) s5-11))\n" " (+! s5-11 1)\n" " )\n" " )\n" @@ -1919,13 +1914,13 @@ TEST_F(FormRegressionTest, ExprValid) { std::string type = "(function object type basic basic object symbol)"; std::string expected = - "(begin\n" - " (set!\n" - " v1-1\n" + "(let\n" + " ((v1-1\n" " (and\n" " (>= (the-as uint arg0) (the-as uint __START-OF-TABLE__))\n" - " (< (the-as uint arg0) (the-as uint 134217728))\n" + " (< (the-as uint arg0) (the-as uint #x8000000))\n" " )\n" + " )\n" " )\n" " (cond\n" " ((not arg1)\n" @@ -1933,24 +1928,24 @@ TEST_F(FormRegressionTest, ExprValid) { " ((nonzero? (logand (the-as int arg0) 3))\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object (misaligned)~%\"\n" - " arg0\n" - " arg2\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object (misaligned)~%\"\n" + " arg0\n" + " arg2\n" + " )\n" " )\n" " #f\n" " )\n" " ((not v1-1)\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object (bad address)~%\"\n" - " arg0\n" - " arg2\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object (bad address)~%\"\n" + " arg0\n" + " arg2\n" + " )\n" " )\n" " #f\n" " )\n" @@ -1965,33 +1960,32 @@ TEST_F(FormRegressionTest, ExprValid) { " ((nonzero? (logand (the-as int arg0) 15))\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" " ((or\n" " (not v1-1)\n" " (begin\n" - " (set! v1-10 32768)\n" - " (.daddu v1-11 v1-10 s7-0)\n" + " (let ((v1-10 #x8000)) (.daddu v1-11 v1-10 s7-0))\n" " (< (the-as uint arg0) (the-as uint v1-11))\n" " )\n" " )\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" @@ -2003,26 +1997,26 @@ TEST_F(FormRegressionTest, ExprValid) { " ((!= (logand (the-as int arg0) 7) 2)\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" " ((not v1-1)\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" @@ -2035,13 +2029,13 @@ TEST_F(FormRegressionTest, ExprValid) { " (else\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" @@ -2050,94 +2044,89 @@ TEST_F(FormRegressionTest, ExprValid) { " ((!= (logand (the-as int arg0) 7) 4)\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" " ((not v1-1)\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" " ((and (= arg1 type) (!= (rtype-of arg0) type))\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type " - "#x~X)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " (rtype-of arg0)\n" - " )\n" + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%\"\n" + " arg0\n" + " arg2\n" + " arg1\n" + " (rtype-of arg0)\n" + " )\n" " )\n" " #f\n" " )\n" " (else\n" " (cond\n" - " ((and\t\n" - " (!= arg1 type)\t\n" - " (not (valid? (rtype-of arg0) type #f #t 0))\t\n" - " )\n" + " ((and (!= arg1 type) (not (valid? (rtype-of arg0) type #f #t 0)))\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type " + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type " "#x~X)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " (rtype-of arg0)\n" - " )\n" + " arg0\n" + " arg2\n" + " arg1\n" + " (rtype-of arg0)\n" + " )\n" " )\n" " #f\n" " )\n" " ((not (type-type? (rtype-of arg0) arg1))\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' " + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' " "instead)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " (rtype-of arg0)\n" - " )\n" + " arg0\n" + " arg2\n" + " arg1\n" + " (rtype-of arg0)\n" + " )\n" " )\n" " #f\n" " )\n" " ((= arg1 symbol)\n" - " (set! v1-43 32768)\n" - " (.daddu v1-44 v1-43 s7-0)\n" + " (let ((v1-43 #x8000)) (.daddu v1-44 v1-43 s7-0))\n" " (cond\n" " ((>= (the-as uint arg0) (the-as uint v1-44))\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol " + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol " "table)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" @@ -2145,20 +2134,19 @@ TEST_F(FormRegressionTest, ExprValid) { " )\n" " )\n" " ((begin\n" - " (set! v1-47 32768)\n" - " (.daddu v1-48 v1-47 s7-0)\n" + " (let ((v1-47 #x8000)) (.daddu v1-48 v1-47 s7-0))\n" " (< (the-as uint arg0) (the-as uint v1-48))\n" " )\n" " (if\n" " arg2\n" - " (format\n" - " arg4\n" - " \"ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol " + " (format\n" + " arg4\n" + " \"ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol " "table)~%\"\n" - " arg0\n" - " arg2\n" - " arg1\n" - " )\n" + " arg0\n" + " arg2\n" + " arg1\n" + " )\n" " )\n" " #f\n" " )\n" @@ -2465,101 +2453,97 @@ TEST_F(FormRegressionTest, ExprStringToInt) { std::string type = "(function string int)"; std::string expected = "(defun test-function ((arg0 string))\n" - " (local-vars\n" - " (v0-0 int)\n" - " (v1-0 symbol)\n" - " (a0-1 (pointer uint8))\n" - " (a0-2 (pointer uint8))\n" - " (a0-3 (pointer uint8))\n" - " (a0-4 (pointer uint8))\n" - " (a1-8 (pointer uint8))\n" - " (a1-14 uint)\n" - " (a1-20 uint)\n" - " (a1-23 uint)\n" - " (a1-47 (pointer uint8))\n" - " )\n" - " (set! a0-1 (-> arg0 data))\n" - " (set! v0-0 0)\n" - " (set! v1-0 #f)\n" - " (cond\n" - " ((= (-> a0-1 0) 35)\n" - " (set! a0-2 (&-> a0-1 1))\n" - " (cond\n" - " ((or (= (-> a0-2 0) 120) (= (-> a0-2 0) 88))\n" - " (set! a0-3 (&-> a0-2 1))\n" - " (when\n" - " (= (-> a0-3 1) 45)\n" - " (set! v1-0 #t)\n" - " (set! a0-3 (&-> a0-3 1))\n" - " (set! a1-8 a0-3)\n" - " )\n" - " (while\n" - " (or\n" - " (and\n" - " (>= (-> a0-3 0) (the-as uint 48))\n" - " (>= (the-as uint 57) (-> a0-3 0))\n" - " )\n" - " (and\n" - " (>= (-> a0-3 0) (the-as uint 65))\n" - " (>= (the-as uint 70) (-> a0-3 0))\n" - " )\n" - " (and\n" - " (>= (-> a0-3 0) (the-as uint 97))\n" - " (>= (the-as uint 102) (-> a0-3 0))\n" - " )\n" - " )\n" - " (cond\n" - " ((and\n" - " (>= (-> a0-3 0) (the-as uint 65))\n" - " (>= (the-as uint 70) (-> a0-3 0))\n" + " (let\n" + " ((a0-1 (-> arg0 data)) (v0-0 0) (v1-0 #f))\n" + " (cond\n" + " ((= (-> a0-1 0) 35)\n" + " (let\n" + " ((a0-2 (&-> a0-1 1)))\n" + " (cond\n" + " ((or (= (-> a0-2 0) 120) (= (-> a0-2 0) 88))\n" + " (let\n" + " ((a0-3 (&-> a0-2 1)))\n" + " (when\n" + " (= (-> a0-3 1) 45)\n" + " (set! v1-0 #t)\n" + " (set! a0-3 (&-> a0-3 1))\n" + " (let ((a1-8 a0-3)))\n" " )\n" - " (set! v0-0 (+ (+ (-> a0-3 0) -55) (the-as uint (shl v0-0 4))))\n" - " (set! a1-14 v0-0)\n" - " )\n" - " (else\n" - " (cond\n" - " ((and\t\n" - " (>= (-> a0-3 0) (the-as uint 97))\t\n" - " (>= (the-as uint 102) (-> a0-3 0))\t\n" + " (while\n" + " (or\n" + " (and\n" + " (>= (-> a0-3 0) (the-as uint 48))\n" + " (>= (the-as uint 57) (-> a0-3 0))\n" + " )\n" + " (and\n" + " (>= (-> a0-3 0) (the-as uint 65))\n" + " (>= (the-as uint 70) (-> a0-3 0))\n" + " )\n" + " (and\n" + " (>= (-> a0-3 0) (the-as uint 97))\n" + " (>= (the-as uint 102) (-> a0-3 0))\n" " )\n" - " (set! v0-0 (+ (+ (-> a0-3 0) -87) (the-as uint (shl v0-0 4))))\n" - " (set! a1-20 v0-0)\n" " )\n" - " (else\n" - " (set! v0-0 (+ (+ (-> a0-3 0) -48) (the-as uint (shl v0-0 4))))\n" - " (set! a1-23 v0-0)\n" + " (cond\n" + " ((and\n" + " (>= (-> a0-3 0) (the-as uint 65))\n" + " (>= (the-as uint 70) (-> a0-3 0))\n" + " )\n" + " (set! v0-0 (+ (+ (-> a0-3 0) -55) (the-as uint (shl v0-0 4))))\n" + " (let ((a1-14 v0-0)))\n" + " )\n" + " (else\n" + " (cond\n" + " ((and\n" + " (>= (-> a0-3 0) (the-as uint 97))\n" + " (>= (the-as uint 102) (-> a0-3 0))\n" + " )\n" + " (set! v0-0 (+ (+ (-> a0-3 0) -87) (the-as uint (shl v0-0 4))))\n" + " (let ((a1-20 v0-0)))\n" + " )\n" + " (else\n" + " (set! v0-0 (+ (+ (-> a0-3 0) -48) (the-as uint (shl v0-0 4))))\n" + " (let ((a1-23 v0-0)))\n" + " )\n" + " )\n" + " )\n" " )\n" + " (set! a0-3 (&-> a0-3 1))\n" + " )\n" + " )\n" + " )\n" + " ((or (= (-> a0-2 0) 98) (= (-> a0-2 0) 66))\n" + " (let\n" + " ((a0-4 (&-> a0-2 1)))\n" + " (while\n" + " (and\n" + " (>= (-> a0-4 0) (the-as uint 48))\n" + " (>= (the-as uint 49) (-> a0-4 0))\n" + " )\n" + " (set! v0-0 (+ (+ (-> a0-4 0) -48) (the-as uint (shl v0-0 1))))\n" + " (set! a0-4 (&-> a0-4 1))\n" " )\n" " )\n" " )\n" - " (set! a0-3 (&-> a0-3 1))\n" - " )\n" - " )\n" - " ((or (= (-> a0-2 0) 98) (= (-> a0-2 0) 66))\n" - " (set! a0-4 (&-> a0-2 1))\n" - " (while\n" - " (and (>= (-> a0-4 0) (the-as uint 48)) (>= (the-as uint 49) (-> a0-4 0)))\n" - " (set! v0-0 (+ (+ (-> a0-4 0) -48) (the-as uint (shl v0-0 1))))\n" - " (set! a0-4 (&-> a0-4 1))\n" " )\n" " )\n" " )\n" - " )\n" - " (else\n" - " (when\n" - " (= (-> a0-1 1) 45)\n" - " (set! v1-0 #t)\n" - " (set! a0-1 (&-> a0-1 1))\n" - " (set! a1-47 a0-1)\n" - " )\n" - " (while\n" - " (and (>= (-> a0-1 0) (the-as uint 48)) (>= (the-as uint 57) (-> a0-1 0)))\n" - " (set! v0-0 (+ (+ (-> a0-1 0) -48) (the-as uint (* 10 v0-0))))\n" - " (set! a0-1 (&-> a0-1 1))\n" + " (else\n" + " (when\n" + " (= (-> a0-1 1) 45)\n" + " (set! v1-0 #t)\n" + " (set! a0-1 (&-> a0-1 1))\n" + " (let ((a1-47 a0-1)))\n" + " )\n" + " (while\n" + " (and (>= (-> a0-1 0) (the-as uint 48)) (>= (the-as uint 57) (-> a0-1 0)))\n" + " (set! v0-0 (+ (+ (-> a0-1 0) -48) (the-as uint (* 10 v0-0))))\n" + " (set! a0-1 (&-> a0-1 1))\n" + " )\n" " )\n" " )\n" + " (cond (v1-0 (- v0-0)) (else (empty) v0-0))\n" " )\n" - " (cond (v1-0 (- v0-0)) (else (empty) v0-0))\n" " )"; test_final_function(func, type, expected); } diff --git a/test/decompiler/test_gkernel_decomp.cpp b/test/decompiler/test_gkernel_decomp.cpp index d5a579cf7..bb1539477 100644 --- a/test/decompiler/test_gkernel_decomp.cpp +++ b/test/decompiler/test_gkernel_decomp.cpp @@ -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] # ~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] # ~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); } \ No newline at end of file diff --git a/test/decompiler/test_math_decomp.cpp b/test/decompiler/test_math_decomp.cpp index 67a07ac12..fb562efa1 100644 --- a/test/decompiler/test_math_decomp.cpp +++ b/test/decompiler/test_math_decomp.cpp @@ -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" " )"; diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index 5ad2167c1..fb10d82d6 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -40,7 +40,20 @@ const std::unordered_set expected_skip_in_decompiler = { const std::unordered_set 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);