diff --git a/common/versions.h b/common/versions.h index 17e58b86b8..52316f8275 100644 --- a/common/versions.h +++ b/common/versions.h @@ -12,7 +12,7 @@ namespace versions { constexpr s32 GOAL_VERSION_MAJOR = 0; constexpr s32 GOAL_VERSION_MINOR = 6; -constexpr int DECOMPILER_VERSION = 1; +constexpr int DECOMPILER_VERSION = 2; // these versions are from the game constexpr u32 ART_FILE_VERSION = 6; diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index c9ca614cdf..8522d1c713 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -153,6 +153,38 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { } } + if (input_type.kind == TP_Type::Kind::OBJECT_PLUS_PRODUCT_WITH_CONSTANT) { + FieldReverseLookupInput rd_in; + DerefKind dk; + dk.is_store = true; + dk.reg_kind = get_reg_kind(ro.reg); + dk.size = m_size; + rd_in.deref = dk; + rd_in.base_type = input_type.get_obj_plus_const_mult_typespec(); + rd_in.stride = input_type.get_multiplier(); + rd_in.offset = ro.offset; + auto rd = env.dts->ts.reverse_field_lookup(rd_in); + + if (rd.success) { + std::vector tokens; + assert(!rd.tokens.empty()); + for (auto& token : rd.tokens) { + tokens.push_back(to_token(token)); + } + + // we pass along the register offset because code generation seems to be a bit + // different in different cases. + auto source = pool.alloc_single_element_form( + nullptr, ro.var, tokens, input_type.get_multiplier(), ro.offset); + + auto val = pool.alloc_single_element_form( + nullptr, m_value.as_expr(), m_my_idx); + + assert(!rd.addr_of); + return pool.alloc_element(source, val); + } + } + FieldReverseLookupInput rd_in; DerefKind dk; dk.is_store = true; diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index c9f6891505..dd39927200 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -274,12 +274,16 @@ void SimpleAtomElement::get_modified_regs(RegSet& regs) const { // SetVarElement ///////////////////////////// -SetVarElement::SetVarElement(const Variable& var, Form* value, bool is_sequence_point) - : m_dst(var), m_src(value), m_is_sequence_point(is_sequence_point) { +SetVarElement::SetVarElement(const Variable& var, + Form* value, + bool is_sequence_point, + const SetVarInfo& info) + : m_dst(var), m_src(value), m_is_sequence_point(is_sequence_point), m_var_info(info) { value->parent_element = this; } goos::Object SetVarElement::to_form_internal(const Env& env) const { + assert(active()); return pretty_print::build_list("set!", m_dst.to_form(env), m_src->to_form(env)); } diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index d8619f1221..0ed74a22d2 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -223,7 +223,10 @@ class SimpleAtomElement : public FormElement { */ class SetVarElement : public FormElement { public: - SetVarElement(const Variable& var, Form* value, bool is_sequence_point); + SetVarElement(const Variable& var, + Form* value, + bool is_sequence_point, + const SetVarInfo& info = {}); 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; @@ -241,28 +244,23 @@ class SetVarElement : public FormElement { const Variable& dst() const { return m_dst; } const Form* src() const { return m_src; } Form* src() { return m_src; } - bool is_eliminated_coloring_move() const { return m_is_eliminated_coloring_move; } - void eliminate_as_coloring_move() { m_is_eliminated_coloring_move = true; } + bool is_eliminated_coloring_move() const { return m_var_info.is_eliminated_coloring_move; } + void eliminate_as_coloring_move() { m_var_info.is_eliminated_coloring_move = true; } - bool is_dead_set() const { return m_is_dead_set; } - void mark_as_dead_set() { m_is_dead_set = true; } + bool is_dead_set() const { return m_var_info.is_dead_set; } + void mark_as_dead_set() { m_var_info.is_dead_set = true; } - bool is_dead_false_set() const { return m_is_dead_false; } - void mark_as_dead_false() { m_is_dead_false = true; } + bool is_dead_false_set() const { return m_var_info.is_dead_false; } + void mark_as_dead_false() { m_var_info.is_dead_false = true; } + + const SetVarInfo& info() const { return m_var_info; } private: Variable m_dst; Form* m_src = nullptr; bool m_is_sequence_point = true; - // is this a compiler-inserted move at the beginning of a function - // that should be eliminated? - bool m_is_eliminated_coloring_move = false; - // is this a (set! var expr) which consumes the reg for expr, - // and var is written and unused? - bool m_is_dead_set = false; - // is this a (set! var #f) where the value of #f isn't used? - bool m_is_dead_false = false; + SetVarInfo m_var_info; }; /*! diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index ffd55b638a..4fc53e19a1 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -746,14 +746,14 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta auto& info = env.reg_use().op.at(var.idx()); if (info.consumes.find(var.reg()) != info.consumes.end()) { stack.push_non_seq_reg_to_reg(m_dst, src_as_se->expr().get_arg(0).var(), m_src, - m_is_eliminated_coloring_move); + m_var_info); return; } } } } - stack.push_value_to_reg(m_dst, m_src, true, m_is_eliminated_coloring_move); + stack.push_value_to_reg(m_dst, m_src, true, m_var_info); for (auto x : m_src->elts()) { assert(x->parent_form == m_src); } @@ -773,8 +773,8 @@ void SetVarElement::update_from_stack(const Env& env, void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { // todo - is the order here right? - m_src->update_children_from_stack(env, pool, stack, false); m_dst->update_children_from_stack(env, pool, stack, false); + m_src->update_children_from_stack(env, pool, stack, false); stack.push_form_element(this, true); } @@ -1141,7 +1141,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac } std::vector new_entries; - if (form == entry.body && rewrite_as_set) { + if (form == entry.body && rewrite_as_set && !set_unused) { new_entries = temp_stack.rewrite_to_get_var(pool, *last_var, env); } else { new_entries = temp_stack.rewrite(pool); @@ -1161,7 +1161,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac } std::vector new_entries; - if (rewrite_as_set) { + if (rewrite_as_set && !set_unused) { new_entries = temp_stack.rewrite_to_get_var(pool, *last_var, env); } else { new_entries = temp_stack.rewrite(pool); @@ -1405,23 +1405,40 @@ FormElement* ConditionElement::make_generic(const Env&, } void ConditionElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { - std::vector source_forms; + std::vector source_forms, popped_forms; std::vector source_types; std::vector vars; for (int i = 0; i < get_condition_num_args(m_kind); i++) { - auto& var = m_src[i]->var(); - vars.push_back(var); - source_types.push_back(env.get_types_before_op(var.idx()).get(var.reg()).typespec()); + if (m_src[i]->is_var()) { + auto& var = m_src[i]->var(); + vars.push_back(var); + source_types.push_back(env.get_types_before_op(var.idx()).get(var.reg()).typespec()); + } else if (m_src[i]->is_int()) { + source_types.push_back(TypeSpec("int")); + } else { + throw std::runtime_error("Unsupported atom in ConditionElement::push_to_stack"); + } } if (m_flipped) { std::reverse(vars.begin(), vars.end()); } - source_forms = pop_to_forms(vars, env, pool, stack, true, m_consumed); + popped_forms = pop_to_forms(vars, env, pool, stack, true, m_consumed); if (m_flipped) { - std::reverse(source_forms.begin(), source_forms.end()); + std::reverse(popped_forms.begin(), popped_forms.end()); + } + + int popped_counter = 0; + for (int i = 0; i < get_condition_num_args(m_kind); i++) { + if (m_src[i]->is_var()) { + source_forms.push_back(popped_forms.at(popped_counter++)); + } else { + source_forms.push_back(pool.alloc_single_element_form(nullptr, *m_src[i])); + } } + assert(popped_counter == int(popped_forms.size())); + assert(source_forms.size() == source_types.size()); stack.push_form_element(make_generic(env, pool, source_forms, source_types), true); } diff --git a/decompiler/IR2/FormStack.cpp b/decompiler/IR2/FormStack.cpp index d62d41422d..9230f426c8 100644 --- a/decompiler/IR2/FormStack.cpp +++ b/decompiler/IR2/FormStack.cpp @@ -25,21 +25,24 @@ std::string FormStack::print(const Env& env) { return result; } -void FormStack::push_value_to_reg(Variable var, Form* value, bool sequence_point, bool is_elim) { +void FormStack::push_value_to_reg(Variable var, + Form* value, + bool sequence_point, + const SetVarInfo& info) { assert(value); StackEntry entry; entry.active = true; // by default, we should display everything! entry.sequence_point = sequence_point; entry.destination = var; entry.source = value; - entry.eliminated_as_coloring_move = is_elim; + entry.set_info = info; m_stack.push_back(entry); } void FormStack::push_non_seq_reg_to_reg(const Variable& dst, const Variable& src, Form* src_as_form, - bool is_elim) { + const SetVarInfo& info) { assert(src_as_form); StackEntry entry; entry.active = true; @@ -47,7 +50,7 @@ void FormStack::push_non_seq_reg_to_reg(const Variable& dst, entry.destination = dst; entry.non_seq_source = src; entry.source = src_as_form; - entry.eliminated_as_coloring_move = is_elim; + entry.set_info = info; m_stack.push_back(entry); } @@ -152,10 +155,8 @@ std::vector FormStack::rewrite(FormPool& pool) { } if (e.destination.has_value()) { - auto elt = pool.alloc_element(*e.destination, e.source, e.sequence_point); - if (e.eliminated_as_coloring_move) { - elt->eliminate_as_coloring_move(); - } + auto elt = + pool.alloc_element(*e.destination, e.source, e.sequence_point, e.set_info); e.source->parent_element = elt; result.push_back(elt); } else { diff --git a/decompiler/IR2/FormStack.h b/decompiler/IR2/FormStack.h index 7abae9fb36..bdf51f45fc 100644 --- a/decompiler/IR2/FormStack.h +++ b/decompiler/IR2/FormStack.h @@ -16,11 +16,11 @@ class FormStack { void push_value_to_reg(Variable var, Form* value, bool sequence_point, - bool is_eliminated = false); + const SetVarInfo& info = {}); void push_non_seq_reg_to_reg(const Variable& dst, const Variable& src, Form* src_as_form, - bool is_elim); + const SetVarInfo& info = {}); void push_form_element(FormElement* elt, bool sequence_point); Form* pop_reg(const Variable& var, const RegSet& barrier, @@ -38,11 +38,13 @@ class FormStack { std::optional destination; // what register we are setting (or nullopt if no dest.) std::optional non_seq_source; // source variable, if we are setting var to var. Form* source = nullptr; // the value we are setting the register to. - bool eliminated_as_coloring_move = false; FormElement* elt = nullptr; bool sequence_point = false; TP_Type type; + + SetVarInfo set_info; + std::string print(const Env& env) const; }; std::vector m_stack; diff --git a/decompiler/IR2/IR2_common.h b/decompiler/IR2/IR2_common.h index a1c945487a..3fcb62f115 100644 --- a/decompiler/IR2/IR2_common.h +++ b/decompiler/IR2/IR2_common.h @@ -149,4 +149,16 @@ struct VariableNames { } } }; + +struct SetVarInfo { + // is this a compiler-inserted move at the beginning of a function + // that should be eliminated? + bool is_eliminated_coloring_move = false; + // is this a (set! var expr) which consumes the reg for expr, + // and var is written and unused? + bool is_dead_set = false; + // is this a (set! var #f) where the value of #f isn't used? + bool is_dead_false = false; +}; + } // namespace decompiler diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 4be355fe57..a14b0072b2 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -2031,7 +2031,7 @@ (state int32 :offset-assert 84) (align uint8 6 :offset-assert 88) (direct uint8 6 :offset-assert 94) - (buzz-val uint16 2 :offset-assert 100) + (buzz-val uint8 2 :offset-assert 100) (buzz-time uint64 2 :offset-assert 104) (buzz basic :offset-assert 120) (buzz-act int32 :offset-assert 124) diff --git a/doc/decompiler_changelog.md b/doc/decompiler_changelog.md index 2d0c373d61..a29c0c4d2e 100644 --- a/doc/decompiler_changelog.md +++ b/doc/decompiler_changelog.md @@ -6,4 +6,10 @@ - Remove useless `(set! )` and eliminate useless temporaries created by these. - Remove useless `set!`s sometimes appearing around functions `(set! (some-function ...))` when the result is unused, but moved into a different register. - Recognize `(break!)` (GOAL breakpoint) -- Support `(new 'process ...)` \ No newline at end of file +- Support `(new 'process ...)` + +## Version 2 +- Expressions like `(set! (-> a b) (-> c d))` are much less likely to have fake temporaries. +- Many more useless `set!`s will be removed +- Stores into arrays are supported +- Fixed bug where unused/eliminated temporaries would sometimes be used as the result of a block diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp index 1da94773e6..e50a7e360a 100644 --- a/test/decompiler/test_FormExpressionBuild.cpp +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -623,7 +623,6 @@ TEST_F(FormRegressionTest, ExprFindParentMethod) { " (set! v0-0 (-> arg0 method-table arg1))\n" " (if (zero? v0-0) (return nothing))\n" " )\n" - " (set! v1-5 '#f)\n" " v0-0\n" " )"; test_with_expr(func, type, expected, false, ""); @@ -665,8 +664,6 @@ TEST_F(FormRegressionTest, ExprRef) { " (set! arg0 (cdr arg0))\n" " (set! v1-0 (+ v1-0 1))\n" " )\n" - " (set! v1-1 '#f)\n" - " (set! v1-2 '#f)\n" " (car arg0)\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -732,7 +729,6 @@ TEST_F(FormRegressionTest, ExprPairMethod4) { " (set! v0-0 (+ v0-0 1))\n" " (set! v1-1 (cdr v1-1))\n" " )\n" - " (set! v1-2 '#f)\n" " )\n" " )\n" " v0-0\n" @@ -784,7 +780,6 @@ TEST_F(FormRegressionTest, ExprLast) { " (nop!)\n" " (nop!)\n" " (set! v0-0 (cdr v0-0)))\n" - " (set! v1-1 '#f)\n" " v0-0\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -837,7 +832,6 @@ TEST_F(FormRegressionTest, ExprMember) { " (not (or (= v1-0 '()) (= (car v1-0) arg0)))\n" " (set! v1-0 (cdr v1-0))\n" " )\n" - " (set! a0-1 '#f)\n" " (if (!= v1-0 '()) v1-0)\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -900,7 +894,6 @@ TEST_F(FormRegressionTest, ExprNmember) { " (not (or (= arg1 '()) (name= (the-as basic (car arg1)) arg0)))\n" " (set! arg1 (cdr arg1))\n" " )\n" - " (set! v1-2 '#f)\n" " (if (!= arg1 '()) arg1)\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -952,7 +945,6 @@ TEST_F(FormRegressionTest, ExprAssoc) { " (not (or (= v1-0 '()) (= (car (car v1-0)) arg0)))\n" " (set! v1-0 (cdr v1-0))\n" " )\n" - " (set! a0-1 '#f)\n" " (if (!= v1-0 '()) (car v1-0))\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -1021,7 +1013,6 @@ TEST_F(FormRegressionTest, ExprAssoce) { " )\n" " (set! v1-0 (cdr v1-0))\n" " )\n" - " (set! a0-1 '#f)\n" " (if (!= v1-0 '()) (car v1-0))\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -1113,7 +1104,6 @@ TEST_F(FormRegressionTest, ExprNassoc) { " )\n" " (set! arg1 (cdr arg1))\n" " )\n" - " (set! v1-3 (quote #f))\n" " (if (!= arg1 (quote ())) (car arg1))\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -1219,7 +1209,6 @@ TEST_F(FormRegressionTest, ExprNassoce) { " )\n" " (set! arg1 (cdr arg1))\n" " )\n" - " (set! v1-4 (quote #f))\n" " (if (!= arg1 (quote ())) (car arg1))\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -1275,7 +1264,6 @@ TEST_F(FormRegressionTest, ExprAppend) { " (else\n" " (set! v1-1 arg0)\n" " (while (!= (cdr v1-1) '()) (nop!) (nop!) (set! v1-1 (cdr v1-1)))\n" - " (set! a2-1 '#f)\n" " (if (!= v1-1 '()) (set! (cdr v1-1) arg1))\n" " arg0\n" " )\n" @@ -1351,7 +1339,6 @@ TEST_F(FormRegressionTest, ExprDelete) { " (set! v1-1 a2-0)\n" " (set! a2-0 (cdr a2-0))\n" " )\n" - " (set! a0-1 (quote #f))\n" " (if (!= a2-0 (quote ())) (set! (cdr v1-1) (cdr a2-0)))\n" " arg1\n" " )\n" @@ -1430,7 +1417,6 @@ TEST_F(FormRegressionTest, ExprDeleteCar) { " (set! v1-2 a2-0)\n" " (set! a2-0 (cdr a2-0))\n" " )\n" - " (set! a0-1 (quote #f))\n" " (if (!= a2-0 (quote ())) (set! (cdr v1-2) (cdr a2-0)))\n" " arg1\n" " )\n" @@ -1602,10 +1588,7 @@ TEST_F(FormRegressionTest, ExprSort) { " )\n" " (set! s3-0 (cdr s3-0))\n" " )\n" - " (set! v1-10 (quote #f))\n" - " (set! v1-11 (quote #f))\n" " )\n" - " (set! v1-12 (quote #f))\n" " arg0\n" " )"; test_with_expr(func, type, expected, true, ""); @@ -1894,8 +1877,6 @@ TEST_F(FormRegressionTest, ExprMemCopy) { " (set! arg1 (+ arg1 (the-as uint 1)))\n" " (set! v1-0 (+ v1-0 1))\n" " )\n" - " (set! v1-1 (quote #f))\n" - " (set! v1-2 (quote #f))\n" " v0-0\n" " )"; test_with_expr(func, type, expected); @@ -1937,8 +1918,6 @@ TEST_F(FormRegressionTest, ExprMemSet32) { " (nop!)\n" " (set! v1-0 (+ v1-0 1))\n" " )\n" - " (set! v1-1 (quote #f))\n" - " (set! v1-2 (quote #f))\n" " v0-0\n" " )"; test_with_expr(func, type, expected); @@ -1989,8 +1968,6 @@ TEST_F(FormRegressionTest, ExprMemOr) { " (set! arg1 (+ arg1 (the-as uint 1)))\n" " (set! v1-0 (+ v1-0 1))\n" " )\n" - " (set! v1-1 (quote #f))\n" - " (set! v1-2 (quote #f))\n" " v0-0\n" " )"; test_with_expr(func, type, expected); @@ -2209,7 +2186,6 @@ TEST_F(FormRegressionTest, ExprPrintTreeBitmask) { " (set! arg0 (shr arg0 1))\n" " (set! s4-0 (+ s4-0 1))\n" " )\n" - " (set! v1-3 (quote #f))\n" " (quote #f)\n" " )"; test_with_expr(func, type, expected, false, "", {{"L323", " "}, {"L322", "| "}}); diff --git a/test/decompiler/test_FormExpressionBuildLong.cpp b/test/decompiler/test_FormExpressionBuildLong.cpp index 77b35443df..0d50491273 100644 --- a/test/decompiler/test_FormExpressionBuildLong.cpp +++ b/test/decompiler/test_FormExpressionBuildLong.cpp @@ -554,8 +554,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-0 (+ s5-0 1))\n" " )\n" - " (set! v1-5 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint32))\n" " (set! s5-1 0)\n" @@ -568,8 +566,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-1 (+ s5-1 1))\n" " )\n" - " (set! v1-10 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote int64))\n" " (set! s5-2 0)\n" @@ -582,8 +578,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-2 (+ s5-2 1))\n" " )\n" - " (set! v1-15 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint64))\n" " (set! s5-3 0)\n" @@ -596,8 +590,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-3 (+ s5-3 1))\n" " )\n" - " (set! v1-20 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote int8))\n" " (set! s5-4 0)\n" @@ -610,8 +602,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-4 (+ s5-4 1))\n" " )\n" - " (set! v1-24 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint8))\n" " (set! s5-5 0)\n" @@ -624,8 +614,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-5 (+ s5-5 1))\n" " )\n" - " (set! v1-28 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote int16))\n" " (set! s5-6 0)\n" @@ -638,8 +626,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-6 (+ s5-6 1))\n" " )\n" - " (set! v1-33 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint16))\n" " (set! s5-7 0)\n" @@ -652,10 +638,9 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-7 (+ s5-7 1))\n" " )\n" - " (set! v1-38 (quote #f))\n" - " (quote #f)\n" " )\n" " (else\n" + // todo - why doesn't this merge? " (set! v1-40 (or (= v1-1 (quote uint128)) (= v1-1 (quote int128))))\n" " (cond\n" " (v1-40\n" @@ -673,8 +658,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " (t9-10 a0-21 a1-11 a2-8)\n" " (set! s5-8 (+ s5-8 1))\n" " )\n" - " (set! v1-44 (quote #f))\n" - " (quote #f)\n" " )\n" " (else\n" " (set! s5-9 0)\n" @@ -687,11 +670,8 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-9 (+ s5-9 1))\n" " )\n" - " (set! v1-49 (quote #f))\n" - " (quote #f)\n" " )\n" " )\n" - " v1-39\n" " )\n" " )\n" " )\n" @@ -708,8 +688,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-10 (+ s5-10 1))\n" " )\n" - " (set! v1-59 (quote #f))\n" - " (quote #f)\n" " )\n" " (else\n" " (set! s5-11 0)\n" @@ -722,8 +700,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " (set! s5-11 (+ s5-11 1))\n" " )\n" - " (set! v1-68 (quote #f))\n" - " (quote #f)\n" " )\n" " )\n" " )\n" @@ -1240,8 +1216,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-0 (+ s5-0 1))\n" " )\n" - " (set! v1-5 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint32))\n" " (set! s5-1 0)\n" @@ -1255,8 +1229,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-1 (+ s5-1 1))\n" " )\n" - " (set! v1-10 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote int64))\n" " (set! s5-2 0)\n" @@ -1270,8 +1242,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-2 (+ s5-2 1))\n" " )\n" - " (set! v1-15 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint64))\n" " (set! s5-3 0)\n" @@ -1285,8 +1255,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-3 (+ s5-3 1))\n" " )\n" - " (set! v1-20 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote int8))\n" " (set! s5-4 0)\n" @@ -1300,8 +1268,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-4 (+ s5-4 1))\n" " )\n" - " (set! v1-24 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint8))\n" " (set! s5-5 0)\n" @@ -1315,8 +1281,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-5 (+ s5-5 1))\n" " )\n" - " (set! v1-28 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote int16))\n" " (set! s5-6 0)\n" @@ -1330,8 +1294,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-6 (+ s5-6 1))\n" " )\n" - " (set! v1-33 (quote #f))\n" - " (quote #f)\n" " )\n" " ((= v1-1 (quote uint16))\n" " (set! s5-7 0)\n" @@ -1345,8 +1307,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-7 (+ s5-7 1))\n" " )\n" - " (set! v1-38 (quote #f))\n" - " (quote #f)\n" " )\n" " (else\n" " (set! v1-40 (or (= v1-1 (quote int128)) (= v1-1 (quote uint128))))\n" @@ -1367,8 +1327,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " (t9-14 a0-25 a1-15 a2-13 a3-10)\n" " (set! s5-8 (+ s5-8 1))\n" " )\n" - " (set! v1-44 (quote #f))\n" - " (quote #f)\n" " )\n" " (else\n" " (set! s5-9 0)\n" @@ -1377,11 +1335,8 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " (format (quote #t) \"~T [~D] ~D~%\" s5-9 (-> arg0 s5-9))\n" " (set! s5-9 (+ s5-9 1))\n" " )\n" - " (set! v1-49 (quote #f))\n" - " (quote #f)\n" " )\n" " )\n" - " v1-39\n" " )\n" " )\n" " )\n" @@ -1399,8 +1354,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-10 (+ s5-10 1))\n" " )\n" - " (set! v1-55 (quote #f))\n" - " (quote #f)\n" " )\n" " (else\n" " (set! s5-11 0)\n" @@ -1414,8 +1367,6 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " (set! s5-11 (+ s5-11 1))\n" " )\n" - " (set! v1-60 (quote #f))\n" - " (quote #f)\n" " )\n" " )\n" " )\n" diff --git a/test/decompiler/test_gkernel_decomp.cpp b/test/decompiler/test_gkernel_decomp.cpp index 4730d3e698..cdad51dc27 100644 --- a/test/decompiler/test_gkernel_decomp.cpp +++ b/test/decompiler/test_gkernel_decomp.cpp @@ -105,4 +105,174 @@ TEST_F(FormRegressionTest, ExprUnloadPackage) { " *kernel-packages*\n" " )"; test_with_expr(func, type, expected, true); -} \ No newline at end of file +} + +TEST_F(FormRegressionTest, ExprMethod1Thread) { + std::string func = + " sll r0, r0, 0\n" + "L274:\n" + " lwu v1, 4(a0)\n" + " lwu v1, 40(v1)\n" + " bne a0, v1, L275\n" + " or v1, s7, r0\n" + + " lw r0, 2(r0)\n" + " addiu v1, r0, 0\n" + + "L275:\n" + " lwu v0, 8(a0)\n" + " lwu v1, 4(a0)\n" + " sw v0, 44(v1)\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function thread none)"; + std::string expected = + "(begin\n" + " (when (= arg0 (-> arg0 process main-thread)) (break!) (set! v1-3 0))\n" + " (set! (-> arg0 process top-thread) (-> arg0 previous))\n" + " )"; + test_with_expr(func, type, expected, false); +} + +TEST_F(FormRegressionTest, ExprMethod2Thread) { + std::string func = + " sll r0, r0, 0\n" + "L273:\n" + " daddiu sp, sp, -32\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " sq gp, 16(sp)\n" + + " or gp, a0, r0\n" + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L343\n" + " lwu a2, -4(gp)\n" + " lwu a3, 0(gp)\n" + " lwu v1, 4(gp)\n" + " lwu t0, 0(v1)\n" + " lwu t1, 20(gp)\n" + " or t2, gp, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " lq gp, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 32"; + std::string type = "(function thread thread)"; + std::string expected = + "(begin\n" + " (format\n" + " (quote #t)\n" + " \"#<~A ~S of ~S pc: #x~X @ #x~X>\"\n" + " (-> arg0 type)\n" + " (-> arg0 name)\n" + " (-> arg0 process name)\n" + " (-> arg0 pc)\n" + " arg0\n" + " )\n" + " arg0\n" + " )"; + test_with_expr(func, type, expected, false, "", {{"L343", "#<~A ~S of ~S pc: #x~X @ #x~X>"}}); +} + +TEST_F(FormRegressionTest, ExprMethod9Thread) { + std::string func = + " sll r0, r0, 0\n" + "L268:\n" + " daddiu sp, sp, -16\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + + " lwu a2, 4(a0)\n" + " lwu v1, 40(a2)\n" + " beq a0, v1, L269\n" + " sll r0, r0, 0\n" + + " lw t9, format(s7)\n" + " addiu a0, r0, 0\n" + " daddiu a1, fp, L342\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + " beq r0, r0, L272\n" + " sll r0, r0, 0\n" + + "L269:\n" + " lw v1, 32(a0)\n" + " bne v1, a1, L270\n" + " sll r0, r0, 0\n" + + " or v1, s7, r0\n" + " beq r0, r0, L272\n" + " sll r0, r0, 0\n" + + "L270:\n" + " lw v1, 32(a0)\n" + " daddiu v1, v1, -4\n" + " lwu a3, -4(a0)\n" + " lhu a3, 8(a3)\n" + " daddu v1, v1, a3\n" + " daddu v1, v1, a0\n" + " lwu a3, 84(a2)\n" + " bne a3, v1, L271\n" + " sll r0, r0, 0\n" + + " daddiu v1, a1, -4\n" + " lwu a3, -4(a0)\n" + " lhu a3, 8(a3)\n" + " daddu v1, v1, a3\n" + " daddu v1, v1, a0\n" + " sw v1, 84(a2)\n" + " sw a1, 32(a0)\n" + " or v1, a1, r0\n" + " beq r0, r0, L272\n" + " sll r0, r0, 0\n" + + "L271:\n" + " lw t9, format(s7)\n" + " addiu a0, r0, 0\n" + " daddiu a1, fp, L341\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + + "L272:\n" + " or v0, r0, r0\n" + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " jr ra\n" + " daddiu sp, sp, 16"; + 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" + " )\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" + " (else (format 0 \"2 ~A ~%\" a2-0))\n" + " )\n" + " (set! v0-2 0)\n" + " )"; + test_with_expr(func, type, expected, false, "", {{"L342", "1 ~A ~%"}, {"L341", "2 ~A ~%"}}); +}