From 69e24ae577e51a65f37cdd9da453691cbeb4a784 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 26 Jun 2021 18:30:35 -0400 Subject: [PATCH] recognize vector, matrix, quaternion constructors in a better way (#630) * recognize vector, matrix, quaternion constructors in a better way * fix bad bug --- decompiler/IR2/FormExpressionAnalysis.cpp | 136 ++++++++++++++++++ decompiler/IR2/FormStack.h | 40 +++++- decompiler/analysis/insert_lets.cpp | 99 ------------- goal_src/engine/math/quaternion-h.gc | 10 ++ goal_src/engine/math/quaternion.gc | 84 ++++++----- .../decompiler/reference/decompiler-macros.gc | 11 ++ .../reference/engine/math/matrix_REF.gc | 5 +- .../reference/engine/math/quaternion_REF.gc | 96 +++++++------ .../engine/target/joint-mod-h_REF.gc | 16 +-- test/decompiler/test_FormExpressionBuild2.cpp | 120 ++++++++++++++++ 10 files changed, 415 insertions(+), 202 deletions(-) diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 743ed05c2c..7215663214 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -1721,10 +1721,140 @@ Form* make_optional_cast(const std::optional& cast_type, return in; } } + +bool try_to_rewrite_vector_inline_ctor(const Env& env, + FormPool& pool, + FormStack& stack, + const std::string& type_name) { + // now, let's check for a matrix initialization. + auto matrix_entries = stack.try_getting_active_stack_entries({true, false}); + if (matrix_entries) { + // the (set! var (new 'stack-no-clear 'matrix)) + if (matrix_entries->at(0).destination->reg() == Register(Reg::GPR, Reg::R0)) { + return false; + } + auto var_name = env.get_variable_name(*matrix_entries->at(0).destination); + auto src = matrix_entries->at(0).source->try_as_element(); + if (!src) { + return false; + } + if (src->type() != TypeSpec(type_name)) { + return false; + } + + // zeroing the rows: + std::vector write_vars; + + auto elt = matrix_entries->at(1).elt; + + std::vector token_matchers = {DerefTokenMatcher::string("vec"), + DerefTokenMatcher::string("quad")}; + if (type_name == "vector") { + token_matchers = {DerefTokenMatcher::string("quad")}; + } + + auto matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false, token_matchers), + Matcher::cast("uint128", Matcher::integer(0))); + + Form hack; + hack.elts().push_back(elt); + auto mr = match(matcher, &hack); + + if (mr.matched) { + if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) { + return false; + } + write_vars.push_back(*mr.maps.regs.at(0)); + } else { + return false; + } + + // success! + for (auto& wv : write_vars) { + env.get_use_def_info(wv); + Env* menv = const_cast(&env); + menv->disable_use(wv); + } + stack.pop(2); + + stack.push_value_to_reg( + *matrix_entries->at(0).destination, + pool.alloc_single_element_form( + nullptr, + GenericOperator::make_function(pool.alloc_single_element_form( + nullptr, fmt::format("new-stack-{}0", type_name)))), + true, TypeSpec(type_name)); + return true; + } + return false; +} + +bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack& stack) { + // now, let's check for a matrix initialization. + auto matrix_entries = stack.try_getting_active_stack_entries({true, false, false, false, false}); + if (matrix_entries) { + // the (set! var (new 'stack-no-clear 'matrix)) + if (matrix_entries->at(0).destination->reg() == Register(Reg::GPR, Reg::R0)) { + return false; + } + auto var_name = env.get_variable_name(*matrix_entries->at(0).destination); + auto src = matrix_entries->at(0).source->try_as_element(); + if (!src) { + return false; + } + if (src->type() != TypeSpec("matrix")) { + return false; + } + + // zeroing the rows: + std::vector write_vars; + for (int i = 0; i < 4; i++) { + auto elt = matrix_entries->at(i + 1).elt; + + auto matcher = Matcher::set( + Matcher::deref(Matcher::any_reg(0), false, + {DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i), + DerefTokenMatcher::string("quad")}), + Matcher::cast("uint128", Matcher::integer(0))); + + Form hack; + hack.elts().push_back(elt); + auto mr = match(matcher, &hack); + + if (mr.matched) { + if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) { + return false; + } + write_vars.push_back(*mr.maps.regs.at(0)); + } else { + return false; + } + } + + // success! + for (auto& wv : write_vars) { + env.get_use_def_info(wv); + Env* menv = const_cast(&env); + menv->disable_use(wv); + } + stack.pop(5); + + stack.push_value_to_reg(*matrix_entries->at(0).destination, + pool.alloc_single_element_form( + nullptr, GenericOperator::make_function( + pool.alloc_single_element_form( + nullptr, "new-stack-matrix0"))), + true, TypeSpec("matrix")); + return true; + } + return false; +} + } // namespace void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { mark_popped(); + if (m_expr.is_var()) { // this matches the order in Compiler::compile_set auto vars = std::vector({m_expr.var(), m_base_var}); @@ -1759,6 +1889,12 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s fr->mark_popped(); stack.push_form_element(fr, true); } + + if (!try_to_rewrite_matrix_inline_ctor(env, pool, stack)) { + if (!try_to_rewrite_vector_inline_ctor(env, pool, stack, "vector")) { + try_to_rewrite_vector_inline_ctor(env, pool, stack, "quaternion"); + } + } } void StoreArrayAccess::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { diff --git a/decompiler/IR2/FormStack.h b/decompiler/IR2/FormStack.h index fa5ea18784..dcfdafcfb7 100644 --- a/decompiler/IR2/FormStack.h +++ b/decompiler/IR2/FormStack.h @@ -46,7 +46,6 @@ class FormStack { std::string print(const Env& env); bool is_root() const { return m_is_root_stack; } - private: struct StackEntry { bool active = true; // should this appear in the output? std::optional @@ -64,6 +63,45 @@ class FormStack { std::string print(const Env& env) const; }; + + std::optional> try_getting_active_stack_entries( + const std::vector& is_set) const { + if (is_set.size() > m_stack.size()) { + return {}; + } + + std::vector entries; + size_t offset = m_stack.size() - is_set.size(); + for (size_t i = 0; i < is_set.size(); i++) { + auto& my_entry = m_stack.at(i + offset); + if (my_entry.active) { + if (is_set.at(i)) { + if (!my_entry.destination) { + return {}; + } + assert(my_entry.source && !my_entry.elt); + } else { + if (my_entry.destination) { + return {}; + } + assert(my_entry.elt && !my_entry.source); + } + entries.push_back(my_entry); + } else { + return {}; + } + } + return entries; + } + + void pop(int count) { + for (int i = 0; i < count; i++) { + assert(!m_stack.empty()); + m_stack.pop_back(); + } + } + + private: std::vector m_stack; bool m_is_root_stack = false; }; diff --git a/decompiler/analysis/insert_lets.cpp b/decompiler/analysis/insert_lets.cpp index 3e2a1cbb33..9129b4041c 100644 --- a/decompiler/analysis/insert_lets.cpp +++ b/decompiler/analysis/insert_lets.cpp @@ -336,100 +336,6 @@ FormElement* fix_up_abs_2(LetElement* in, const Env& env, FormPool& pool) { return in; } -FormElement* fix_up_vector_inline_zero(LetElement* in, const Env& env, FormPool& pool) { - /* - * (let ((local-trans (new 'stack-no-clear 'vector))) - * (set! (-> local-trans quad) (the-as uint128 0)) - */ - - if (in->entries().size() != 1) { - return nullptr; - } - - if (in->body()->elts().empty()) { - return nullptr; - } - - Form* src = in->entries().at(0).src; - auto src_as_stackvar = src->try_as_element(); - if (!src_as_stackvar) { - return nullptr; - } - - bool is_vector = src_as_stackvar->type() == TypeSpec("vector"); - bool is_matrix = src_as_stackvar->type() == TypeSpec("matrix"); - - if (is_vector) { - auto first_elt = in->body()->elts().at(0); - - auto matcher = Matcher::set( - Matcher::deref(Matcher::any_reg(0), false, {DerefTokenMatcher::string("quad")}), - Matcher::cast("uint128", Matcher::integer(0))); - - Form hack; - hack.elts().push_back(first_elt); - auto mr = match(matcher, &hack); - - if (mr.matched) { - auto var = in->entries().at(0).dest; - auto var_name = env.get_variable_name(var); - - if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) { - return nullptr; - } - - auto new_op = pool.alloc_single_element_form( - nullptr, - GenericOperator::make_function( - pool.alloc_single_element_form(nullptr, "new-stack-vector0"))); - src->parent_element = in; - in->entries().at(0).src = new_op; - in->body()->elts().erase(in->body()->elts().begin()); - return in; - } - } else if (is_matrix) { - if (in->body()->elts().size() < 4) { - return nullptr; - } - - auto var = in->entries().at(0).dest; - auto var_name = env.get_variable_name(var); - - for (int i = 0; i < 4; i++) { - auto elt = in->body()->elts().at(i); - - auto matcher = Matcher::set( - Matcher::deref(Matcher::any_reg(0), false, - {DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i), - DerefTokenMatcher::string("quad")}), - Matcher::cast("uint128", Matcher::integer(0))); - - Form hack; - hack.elts().push_back(elt); - auto mr = match(matcher, &hack); - - if (mr.matched) { - if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) { - return nullptr; - } - } else { - return nullptr; - } - } - - auto new_op = pool.alloc_single_element_form( - nullptr, - GenericOperator::make_function( - pool.alloc_single_element_form(nullptr, "new-stack-matrix0"))); - src->parent_element = in; - in->entries().at(0).src = new_op; - in->body()->elts().erase(in->body()->elts().begin(), in->body()->elts().begin() + 4); - return in; - } - - return nullptr; -} - /*! * Attempt to rewrite a let as another form. If it cannot be rewritten, this will return nullptr. */ @@ -454,11 +360,6 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool) { return as_abs_2; } - auto as_vector = fix_up_vector_inline_zero(in, env, pool); - if (as_vector) { - return as_vector; - } - // nothing matched. return nullptr; } diff --git a/goal_src/engine/math/quaternion-h.gc b/goal_src/engine/math/quaternion-h.gc index 0b992c67ff..f74cdd729b 100644 --- a/goal_src/engine/math/quaternion-h.gc +++ b/goal_src/engine/math/quaternion-h.gc @@ -23,3 +23,13 @@ (define-extern matrix->quaternion (function quaternion matrix quaternion)) (define-extern vector-y-angle (function vector float)) + +(defmacro new-stack-quaternion0 () + "Get a stack quaternion that's set to 0. + This is more efficient than (new 'stack 'quaternion) because + this doesn't call the constructor." + `(let ((q (new 'stack-no-clear 'quaternion))) + (set! (-> q quad) (the-as uint128 0)) + q + ) + ) diff --git a/goal_src/engine/math/quaternion.gc b/goal_src/engine/math/quaternion.gc index 532f82a490..885ea5664f 100644 --- a/goal_src/engine/math/quaternion.gc +++ b/goal_src/engine/math/quaternion.gc @@ -892,84 +892,80 @@ (defun quaternion-rotate-local-x! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) "Rotate existing quaternion along x axis." - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) + (let ((a2-1 (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :x 1.0 :w 1.0) + arg2 + ) + ) ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a2-1 (t9-0 a0-1 (new 'static 'vector :x 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) - ) + (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) ) ) (defun quaternion-rotate-local-y! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) "Rotate existing quaternion along y axis" - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) + (let ((a2-1 (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :y 1.0 :w 1.0) + arg2 + ) + ) ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a2-1 (t9-0 a0-1 (new 'static 'vector :y 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) - ) + (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) ) ) (defun quaternion-rotate-local-z! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) "Rotate existing quaternion along z axis." - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) + (let ((a2-1 (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :z 1.0 :w 1.0) + arg2 + ) + ) ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a2-1 (t9-0 a0-1 (new 'static 'vector :z 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) - ) + (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) ) ) (defun quaternion-rotate-y! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) "Rotate existing quaternion along y axis (right multiply)" - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) + (let ((a1-2 (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :y 1.0 :w 1.0) + arg2 + ) + ) ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a1-2 (t9-0 a0-1 (new 'static 'vector :y 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 a1-2 arg1)) - ) + (quaternion-normalize! (quaternion*! arg0 a1-2 arg1)) ) ) (defun quaternion-rotate-x! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) "Rotate existing quaternion along x axis. This has a different implementation from the others for some reason." - (let ((s4-0 quaternion-vector-angle!) - (s3-0 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> s3-0 vec quad) (the-as uint128 0)) - (let ((t9-0 vector-x-quaternion!) - (a0-1 (new 'stack-no-clear 'vector)) + (let ((a1-3 (quaternion-vector-angle! + (new-stack-quaternion0) + (vector-x-quaternion! (new-stack-vector0) arg1) + arg2 + ) ) - (set! (-> a0-1 quad) (the-as uint128 0)) - (let ((a1-3 (s4-0 s3-0 (t9-0 a0-1 arg1) arg2))) - (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) ) - ) + (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) ) ) (defun quaternion-rotate-z! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) "Rotate existing quaternion along z axis. Has the weird implementation too." - (let ((s4-0 quaternion-vector-angle!) - (s3-0 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> s3-0 vec quad) (the-as uint128 0)) - (let ((t9-0 vector-z-quaternion!) - (a0-1 (new 'stack-no-clear 'vector)) + (let ((a1-3 (quaternion-vector-angle! + (new-stack-quaternion0) + (vector-z-quaternion! (new-stack-vector0) arg1) + arg2 + ) ) - (set! (-> a0-1 quad) (the-as uint128 0)) - (let ((a1-3 (s4-0 s3-0 (t9-0 a0-1 arg1) arg2))) - (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) ) - ) + (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) ) ) diff --git a/test/decompiler/reference/decompiler-macros.gc b/test/decompiler/reference/decompiler-macros.gc index 465a039592..59ab73bdb0 100644 --- a/test/decompiler/reference/decompiler-macros.gc +++ b/test/decompiler/reference/decompiler-macros.gc @@ -66,6 +66,17 @@ ) ) +(defmacro new-stack-quaternion0 () + "Get a stack quaternion that's set to 0. + This is more efficient than (new 'stack 'quaternion) because + this doesn't call the constructor." + `(let ((q (new 'stack-no-clear 'quaternion))) + (set! (-> q quad) (the-as uint128 0)) + q + ) + ) + + (defmacro with-pp (&rest body) `(rlet ((pp :reg r13 :reset-here #t :type process)) ,@body) diff --git a/test/decompiler/reference/engine/math/matrix_REF.gc b/test/decompiler/reference/engine/math/matrix_REF.gc index ec043498a3..37cae577b8 100644 --- a/test/decompiler/reference/engine/math/matrix_REF.gc +++ b/test/decompiler/reference/engine/math/matrix_REF.gc @@ -772,10 +772,7 @@ ;; Used lq/sq (defun matrix-rotate-yx! ((dst matrix) (rot-y-deg float) (rot-x-deg float)) (matrix-rotate-y! dst rot-y-deg) - (let* ((t9-1 matrix-rotate-x!) - (a0-2 (new-stack-matrix0)) - (a1-2 (t9-1 a0-2 rot-x-deg)) - ) + (let ((a1-2 (matrix-rotate-x! (new-stack-matrix0) rot-x-deg))) (matrix*! dst a1-2 dst) ) dst diff --git a/test/decompiler/reference/engine/math/quaternion_REF.gc b/test/decompiler/reference/engine/math/quaternion_REF.gc index 79c5c9d673..68fa9cdd94 100644 --- a/test/decompiler/reference/engine/math/quaternion_REF.gc +++ b/test/decompiler/reference/engine/math/quaternion_REF.gc @@ -924,13 +924,16 @@ (defun quaternion-rotate-local-x! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a2-1 (t9-0 a0-1 (new 'static 'vector :x 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) + (let + ((a2-1 + (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :x 1.0 :w 1.0) + arg2 + ) + ) ) + (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) ) ) @@ -939,13 +942,16 @@ (defun quaternion-rotate-local-y! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a2-1 (t9-0 a0-1 (new 'static 'vector :y 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) + (let + ((a2-1 + (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :y 1.0 :w 1.0) + arg2 + ) + ) ) + (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) ) ) @@ -954,58 +960,64 @@ (defun quaternion-rotate-local-z! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a2-1 (t9-0 a0-1 (new 'static 'vector :z 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) + (let + ((a2-1 + (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :z 1.0 :w 1.0) + arg2 + ) + ) ) + (quaternion-normalize! (quaternion*! arg0 arg1 a2-1)) ) ) ;; definition for function quaternion-rotate-y! ;; Used lq/sq (defun quaternion-rotate-y! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) - (let ((t9-0 quaternion-vector-angle!) - (a0-1 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> a0-1 vec quad) (the-as uint128 0)) - (let ((a1-2 (t9-0 a0-1 (new 'static 'vector :y 1.0 :w 1.0) arg2))) - (quaternion-normalize! (quaternion*! arg0 a1-2 arg1)) + (let + ((a1-2 + (quaternion-vector-angle! + (new-stack-quaternion0) + (new 'static 'vector :y 1.0 :w 1.0) + arg2 + ) + ) ) + (quaternion-normalize! (quaternion*! arg0 a1-2 arg1)) ) ) ;; definition for function quaternion-rotate-x! ;; Used lq/sq (defun quaternion-rotate-x! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) - (let ((s4-0 quaternion-vector-angle!) - (s3-0 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> s3-0 vec quad) (the-as uint128 0)) - (let* ((t9-0 vector-x-quaternion!) - (a0-1 (new-stack-vector0)) - (a1-3 (s4-0 s3-0 (t9-0 a0-1 arg1) arg2)) - ) - (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) + (let + ((a1-3 + (quaternion-vector-angle! + (new-stack-quaternion0) + (vector-x-quaternion! (new-stack-vector0) arg1) + arg2 + ) + ) ) + (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) ) ) ;; definition for function quaternion-rotate-z! ;; Used lq/sq (defun quaternion-rotate-z! ((arg0 quaternion) (arg1 quaternion) (arg2 float)) - (let ((s4-0 quaternion-vector-angle!) - (s3-0 (new 'stack-no-clear 'quaternion)) - ) - (set! (-> s3-0 vec quad) (the-as uint128 0)) - (let* ((t9-0 vector-z-quaternion!) - (a0-1 (new-stack-vector0)) - (a1-3 (s4-0 s3-0 (t9-0 a0-1 arg1) arg2)) - ) - (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) + (let + ((a1-3 + (quaternion-vector-angle! + (new-stack-quaternion0) + (vector-z-quaternion! (new-stack-vector0) arg1) + arg2 + ) + ) ) + (quaternion-normalize! (quaternion*! arg0 a1-3 arg1)) ) ) diff --git a/test/decompiler/reference/engine/target/joint-mod-h_REF.gc b/test/decompiler/reference/engine/target/joint-mod-h_REF.gc index 6d62003c90..b15f53514c 100644 --- a/test/decompiler/reference/engine/target/joint-mod-h_REF.gc +++ b/test/decompiler/reference/engine/target/joint-mod-h_REF.gc @@ -415,9 +415,7 @@ (set! sv-56 (t9-3 a0-5 1.0)) ) (let* ((f30-0 (vector-y-angle sv-52)) - (t9-5 vector-flatten!) - (a0-7 (new-stack-vector0)) - (a0-8 (t9-5 a0-7 sv-56 sv-48)) + (a0-8 (vector-flatten! (new-stack-vector0) sv-56 sv-48)) (f0-0 (vector-y-angle a0-8)) (f0-1 (deg-diff f30-0 f0-0)) ) @@ -482,9 +480,7 @@ ) ) (f30-2 (vector-x-angle sv-52)) - (t9-16 vector-flatten!) - (a0-19 (new-stack-vector0)) - (s3-2 (t9-16 a0-19 sv-56 s3-1)) + (s3-2 (vector-flatten! (new-stack-vector0) sv-56 s3-1)) (f0-15 (vector-x-angle s3-2)) (f0-21 (fmax @@ -595,9 +591,7 @@ (set! sv-56 (t9-3 a0-3 1.0)) ) (let* ((f30-0 (vector-y-angle sv-52)) - (t9-5 vector-flatten!) - (a0-5 (new-stack-vector0)) - (a0-6 (t9-5 a0-5 sv-56 sv-48)) + (a0-6 (vector-flatten! (new-stack-vector0) sv-56 sv-48)) (f0-0 (vector-y-angle a0-6)) (f0-1 (deg-diff f30-0 f0-0)) ) @@ -645,9 +639,7 @@ ) ) (f30-2 (vector-x-angle sv-52)) - (t9-14 vector-flatten!) - (a0-14 (new-stack-vector0)) - (s4-4 (t9-14 a0-14 sv-56 s4-3)) + (s4-4 (vector-flatten! (new-stack-vector0) sv-56 s4-3)) (f0-14 (vector-x-angle s4-4)) (f0-20 (fmax diff --git a/test/decompiler/test_FormExpressionBuild2.cpp b/test/decompiler/test_FormExpressionBuild2.cpp index dc51c7c84c..2a4e9f5682 100644 --- a/test/decompiler/test_FormExpressionBuild2.cpp +++ b/test/decompiler/test_FormExpressionBuild2.cpp @@ -1382,4 +1382,124 @@ TEST_F(FormRegressionTest, DebugMenuFuncDecode) { " )\n" " )"; test_with_expr(func, type, expected, false, "", {}, "[[13, \"a0\", \"symbol\"]]"); +} + +TEST_F(FormRegressionTest, MatrixNewInlineProp) { + std::string func = + "sll r0, r0, 0\n" + " daddiu sp, sp, -112\n" + " sd ra, 0(sp)\n" + " sq s5, 80(sp)\n" + " sq gp, 96(sp)\n" + + " or gp, a0, r0\n" + " or s5, a2, r0\n" + " lw t9, matrix-rotate-y!(s7)\n" + " or a0, gp, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, matrix-rotate-x!(s7)\n" + " daddiu a0, sp, 16\n" + " sq r0, 0(a0)\n" + " sq r0, 16(a0)\n" + " sq r0, 32(a0)\n" + " sq r0, 48(a0)\n" + " or a1, s5, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or a1, v0, r0\n" + " lw t9, matrix*!(s7)\n" + " or a0, gp, r0\n" + " or a2, gp, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " lq gp, 96(sp)\n" + " lq s5, 80(sp)\n" + " jr ra\n" + " daddiu sp, sp, 112\n" + + " sll r0, r0, 0\n" + " sll r0, r0, 0\n" + " sll r0, r0, 0\n"; + std::string type = "(function matrix float float matrix)"; + std::string expected = + "(begin\n" + " (matrix-rotate-y! arg0 arg1)\n" + " (let ((a1-2 (matrix-rotate-x! (new-stack-matrix0) arg2)))\n" + " (matrix*! arg0 a1-2 arg0)\n" + " )\n" + " arg0\n" + " )"; + test_with_stack_structures(func, type, expected, R"([[16, "matrix"]])"); +} + +TEST_F(FormRegressionTest, VectorNewInlineProp) { + std::string func = + "sll r0, r0, 0\n" + " daddiu sp, sp, -64\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " sq s5, 32(sp)\n" + " sq gp, 48(sp)\n" + " or gp, a0, r0\n" + " daddiu s5, sp, 16\n" + " sq r0, 0(s5)\n" + " or v1, s5, r0\n" + " lwc1 f0, 0(a1)\n" + " swc1 f0, 0(v1)\n" + " lwc1 f0, 4(a1)\n" + " swc1 f0, 4(v1)\n" + " lwc1 f0, 8(a1)\n" + " swc1 f0, 8(v1)\n" + " mtc1 f0, r0\n" + " swc1 f0, 12(v1)\n" + " lw t9, vector-matrix*!(s7)\n" + " or a0, s5, r0\n" + " or a1, s5, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lwc1 f0, 0(s5)\n" + " swc1 f0, 0(gp)\n" + " lwc1 f0, 4(s5)\n" + " swc1 f0, 4(gp)\n" + " lwc1 f0, 8(s5)\n" + " swc1 f0, 8(gp)\n" + " or v1, gp, r0\n" + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " lq gp, 48(sp)\n" + " lq s5, 32(sp)\n" + " jr ra\n" + " daddiu sp, sp, 64\n" + + " sll r0, r0, 0\n" + " sll r0, r0, 0\n" + " sll r0, r0, 0\n"; + std::string type = "(function vector3s vector3s matrix vector3s)"; + std::string expected = + "(begin\n" + " (let ((s5-0 (new-stack-vector0)))\n" + " (let ((v1-0 s5-0))\n" + " (set! (-> v1-0 x) (-> arg1 x))\n" + " (set! (-> v1-0 y) (-> arg1 y))\n" + " (set! (-> v1-0 z) (-> arg1 z))\n" + " (set! (-> v1-0 w) 0.0)\n" + " )\n" + " (vector-matrix*! s5-0 s5-0 arg2)\n" + " (set! (-> arg0 x) (-> s5-0 x))\n" + " (set! (-> arg0 y) (-> s5-0 y))\n" + " (set! (-> arg0 z) (-> s5-0 z))\n" + " )\n" + " arg0\n" + " )"; + test_with_stack_structures(func, type, expected, R"([[16, "vector"]])"); } \ No newline at end of file