diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index 06cb9bf609..ce86115710 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -10,6 +10,7 @@ add_library( analysis/inline_asm_rewrite.cpp analysis/insert_lets.cpp analysis/reg_usage.cpp + analysis/type_analysis.cpp analysis/variable_naming.cpp data/game_count.cpp @@ -27,7 +28,6 @@ add_library( Function/BasicBlocks.cpp Function/CfgVtx.cpp Function/Function.cpp - Function/TypeAnalysis.cpp Function/TypeInspector.cpp IR/BasicOpBuilder.cpp @@ -48,6 +48,7 @@ add_library( ObjectFile/ObjectFileDB.cpp ObjectFile/ObjectFileDB_IR2.cpp + util/config_parsers.cpp util/data_decompile.cpp util/DataParser.cpp util/DecompilerTypeSystem.cpp diff --git a/decompiler/Function/Function.h b/decompiler/Function/Function.h index ed29fc1d99..528cb4cf98 100644 --- a/decompiler/Function/Function.h +++ b/decompiler/Function/Function.h @@ -90,12 +90,6 @@ class Function { const AtomicOp& get_atomic_op_at_instr(int idx); int get_basic_op_count(); int get_failed_basic_op_count(); - - bool run_type_analysis_ir2(const TypeSpec& my_type, - DecompilerTypeSystem& dts, - LinkedObjectFile& file, - const std::unordered_map>& casts, - const std::unordered_map& label_types); BlockTopologicalSort bb_topo_sort(); TypeSpec type; diff --git a/decompiler/IR2/AtomicOp.cpp b/decompiler/IR2/AtomicOp.cpp index 60bd12a023..a3ca0f9b8a 100644 --- a/decompiler/IR2/AtomicOp.cpp +++ b/decompiler/IR2/AtomicOp.cpp @@ -963,38 +963,47 @@ void SetVarConditionOp::collect_vars(RegAccessSet& vars) const { // StoreOp ///////////////////////////// -StoreOp::StoreOp(int size, bool is_float, SimpleExpression addr, SimpleAtom value, int my_idx) +StoreOp::StoreOp(int size, Kind kind, SimpleExpression addr, SimpleAtom value, int my_idx) : AtomicOp(my_idx), m_size(size), - m_is_float(is_float), + m_kind(kind), m_addr(std::move(addr)), m_value(std::move(value)) {} goos::Object StoreOp::to_form(const std::vector& labels, const Env& env) const { std::string store_name; - if (m_is_float) { - assert(m_size == 4); - store_name = "s.f!"; - } else { - switch (m_size) { - case 1: - store_name = "s.b!"; - break; - case 2: - store_name = "s.h!"; - break; - case 4: - store_name = "s.w!"; - break; - case 8: - store_name = "s.d!"; - break; - case 16: - store_name = "s.q!"; - break; - default: - assert(false); - } + switch (m_kind) { + case Kind::INTEGER: + switch (m_size) { + case 1: + store_name = "s.b!"; + break; + case 2: + store_name = "s.h!"; + break; + case 4: + store_name = "s.w!"; + break; + case 8: + store_name = "s.d!"; + break; + case 16: + store_name = "s.q!"; + break; + default: + assert(false); + } + break; + case Kind::FLOAT: + assert(m_size == 4); + store_name = "s.f!"; + break; + case Kind::VECTOR_FLOAT: + assert(m_size == 16); + store_name = "s.vf!"; + break; + default: + assert(false); } return pretty_print::build_list(pretty_print::to_symbol(store_name), m_addr.to_form(labels, env), @@ -1081,6 +1090,11 @@ goos::Object LoadVarOp::to_form(const std::vector& labels, cons assert(false); } break; + case Kind::VECTOR_FLOAT: + assert(m_size == 16); + forms.push_back(pretty_print::build_list("l.vf", m_src.to_form(labels, env))); + break; + default: assert(false); } diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index a55c4c25ac..0ebf2c2d36 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -420,12 +420,14 @@ class SetVarConditionOp : public AtomicOp { */ class StoreOp : public AtomicOp { public: - StoreOp(int size, bool is_float, SimpleExpression addr, SimpleAtom value, int my_idx); + enum class Kind { INTEGER, FLOAT, VECTOR_FLOAT, INVALID }; + StoreOp(int size, Kind kind, SimpleExpression addr, SimpleAtom value, int my_idx); goos::Object to_form(const std::vector& labels, const Env& env) const override; bool operator==(const AtomicOp& other) const override; bool is_sequence_point() const override; RegisterAccess get_set_destination() const override; FormElement* get_as_form(FormPool& pool, const Env& env) const override; + FormElement* get_vf_store_as_form(FormPool& pool, const Env& env) const; void update_register_info() override; TypeState propagate_types_internal(const TypeState& input, const Env& env, @@ -436,7 +438,7 @@ class StoreOp : public AtomicOp { private: int m_size; - bool m_is_float; + Kind m_kind = Kind::INVALID; SimpleExpression m_addr; SimpleAtom m_value; }; @@ -447,13 +449,14 @@ class StoreOp : public AtomicOp { */ class LoadVarOp : public AtomicOp { public: - enum class Kind { UNSIGNED, SIGNED, FLOAT }; + enum class Kind { UNSIGNED, SIGNED, FLOAT, VECTOR_FLOAT }; LoadVarOp(Kind kind, int size, RegisterAccess dst, SimpleExpression src, int my_idx); goos::Object to_form(const std::vector& labels, const Env& env) const override; bool operator==(const AtomicOp& other) const override; bool is_sequence_point() const override; RegisterAccess get_set_destination() const override; FormElement* get_as_form(FormPool& pool, const Env& env) const override; + Form* get_load_src(FormPool& pool, const Env& env) const; void update_register_info() override; TypeState propagate_types_internal(const TypeState& input, const Env& env, diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index 50f0faab66..50134f7dc0 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -40,28 +40,40 @@ ConditionElement* IR2_Condition::get_as_form(FormPool& pool, const Env& env, int FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const { if (env.has_type_analysis() && m_src.args() == 2 && m_src.get_arg(1).is_int() && m_src.get_arg(0).is_var() && m_src.kind() == SimpleExpression::Kind::ADD) { - auto arg0_type = env.get_types_before_op(m_my_idx).get(m_src.get_arg(0).var().reg()); - if (arg0_type.kind == TP_Type::Kind::TYPESPEC) { - // access a field. - FieldReverseLookupInput rd_in; - rd_in.deref = std::nullopt; - rd_in.stride = 0; - rd_in.offset = m_src.get_arg(1).get_int(); - rd_in.base_type = arg0_type.typespec(); - auto rd = env.dts->ts.reverse_field_lookup(rd_in); - - if (rd.success) { - auto source = pool.alloc_single_element_form( - nullptr, SimpleAtom::make_var(m_src.get_arg(0).var()).as_expr(), m_my_idx); - std::vector tokens; - for (auto& x : rd.tokens) { - tokens.push_back(to_token(x)); + if (m_src.get_arg(0).var().reg() == Register(Reg::GPR, Reg::SP)) { + // get a stack variable. + for (auto& var : env.stack_var_hints()) { + if (var.hint.stack_offset == m_src.get_arg(1).get_int()) { + // match! + return pool.alloc_element( + m_dst, pool.alloc_single_element_form(nullptr, var), true, + var.ref_type); } - auto load = - pool.alloc_single_element_form(nullptr, source, rd.addr_of, tokens); + } + } else { + // access a field + auto arg0_type = env.get_types_before_op(m_my_idx).get(m_src.get_arg(0).var().reg()); + if (arg0_type.kind == TP_Type::Kind::TYPESPEC) { + FieldReverseLookupInput rd_in; + rd_in.deref = std::nullopt; + rd_in.stride = 0; + rd_in.offset = m_src.get_arg(1).get_int(); + rd_in.base_type = arg0_type.typespec(); + auto rd = env.dts->ts.reverse_field_lookup(rd_in); - return pool.alloc_element(m_dst, load, true, - m_source_type.value_or(TypeSpec("object"))); + if (rd.success) { + auto source = pool.alloc_single_element_form( + nullptr, SimpleAtom::make_var(m_src.get_arg(0).var()).as_expr(), m_my_idx); + std::vector tokens; + for (auto& x : rd.tokens) { + tokens.push_back(to_token(x)); + } + auto load = + pool.alloc_single_element_form(nullptr, source, rd.addr_of, tokens); + + return pool.alloc_element(m_dst, load, true, + m_source_type.value_or(TypeSpec("object"))); + } } } } @@ -115,6 +127,9 @@ std::optional get_typecast_for_atom(const SimpleAtom& atom, auto type_info = env.dts->ts.lookup_type(expected_type); switch (atom.get_kind()) { case SimpleAtom::Kind::VARIABLE: { + if (atom.var().reg().get_kind() == Reg::VF) { + return {}; // no casts needed for VF registers. + } auto src_type = env.get_types_before_op(my_idx).get(atom.var().reg()); if (src_type.requires_cast() || !env.dts->ts.tc(expected_type, src_type.typespec())) { @@ -162,7 +177,48 @@ std::optional get_typecast_for_atom(const SimpleAtom& atom, } } // namespace +FormElement* StoreOp::get_vf_store_as_form(FormPool& pool, const Env& env) const { + assert(m_value.is_var() && m_value.var().reg().get_kind() == Reg::VF); + if (env.has_type_analysis()) { + IR2_RegOffset ro; + if (get_as_reg_offset(m_addr, &ro)) { + auto& input_type = env.get_types_before_op(m_my_idx).get(ro.reg); + + 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.typespec(); + rd_in.stride = 0; + rd_in.offset = ro.offset; + auto rd = env.dts->ts.reverse_field_lookup(rd_in); + + if (rd.success) { + auto source = pool.alloc_single_element_form( + nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); + std::vector tokens; + for (auto& x : rd.tokens) { + tokens.push_back(to_token(x)); + } + assert(!rd.addr_of); // we'll change this to true because .svf uses an address. + auto addr = pool.alloc_single_element_form(nullptr, source, true, tokens); + + return pool.alloc_element(m_value.var().reg(), addr, false); + } + } + } + + // nothing worked. + throw std::runtime_error("NYI get_vf_store_as_form fallback"); +} + FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { + if (m_kind == Kind::VECTOR_FLOAT) { + return get_vf_store_as_form(pool, env); + } + if (env.has_type_analysis()) { if (m_addr.is_identity() && m_addr.get_arg(0).is_sym_val()) { // we are storing a value in a global symbol. This is something like sw rx, offset(s7) @@ -353,7 +409,7 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { return pool.alloc_element(this); } -FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { +Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const { if (env.has_type_analysis()) { IR2_RegOffset ro; if (get_as_reg_offset(m_src, &ro)) { @@ -372,9 +428,7 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { tokens.push_back(DerefToken::make_field_name(method_info.name)); auto source = pool.alloc_single_element_form( nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); - auto load = pool.alloc_single_element_form(nullptr, source, false, tokens); - return pool.alloc_element(m_dst, load, true, - m_type.value_or(TypeSpec("object"))); + return pool.alloc_single_element_form(nullptr, source, false, tokens); } // todo structure method @@ -385,9 +439,7 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { if (input_type.kind == TP_Type::Kind::DYNAMIC_METHOD_ACCESS && ro.offset == 16) { // access method vtable. The input is type + (4 * method), and the 16 is the offset // of method 0. - auto load = pool.alloc_single_element_form(nullptr, ro.var); - return pool.alloc_element(m_dst, load, true, - m_type.value_or(TypeSpec("object"))); + return pool.alloc_single_element_form(nullptr, ro.var); } if (input_type.kind == TP_Type::Kind::OBJECT_PLUS_PRODUCT_WITH_CONSTANT) { @@ -412,10 +464,8 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { // we pass along the register offset because code generation seems to be a bit // different in different cases. - auto load = pool.alloc_single_element_form( + return pool.alloc_single_element_form( nullptr, ro.var, tokens, input_type.get_multiplier(), ro.offset); - return pool.alloc_element(m_dst, load, true, - m_type.value_or(TypeSpec("object"))); } } @@ -427,20 +477,15 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { if (ro.offset == 2) { auto source = pool.alloc_single_element_form( nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); - auto load = pool.alloc_single_element_form( + return pool.alloc_single_element_form( nullptr, GenericOperator::make_fixed(FixedOperatorKind::CDR), source); - // cdr = another pair. - return pool.alloc_element(m_dst, load, true, - m_type.value_or(TypeSpec("object"))); } else if (ro.offset == -2) { // car = some object. auto source = pool.alloc_single_element_form( nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); - auto load = pool.alloc_single_element_form( + return pool.alloc_single_element_form( nullptr, GenericOperator::make_fixed(FixedOperatorKind::CAR), source); // cdr = another pair. - return pool.alloc_element(m_dst, load, true, - m_type.value_or(TypeSpec("object"))); } } @@ -467,10 +512,7 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { tokens.push_back(to_token(x)); } - auto load = - pool.alloc_single_element_form(nullptr, source, rd.addr_of, tokens); - return pool.alloc_element(m_dst, load, true, - m_type.value_or(TypeSpec("object"))); + return pool.alloc_single_element_form(nullptr, source, rd.addr_of, tokens); } if (input_type.typespec() == TypeSpec("pointer") || @@ -505,10 +547,8 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); auto cast_dest = pool.alloc_single_element_form( nullptr, TypeSpec("pointer", {TypeSpec(cast_type)}), dest); - auto deref = pool.alloc_single_element_form(nullptr, cast_dest, false, - std::vector()); - return pool.alloc_element(m_dst, deref, true, - m_type.value_or(TypeSpec("object"))); + return pool.alloc_single_element_form(nullptr, cast_dest, false, + std::vector()); } } } @@ -527,9 +567,7 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { assert(word.kind == LinkedWord::PLAIN_DATA); float value; memcpy(&value, &word.data, 4); - auto float_elt = pool.alloc_single_element_form(nullptr, value); - return pool.alloc_element(m_dst, float_elt, true, - m_type.value_or(TypeSpec("object"))); + return pool.alloc_single_element_form(nullptr, value); } else if (hint->second.type_name == "uint64" && m_kind != Kind::FLOAT && m_size == 8) { assert((label.offset % 8) == 0); auto word0 = env.file->words_by_seg.at(label.target_segment).at(label.offset / 4); @@ -540,18 +578,41 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { memcpy(&value, &word0.data, 4); memcpy(((u8*)&value) + 4, &word1.data, 4); - auto val_elt = pool.alloc_single_element_form( - nullptr, fmt::format("#x{:x}", value)); - return pool.alloc_element(m_dst, val_elt, true, - m_type.value_or(TypeSpec("object"))); + return pool.alloc_single_element_form(nullptr, + fmt::format("#x{:x}", value)); } } } } auto source = pool.alloc_single_element_form(nullptr, m_src, m_my_idx); - auto load = pool.alloc_single_element_form(nullptr, source, m_size, m_kind); - return pool.alloc_element(m_dst, load, true, m_type.value_or(TypeSpec("object"))); + return pool.alloc_single_element_form(nullptr, source, m_size, m_kind); +} + +FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { + auto src = get_load_src(pool, env); + if (m_kind == Kind::VECTOR_FLOAT) { + assert(m_dst.reg().get_kind() == Reg::VF); + + auto src_as_deref = dynamic_cast(src->try_as_single_element()); + if (src_as_deref) { + assert(!src_as_deref->is_addr_of()); + src_as_deref->set_addr_of(true); + return pool.alloc_element(m_dst.reg(), src, true); + } + + auto src_as_unrecognized = dynamic_cast(src->try_as_single_element()); + if (src_as_unrecognized) { + return pool.alloc_element(m_dst.reg(), + src_as_unrecognized->location(), true); + } + + throw std::runtime_error("VF unknown load"); + + } else { + assert(m_dst.reg().get_kind() != Reg::VF); + return pool.alloc_element(m_dst, src, true, m_type.value_or(TypeSpec("object"))); + } } FormElement* BranchOp::get_as_form(FormPool& pool, const Env&) const { diff --git a/decompiler/IR2/AtomicOpTypeAnalysis.cpp b/decompiler/IR2/AtomicOpTypeAnalysis.cpp index 58d174b46b..e94ab8c16b 100644 --- a/decompiler/IR2/AtomicOpTypeAnalysis.cpp +++ b/decompiler/IR2/AtomicOpTypeAnalysis.cpp @@ -223,6 +223,48 @@ TP_Type SimpleExpression::get_type_int1(const TypeState& input, to_form(env.file->labels, env).print() + " " + arg_type.print()); } +namespace { +/*! + * Get the type of sp + offset. + */ +TP_Type get_stack_type_at_constant_offset(int offset, + const Env& env, + const DecompilerTypeSystem& dts) { + (void)dts; + for (auto& var : env.stack_var_hints()) { + if (offset < var.hint.stack_offset || offset >= (var.hint.stack_offset + var.size)) { + continue; // reject, it isn't in this variable + } + + if (offset == var.hint.stack_offset) { + // special case just getting the variable + if (var.hint.container_type == StackVariableHint::ContainerType::NONE) { + return TP_Type::make_from_ts(coerce_to_reg_type(var.ref_type)); + } + } + + // Note: GOAL doesn't seem to constant propagate memory access on the stack, so the code + // below should never be needed. + /* + // yes, it is in the variable! + FieldReverseLookupInput rd_in; + rd_in.deref = std::nullopt; // not a deref + rd_in.stride = 0; // not a strided access + rd_in.offset = offset - var.hint.stack_offset; // offset into this var + rd_in.base_type = var.ref_type; // use ref type for ptr. + auto rd = dts.ts.reverse_field_lookup(rd_in); + if (rd.success) { + auto result = TP_Type::make_from_ts(coerce_to_reg_type(rd.result_type)); + fmt::print("Matched a stack variable! {}\n", result.print()); + return result; + } + */ + // if we fail, keep trying others. This lets us have overlays in stack memory. + } + throw std::runtime_error(fmt::format("Failed to find a stack variable at offset {}", offset)); +} +} // namespace + /*! * Special case for "integer math". */ @@ -267,6 +309,12 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input, } break; case Kind::ADD: + // get stack address: + if (m_args[0].is_var() && m_args[0].var().reg() == Register(Reg::GPR, Reg::SP) && + m_args[1].is_int()) { + return get_stack_type_at_constant_offset(m_args[1].get_int(), env, dts); + } + if (arg0_type.is_product_with(4) && tc(dts, TypeSpec("type"), arg1_type)) { // dynamic access into the method array with shift, add, offset-load // no need to track the type because we don't know the method index anyway. @@ -726,7 +774,7 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input, } // rd failed, try as pair. - if (dts.type_prop_settings.allow_pair) { + if (env.allow_sloppy_pair_typing()) { // we are strict here - only permit pair-type loads from object or pair. // object is permitted for stuff like association lists where the car is also a pair. if (m_kind == Kind::SIGNED && m_size == 4 && @@ -755,11 +803,17 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input, TypeState LoadVarOp::propagate_types_internal(const TypeState& input, const Env& env, DecompilerTypeSystem& dts) { - TypeState result = input; - auto load_type = get_src_type(input, env, dts); - result.get(m_dst.reg()) = load_type; - m_type = load_type.typespec(); - return result; + if (m_dst.reg().get_kind() == Reg::FPR || m_dst.reg().get_kind() == Reg::GPR) { + TypeState result = input; + auto load_type = get_src_type(input, env, dts); + result.get(m_dst.reg()) = load_type; + m_type = load_type.typespec(); + return result; + } else { + // vector float loads show up as LoadVarOps, but we don't want to track types in the + // vector float registers. + return input; + } } TypeState BranchOp::propagate_types_internal(const TypeState& input, diff --git a/decompiler/IR2/Env.cpp b/decompiler/IR2/Env.cpp index 7f8415ff61..7d13576584 100644 --- a/decompiler/IR2/Env.cpp +++ b/decompiler/IR2/Env.cpp @@ -6,6 +6,7 @@ #include "Form.h" #include "decompiler/analysis/atomic_op_builder.h" #include "common/goos/PrettyPrinter.h" +#include "common/util/math_util.h" namespace decompiler { void Env::set_remap_for_function(int nargs) { @@ -441,4 +442,45 @@ const UseDefInfo& Env::get_use_def_info(const RegisterAccess& ra) const { auto var_id = get_program_var_id(ra); return m_var_names.use_def_info.at(var_id); } + +/*! + * Set the stack hints. This must be done before type analysis. + * This actually parses the types, so it should be done after the dts is set up. + */ +void Env::set_stack_var_hints(const std::vector& hints) { + for (auto& hint : hints) { + StackVarEntry entry; + entry.hint = hint; + // parse the type spec. + TypeSpec base_typespec = dts->parse_type_spec(hint.element_type); + auto type_info = dts->ts.lookup_type(base_typespec); + + switch (hint.container_type) { + case StackVariableHint::ContainerType::NONE: + // just a plain object on the stack. + if (!type_info->is_reference()) { + throw std::runtime_error( + fmt::format("Stack variable type {} is not a reference and cannot be stored directly " + "on the stack. Use an array instead.", + base_typespec.print())); + } + entry.ref_type = base_typespec; + entry.size = type_info->get_size_in_memory(); + // sanity check the alignment + if (align(entry.hint.stack_offset, type_info->get_in_memory_alignment()) != + entry.hint.stack_offset) { + lg::error("Misaligned stack variable of type {} offset {} required align {}\n", + entry.ref_type.print(), entry.hint.stack_offset, + type_info->get_in_memory_alignment()); + } + + break; + default: + assert(false); + } + + m_stack_vars.push_back(entry); + } +} + } // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR2/Env.h b/decompiler/IR2/Env.h index 7778d1ceb6..8fe8191618 100644 --- a/decompiler/IR2/Env.h +++ b/decompiler/IR2/Env.h @@ -16,6 +16,12 @@ class Form; class DecompilerTypeSystem; struct FunctionAtomicOps; +struct StackVarEntry { + StackVariableHint hint; + TypeSpec ref_type; // the actual type of the address. + int size = -1; +}; + /*! * An "environment" for a single function. * This contains data for an entire function, like which registers are live when, the types of @@ -108,6 +114,8 @@ class Env { m_typecasts = casts; } + const std::unordered_map>& casts() const { return m_typecasts; } + void set_remap_for_function(int nargs); void set_remap_for_method(int nargs); void set_remap_for_new_method(int nargs); @@ -129,6 +137,9 @@ class Env { m_label_types = types; } + void set_stack_var_hints(const std::vector& hints); + const std::vector& stack_var_hints() const { return m_stack_vars; } + const UseDefInfo& get_use_def_info(const RegisterAccess& ra) const; void disable_use(const RegisterAccess& access) { if (has_local_vars()) { @@ -146,6 +157,7 @@ class Env { void set_retype_map(const std::unordered_map& map) { m_var_retype = map; } + // todo - remove these hacks at some point. LinkedObjectFile* file = nullptr; DecompilerTypeSystem* dts = nullptr; @@ -166,6 +178,7 @@ class Env { bool m_allow_sloppy_pair_typing = false; std::unordered_map> m_typecasts; + std::vector m_stack_vars; std::unordered_map m_var_remap; std::unordered_map m_var_retype; std::unordered_map m_label_types; diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index e9a3e5a9f2..ae12995f65 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -211,6 +211,8 @@ goos::Object LoadSourceElement::to_form_internal(const Env& env) const { return pretty_print::build_list("l.wu", m_addr->to_form(env)); case 8: return pretty_print::build_list("l.d", m_addr->to_form(env)); + case 16: + return pretty_print::build_list("l.q", m_addr->to_form(env)); default: assert(false); return {}; @@ -229,6 +231,10 @@ goos::Object LoadSourceElement::to_form_internal(const Env& env) const { return {}; } break; + case LoadVarOp::Kind::VECTOR_FLOAT: + assert(m_size == 16); + return pretty_print::build_list("l.vf", m_addr->to_form(env)); + break; default: assert(false); return {}; @@ -2213,6 +2219,75 @@ void LambdaDefinitionElement::collect_vars(RegAccessSet&, bool) const {} void LambdaDefinitionElement::get_modified_regs(RegSet&) const {} +///////////////////////////// +// StackVarDefElement +///////////////////////////// + +StackVarDefElement::StackVarDefElement(const StackVarEntry& entry) : m_entry(entry) {} + +goos::Object StackVarDefElement::to_form_internal(const Env&) const { + switch (m_entry.hint.container_type) { + case StackVariableHint::ContainerType::NONE: + return pretty_print::build_list(fmt::format("new 'stack '{}", m_entry.ref_type.print())); + default: + assert(false); + } +} + +void StackVarDefElement::apply_form(const std::function&) {} + +void StackVarDefElement::apply(const std::function& f) { + f(this); +} + +void StackVarDefElement::collect_vars(RegAccessSet&, bool) const {} + +void StackVarDefElement::get_modified_regs(RegSet&) const {} + +//////////////////////////////// +// VectorFloatLoadStoreElement +//////////////////////////////// + +VectorFloatLoadStoreElement::VectorFloatLoadStoreElement(Register vf_reg, + Form* location, + bool is_load) + : m_vf_reg(vf_reg), m_location(location), m_is_load(is_load) { + location->parent_element = this; +} + +goos::Object VectorFloatLoadStoreElement::to_form_internal(const Env& env) const { + if (m_is_load) { + return pretty_print::build_list(".lvf", pretty_print::to_symbol(m_vf_reg.to_charp()), + m_location->to_form(env)); + } else { + return pretty_print::build_list(".svf", m_location->to_form(env), + pretty_print::to_symbol(m_vf_reg.to_charp())); + } +} + +void VectorFloatLoadStoreElement::apply(const std::function& f) { + f(this); + m_location->apply(f); +} + +void VectorFloatLoadStoreElement::apply_form(const std::function& f) { + m_location->apply_form(f); +} + +void VectorFloatLoadStoreElement::collect_vars(RegAccessSet& vars, bool recursive) const { + if (recursive) { + m_location->collect_vars(vars, recursive); + } +} + +void VectorFloatLoadStoreElement::get_modified_regs(RegSet&) const { + // vf's dont count +} + +void VectorFloatLoadStoreElement::collect_vf_regs(RegSet& regs) const { + regs.insert(m_vf_reg); +} + std::optional form_as_atom(const Form* f) { auto as_single = f->try_as_single_element(); auto as_atom = dynamic_cast(as_single); diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 136b70f847..fd6b3d7160 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -199,6 +199,7 @@ class LoadSourceElement : public FormElement { int size() const { return m_size; } LoadVarOp::Kind kind() const { return m_kind; } const Form* location() const { return m_addr; } + Form* location() { return m_addr; } void update_from_stack(const Env& env, FormPool& pool, FormStack& stack, @@ -1001,6 +1002,7 @@ class DerefElement : public FormElement { Form* base() { return m_base; } const std::vector& tokens() const { return m_tokens; } void set_base(Form* new_base); + void set_addr_of(bool is_addr_of) { m_is_addr_of = is_addr_of; } private: Form* m_base = nullptr; @@ -1247,6 +1249,41 @@ class LambdaDefinitionElement : public FormElement { goos::Object m_def; }; +class StackVarDefElement : public FormElement { + public: + StackVarDefElement(const StackVarEntry& entry); + 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; + void update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) override; + + private: + StackVarEntry m_entry; +}; + +class VectorFloatLoadStoreElement : public FormElement { + public: + VectorFloatLoadStoreElement(Register vf_reg, Form* location, bool is_load); + 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; + void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; + void collect_vf_regs(RegSet& regs) const; + + private: + Register m_vf_reg; + Form* m_location = nullptr; + bool m_is_load = false; +}; + /*! * A Form is a wrapper around one or more FormElements. * This is done for two reasons: diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 85aa2f6ef4..8750701263 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -2600,6 +2600,11 @@ void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool, true, TypeSpec("symbol")); } +void VectorFloatLoadStoreElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { + mark_popped(); + stack.push_form_element(this, true); +} + void SimpleAtomElement::update_from_stack(const Env&, FormPool&, FormStack&, @@ -2654,4 +2659,13 @@ void ConstantFloatElement::update_from_stack(const Env&, result->push_back(this); } +void StackVarDefElement::update_from_stack(const Env&, + FormPool&, + FormStack&, + std::vector* result, + bool) { + mark_popped(); + result->push_back(this); +} + } // namespace decompiler diff --git a/decompiler/IR2/OpenGoalMapping.cpp b/decompiler/IR2/OpenGoalMapping.cpp index 05341b4337..63844aefed 100644 --- a/decompiler/IR2/OpenGoalMapping.cpp +++ b/decompiler/IR2/OpenGoalMapping.cpp @@ -13,9 +13,6 @@ const std::map MIPS_ASM_TO_OPEN_GOAL_FUN {InstructionKind::PSRAW, {"TODO.PSRAW", {}}}, {InstructionKind::PSUBW, {"TODO.PSUBW", {}}}, - {InstructionKind::LQ, {"TODO.LQ", {MOD::OFFSET}}}, - {InstructionKind::SQ, {"TODO.SQ", {MOD::OFFSET}}}, - // NOTE - depending on how this is used, this may case issues! Be Warned! // lots of implicit logic in OpenGOAL depending on argument types! {InstructionKind::MFC1, {".mov", {}}}, diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index 60b32da5bd..3a339db1ac 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -9,6 +9,7 @@ #include "common/util/Timer.h" #include "common/util/FileUtil.h" #include "decompiler/Function/TypeInspector.h" +#include "decompiler/analysis/type_analysis.h" #include "decompiler/analysis/reg_usage.h" #include "decompiler/analysis/insert_lets.h" #include "decompiler/analysis/variable_naming.h" @@ -296,10 +297,17 @@ void ObjectFileDB::ir2_type_analysis_pass() { func.type = ts; attempted_functions++; // try type analysis here. - auto hints = - get_config().type_casts_by_function_by_atomic_op_idx[func.guessed_name.to_string()]; + auto func_name = func.guessed_name.to_string(); + auto casts = get_config().type_casts_by_function_by_atomic_op_idx[func_name]; auto label_types = get_config().label_types[data.to_unique_name()]; - if (func.run_type_analysis_ir2(ts, dts, data.linked_data, hints, label_types)) { + func.ir2.env.set_type_casts(casts); + func.ir2.env.set_label_types(label_types); + if (get_config().pair_functions_by_name.find(func_name) != + get_config().pair_functions_by_name.end()) { + func.ir2.env.set_sloppy_pair_typing(); + } + func.ir2.env.set_stack_var_hints(get_config().stack_var_hints_by_function[func_name]); + if (run_type_analysis_ir2(ts, dts, func)) { successful_functions++; func.ir2.env.types_succeeded = true; } else { diff --git a/decompiler/analysis/atomic_op_builder.cpp b/decompiler/analysis/atomic_op_builder.cpp index 00493c45e1..793ed39857 100644 --- a/decompiler/analysis/atomic_op_builder.cpp +++ b/decompiler/analysis/atomic_op_builder.cpp @@ -164,17 +164,17 @@ std::unique_ptr make_standard_load(const Instruction& i0, std::unique_ptr make_standard_store(const Instruction& i0, int idx, int store_size, - bool is_float) { + StoreOp::Kind kind) { if (i0.get_src(2).is_reg(Register(Reg::GPR, Reg::SP))) { return std::make_unique(i0, idx); } SimpleAtom val; SimpleExpression dst; if (i0.get_src(0).is_reg(rs7())) { - assert(!is_float); + assert(kind == StoreOp::Kind::INTEGER); val = SimpleAtom::make_sym_val("#f"); } else if (i0.get_src(0).is_reg(rr0())) { - assert(!is_float); + assert(kind == StoreOp::Kind::INTEGER); val = SimpleAtom::make_int_constant(0); } else { val = make_src_atom(i0.get_src(0).get_reg(), idx); @@ -189,7 +189,7 @@ std::unique_ptr make_standard_store(const Instruction& i0, SimpleAtom::make_int_constant(offset)); } - return std::make_unique(store_size, is_float, dst, val, idx); + return std::make_unique(store_size, kind, dst, val, idx); } std::unique_ptr make_asm_op(const Instruction& i0, int idx) { @@ -277,8 +277,6 @@ std::unique_ptr make_asm_op(const Instruction& i0, int idx) { // Moves / Loads / Stores case InstructionKind::CTC2: case InstructionKind::CFC2: - case InstructionKind::SQC2: - case InstructionKind::LQC2: case InstructionKind::LDR: case InstructionKind::LDL: case InstructionKind::QMTC2: @@ -593,9 +591,10 @@ std::unique_ptr convert_sw_1(const Instruction& i0, int idx) { // store a register. val = make_src_atom(i0.get_src(0).get_reg(), idx); } - return std::make_unique(4, false, SimpleAtom::make_sym_val(name).as_expr(), val, idx); + return std::make_unique(4, StoreOp::Kind::INTEGER, + SimpleAtom::make_sym_val(name).as_expr(), val, idx); } else { - return make_standard_store(i0, idx, 4, false); + return make_standard_store(i0, idx, 4, StoreOp::Kind::INTEGER); } } @@ -603,7 +602,7 @@ std::unique_ptr convert_sd_1(const Instruction& i0, int idx) { if (i0.get_src(0).is_reg(rr0()) && i0.get_src(1).is_imm(2) && i0.get_src(2).is_reg(rr0())) { return std::make_unique(SpecialOp::Kind::CRASH, idx); } else { - return make_standard_store(i0, idx, 8, false); + return make_standard_store(i0, idx, 8, StoreOp::Kind::INTEGER); } } @@ -719,6 +718,8 @@ std::unique_ptr convert_1(const Instruction& i0, int idx) { return make_standard_load(i0, idx, 8, LoadVarOp::Kind::UNSIGNED); case InstructionKind::LQ: return make_standard_load(i0, idx, 16, LoadVarOp::Kind::UNSIGNED); + case InstructionKind::LQC2: + return make_standard_load(i0, idx, 16, LoadVarOp::Kind::VECTOR_FLOAT); case InstructionKind::DSLL: return make_2reg_1imm_op(i0, SimpleExpression::Kind::LEFT_SHIFT, idx); case InstructionKind::DSLL32: @@ -774,17 +775,19 @@ std::unique_ptr convert_1(const Instruction& i0, int idx) { case InstructionKind::DSLLV: return make_3reg_op(i0, SimpleExpression::Kind::LEFT_SHIFT, idx); case InstructionKind::SB: - return make_standard_store(i0, idx, 1, false); + return make_standard_store(i0, idx, 1, StoreOp::Kind::INTEGER); case InstructionKind::SH: - return make_standard_store(i0, idx, 2, false); + return make_standard_store(i0, idx, 2, StoreOp::Kind::INTEGER); case InstructionKind::SW: return convert_sw_1(i0, idx); case InstructionKind::SD: return convert_sd_1(i0, idx); case InstructionKind::SQ: - return make_standard_store(i0, idx, 16, false); + return make_standard_store(i0, idx, 16, StoreOp::Kind::INTEGER); + case InstructionKind::SQC2: + return make_standard_store(i0, idx, 16, StoreOp::Kind::VECTOR_FLOAT); case InstructionKind::SWC1: - return make_standard_store(i0, idx, 4, true); + return make_standard_store(i0, idx, 4, StoreOp::Kind::FLOAT); case InstructionKind::CVTWS: // float to int return make_2reg_op(i0, SimpleExpression::Kind::FLOAT_TO_INT, idx); case InstructionKind::CVTSW: // int to float diff --git a/decompiler/analysis/inline_asm_rewrite.cpp b/decompiler/analysis/inline_asm_rewrite.cpp index df34185427..555cd7b842 100644 --- a/decompiler/analysis/inline_asm_rewrite.cpp +++ b/decompiler/analysis/inline_asm_rewrite.cpp @@ -26,6 +26,10 @@ bool rewrite_inline_asm_instructions(Form* top_level_form, // operations AsmOpElement* elem = dynamic_cast(entry); if (!elem) { + auto as_load_store = dynamic_cast(entry); + if (as_load_store) { + as_load_store->collect_vf_regs(vf_regs); + } new_entries.push_back(entry); continue; } diff --git a/decompiler/analysis/insert_lets.cpp b/decompiler/analysis/insert_lets.cpp index 6a390f75da..28ef0fd693 100644 --- a/decompiler/analysis/insert_lets.cpp +++ b/decompiler/analysis/insert_lets.cpp @@ -296,6 +296,10 @@ Form* insert_cast_for_let(RegisterAccess dst, return src; } + +bool register_can_hold_var(const Register& reg) { + return reg.get_kind() == Reg::FPR || reg.get_kind() == Reg::GPR; +} } // namespace LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_level_form) { @@ -325,7 +329,7 @@ LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_l // and add it. for (auto& access : reg_accesses) { - if (access.reg().get_kind() == Reg::FPR || access.reg().get_kind() == Reg::GPR) { + if (register_can_hold_var(access.reg())) { auto name = env.get_variable_name(access); var_info[name].elts_using_var.insert(elt); var_info[name].var_name = name; @@ -406,7 +410,7 @@ LetStats insert_lets(const Function& func, Env& env, FormPool& pool, Form* top_l 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 && + if (first_form_as_set && register_can_hold_var(first_form_as_set->dst().reg()) && env.get_variable_name(first_form_as_set->dst()) == env.get_variable_name(info.access) && !first_form_as_set->info().is_eliminated_coloring_move) { bool allowed = true; diff --git a/decompiler/Function/TypeAnalysis.cpp b/decompiler/analysis/type_analysis.cpp similarity index 63% rename from decompiler/Function/TypeAnalysis.cpp rename to decompiler/analysis/type_analysis.cpp index 34677960d0..1126d52b1e 100644 --- a/decompiler/Function/TypeAnalysis.cpp +++ b/decompiler/analysis/type_analysis.cpp @@ -1,7 +1,4 @@ -#include "decompiler/Function/Function.h" -#include "decompiler/IR/IR.h" -#include "third-party/fmt/core.h" -#include "decompiler/config.h" +#include "type_analysis.h" namespace decompiler { namespace { @@ -66,59 +63,32 @@ void try_modify_input_types_for_casts( } } // namespace -bool Function::run_type_analysis_ir2( - const TypeSpec& my_type, - DecompilerTypeSystem& dts, - LinkedObjectFile& file, - const std::unordered_map>& casts, - const std::unordered_map& label_types) { - (void)file; - ir2.env.set_type_casts(casts); - ir2.env.set_label_types(label_types); +bool run_type_analysis_ir2(const TypeSpec& my_type, DecompilerTypeSystem& dts, Function& func) { // STEP 0 - set decompiler type system settings for this function. In config we can manually - // specify some settings for type propagation to reduce the strictness of type propagation. - // TODO - this is kinda hacky so that it works in both unit tests and actual decompilation. - // it would be better if this setting came 100% from the IR2 env. - if (!dts.type_prop_settings.locked) { - dts.type_prop_settings.reset(); - if (get_config().pair_functions_by_name.find(guessed_name.to_string()) != - get_config().pair_functions_by_name.end()) { - dts.type_prop_settings.allow_pair = true; - ir2.env.set_sloppy_pair_typing(); - } - } else { - if (dts.type_prop_settings.allow_pair) { - ir2.env.set_sloppy_pair_typing(); - } - } - - if (guessed_name.kind == FunctionName::FunctionKind::METHOD) { - dts.type_prop_settings.current_method_type = guessed_name.type_name; + if (func.guessed_name.kind == FunctionName::FunctionKind::METHOD) { + dts.type_prop_settings.current_method_type = func.guessed_name.type_name; } if (my_type.last_arg() == TypeSpec("none")) { - auto as_end = dynamic_cast(ir2.atomic_ops->ops.back().get()); + auto as_end = dynamic_cast(func.ir2.atomic_ops->ops.back().get()); assert(as_end); as_end->mark_function_as_no_return_value(); } std::vector block_init_types, op_types; - block_init_types.resize(basic_blocks.size()); - op_types.resize(ir2.atomic_ops->ops.size()); - auto& aop = ir2.atomic_ops; + block_init_types.resize(func.basic_blocks.size()); + op_types.resize(func.ir2.atomic_ops->ops.size()); + auto& aop = func.ir2.atomic_ops; // STEP 1 - topologocial sort the blocks. This gives us an order where we: // - never visit unreachable blocks (we can't type propagate these) // - always visit at least one predecessor of a block before that block - auto order = bb_topo_sort(); + auto order = func.bb_topo_sort(); assert(!order.vist_order.empty()); assert(order.vist_order.front() == 0); // STEP 2 - initialize type state for the first block to the function argument types. block_init_types.at(0) = construct_initial_typestate(my_type); - // and add hints from config - // TODO - this should be moved into the construct_initial_typestate - // try_apply_hints(0, hints, &block_init_types.at(0), dts); // STEP 3 - propagate types until the result stops changing bool run_again = true; @@ -126,25 +96,22 @@ bool Function::run_type_analysis_ir2( run_again = false; // do each block in the topological sort order: for (auto block_id : order.vist_order) { - auto& block = basic_blocks.at(block_id); + auto& block = func.basic_blocks.at(block_id); TypeState* init_types = &block_init_types.at(block_id); for (int op_id = aop->block_id_to_first_atomic_op.at(block_id); op_id < aop->block_id_to_end_atomic_op.at(block_id); op_id++) { - // apply type hints only if we are not the first op. - std::unordered_map restore_cast_types; - // if (op_id != aop->block_id_to_first_atomic_op.at(block_id)) { - try_modify_input_types_for_casts(op_id, casts, init_types, &restore_cast_types, dts); - //} + try_modify_input_types_for_casts(op_id, func.ir2.env.casts(), init_types, + &restore_cast_types, dts); auto& op = aop->ops.at(op_id); try { - op_types.at(op_id) = op->propagate_types(*init_types, ir2.env, dts); + op_types.at(op_id) = op->propagate_types(*init_types, func.ir2.env, dts); } catch (std::runtime_error& e) { - lg::warn("Function {} failed type prop: {}", guessed_name.to_string(), e.what()); - warnings.type_prop_warning("{}", e.what()); - ir2.env.set_types(block_init_types, op_types, *ir2.atomic_ops, my_type); + lg::warn("Function {} failed type prop: {}", func.guessed_name.to_string(), e.what()); + func.warnings.type_prop_warning("{}", e.what()); + func.ir2.env.set_types(block_init_types, op_types, *func.ir2.atomic_ops, my_type); return false; } @@ -165,11 +132,6 @@ bool Function::run_type_analysis_ir2( // propagate the types: for each possible succ for (auto succ_block_id : {block.succ_ft, block.succ_branch}) { if (succ_block_id != -1) { - // apply hint - // try_apply_hints(aop->block_id_to_first_atomic_op.at(succ_block_id), hints, - // init_types, - // dts); - // set types to LCA (current, new) if (dts.tp_lca(&block_init_types.at(succ_block_id), *init_types)) { // if something changed, run again! @@ -182,7 +144,8 @@ bool Function::run_type_analysis_ir2( auto last_type = op_types.back().get(Register(Reg::GPR, Reg::V0)).typespec(); if (last_type != my_type.last_arg()) { - warnings.info("Return type mismatch {} vs {}.", last_type.print(), my_type.last_arg().print()); + func.warnings.info("Return type mismatch {} vs {}.", last_type.print(), + my_type.last_arg().print()); } // and apply final casts: @@ -190,15 +153,16 @@ bool Function::run_type_analysis_ir2( for (int op_id = aop->block_id_to_first_atomic_op.at(block_id); op_id < aop->block_id_to_end_atomic_op.at(block_id); op_id++) { if (op_id == aop->block_id_to_first_atomic_op.at(block_id)) { - try_modify_input_types_for_casts(op_id, casts, &block_init_types.at(block_id), nullptr, - dts); + try_modify_input_types_for_casts(op_id, func.ir2.env.casts(), + &block_init_types.at(block_id), nullptr, dts); } else { - try_modify_input_types_for_casts(op_id, casts, &op_types.at(op_id - 1), nullptr, dts); + try_modify_input_types_for_casts(op_id, func.ir2.env.casts(), &op_types.at(op_id - 1), + nullptr, dts); } } } - ir2.env.set_types(block_init_types, op_types, *ir2.atomic_ops, my_type); + func.ir2.env.set_types(block_init_types, op_types, *func.ir2.atomic_ops, my_type); return true; } diff --git a/decompiler/analysis/type_analysis.h b/decompiler/analysis/type_analysis.h new file mode 100644 index 0000000000..7957f77fdb --- /dev/null +++ b/decompiler/analysis/type_analysis.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include "common/type_system/TypeSpec.h" +#include "decompiler/config.h" +#include "decompiler/util/DecompilerTypeSystem.h" +#include "decompiler/ObjectFile/LinkedObjectFile.h" + +namespace decompiler { +bool run_type_analysis_ir2(const TypeSpec& my_type, DecompilerTypeSystem& dts, Function& func); +} \ No newline at end of file diff --git a/decompiler/config.cpp b/decompiler/config.cpp index b6a27b0633..c962da633f 100644 --- a/decompiler/config.cpp +++ b/decompiler/config.cpp @@ -3,6 +3,7 @@ #include "third-party/fmt/core.h" #include "common/util/FileUtil.h" #include "common/util/json_util.h" +#include "decompiler/util/config_parsers.h" namespace decompiler { Config gConfig; @@ -151,5 +152,13 @@ void set_config(const std::string& path_to_config_file) { } } } + + auto stack_vars_json = read_json_file_from_config(cfg, "stack_vars_file"); + for (auto& kv : stack_vars_json.items()) { + auto& func_name = kv.key(); + auto& stack_vars = kv.value(); + gConfig.stack_var_hints_by_function[func_name] = parse_stack_var_hints(stack_vars); + } } + } // namespace decompiler \ No newline at end of file diff --git a/decompiler/config.h b/decompiler/config.h index 62e85e2e9a..a4d0b863ec 100644 --- a/decompiler/config.h +++ b/decompiler/config.h @@ -27,6 +27,21 @@ struct LocalVarOverride { std::optional type; }; +/*! + * Information about a variable pointing to some data on the stack. + */ +struct StackVariableHint { + std::string element_type; // type of the thing stored + // todo - is boxed array on the stack supported? + enum class ContainerType { + NONE, // just store the plain thing. + ARRAY, // for refs, array of refs. For values, array of values. + INLINE_ARRAY // for refs, array of values, for values, invalid + } container_type = ContainerType::NONE; + int container_size = -1; // if container other than NONE, the number of elements. + int stack_offset = 0; // where it's located on the stack (relative to sp after prologue) +}; + struct Config { int game_version = -1; std::vector dgo_names; @@ -60,11 +75,12 @@ struct Config { std::unordered_map> function_arg_names; std::unordered_map> function_var_overrides; - std::unordered_map> label_types; + std::unordered_map> stack_var_hints_by_function; bool run_ir2 = false; }; Config& get_config(); void set_config(const std::string& path_to_config_file); + } // namespace decompiler diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index c438471bdb..748dae067d 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -1409,49 +1409,44 @@ (define-extern matrixp*! (function matrix matrix matrix matrix)) (define-extern vector-matrix*! (function vector vector matrix vector)) (define-extern vector-rotate*! (function vector vector matrix vector)) -(define-extern vector3s-matrix*! function) -(define-extern vector3s-rotate*! function) +(define-extern vector3s-matrix*! (function vector3s vector3s matrix vector3s)) +(define-extern vector3s-rotate*! (function vector3s vector3s matrix vector3s)) -(define-extern matrix-inverse-of-rot-trans! function) -(define-extern matrix-3x3-determinant function) -(define-extern matrix-3x3-inverse-transpose! function) - -(define-extern matrix-scale! function) -(define-extern column-scale-matrix! function) -(define-extern matrix-rotate-yx! function) -(define-extern matrix-y-angle function) -(define-extern matrix-3x3-inverse! function) -(define-extern matrix-rotate-z! function) -;;(define-extern *identity-matrix* object) ;; unknown type -(define-extern matrix-axis-angle! function) +(define-extern matrix-transpose! (function matrix matrix matrix)) +(define-extern matrix-inverse-of-rot-trans! (function matrix matrix matrix)) +(define-extern matrix-4x4-inverse! (function matrix matrix matrix)) +(define-extern matrix-translate! (function matrix vector matrix)) +(define-extern matrix-translate+! (function matrix matrix vector matrix)) +(define-extern matrix-scale! (function matrix vector matrix)) +(define-extern scale-matrix! (function matrix vector matrix matrix)) +(define-extern matrix-inv-scale! (function matrix vector matrix)) +(define-extern column-scale-matrix! (function matrix vector matrix matrix)) +(define-extern matrix-rotate-x! (function matrix float matrix)) +(define-extern matrix-rotate-y! (function matrix float matrix)) +(define-extern matrix-rotate-z! (function matrix float matrix)) (define-extern matrix-rotate-zyx! (function matrix vector matrix)) -(define-extern matrix-rotate-x! function) +(define-extern matrix-rotate-xyz! (function matrix vector matrix)) +(define-extern matrix-rotate-zxy! (function matrix vector matrix)) +(define-extern matrix-rotate-yxz! (function matrix vector matrix)) +(define-extern matrix-rotate-yzx! (function matrix vector matrix)) +(define-extern matrix-rotate-yxy! (function matrix vector matrix)) +(define-extern matrix-rotate-yx! (function matrix float float matrix)) +(define-extern matrix-lerp! (function matrix matrix matrix float matrix)) +(define-extern matrix-3x3-determinant (function matrix float)) +(define-extern matrix3-determinant (function matrix float)) +(define-extern matrix-3x3-inverse! (function matrix matrix matrix)) +(define-extern matrix-3x3-inverse-transpose! (function matrix matrix matrix)) +(define-extern matrix3-inverse-transpose! (function matrix matrix matrix)) +(define-extern matrix-4x4-determinant (function matrix float)) +(define-extern matrix-4x4-inverse-transpose! (function matrix matrix matrix)) +(define-extern matrix-y-angle (function matrix float)) -(define-extern matrix-rotate-yxy! function) +(define-extern *identity-matrix* matrix) +(define-extern matrix-axis-sin-cos! (function matrix vector float float none)) +(define-extern matrix-axis-angle! (function matrix vector float none)) -(define-extern matrix-4x4-determinant function) -(define-extern matrix-inv-scale! function) -(define-extern matrix-rotate-yzx! function) -(define-extern matrix-axis-sin-cos! function) -(define-extern matrix-lerp! function) -(define-extern matrix-rotate-y! function) - -(define-extern matrix-rotate-xyz! function) -(define-extern scale-matrix! function) -(define-extern matrix-rotate-yxz! function) -(define-extern matrix-rotate-zxy! function) - -(define-extern matrix3-determinant function) -(define-extern matrix3-inverse-transpose! function) -(define-extern matrix-translate+! function) -(define-extern matrix-transpose! function) -(define-extern matrix-4x4-inverse-transpose! function) (define-extern matrix-axis-sin-cos-vu! function) -(define-extern matrix-translate! function) -(define-extern matrix-4x4-inverse! function) - - (define-extern trs-matrix-calc! function) (define-extern transform-matrix-parent-calc! function) (define-extern transform-matrix-calc! function) diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index 496b8e696e..31fe2a61b4 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -57,6 +57,7 @@ "anonymous_function_types_file":"decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc", "var_names_file":"decompiler/config/jak1_ntsc_black_label/var_names.jsonc", "label_types_file":"decompiler/config/jak1_ntsc_black_label/label_types.jsonc", + "stack_vars_file":"decompiler/config/jak1_ntsc_black_label/stack_vars.jsonc", "analyze_functions":true, "analyze_expressions":true, diff --git a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc index 2bebe23d87..b382aedc93 100644 --- a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc @@ -45,6 +45,10 @@ ["L2", "_auto_", true] ], + "matrix":[ + ["L60", "float", true] + ], + "trigonometry": [ ["L143", "float", true], ["L144", "float", true], diff --git a/decompiler/config/jak1_ntsc_black_label/stack_vars.jsonc b/decompiler/config/jak1_ntsc_black_label/stack_vars.jsonc new file mode 100644 index 0000000000..5a9d2a8133 --- /dev/null +++ b/decompiler/config/jak1_ntsc_black_label/stack_vars.jsonc @@ -0,0 +1,42 @@ +{ + "matrixp*!": [[16, "matrix"]], + + "vector3s-matrix*!": [[16, "vector"]], + + "vector3s-rotate*!": [[16, "vector"]], + + "matrix-rotate-zyx!": [ + [16, "matrix"], + [80, "matrix"] + ], + + "matrix-rotate-xyz!": [ + [16, "matrix"], + [80, "matrix"] + ], + + "matrix-rotate-zxy!": [ + [16, "matrix"], + [80, "matrix"] + ], + + "matrix-rotate-yxz!": [ + [16, "matrix"], + [80, "matrix"] + ], + + "matrix-rotate-yzx!": [ + [16, "matrix"], + [80, "matrix"] + ], + + "matrix-rotate-yxy!":[ + [16, "vector"], + [32, "vector"], + [48, "vector"] + ], + + "matrix-rotate-yx!":[ + [16, "matrix"] + ] +} diff --git a/decompiler/util/DecompilerTypeSystem.h b/decompiler/util/DecompilerTypeSystem.h index 5161c914ce..565d83a151 100644 --- a/decompiler/util/DecompilerTypeSystem.h +++ b/decompiler/util/DecompilerTypeSystem.h @@ -44,14 +44,10 @@ class DecompilerTypeSystem { int get_format_arg_count(const TP_Type& type) const; TypeSpec lookup_symbol_type(const std::string& name) const; + // todo - totally eliminate this. struct { - bool locked = false; - bool allow_pair; std::string current_method_type; - void reset() { - allow_pair = false; - current_method_type.clear(); - } + void reset() { current_method_type.clear(); } } type_prop_settings; private: diff --git a/decompiler/util/TP_Type.h b/decompiler/util/TP_Type.h index 79872b8320..4c8f66cb7c 100644 --- a/decompiler/util/TP_Type.h +++ b/decompiler/util/TP_Type.h @@ -280,7 +280,6 @@ struct TypeState { case Reg::FPR: return fpr_types[r.get_fpr()]; default: - lg::die("Cannot use register {} with TypeState.", r.to_charp()); assert(false); throw std::runtime_error("TP_Type::get failed"); } diff --git a/decompiler/util/config_parsers.cpp b/decompiler/util/config_parsers.cpp new file mode 100644 index 0000000000..4c40bcef48 --- /dev/null +++ b/decompiler/util/config_parsers.cpp @@ -0,0 +1,52 @@ +#include "config_parsers.h" +#include "common/util/json_util.h" + +namespace decompiler { +std::vector parse_stack_var_hints(const nlohmann::json& json) { + std::vector result; + for (auto& stack_var : json) { + StackVariableHint hint; + hint.stack_offset = stack_var.at(0).get(); + auto& type_info = stack_var.at(1); + if (type_info.is_array()) { + auto container_type = type_info.at(0).get(); + if (container_type == "array") { + hint.container_type = StackVariableHint::ContainerType::ARRAY; + } else if (container_type == "inline-array") { + hint.container_type = StackVariableHint::ContainerType::INLINE_ARRAY; + } else { + throw std::runtime_error("Container type is invalid: " + container_type); + } + hint.element_type = type_info.at(1).get(); + hint.container_size = type_info.at(2).get(); + } else if (type_info.is_string()) { + hint.container_type = StackVariableHint::ContainerType::NONE; + hint.container_size = -1; + hint.element_type = type_info.get(); + } else { + throw std::runtime_error("Invalid stack var override"); + } + result.push_back(hint); + } + return result; +} + +std::unordered_map> parse_cast_hints( + const nlohmann::json& casts) { + std::unordered_map> out; + + for (auto& cast : casts) { + auto idx_range = parse_json_optional_integer_range(cast.at(0)); + for (auto idx : idx_range) { + TypeCast type_cast; + type_cast.atomic_op_idx = idx; + type_cast.reg = Register(cast.at(1)); + type_cast.type_name = cast.at(2).get(); + out[idx].push_back(type_cast); + } + } + + return out; +} + +} // namespace decompiler \ No newline at end of file diff --git a/decompiler/util/config_parsers.h b/decompiler/util/config_parsers.h new file mode 100644 index 0000000000..ac32473011 --- /dev/null +++ b/decompiler/util/config_parsers.h @@ -0,0 +1,10 @@ +#pragma once +#include +#include "decompiler/config.h" +#include "third-party/json.hpp" + +namespace decompiler { +std::vector parse_stack_var_hints(const nlohmann::json& json); +std::unordered_map> parse_cast_hints( + const nlohmann::json& casts); +} // namespace decompiler diff --git a/goal_src/engine/math/matrix.gc b/goal_src/engine/math/matrix.gc index 1f5dd42692..533ad2e6ae 100644 --- a/goal_src/engine/math/matrix.gc +++ b/goal_src/engine/math/matrix.gc @@ -5,7 +5,81 @@ ;; name in dgo: matrix ;; dgos: GAME, ENGINE +;; NOTE: basically everything here is transposed from what normal people do. +;; They treat their vectors as column vectors and do v*M as their normal matrix multiply. +;; w = v*M +;; w^T = (v*M)^T +;; w^T = M^T*v^T +;; So to swap between ND convention and normal convention: +;; - treat ND row vectors as column vectors +;; - transpose all matrices + +;; Matrices are stored in row major order. +;; One nice result of row-major + everything transposed is that a translation + rotation stores +;; the translation vector (bottom row!) contiguously in memory so it is fast to load/store. +;; Also, the order of transformations is left-to-right instead of right-to-left when writing things out. + +;; TODO: +;; - matrix-transpose! +;; - matrix-4x4-inverse! +;; - matrix-axis-sin-cos-vu! +;; - matrix-axis-sin-cos! +;; - matrix-axis-angle! +;; - (method 9 matrix) + +(defmethod inspect matrix ((obj matrix)) + "Print out a matrix" + (format #t "[~8x] matrix~%" obj) + (format #t "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 0) + (-> obj data 1) + (-> obj data 2) + (-> obj data 3) + ) + (format #t "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 4) + (-> obj data 5) + (-> obj data 6) + (-> obj data 7) + ) + (format #t "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 8) + (-> obj data 9) + (-> obj data 10) + (-> obj data 11) + ) + (format #t "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 12) + (-> obj data 13) + (-> obj data 14) + (-> obj data 15) + ) + obj + ) + +(defmethod inspect matrix3 ((obj matrix3)) + "Print out a matrix3" + (format #t "[~8x] matrix3~%" obj) + (format #t "~T[~F] [~F] [~F]~%" + (-> obj data 0) + (-> obj data 1) + (-> obj data 2) + ) + (format #t "~T[~F] [~F] [~F]~%" + (-> obj data 4) + (-> obj data 5) + (-> obj data 6) + ) + (format #t "~T[~F] [~F] [~F]~%" + (-> obj data 8) + (-> obj data 9) + (-> obj data 10) + ) + obj + ) + (defun matrix-identity! ((m matrix)) + "Set m to the identity matrix." (rlet ((vf1 :class vf)) ;; zero (.xor.vf vf1 vf1 vf1) @@ -22,3 +96,1486 @@ ) m ) + +(define *identity-matrix* (the-as matrix (new 'global 'matrix))) +(matrix-identity! *identity-matrix*) + +(defun matrix+! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + "Set arg0 = arg1 + arg2. Not particularly efficient." + (dotimes (v1-0 16) + (set! (-> arg0 data v1-0) (+ (-> arg1 data v1-0) (-> arg2 data v1-0))) + ) + arg0 + ) + +(defun matrix-! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + "Set arg0 = arg1 - arg2. Not particularly efficient." + (dotimes (v1-0 16) + (set! (-> arg0 data v1-0) (- (-> arg1 data v1-0) (-> arg2 data v1-0))) + ) + arg0 + ) + +(defun matrix*! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + "4x4 matrix multiplication. Set arg0 = arg1 * arg2." + (rlet ((acc :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + (vf14 :class vf) + (vf15 :class vf) + (vf16 :class vf) + (vf17 :class vf) + (vf18 :class vf) + (vf19 :class vf) + (vf20 :class vf) + (vf21 :class vf) + ) + (.lvf vf10 arg1) + (.lvf vf14 arg2) + (.lvf vf15 arg2 :offset 16) + (.lvf vf16 arg2 :offset 32) + (.lvf vf17 arg2 :offset 48) + (.lvf vf11 arg1 :offset 16) + (.lvf vf12 arg1 :offset 32) + (.lvf vf13 arg1 :offset 48) + (.mul.x.vf acc vf14 vf10) + (.add.mul.y.vf acc vf15 vf10 acc) + (.add.mul.z.vf acc vf16 vf10 acc) + (.add.mul.w.vf vf18 vf17 vf10 acc) + (.mul.x.vf acc vf14 vf11) + (.add.mul.y.vf acc vf15 vf11 acc) + (.add.mul.z.vf acc vf16 vf11 acc) + (.add.mul.w.vf vf19 vf17 vf11 acc) + (.mul.x.vf acc vf14 vf12) + (.add.mul.y.vf acc vf15 vf12 acc) + (.add.mul.z.vf acc vf16 vf12 acc) + (.add.mul.w.vf vf20 vf17 vf12 acc) + (.mul.x.vf acc vf14 vf13) + (.add.mul.y.vf acc vf15 vf13 acc) + (.add.mul.z.vf acc vf16 vf13 acc) + (.add.mul.w.vf vf21 vf17 vf13 acc) + (.svf arg0 vf18) + (.svf arg0 vf19 :offset 16) + (.svf arg0 vf20 :offset 32) + (.svf arg0 vf21 :offset 48) + arg0 + ) + ) + +(defun matrixp*! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + "Also 4x4 matrix multiplication, but first stores the result in a temporary. + So this appears to be a strictly worse version of matrix*!. + This function is never used" + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix*! s5-0 arg1 arg2) + (set! (-> arg0 vector 0 quad) (-> s5-0 vector 0 quad)) + (set! (-> arg0 vector 1 quad) (-> s5-0 vector 1 quad)) + (set! (-> arg0 vector 2 quad) (-> s5-0 vector 2 quad)) + (set! (-> arg0 vector 3 quad) (-> s5-0 vector 3 quad)) + ) + arg0 + ) + +(defun vector-matrix*! ((arg0 vector) (arg1 vector) (arg2 matrix)) + "Multiply vector by matrix. This is probably the opposite of what you expect and treats + arg1 as a 1x4 row vector. + arg0 = arg1 * arg2 + 1x4 1x4 4x4" + (rlet ((acc :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (.lvf vf1 (&-> arg2 vector 0 quad)) + (.lvf vf2 (&-> arg2 vector 1 quad)) + (.lvf vf3 (&-> arg2 vector 2 quad)) + (.lvf vf4 (&-> arg2 vector 3 quad)) + (.lvf vf5 (&-> arg1 quad)) + (.mul.x.vf acc vf1 vf5) + (.add.mul.y.vf acc vf2 vf5 acc) + (.add.mul.z.vf acc vf3 vf5 acc) + (.add.mul.w.vf vf5 vf4 vf5 acc) + (.svf (&-> arg0 quad) vf5) + arg0 + ) + ) + + +(defun vector-rotate*! ((arg0 vector) (arg1 vector) (arg2 matrix)) + "Special case of matrix-vector multiplication for just rotating." + (rlet ((acc :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (.lvf vf5 (&-> arg1 quad)) + (.lvf vf1 (&-> arg2 vector 0 quad)) + (.lvf vf2 (&-> arg2 vector 1 quad)) + (.mul.x.vf acc vf1 vf5) + (.lvf vf3 (&-> arg2 vector 2 quad)) + (.add.mul.y.vf acc vf2 vf5 acc) + (.lvf vf4 (&-> arg2 vector 3 quad)) ;; this doesn't need to be here... + (.add.mul.z.vf vf5 vf3 vf5 acc) + (.svf (&-> arg0 quad) vf5) + arg0 + ) + ) + +(defun vector3s-matrix*! ((arg0 vector3s) (arg1 vector3s) (arg2 matrix)) + "Multiply a vector3s by a matrix. The w component is treated as 1.0. + The w component of the output is not written." + (let ((s5-0 (new 'stack 'vector))) + (set! (-> s5-0 quad) (the-as uint128 0)) + (let ((v1-0 s5-0)) + (set! (-> v1-0 data 0) (-> arg1 data 0)) + (set! (-> v1-0 data 1) (-> arg1 data 1)) + (set! (-> v1-0 data 2) (-> arg1 data 2)) + (set! (-> v1-0 data 3) 1.0) + ) + (vector-matrix*! s5-0 s5-0 arg2) + (set! (-> arg0 data 0) (-> s5-0 data 0)) + (set! (-> arg0 data 1) (-> s5-0 data 1)) + (set! (-> arg0 data 2) (-> s5-0 data 2)) + ) + arg0 + ) + +(defun vector3s-rotate*! ((arg0 vector3s) (arg1 vector3s) (arg2 matrix)) + "Do a vector-rotate*!, treating the input's w as 1.0. Does not write output's w." + (let ((s5-0 (new 'stack 'vector))) + (set! (-> s5-0 quad) (the-as uint128 0)) + (let ((v1-0 s5-0)) + (set! (-> v1-0 data 0) (-> arg1 data 0)) + (set! (-> v1-0 data 1) (-> arg1 data 1)) + (set! (-> v1-0 data 2) (-> arg1 data 2)) + (set! (-> v1-0 data 3) 1.0) + ) + (vector-rotate*! s5-0 s5-0 arg2) + (set! (-> arg0 data 0) (-> s5-0 data 0)) + (set! (-> arg0 data 1) (-> s5-0 data 1)) + (set! (-> arg0 data 2) (-> s5-0 data 2)) + ) + (let ((v1-1 arg0)) + ) + arg0 + ) + +;; todo: matrix-transpose! +(define-extern matrix-transpose! (function matrix matrix matrix)) + +(defun matrix-inverse-of-rot-trans! ((arg0 matrix) (arg1 matrix)) + "Invert arg1 and store in arg0. This only works if arg1 is a rotation and translation. + It is not safe to call this in place (arg0 and arg1 are the same matrix)" + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf8 :class vf) + ) + (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) + ;; transpose the whole matrix. This takes care of the upper 3x3 + ;; because R^T = R^-1 for any orthonormal matrix, and rotations are + ;; always orthonormal. The rest of the function is cleaning up the + ;; stuff that's not in this 3x3. + (matrix-transpose! arg0 arg1) + + ;; load the transposed matrix. + (.lvf vf1 (&-> arg0 vector 0 quad)) + (.lvf vf2 (&-> arg0 vector 1 quad)) + (.lvf vf3 (&-> arg0 vector 2 quad)) + + ;; zero out the upper 3x1 right column of the matrix. + ;; their transformation matrices are transposed. + (.sub.vf vf1 vf1 vf1 :mask #b1000) + (.sub.vf vf2 vf2 vf2 :mask #b1000) + (.sub.vf vf3 vf3 vf3 :mask #b1000) + + ;; this is the original translation. + (.lvf vf8 (&-> arg1 vector 3 quad)) + ;; which is now multiplied by the rotation. + (.mul.x.vf acc vf1 vf8) + (.add.mul.y.vf acc vf2 vf8 acc) + (.add.mul.z.vf vf4 vf3 vf8 acc) + ;; and inverted. + (.sub.vf vf4 vf0 vf4) + ;; and w is set to 1. + (.mov.vf vf4 vf0 :mask #b1000) + + ;; store the rotation rows + (.svf (&-> arg0 vector 0 quad) vf1) + (.svf (&-> arg0 vector 1 quad) vf2) + (.svf (&-> arg0 vector 2 quad) vf3) + ;; store the translation. + (.svf (&-> arg0 vector 3 quad) vf4) + arg0 + ) + ) + +(define-extern matrix-4x4-inverse! (function matrix matrix matrix)) +#| +(defun matrix-4x4-inverse! ((arg0 matrix) (arg1 matrix)) +(rlet ((acc :class vf) +(Q :class vf) +(vf0 :class vf) +(vf1 :class vf) +(vf10 :class vf) +(vf11 :class vf) +(vf12 :class vf) +(vf13 :class vf) +(vf14 :class vf) +(vf15 :class vf) +(vf16 :class vf) +(vf17 :class vf) +(vf18 :class vf) +(vf19 :class vf) +(vf2 :class vf) +(vf20 :class vf) +(vf23 :class vf) +(vf24 :class vf) +(vf25 :class vf) +(vf26 :class vf) +(vf27 :class vf) +(vf28 :class vf) +(vf29 :class vf) +(vf3 :class vf) +(vf30 :class vf) +(vf31 :class vf) +(vf4 :class vf) +(vf5 :class vf) +(vf6 :class vf) +(vf7 :class vf) +(vf8 :class vf) +(vf9 :class vf) +) +(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) +(.lvf vf23 (&-> arg1 vector 0 quad)) +(.lvf vf24 (&-> arg1 vector 1 quad)) +(.lvf vf25 (&-> arg1 vector 2 quad)) +(.lvf vf1 (&-> arg1 vector 3 quad)) +(.mul.x.vf vf7 vf24 vf23) +(.mul.y.vf vf8 vf24 vf23) +(.mul.z.vf vf9 vf24 vf23) +(.mul.x.vf vf10 vf25 vf23) +(.mul.y.vf vf11 vf25 vf23) +(.mul.z.vf vf12 vf25 vf23) +(.mul.x.vf vf13 vf25 vf24) +(.mul.y.vf vf14 vf25 vf24) +(.mul.z.vf vf15 vf25 vf24) +(.mul.z.vf vf26 vf7 vf25 :mask #b10) +(.mul.z.vf vf27 vf11 vf24 :mask #b1) +(.mul.y.vf vf28 vf9 vf25 :mask #b1) +(.mul.z.vf vf29 vf14 vf23 :mask #b1) +(.mul.z.vf vf30 vf8 vf25 :mask #b1) +(.mul.y.vf vf31 vf7 vf25 :mask #b100) +(.add.y.vf vf16 vf27 vf26 :mask #b1) +(.sub.vf vf1 vf0 vf1) +(.add.x.vf vf17 vf29 vf30 :mask #b1) +(.sub.z.vf vf18 vf28 vf31 :mask #b1) +(.sub.y.vf vf23 vf14 vf15 :mask #b100) +(.sub.z.vf vf26 vf15 vf13 :mask #b1) +(.sub.x.vf vf29 vf13 vf14 :mask #b10) +(.sub.vf vf19 vf16 vf17 :mask #b1) +(.sub.z.vf vf24 vf12 vf11 :mask #b10) +(.sub.x.vf vf27 vf10 vf12 :mask #b100) +(.sub.y.vf vf30 vf11 vf10 :mask #b1) +(.add.vf vf20 vf19 vf18 :mask #b1) +(.sub.y.vf vf25 vf8 vf9 :mask #b100) +(.sub.z.vf vf28 vf9 vf7 :mask #b1) +(.sub.x.vf vf31 vf7 vf8 :mask #b10) +(.div.vf Q vf0 vf20 :ftf #b11 :fsf #b0) +;; Added for PC port: zero out these vectors entirely +(.xor.vf vf3 vf3 vf3) +(.xor.vf vf4 vf4 vf4) +(.xor.vf vf5 vf5 vf5) +;; This has no effect on the result, but prevents use from doing +;; math on uninitialized values, which can be slow if they happen to +;; be NaN's +;; ================== +;;(.sub.w.vf vf3 vf3 vf3 :mask #b1000) +;;(.sub.w.vf vf4 vf4 vf4 :mask #b1000) +;;(.sub.w.vf vf5 vf5 vf5 :mask #b1000) +(.mov.vf vf6 vf0 :mask #b1000) +;;(.wait.vf) +(.add.vf vf2 vf0 Q :mask #b1) +(.add.x.vf vf2 vf0 vf2 :mask #b111) +(.mul.z.vf vf3 vf2 vf23 :mask #b1) +(.mul.x.vf vf4 vf2 vf26 :mask #b1) +(.mul.y.vf vf5 vf2 vf29 :mask #b1) +(.mul.y.vf vf3 vf2 vf24 :mask #b10) +(.mul.z.vf vf4 vf2 vf27 :mask #b10) +(.mul.x.vf vf5 vf2 vf30 :mask #b10) +(.mul.z.vf vf3 vf2 vf25 :mask #b100) +(.mul.x.vf vf4 vf2 vf28 :mask #b100) +(.mul.y.vf vf5 vf2 vf31 :mask #b100) +(.mul.x.vf acc vf3 vf1) +(.svf (&-> arg0 vector 0 quad) vf3) +(.add.mul.y.vf acc vf4 vf1 acc) +(.svf (&-> arg0 vector 1 quad) vf4) +(.add.mul.z.vf vf6 vf5 vf1 acc :mask #b111) +(.svf (&-> arg0 vector 2 quad) vf5) +(nop!) +(.svf (&-> arg0 vector 3 quad) vf6) +arg0 +) +) +|# + +(defun matrix-translate! ((arg0 matrix) (arg1 vector)) + "Create a translation matrix." + (matrix-identity! arg0) + (set! (-> arg0 data 12) (-> arg1 data 0)) + (set! (-> arg0 data 13) (-> arg1 data 1)) + (set! (-> arg0 data 14) (-> arg1 data 2)) + arg0 + ) + +(defun matrix-translate+! ((arg0 matrix) (arg1 matrix) (arg2 vector)) + "Set arg0 = arg1 with added translation of arg2. + It's okay to call this with arg0 == arg1 or not." + (set! (-> arg0 data 12) (+ (-> arg1 data 12) (-> arg2 data 0))) + (set! (-> arg0 data 13) (+ (-> arg1 data 13) (-> arg2 data 1))) + (set! (-> arg0 data 14) (+ (-> arg1 data 14) (-> arg2 data 2))) + (when (!= arg0 arg1) + ;; only copy matrix if we actually need to. + (set! (-> arg0 vector 0 quad) (-> arg1 vector 0 quad)) + (set! (-> arg0 vector 1 quad) (-> arg1 vector 1 quad)) + (set! (-> arg0 vector 2 quad) (-> arg1 vector 2 quad)) + ) + arg0 + ) + +(defun matrix-scale! ((arg0 matrix) (arg1 vector)) + "Make arg0 a scaling matrix." + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) (-> arg1 data 0)) + (set! (-> arg0 data 5) (-> arg1 data 1)) + (set! (-> arg0 data 10) (-> arg1 data 2)) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +(defun scale-matrix! ((arg0 matrix) (arg1 vector) (arg2 matrix)) + "Apply a scale to an existing matrix" + (rlet ((vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + ) + (.lvf vf4 (&-> arg1 quad)) + (.lvf vf5 (&-> arg2 vector 0 quad)) + (.lvf vf6 (&-> arg2 vector 1 quad)) + (.lvf vf7 (&-> arg2 vector 2 quad)) + (.lvf vf8 (&-> arg2 vector 3 quad)) + (.mul.x.vf vf5 vf5 vf4) + (.mul.y.vf vf6 vf6 vf4) + (.mul.z.vf vf7 vf7 vf4) + (.mul.w.vf vf8 vf8 vf4) + (.svf (&-> arg0 vector 0 quad) vf5) + (.svf (&-> arg0 vector 1 quad) vf6) + (.svf (&-> arg0 vector 2 quad) vf7) + (.svf (&-> arg0 vector 3 quad) vf8) + arg0 + ) + ) + +(defun matrix-inv-scale! ((arg0 matrix) (arg1 vector)) + "Create a scaling matrix which uses the inverse of the coefficients in arg1" + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) (/ 1.0 (-> arg1 data 0))) + (set! (-> arg0 data 5) (/ 1.0 (-> arg1 data 1))) + (set! (-> arg0 data 10) (/ 1.0 (-> arg1 data 2))) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +(defun column-scale-matrix! ((arg0 matrix) (arg1 vector) (arg2 matrix)) + "Scale an existing matrix, but treat the scale factors in the opposite direction." + (rlet ((vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + ) + (.lvf vf4 (&-> arg1 quad)) + (.lvf vf5 (&-> arg2 vector 0 quad)) + (.lvf vf6 (&-> arg2 vector 1 quad)) + (.lvf vf7 (&-> arg2 vector 2 quad)) + (.lvf vf8 (&-> arg2 vector 3 quad)) + (.mul.vf vf5 vf5 vf4) + (.mul.vf vf6 vf6 vf4) + (.mul.vf vf7 vf7 vf4) + (.mul.vf vf8 vf8 vf4) + (.svf (&-> arg0 vector 0 quad) vf5) + (.svf (&-> arg0 vector 1 quad) vf6) + (.svf (&-> arg0 vector 2 quad) vf7) + (.svf (&-> arg0 vector 3 quad) vf8) + arg0 + ) + ) + +(defun matrix-rotate-x! ((arg0 matrix) (arg1 float)) + "Create a matrix which represents a rotation around the x axis" + (let ((f30-0 (sin arg1)) + (f0-0 (cos arg1)) + ) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) 1.0) + (set! (-> arg0 data 5) f0-0) + (set! (-> arg0 data 6) f30-0) + (set! (-> arg0 data 9) (- f30-0)) + (set! (-> arg0 data 10) f0-0) + ) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +(defun matrix-rotate-y! ((arg0 matrix) (arg1 float)) + "Create a matrix for rotating around the y axis" + (let ((f30-0 (sin arg1)) + (f0-0 (cos arg1)) + ) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) f0-0) + (set! (-> arg0 data 2) (- f30-0)) + (set! (-> arg0 data 5) 1.0) + (set! (-> arg0 data 8) f30-0) + (set! (-> arg0 data 10) f0-0) + ) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +(defun matrix-rotate-z! ((arg0 matrix) (arg1 float)) + "Create a matrix for rotating around the z axis" + (let ((f30-0 (sin arg1)) + (f0-0 (cos arg1)) + ) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) f0-0) + (set! (-> arg0 data 1) f30-0) + (set! (-> arg0 data 4) (- f30-0)) + (set! (-> arg0 data 5) f0-0) + ) + (set! (-> arg0 data 10) 1.0) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +(defun matrix-rotate-zyx! ((arg0 matrix) (arg1 vector)) + "Create a matrix for a series of rotations" + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-x! arg0 (-> arg1 data 0)) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-z! gp-0 (-> arg1 data 2)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +(defun matrix-rotate-xyz! ((arg0 matrix) (arg1 vector)) + "Create a matrix for a series of rotations" + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-z! arg0 (-> arg1 data 2)) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-x! gp-0 (-> arg1 data 0)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +(defun matrix-rotate-zxy! ((arg0 matrix) (arg1 vector)) + "Create a matrix for a series of rotations" + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-y! arg0 (-> arg1 data 1)) + (matrix-rotate-x! gp-0 (-> arg1 data 0)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-z! gp-0 (-> arg1 data 2)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +(defun matrix-rotate-yxz! ((arg0 matrix) (arg1 vector)) + "Create a matrix for a series of rotations" + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-z! arg0 (-> arg1 data 2)) + (matrix-rotate-x! gp-0 (-> arg1 data 0)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + + +(defun matrix-rotate-yzx! ((arg0 matrix) (arg1 vector)) + "Create a matrix for a series of rotations" + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-z! arg0 (-> arg1 data 0)) + (matrix-rotate-x! gp-0 (-> arg1 data 2)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +(defun matrix-rotate-yxy! ((arg0 matrix) (arg1 vector)) + "Create a matrix for a series of rotations" + (let ((a2-0 (new 'stack 'vector)) + (s5-0 (new 'stack 'vector)) + (s4-0 (new 'stack 'vector)) + ) + (let ((v1-0 a2-0)) + (set! (-> v1-0 data 0) (-> arg1 data 0)) + (set! (-> v1-0 data 1) (- (-> arg1 data 1) (-> arg1 data 2))) + (set! (-> v1-0 data 2) (-> arg1 data 2)) + (set! (-> v1-0 data 3) 1.0) + ) + (vector-sincos! s5-0 s4-0 a2-0) + (let ((f1-1 (-> s4-0 data 1)) + (f0-5 (-> s5-0 data 1)) + (f2-0 (-> s4-0 data 0)) + (f5-0 (-> s5-0 data 0)) + (f3-0 (-> s4-0 data 2)) + (f4-0 (-> s5-0 data 2)) + ) + (set! (-> arg0 data 0) (- (* f1-1 f3-0) (* (* f0-5 f2-0) f4-0))) + (set! (-> arg0 data 1) (* f0-5 f5-0)) + (set! (-> arg0 data 2) (- (+ (* f1-1 f4-0) (* (* f0-5 f2-0) f3-0)))) + (set! (-> arg0 data 3) 0.0) + (set! (-> arg0 data 4) (* f5-0 f4-0)) + (set! (-> arg0 data 5) f2-0) + (set! (-> arg0 data 6) (* f5-0 f3-0)) + (set! (-> arg0 data 7) 0.0) + (set! (-> arg0 data 8) (+ (* f0-5 f3-0) (* (* f1-1 f2-0) f4-0))) + (set! (-> arg0 data 9) (- (* f1-1 f5-0))) + (set! (-> arg0 data 10) (- (* (* f1-1 f2-0) f3-0) (* f0-5 f4-0))) + ) + ) + (set! (-> arg0 data 11) 0.0) + (set! (-> arg0 data 12) 0.0) + (set! (-> arg0 data 13) 0.0) + (set! (-> arg0 data 14) 0.0) + (set! (-> arg0 data 16) 1.0) + arg0 + ) + +(defun matrix-rotate-yx! ((arg0 matrix) (arg1 float) (arg2 float)) + (matrix-rotate-y! arg0 arg1) + ;; this is ugly because of the inline ctor. + (let ((t9-1 matrix-rotate-x!) + (a0-2 (new 'stack 'matrix)) + ) + (set! (-> a0-2 vector 0 quad) (the-as uint128 0)) + (set! (-> a0-2 vector 1 quad) (the-as uint128 0)) + (set! (-> a0-2 vector 2 quad) (the-as uint128 0)) + (set! (-> a0-2 vector 3 quad) (the-as uint128 0)) + (let ((a1-2 (t9-1 a0-2 arg2))) + (matrix*! arg0 a1-2 arg0) + ) + ) + arg0 + ) + +;; todo: matrix-axis-sin-cos-vu! +;; todo: matrix-axis-sin-cos! +;; todo: matrix-axis-angle! + +(defun matrix-lerp! ((arg0 matrix) (arg1 matrix) (arg2 matrix) (arg3 float)) + (rlet ((vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + (vf9 :class vf) + ) + (.mov vf9 arg3) + (.lvf vf1 (&-> arg1 vector 0 quad)) + (.lvf vf2 (&-> arg1 vector 1 quad)) + (.lvf vf3 (&-> arg1 vector 2 quad)) + (.lvf vf4 (&-> arg1 vector 3 quad)) + (.lvf vf5 (&-> arg2 vector 0 quad)) + (.lvf vf6 (&-> arg2 vector 1 quad)) + (.lvf vf7 (&-> arg2 vector 2 quad)) + (.lvf vf8 (&-> arg2 vector 3 quad)) + (.sub.vf vf5 vf5 vf1) + (.sub.vf vf6 vf6 vf2) + (.sub.vf vf7 vf7 vf3) + (.sub.vf vf8 vf8 vf4) + (.mul.x.vf vf5 vf5 vf9) + (.mul.x.vf vf6 vf6 vf9) + (.mul.x.vf vf7 vf7 vf9) + (.mul.x.vf vf8 vf8 vf9) + (.add.vf vf1 vf1 vf5) + (.add.vf vf2 vf2 vf6) + (.add.vf vf3 vf3 vf7) + (.add.vf vf4 vf4 vf8) + (.svf (&-> arg0 vector 0 quad) vf1) + (.svf (&-> arg0 vector 1 quad) vf2) + (.svf (&-> arg0 vector 2 quad) vf3) + (.svf (&-> arg0 vector 3 quad) vf4) + arg0 + ) + ) + +(defun matrix-3x3-determinant ((arg0 matrix)) + (let ((f8-0 (-> arg0 data 0)) + (f1-0 (-> arg0 data 1)) + (f4-0 (-> arg0 data 2)) + (f2-0 (-> arg0 data 4)) + (f5-0 (-> arg0 data 5)) + (f9-0 (-> arg0 data 6)) + (f3-0 (-> arg0 data 8)) + (f6-0 (-> arg0 data 9)) + (f0-0 (-> arg0 data 10)) + ) + (- (+ (+ (* (* f8-0 f5-0) f0-0) (* (* f1-0 f9-0) f3-0)) (* (* f4-0 f2-0) f6-0)) + (+ (+ (* (* f8-0 f9-0) f6-0) (* (* f4-0 f5-0) f3-0)) (* (* f1-0 f2-0) f0-0)) + ) + ) + ) + +(defun matrix3-determinant ((arg0 matrix)) + (local-vars (v0-0 int)) + (rlet ((acc :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + ) + (.lvf vf11 (&-> arg0 vector 1 quad)) + (.lvf vf12 (&-> arg0 vector 2 quad)) + (.lvf vf10 (&-> arg0 vector 0 quad)) + (.outer.product.vf vf13 vf11 vf12) + (.mul.vf vf13 vf13 vf10 :mask #b111) + (.add.y.vf vf13 vf13 vf13 :mask #b1) + (.add.z.vf vf13 vf13 vf13 :mask #b1) + (.mov v0-0 vf13) + (the-as float v0-0) + ) + ) + +(defun matrix-3x3-inverse! ((arg0 matrix) (arg1 matrix)) + (let ((f0-0 (matrix-3x3-determinant arg1))) + (set! (-> arg0 data 0) + (/ (- (* (-> arg1 data 5) (-> arg1 data 10)) + (* (-> arg1 data 6) (-> arg1 data 9)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 4) + (/ (- (* (-> arg1 data 6) (-> arg1 data 8)) + (* (-> arg1 data 4) (-> arg1 data 10)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 8) + (/ (- (* (-> arg1 data 4) (-> arg1 data 9)) + (* (-> arg1 data 5) (-> arg1 data 8)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 1) + (/ (- (* (-> arg1 data 9) (-> arg1 data 2)) + (* (-> arg1 data 10) (-> arg1 data 1)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 5) + (/ (- (* (-> arg1 data 10) (-> arg1 data 0)) + (* (-> arg1 data 8) (-> arg1 data 2)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 9) + (/ (- (* (-> arg1 data 8) (-> arg1 data 1)) + (* (-> arg1 data 9) (-> arg1 data 0)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 2) + (/ (- (* (-> arg1 data 1) (-> arg1 data 6)) + (* (-> arg1 data 2) (-> arg1 data 5)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 6) + (/ (- (* (-> arg1 data 2) (-> arg1 data 4)) + (* (-> arg1 data 0) (-> arg1 data 6)) + ) + f0-0 + ) + ) + (set! (-> arg0 data 10) + (/ (- (* (-> arg1 data 0) (-> arg1 data 5)) + (* (-> arg1 data 1) (-> arg1 data 4)) + ) + f0-0 + ) + ) + ) + arg0 + ) + +(defun matrix-3x3-inverse-transpose! ((arg0 matrix) (arg1 matrix)) + (let ((f0-0 (matrix-3x3-determinant arg1))) + (set! + (-> arg0 data 0) + (/ + (- + (* (-> arg1 data 5) (-> arg1 data 10)) + (* (-> arg1 data 6) (-> arg1 data 9)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 1) + (/ + (- + (* (-> arg1 data 6) (-> arg1 data 8)) + (* (-> arg1 data 4) (-> arg1 data 10)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 2) + (/ + (- + (* (-> arg1 data 4) (-> arg1 data 9)) + (* (-> arg1 data 5) (-> arg1 data 8)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 4) + (/ + (- + (* (-> arg1 data 9) (-> arg1 data 2)) + (* (-> arg1 data 10) (-> arg1 data 1)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 5) + (/ + (- + (* (-> arg1 data 10) (-> arg1 data 0)) + (* (-> arg1 data 8) (-> arg1 data 2)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 6) + (/ + (- + (* (-> arg1 data 8) (-> arg1 data 1)) + (* (-> arg1 data 9) (-> arg1 data 0)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 8) + (/ + (- + (* (-> arg1 data 1) (-> arg1 data 6)) + (* (-> arg1 data 2) (-> arg1 data 5)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 9) + (/ + (- + (* (-> arg1 data 2) (-> arg1 data 4)) + (* (-> arg1 data 0) (-> arg1 data 6)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 10) + (/ + (- + (* (-> arg1 data 0) (-> arg1 data 5)) + (* (-> arg1 data 1) (-> arg1 data 4)) + ) + f0-0 + ) + ) + ) + arg0 + ) + +(defun matrix3-inverse-transpose! ((arg0 matrix) (arg1 matrix)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + (vf14 :class vf) + (vf15 :class vf) + ) + (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) + (.lvf vf10 (&-> arg1 vector 0 quad)) + (.lvf vf11 (&-> arg1 vector 1 quad)) + (.lvf vf12 (&-> arg1 vector 2 quad)) + (.outer.product.vf vf13 vf11 vf12) + (.outer.product.vf vf14 vf12 vf10) + (.mul.vf vf1 vf10 vf13 :mask #b111) + (.outer.product.vf vf15 vf10 vf11) + (.add.y.vf vf1 vf1 vf1 :mask #b1) + (.add.z.vf vf1 vf1 vf1 :mask #b1) + (.div.vf Q vf0 vf1 :ftf #b11 :fsf #b0) + ;;(.wait.vf) + (.mul.vf vf13 vf13 Q) + (.mul.vf vf14 vf14 Q) + (.mul.vf vf15 vf15 Q) + (.svf (&-> arg0 vector 0 quad) vf13) + (.svf (&-> arg0 vector 1 quad) vf14) + (.svf (&-> arg0 vector 2 quad) vf15) + arg0 + ) + ) + +(defun matrix-4x4-determinant ((arg0 matrix)) + (let ((f15-0 (-> arg0 data 0)) + (f14-0 (-> arg0 data 1)) + (f10-0 (-> arg0 data 2)) + (f2-0 (-> arg0 data 3)) + (f9-0 (-> arg0 data 4)) + (f6-0 (-> arg0 data 5)) + (f3-0 (-> arg0 data 6)) + (f11-0 (-> arg0 data 7)) + (f5-0 (-> arg0 data 8)) + (f1-0 (-> arg0 data 9)) + (f8-0 (-> arg0 data 10)) + (f13-0 (-> arg0 data 11)) + (f0-0 (-> arg0 data 12)) + (f7-0 (-> arg0 data 13)) + (f4-0 (-> arg0 data 14)) + (f12-0 (-> arg0 data 15)) + ) + (- (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (+ (* (* (* f15-0 f6-0) f8-0) f12-0) + (* (* (* f15-0 f3-0) f13-0) f7-0) + ) + (* (* (* f15-0 f11-0) f1-0) f4-0) + ) + (* (* (* f14-0 f9-0) f13-0) f4-0) + ) + (* (* (* f14-0 f3-0) f5-0) f4-0) + ) + (* (* (* f14-0 f11-0) f8-0) f0-0) + ) + (* (* (* f10-0 f9-0) f1-0) f12-0) + ) + (* (* (* f10-0 f6-0) f13-0) f0-0) + ) + (* (* (* f10-0 f11-0) f5-0) f7-0) + ) + (* (* (* f2-0 f9-0) f1-0) f4-0) + ) + (* (* (* f2-0 f6-0) f8-0) f0-0) + ) + (* (* (* f2-0 f3-0) f5-0) f7-0) + ) + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (* (* (* f15-0 f6-0) f13-0) f4-0) + (* (* (* f15-0 f3-0) f1-0) f12-0) + ) + (* (* (* f15-0 f11-0) f8-0) f7-0) + ) + (* (* (* f14-0 f9-0) f8-0) f12-0) + ) + (* (* (* f14-0 f3-0) f13-0) f0-0) + ) + (* (* (* f14-0 f11-0) f5-0) f4-0) + ) + (* (* (* f10-0 f9-0) f13-0) f7-0) + ) + (* (* (* f10-0 f6-0) f5-0) f12-0) + ) + (* (* (* f10-0 f11-0) f1-0) f0-0) + ) + (* (* (* f2-0 f9-0) f8-0) f7-0) + ) + (* (* (* f2-0 f6-0) f5-0) f4-0) + ) + (* (* (* f2-0 f3-0) f1-0) f0-0) + ) + ) + ) + ) + + +(defun matrix-4x4-inverse-transpose! ((arg0 matrix) (arg1 matrix)) + (let ((f0-0 (matrix-4x4-determinant arg1))) + (let ((f9-0 (-> arg1 data 5)) + (f2-0 (-> arg1 data 6)) + (f5-0 (-> arg1 data 7)) + (f3-0 (-> arg1 data 9)) + (f6-0 (-> arg1 data 10)) + (f10-0 (-> arg1 data 11)) + (f4-0 (-> arg1 data 13)) + (f7-0 (-> arg1 data 14)) + (f1-0 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 0) + (/ + (- + (+ + (+ (* (* f9-0 f6-0) f1-0) (* (* f2-0 f10-0) f4-0)) + (* (* f5-0 f3-0) f7-0) + ) + (+ + (+ (* (* f9-0 f10-0) f7-0) (* (* f5-0 f6-0) f4-0)) + (* (* f2-0 f3-0) f1-0) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-2 (-> arg1 data 4)) + (f2-2 (-> arg1 data 6)) + (f5-2 (-> arg1 data 7)) + (f3-1 (-> arg1 data 8)) + (f6-1 (-> arg1 data 10)) + (f10-1 (-> arg1 data 11)) + (f4-3 (-> arg1 data 12)) + (f7-2 (-> arg1 data 14)) + (f1-6 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 1) + (- + (/ + (- + (+ + (+ (* (* f9-2 f6-1) f1-6) (* (* f2-2 f10-1) f4-3)) + (* (* f5-2 f3-1) f7-2) + ) + (+ + (+ (* (* f9-2 f10-1) f7-2) (* (* f5-2 f6-1) f4-3)) + (* (* f2-2 f3-1) f1-6) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-4 (-> arg1 data 4)) + (f2-4 (-> arg1 data 5)) + (f5-4 (-> arg1 data 7)) + (f3-2 (-> arg1 data 8)) + (f6-2 (-> arg1 data 9)) + (f10-2 (-> arg1 data 11)) + (f4-6 (-> arg1 data 12)) + (f7-4 (-> arg1 data 13)) + (f1-13 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 2) + (/ + (- + (+ + (+ (* (* f9-4 f6-2) f1-13) (* (* f2-4 f10-2) f4-6)) + (* (* f5-4 f3-2) f7-4) + ) + (+ + (+ (* (* f9-4 f10-2) f7-4) (* (* f5-4 f6-2) f4-6)) + (* (* f2-4 f3-2) f1-13) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-6 (-> arg1 data 4)) + (f2-6 (-> arg1 data 5)) + (f5-6 (-> arg1 data 6)) + (f3-3 (-> arg1 data 8)) + (f6-3 (-> arg1 data 9)) + (f10-3 (-> arg1 data 10)) + (f4-9 (-> arg1 data 12)) + (f7-6 (-> arg1 data 13)) + (f1-19 (-> arg1 data 14)) + ) + (set! + (-> arg0 data 3) + (- + (/ + (- + (+ + (+ (* (* f9-6 f6-3) f1-19) (* (* f2-6 f10-3) f4-9)) + (* (* f5-6 f3-3) f7-6) + ) + (+ + (+ (* (* f9-6 f10-3) f7-6) (* (* f5-6 f6-3) f4-9)) + (* (* f2-6 f3-3) f1-19) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-8 (-> arg1 data 1)) + (f2-8 (-> arg1 data 2)) + (f5-8 (-> arg1 data 3)) + (f3-4 (-> arg1 data 9)) + (f6-4 (-> arg1 data 10)) + (f10-4 (-> arg1 data 11)) + (f4-12 (-> arg1 data 13)) + (f7-8 (-> arg1 data 14)) + (f1-26 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 4) + (- + (/ + (- + (+ + (+ (* (* f9-8 f6-4) f1-26) (* (* f2-8 f10-4) f4-12)) + (* (* f5-8 f3-4) f7-8) + ) + (+ + (+ (* (* f9-8 f10-4) f7-8) (* (* f5-8 f6-4) f4-12)) + (* (* f2-8 f3-4) f1-26) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-10 (-> arg1 data 0)) + (f2-10 (-> arg1 data 2)) + (f5-10 (-> arg1 data 3)) + (f3-5 (-> arg1 data 8)) + (f6-5 (-> arg1 data 10)) + (f10-5 (-> arg1 data 11)) + (f4-15 (-> arg1 data 12)) + (f7-10 (-> arg1 data 14)) + (f1-33 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 5) + (/ + (- + (+ + (+ (* (* f9-10 f6-5) f1-33) (* (* f2-10 f10-5) f4-15)) + (* (* f5-10 f3-5) f7-10) + ) + (+ + (+ (* (* f9-10 f10-5) f7-10) (* (* f5-10 f6-5) f4-15)) + (* (* f2-10 f3-5) f1-33) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-12 (-> arg1 data 0)) + (f2-12 (-> arg1 data 1)) + (f5-12 (-> arg1 data 3)) + (f3-6 (-> arg1 data 8)) + (f6-6 (-> arg1 data 9)) + (f10-6 (-> arg1 data 11)) + (f4-18 (-> arg1 data 12)) + (f7-12 (-> arg1 data 13)) + (f1-39 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 6) + (- + (/ + (- + (+ + (+ (* (* f9-12 f6-6) f1-39) (* (* f2-12 f10-6) f4-18)) + (* (* f5-12 f3-6) f7-12) + ) + (+ + (+ (* (* f9-12 f10-6) f7-12) (* (* f5-12 f6-6) f4-18)) + (* (* f2-12 f3-6) f1-39) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-14 (-> arg1 data 0)) + (f2-14 (-> arg1 data 1)) + (f5-14 (-> arg1 data 2)) + (f3-7 (-> arg1 data 8)) + (f6-7 (-> arg1 data 9)) + (f10-7 (-> arg1 data 10)) + (f4-21 (-> arg1 data 12)) + (f7-14 (-> arg1 data 13)) + (f1-46 (-> arg1 data 14)) + ) + (set! + (-> arg0 data 7) + (/ + (- + (+ + (+ (* (* f9-14 f6-7) f1-46) (* (* f2-14 f10-7) f4-21)) + (* (* f5-14 f3-7) f7-14) + ) + (+ + (+ (* (* f9-14 f10-7) f7-14) (* (* f5-14 f6-7) f4-21)) + (* (* f2-14 f3-7) f1-46) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-16 (-> arg1 data 1)) + (f2-16 (-> arg1 data 2)) + (f5-16 (-> arg1 data 3)) + (f3-8 (-> arg1 data 5)) + (f6-8 (-> arg1 data 6)) + (f10-8 (-> arg1 data 7)) + (f4-24 (-> arg1 data 13)) + (f7-16 (-> arg1 data 14)) + (f1-52 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 8) + (/ + (- + (+ + (+ (* (* f9-16 f6-8) f1-52) (* (* f2-16 f10-8) f4-24)) + (* (* f5-16 f3-8) f7-16) + ) + (+ + (+ (* (* f9-16 f10-8) f7-16) (* (* f5-16 f6-8) f4-24)) + (* (* f2-16 f3-8) f1-52) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-18 (-> arg1 data 0)) + (f2-18 (-> arg1 data 2)) + (f5-18 (-> arg1 data 3)) + (f3-9 (-> arg1 data 4)) + (f6-9 (-> arg1 data 6)) + (f10-9 (-> arg1 data 7)) + (f4-27 (-> arg1 data 12)) + (f7-18 (-> arg1 data 14)) + (f1-58 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 9) + (- + (/ + (- + (+ + (+ (* (* f9-18 f6-9) f1-58) (* (* f2-18 f10-9) f4-27)) + (* (* f5-18 f3-9) f7-18) + ) + (+ + (+ (* (* f9-18 f10-9) f7-18) (* (* f5-18 f6-9) f4-27)) + (* (* f2-18 f3-9) f1-58) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-20 (-> arg1 data 0)) + (f2-20 (-> arg1 data 1)) + (f5-20 (-> arg1 data 3)) + (f3-10 (-> arg1 data 4)) + (f6-10 (-> arg1 data 5)) + (f10-10 (-> arg1 data 7)) + (f4-30 (-> arg1 data 12)) + (f7-20 (-> arg1 data 13)) + (f1-65 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 10) + (/ + (- + (+ + (+ (* (* f9-20 f6-10) f1-65) (* (* f2-20 f10-10) f4-30)) + (* (* f5-20 f3-10) f7-20) + ) + (+ + (+ (* (* f9-20 f10-10) f7-20) (* (* f5-20 f6-10) f4-30)) + (* (* f2-20 f3-10) f1-65) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-22 (-> arg1 data 0)) + (f2-22 (-> arg1 data 1)) + (f5-22 (-> arg1 data 2)) + (f3-11 (-> arg1 data 4)) + (f6-11 (-> arg1 data 5)) + (f10-11 (-> arg1 data 6)) + (f4-33 (-> arg1 data 12)) + (f7-22 (-> arg1 data 13)) + (f1-71 (-> arg1 data 14)) + ) + (set! + (-> arg0 data 11) + (- + (/ + (- + (+ + (+ (* (* f9-22 f6-11) f1-71) (* (* f2-22 f10-11) f4-33)) + (* (* f5-22 f3-11) f7-22) + ) + (+ + (+ (* (* f9-22 f10-11) f7-22) (* (* f5-22 f6-11) f4-33)) + (* (* f2-22 f3-11) f1-71) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-24 (-> arg1 data 1)) + (f2-24 (-> arg1 data 2)) + (f5-24 (-> arg1 data 3)) + (f3-12 (-> arg1 data 5)) + (f6-12 (-> arg1 data 6)) + (f10-12 (-> arg1 data 7)) + (f4-36 (-> arg1 data 9)) + (f7-24 (-> arg1 data 10)) + (f1-78 (-> arg1 data 11)) + ) + (set! + (-> arg0 data 12) + (- + (/ + (- + (+ + (+ (* (* f9-24 f6-12) f1-78) (* (* f2-24 f10-12) f4-36)) + (* (* f5-24 f3-12) f7-24) + ) + (+ + (+ (* (* f9-24 f10-12) f7-24) (* (* f5-24 f6-12) f4-36)) + (* (* f2-24 f3-12) f1-78) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-26 (-> arg1 data 0)) + (f2-26 (-> arg1 data 2)) + (f5-26 (-> arg1 data 3)) + (f3-13 (-> arg1 data 4)) + (f6-13 (-> arg1 data 6)) + (f10-13 (-> arg1 data 7)) + (f4-39 (-> arg1 data 8)) + (f7-26 (-> arg1 data 10)) + (f1-85 (-> arg1 data 11)) + ) + (set! + (-> arg0 data 13) + (/ + (- + (+ + (+ (* (* f9-26 f6-13) f1-85) (* (* f2-26 f10-13) f4-39)) + (* (* f5-26 f3-13) f7-26) + ) + (+ + (+ (* (* f9-26 f10-13) f7-26) (* (* f5-26 f6-13) f4-39)) + (* (* f2-26 f3-13) f1-85) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-28 (-> arg1 data 0)) + (f2-28 (-> arg1 data 1)) + (f5-28 (-> arg1 data 3)) + (f3-14 (-> arg1 data 4)) + (f6-14 (-> arg1 data 5)) + (f10-14 (-> arg1 data 7)) + (f4-42 (-> arg1 data 8)) + (f7-28 (-> arg1 data 9)) + (f1-91 (-> arg1 data 11)) + ) + (set! + (-> arg0 data 14) + (- + (/ + (- + (+ + (+ (* (* f9-28 f6-14) f1-91) (* (* f2-28 f10-14) f4-42)) + (* (* f5-28 f3-14) f7-28) + ) + (+ + (+ (* (* f9-28 f10-14) f7-28) (* (* f5-28 f6-14) f4-42)) + (* (* f2-28 f3-14) f1-91) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f8-60 (-> arg1 data 0)) + (f1-98 (-> arg1 data 1)) + (f5-30 (-> arg1 data 2)) + (f2-30 (-> arg1 data 4)) + (f6-15 (-> arg1 data 5)) + (f9-30 (-> arg1 data 6)) + (f4-45 (-> arg1 data 8)) + (f7-30 (-> arg1 data 9)) + (f3-15 (-> arg1 data 10)) + ) + (set! + (-> arg0 data 15) + (/ + (- + (+ + (+ (* (* f8-60 f6-15) f3-15) (* (* f1-98 f9-30) f4-45)) + (* (* f5-30 f2-30) f7-30) + ) + (+ + (+ (* (* f8-60 f9-30) f7-30) (* (* f5-30 f6-15) f4-45)) + (* (* f1-98 f2-30) f3-15) + ) + ) + f0-0 + ) + ) + ) + ) + arg0 + ) + +(defun matrix-y-angle ((arg0 matrix)) + (let ((v1-0 (&-> arg0 data 8))) + (atan (-> v1-0 0) (-> v1-0 2)) + ) + ) + +;; todo (method 9 matrix) diff --git a/goal_src/engine/math/trigonometry-h.gc b/goal_src/engine/math/trigonometry-h.gc index 2c1a3c93a5..c59eb9c933 100644 --- a/goal_src/engine/math/trigonometry-h.gc +++ b/goal_src/engine/math/trigonometry-h.gc @@ -5,4 +5,9 @@ ;; name in dgo: trigonometry-h ;; dgos: GAME, ENGINE -;; this file generates no code. \ No newline at end of file +;; this file generates no code. + +(defun-extern sin float float) +(defun-extern cos float float) +(defun-extern vector-sincos! vector vector vector int) +(defun-extern atan float float float) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 43ceaab5fc..fcd6944b36 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable(goalc-test ${CMAKE_CURRENT_LIST_DIR}/decompiler/test_AtomicOpBuilder.cpp ${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormBeforeExpressions.cpp ${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormExpressionBuild.cpp + ${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormExpressionBuild2.cpp ${CMAKE_CURRENT_LIST_DIR}/decompiler/test_FormExpressionBuildLong.cpp ${CMAKE_CURRENT_LIST_DIR}/decompiler/test_InstructionDecode.cpp ${CMAKE_CURRENT_LIST_DIR}/decompiler/test_InstructionParser.cpp diff --git a/test/decompiler/FormRegressionTest.cpp b/test/decompiler/FormRegressionTest.cpp index af76c0fa45..335f43b478 100644 --- a/test/decompiler/FormRegressionTest.cpp +++ b/test/decompiler/FormRegressionTest.cpp @@ -1,11 +1,13 @@ #include "FormRegressionTest.h" +#include "decompiler/analysis/type_analysis.h" #include "decompiler/analysis/variable_naming.h" #include "decompiler/analysis/reg_usage.h" #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 "decompiler/util/config_parsers.h" #include "common/goos/PrettyPrinter.h" #include "common/util/json_util.h" #include "decompiler/IR2/Form.h" @@ -108,55 +110,78 @@ parse_var_json(const std::string& str) { std::unique_ptr FormRegressionTest::make_function( const std::string& code, const TypeSpec& function_type, - bool do_expressions, - bool allow_pairs, - const std::string& method_name, - const std::vector>& strings, - const std::unordered_map>& casts, - const std::string& var_map_json) { - dts->type_prop_settings.locked = true; + const TestSettings& settings) { + // Set up decompiler type system dts->type_prop_settings.reset(); - dts->type_prop_settings.allow_pair = allow_pairs; - dts->type_prop_settings.current_method_type = method_name; + dts->type_prop_settings.current_method_type = settings.method_name; + // set up label names for string constants std::vector string_label_names; - for (auto& x : strings) { + for (auto& x : settings.strings) { string_label_names.push_back(x.first); } + + // parse the assembly auto program = parser->parse_program(code, string_label_names); - // printf("prg:\n%s\n\n", program.print().c_str()); + + // create the test data collection auto test = std::make_unique(program.instructions.size()); + // populate the LinkedObjectFile test->file.words_by_seg.resize(3); test->file.labels = program.labels; + // Set up the environment test->func.ir2.env.file = &test->file; test->func.ir2.env.dts = dts.get(); + // Set up the function test->func.instructions = program.instructions; test->func.guessed_name.set_as_global("test-function"); test->func.type = function_type; - for (auto& str : strings) { + // set up string constants in the data + for (auto& str : settings.strings) { test->add_string_at_label(str.first, str.second); } + // find basic blocks test->func.basic_blocks = find_blocks_in_function(test->file, 0, test->func); + // analyze function prologue/epilogue test->func.analyze_prologue(test->file); + // build control flow graph test->func.cfg = build_cfg(test->file, 0, test->func); EXPECT_TRUE(test->func.cfg->is_fully_resolved()); if (!test->func.cfg->is_fully_resolved()) { fmt::print("CFG:\n{}\n", test->func.cfg->to_dot()); } + // convert instruction to atomic ops DecompWarnings warnings; auto ops = convert_function_to_atomic_ops(test->func, program.labels, warnings); test->func.ir2.atomic_ops = std::make_shared(std::move(ops)); test->func.ir2.atomic_ops_succeeded = true; test->func.ir2.env.set_end_var(test->func.ir2.atomic_ops->end_op().return_var()); - EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, casts, {})); + // set up type settings + if (!settings.casts_json.empty()) { + test->func.ir2.env.set_type_casts(parse_cast_hints(nlohmann::json::parse(settings.casts_json))); + } + + if (settings.allow_pairs) { + test->func.ir2.env.set_sloppy_pair_typing(); + } + + if (!settings.stack_var_json.empty()) { + auto stack_hints = parse_stack_var_hints(nlohmann::json::parse(settings.stack_var_json)); + test->func.ir2.env.set_stack_var_hints(stack_hints); + } + + // analyze types + EXPECT_TRUE(run_type_analysis_ir2(function_type, *dts, test->func)); test->func.ir2.env.types_succeeded = true; + // analyze registers test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func)); + // split to variables auto result = run_variable_renaming(test->func, test->func.ir2.env.reg_use(), *test->func.ir2.atomic_ops, *dts); if (result.has_value()) { @@ -165,16 +190,18 @@ std::unique_ptr FormRegressionTest::make_function( EXPECT_TRUE(false); } + // structure build_initial_forms(test->func); EXPECT_TRUE(test->func.ir2.top_form); - // for now, just test that this can at least be called. if (test->func.ir2.top_form) { + // just make sure this doesn't crash RegAccessSet vars; test->func.ir2.top_form->collect_vars(vars, true); - if (do_expressions) { - auto config = parse_var_json(var_map_json); + if (settings.do_expressions) { + auto config = parse_var_json(settings.var_map_json); + // build expressions (most of the fancy decompilation happens here) bool success = convert_to_expressions(test->func.ir2.top_form, *test->func.ir2.form_pool, test->func, config.first, config.second, *dts); @@ -182,6 +209,7 @@ std::unique_ptr FormRegressionTest::make_function( if (!success) { return nullptr; } + // move variables into lets. insert_lets(test->func, test->func.ir2.env, *test->func.ir2.form_pool, test->func.ir2.top_form); } @@ -205,15 +233,9 @@ std::unique_ptr FormRegressionTest::make_function( void FormRegressionTest::test(const std::string& code, const std::string& type, const std::string& expected, - bool do_expressions, - bool allow_pairs, - const std::string& method_name, - const std::vector>& strings, - const std::unordered_map>& casts, - const std::string& var_map_json) { + const TestSettings& settings) { auto ts = dts->parse_type_spec(type); - auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings, casts, - var_map_json); + auto test = make_function(code, ts, settings); ASSERT_TRUE(test); auto expected_form = pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car; @@ -237,10 +259,16 @@ void FormRegressionTest::test_final_function( const std::string& expected, bool allow_pairs, const std::vector>& strings, - const std::unordered_map>& casts, + const std::string& cast_json, const std::string& var_map_json) { auto ts = dts->parse_type_spec(type); - auto test = make_function(code, ts, true, allow_pairs, "", strings, casts, var_map_json); + TestSettings settings; + settings.allow_pairs = allow_pairs; + settings.strings = strings; + settings.casts_json = cast_json; + settings.var_map_json = var_map_json; + settings.do_expressions = true; + auto test = make_function(code, ts, settings); ASSERT_TRUE(test); auto expected_form = pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car; @@ -256,23 +284,18 @@ void FormRegressionTest::test_final_function( EXPECT_TRUE(expected_form == actual_form); } -std::unordered_map> FormRegressionTest::parse_cast_json( - const std::string& in) { - std::unordered_map> out; - auto casts = nlohmann::json::parse(in); - - for (auto& cast : casts) { - auto idx_range = parse_json_optional_integer_range(cast.at(0)); - for (auto idx : idx_range) { - TypeCast type_cast; - type_cast.atomic_op_idx = idx; - type_cast.reg = Register(cast.at(1)); - type_cast.type_name = cast.at(2).get(); - out[idx].push_back(type_cast); - } - } - - return out; +void FormRegressionTest::test_with_stack_vars(const std::string& code, + const std::string& type, + const std::string& expected, + const std::string& stack_map_json, + const std::string& cast_json, + const std::string& var_map_json) { + TestSettings settings; + settings.do_expressions = true; + settings.stack_var_json = stack_map_json; + settings.var_map_json = var_map_json; + settings.casts_json = cast_json; + test(code, type, expected, settings); } std::unique_ptr FormRegressionTest::parser; diff --git a/test/decompiler/FormRegressionTest.h b/test/decompiler/FormRegressionTest.h index ba1f4b8d58..dd26f6d2da 100644 --- a/test/decompiler/FormRegressionTest.h +++ b/test/decompiler/FormRegressionTest.h @@ -11,6 +11,16 @@ namespace decompiler { struct TypeCast; } +struct TestSettings { + bool do_expressions = false; + bool allow_pairs = false; + std::string method_name; + std::vector> strings; + std::string casts_json; + std::string var_map_json; + std::string stack_var_json; +}; + class FormRegressionTest : public ::testing::Test { protected: static std::unique_ptr parser; @@ -27,25 +37,22 @@ class FormRegressionTest : public ::testing::Test { void add_string_at_label(const std::string& label_name, const std::string& data); }; - std::unique_ptr make_function( - const std::string& code, - const TypeSpec& function_type, - bool do_expressions, - bool allow_pairs = false, - const std::string& method_name = "", - const std::vector>& strings = {}, - const std::unordered_map>& casts = {}, - const std::string& var_map_json = ""); + std::unique_ptr make_function(const std::string& code, + const TypeSpec& function_type, + const TestSettings& settings); void test(const std::string& code, const std::string& type, const std::string& expected, - bool do_expressions, - bool allow_pairs = false, - const std::string& method_name = "", - const std::vector>& strings = {}, - const std::unordered_map>& casts = {}, - const std::string& var_map_json = ""); + const TestSettings& settings); + + void test_final_function(const std::string& code, + const std::string& type, + const std::string& expected, + bool allow_pairs = false, + const std::vector>& strings = {}, + const std::string& cast_json = "", + const std::string& var_map_json = ""); void test_no_expr(const std::string& code, const std::string& type, @@ -53,9 +60,16 @@ class FormRegressionTest : public ::testing::Test { bool allow_pairs = false, const std::string& method_name = "", const std::vector>& strings = {}, - const std::unordered_map>& casts = {}, + const std::string& cast_json = "", const std::string& var_map_json = "") { - test(code, type, expected, false, allow_pairs, method_name, strings, casts, var_map_json); + TestSettings settings; + settings.allow_pairs = allow_pairs; + settings.method_name = method_name; + settings.strings = strings; + settings.casts_json = cast_json; + settings.var_map_json = var_map_json; + settings.do_expressions = false; + test(code, type, expected, settings); } void test_with_expr(const std::string& code, @@ -64,19 +78,22 @@ class FormRegressionTest : public ::testing::Test { bool allow_pairs = false, const std::string& method_name = "", const std::vector>& strings = {}, - const std::unordered_map>& casts = {}, + const std::string& cast_json = "", const std::string& var_map_json = "") { - test(code, type, expected, true, allow_pairs, method_name, strings, casts, var_map_json); + TestSettings settings; + settings.allow_pairs = allow_pairs; + settings.method_name = method_name; + settings.strings = strings; + settings.casts_json = cast_json; + settings.var_map_json = var_map_json; + settings.do_expressions = true; + test(code, type, expected, settings); } - void test_final_function( - const std::string& code, - const std::string& type, - const std::string& expected, - bool allow_pairs = false, - const std::vector>& strings = {}, - const std::unordered_map>& casts = {}, - const std::string& var_map_json = ""); - - std::unordered_map> parse_cast_json(const std::string& in); + void test_with_stack_vars(const std::string& code, + const std::string& type, + const std::string& expected, + const std::string& stack_map_json, + const std::string& cast_json = "", + const std::string& var_map_json = ""); }; \ No newline at end of file diff --git a/test/decompiler/reference/all_forward_declarations.gc b/test/decompiler/reference/all_forward_declarations.gc index 44e24be2a2..ce715bbfed 100644 --- a/test/decompiler/reference/all_forward_declarations.gc +++ b/test/decompiler/reference/all_forward_declarations.gc @@ -87,4 +87,14 @@ (define-extern fabs (function float float)) (define-extern abs (function int int)) (define-extern rand-vu-init (function float none)) -(define-extern rand-vu (function float)) \ No newline at end of file +(define-extern rand-vu (function float)) + +;; matrix +(declare-type matrix structure) +(declare-type vector structure) +(define-extern matrix-transpose! (function matrix matrix matrix)) +(define-extern sin (function float float)) +(define-extern cos (function float float)) +(define-extern vector-sincos! (function vector vector vector int)) +(define-extern matrix-axis-sin-cos! (function matrix vector float float none)) +(define-extern atan (function float float float)) \ No newline at end of file diff --git a/test/decompiler/reference/bounding-box_REF.gc b/test/decompiler/reference/bounding-box_REF.gc index 2869f436ec..9a068122ab 100644 --- a/test/decompiler/reference/bounding-box_REF.gc +++ b/test/decompiler/reference/bounding-box_REF.gc @@ -45,8 +45,8 @@ (.max.vf vf2 vf4 vf5) (.mov.vf vf1 vf0 :mask #b1000) (.mov.vf vf2 vf0 :mask #b1000) - (.svf obj vf1) - (.svf obj vf2 :offset 16) + (.svf (&-> obj min quad) vf1) + (.svf (&-> obj max quad) vf2) 0 ) ) @@ -57,13 +57,13 @@ (vf2 :class vf) (vf3 :class vf) ) - (.lvf vf1 obj) - (.lvf vf2 obj :offset 16) + (.lvf vf1 (&-> obj min quad)) + (.lvf vf2 (&-> obj max quad)) (.lvf vf3 arg0) (.min.vf vf1 vf1 vf3) (.max.vf vf2 vf2 vf3) - (.svf obj vf1) - (.svf obj vf2 :offset 16) + (.svf (&-> obj min quad) vf1) + (.svf (&-> obj max quad) vf2) 0 ) ) @@ -75,14 +75,14 @@ (vf3 :class vf) (vf4 :class vf) ) - (.lvf vf1 obj) - (.lvf vf2 obj :offset 16) - (.lvf vf3 arg0) - (.lvf vf4 arg0 :offset 16) + (.lvf vf1 (&-> obj min quad)) + (.lvf vf2 (&-> obj max quad)) + (.lvf vf3 (&-> arg0 min quad)) + (.lvf vf4 (&-> arg0 max quad)) (.min.vf vf1 vf1 vf3) (.max.vf vf2 vf2 vf4) - (.svf obj vf1) - (.svf obj vf2 :offset 16) + (.svf (&-> obj min quad) vf1) + (.svf (&-> obj max quad) vf2) 0 ) ) @@ -111,8 +111,8 @@ (.sub.x.vf vf2 vf2 vf1 :mask #b111) (.mov.vf vf2 vf0 :mask #b1000) (.mov.vf vf3 vf0 :mask #b1000) - (.svf obj vf2) - (.svf obj vf3 :offset 16) + (.svf (&-> obj min quad) vf2) + (.svf (&-> obj max quad) vf3) 0 ) ) @@ -125,13 +125,13 @@ (vf3 :class vf) ) (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) - (.lvf vf1 arg0) + (.lvf vf1 (&-> arg0 quad)) (.sub.w.vf vf2 vf1 vf1 :mask #b111) (.add.w.vf vf3 vf1 vf1 :mask #b111) (.mov.vf vf2 vf0 :mask #b1000) (.mov.vf vf3 vf0 :mask #b1000) - (.svf obj vf2) - (.svf obj vf3 :offset 16) + (.svf (&-> obj min quad) vf2) + (.svf (&-> obj max quad) vf3) 0 ) ) diff --git a/test/decompiler/reference/matrix-h_REF.gc b/test/decompiler/reference/matrix-h_REF.gc index b6cda33778..90289dd837 100644 --- a/test/decompiler/reference/matrix-h_REF.gc +++ b/test/decompiler/reference/matrix-h_REF.gc @@ -16,6 +16,7 @@ ) ;; definition for method 3 of type matrix +;; INFO: this function exists in multiple non-identical object files (defmethod inspect matrix ((obj matrix)) (format #t "[~8x] ~A~%" obj 'matrix) (format #t "~Tdata[16] @ #x~X~%" (-> obj data)) @@ -36,6 +37,7 @@ ) ;; definition for method 3 of type matrix3 +;; INFO: this function exists in multiple non-identical object files (defmethod inspect matrix3 ((obj matrix3)) (format #t "[~8x] ~A~%" obj 'matrix3) (format #t "~Tdata[12] @ #x~X~%" (-> obj data)) diff --git a/test/decompiler/reference/matrix_REF.gc b/test/decompiler/reference/matrix_REF.gc new file mode 100644 index 0000000000..5cd93b6574 --- /dev/null +++ b/test/decompiler/reference/matrix_REF.gc @@ -0,0 +1,1741 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for method 3 of type matrix +;; INFO: this function exists in multiple non-identical object files +(defmethod inspect matrix ((obj matrix)) + (format #t "[~8x] matrix~%" obj) + (format + #t + "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 0) + (-> obj data 1) + (-> obj data 2) + (-> obj data 3) + ) + (format + #t + "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 4) + (-> obj data 5) + (-> obj data 6) + (-> obj data 7) + ) + (format + #t + "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 8) + (-> obj data 9) + (-> obj data 10) + (-> obj data 11) + ) + (format + #t + "~T[~F] [~F] [~F] [~F]~%" + (-> obj data 12) + (-> obj data 13) + (-> obj data 14) + (-> obj data 15) + ) + obj + ) + +;; definition for method 3 of type matrix3 +;; INFO: this function exists in multiple non-identical object files +(defmethod inspect matrix3 ((obj matrix3)) + (format #t "[~8x] matrix3~%" obj) + (format + #t + "~T[~F] [~F] [~F]~%" + (-> obj data 0) + (-> obj data 1) + (-> obj data 2) + ) + (format + #t + "~T[~F] [~F] [~F]~%" + (-> obj data 4) + (-> obj data 5) + (-> obj data 6) + ) + (format + #t + "~T[~F] [~F] [~F]~%" + (-> obj data 8) + (-> obj data 9) + (-> obj data 10) + ) + obj + ) + +;; definition for function matrix-identity! +;; Used lq/sq +(defun matrix-identity! ((arg0 matrix)) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (let ((f0-0 1.0)) + (set! (-> arg0 data 15) f0-0) + (set! (-> arg0 data 10) f0-0) + (set! (-> arg0 data 5) f0-0) + (set! (-> arg0 data 0) f0-0) + ) + arg0 + ) + +;; definition for symbol *identity-matrix*, type matrix +(define *identity-matrix* (the-as matrix (new 'global 'matrix))) + +;; failed to figure out what this is: +(matrix-identity! *identity-matrix*) + +;; definition for function matrix+! +(defun matrix+! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + (dotimes (v1-0 16) + (set! (-> arg0 data v1-0) (+ (-> arg1 data v1-0) (-> arg2 data v1-0))) + ) + arg0 + ) + +;; definition for function matrix-! +(defun matrix-! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + (dotimes (v1-0 16) + (set! (-> arg0 data v1-0) (- (-> arg1 data v1-0) (-> arg2 data v1-0))) + ) + arg0 + ) + +;; definition for function matrix*! +(defun matrix*! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + (rlet ((acc :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + (vf14 :class vf) + (vf15 :class vf) + (vf16 :class vf) + (vf17 :class vf) + (vf18 :class vf) + (vf19 :class vf) + (vf20 :class vf) + (vf21 :class vf) + ) + (.lvf vf10 (&-> arg1 vector 0 quad)) + (.lvf vf14 (&-> arg2 vector 0 quad)) + (.lvf vf15 (&-> arg2 vector 1 quad)) + (.lvf vf16 (&-> arg2 vector 2 quad)) + (.lvf vf17 (&-> arg2 vector 3 quad)) + (.lvf vf11 (&-> arg1 vector 1 quad)) + (.lvf vf12 (&-> arg1 vector 2 quad)) + (.lvf vf13 (&-> arg1 vector 3 quad)) + (.mul.x.vf acc vf14 vf10) + (.add.mul.y.vf acc vf15 vf10 acc) + (.add.mul.z.vf acc vf16 vf10 acc) + (.add.mul.w.vf vf18 vf17 vf10 acc) + (.mul.x.vf acc vf14 vf11) + (.add.mul.y.vf acc vf15 vf11 acc) + (.add.mul.z.vf acc vf16 vf11 acc) + (.add.mul.w.vf vf19 vf17 vf11 acc) + (.mul.x.vf acc vf14 vf12) + (.add.mul.y.vf acc vf15 vf12 acc) + (.add.mul.z.vf acc vf16 vf12 acc) + (.add.mul.w.vf vf20 vf17 vf12 acc) + (.mul.x.vf acc vf14 vf13) + (.add.mul.y.vf acc vf15 vf13 acc) + (.add.mul.z.vf acc vf16 vf13 acc) + (.add.mul.w.vf vf21 vf17 vf13 acc) + (.svf (&-> arg0 vector 0 quad) vf18) + (.svf (&-> arg0 vector 1 quad) vf19) + (.svf (&-> arg0 vector 2 quad) vf20) + (.svf (&-> arg0 vector 3 quad) vf21) + arg0 + ) + ) + +;; definition for function matrixp*! +;; Used lq/sq +(defun matrixp*! ((arg0 matrix) (arg1 matrix) (arg2 matrix)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix*! s5-0 arg1 arg2) + (set! (-> arg0 vector 0 quad) (-> s5-0 vector 0 quad)) + (set! (-> arg0 vector 1 quad) (-> s5-0 vector 1 quad)) + (set! (-> arg0 vector 2 quad) (-> s5-0 vector 2 quad)) + (set! (-> arg0 vector 3 quad) (-> s5-0 vector 3 quad)) + ) + arg0 + ) + +;; definition for function vector-matrix*! +(defun vector-matrix*! ((arg0 vector) (arg1 vector) (arg2 matrix)) + (rlet ((acc :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (.lvf vf1 (&-> arg2 vector 0 quad)) + (.lvf vf2 (&-> arg2 vector 1 quad)) + (.lvf vf3 (&-> arg2 vector 2 quad)) + (.lvf vf4 (&-> arg2 vector 3 quad)) + (.lvf vf5 (&-> arg1 quad)) + (.mul.x.vf acc vf1 vf5) + (.add.mul.y.vf acc vf2 vf5 acc) + (.add.mul.z.vf acc vf3 vf5 acc) + (.add.mul.w.vf vf5 vf4 vf5 acc) + (.svf (&-> arg0 quad) vf5) + arg0 + ) + ) + +;; definition for function vector-rotate*! +(defun vector-rotate*! ((arg0 vector) (arg1 vector) (arg2 matrix)) + (rlet ((acc :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (nop!) + (nop!) + (.lvf vf5 (&-> arg1 quad)) + (nop!) + (.lvf vf1 (&-> arg2 vector 0 quad)) + (nop!) + (.lvf vf2 (&-> arg2 vector 1 quad)) + (.mul.x.vf acc vf1 vf5) + (.lvf vf3 (&-> arg2 vector 2 quad)) + (.add.mul.y.vf acc vf2 vf5 acc) + (.lvf vf4 (&-> arg2 vector 3 quad)) + (.add.mul.z.vf vf5 vf3 vf5 acc) + (nop!) + (nop!) + (.svf (&-> arg0 quad) vf5) + arg0 + ) + ) + +;; definition for function vector3s-matrix*! +;; Used lq/sq +(defun vector3s-matrix*! ((arg0 vector3s) (arg1 vector3s) (arg2 matrix)) + (let ((s5-0 (new 'stack 'vector))) + (set! (-> s5-0 quad) (the-as uint128 0)) + (let ((v1-0 s5-0)) + (set! (-> v1-0 data 0) (-> arg1 data 0)) + (set! (-> v1-0 data 1) (-> arg1 data 1)) + (set! (-> v1-0 data 2) (-> arg1 data 2)) + (set! (-> v1-0 data 3) 1.0) + ) + (vector-matrix*! s5-0 s5-0 arg2) + (set! (-> arg0 data 0) (-> s5-0 data 0)) + (set! (-> arg0 data 1) (-> s5-0 data 1)) + (set! (-> arg0 data 2) (-> s5-0 data 2)) + ) + (let ((v1-1 arg0)) + ) + arg0 + ) + +;; definition for function vector3s-rotate*! +;; Used lq/sq +(defun vector3s-rotate*! ((arg0 vector3s) (arg1 vector3s) (arg2 matrix)) + (let ((s5-0 (new 'stack 'vector))) + (set! (-> s5-0 quad) (the-as uint128 0)) + (let ((v1-0 s5-0)) + (set! (-> v1-0 data 0) (-> arg1 data 0)) + (set! (-> v1-0 data 1) (-> arg1 data 1)) + (set! (-> v1-0 data 2) (-> arg1 data 2)) + (set! (-> v1-0 data 3) 1.0) + ) + (vector-rotate*! s5-0 s5-0 arg2) + (set! (-> arg0 data 0) (-> s5-0 data 0)) + (set! (-> arg0 data 1) (-> s5-0 data 1)) + (set! (-> arg0 data 2) (-> s5-0 data 2)) + ) + (let ((v1-1 arg0)) + ) + arg0 + ) + +;; definition for function matrix-transpose! +;; WARN: Unsupported inline assembly instruction kind - [105] +;; WARN: Unsupported inline assembly instruction kind - [118] +;; WARN: Unsupported inline assembly instruction kind - [105] +;; WARN: Unsupported inline assembly instruction kind - [118] +;; WARN: Unsupported inline assembly instruction kind - [125] +;; WARN: Unsupported inline assembly instruction kind - [132] +;; WARN: Unsupported inline assembly instruction kind - [125] +;; WARN: Unsupported inline assembly instruction kind - [132] +;; Used lq/sq +(defun matrix-transpose! ((arg0 matrix) (arg1 matrix)) + (local-vars + (r0-0 int) + (r0-1 int) + (r0-2 int) + (r0-3 int) + (v1-0 int) + (v1-1 int) + (v1-2 int) + (a1-1 int) + (a2-1 int) + (a3-1 int) + (a3-2 int) + (t0-1 int) + (f31-0 none) + ) + (nop!) + (nop!) + (let ((t0-0 (-> arg1 vector 0 quad))) + (nop!) + (let ((t1-0 (-> arg1 vector 1 quad))) + (nop!) + (let ((a2-0 (-> arg1 vector 2 quad))) + (.pextlw v1-0 t1-0 t0-0) + (let ((a3-0 (-> arg1 vector 3 quad))) + (.pextuw a1-1 t1-0 t0-0) + (.mov r0-0 f31-0) + (.pextlw t0-1 a3-0 a2-0) + (.mov r0-1 f31-0) + (.pextuw a2-1 a3-0 a2-0) + ) + ) + ) + ) + (.mov r0-2 f31-0) + (.pcpyld a3-1 t0-1 v1-0) + (.mov r0-3 f31-0) + (.pcpyud v1-1 v1-0 t0-1) + (set! (-> arg0 vector 0 quad) (the-as uint128 a3-1)) + (.pcpyld a3-2 a2-1 a1-1) + (set! (-> arg0 vector 1 quad) (the-as uint128 v1-1)) + (.pcpyud v1-2 a1-1 a2-1) + (set! (-> arg0 vector 2 quad) (the-as uint128 a3-2)) + (nop!) + (set! (-> arg0 vector 3 quad) (the-as uint128 v1-2)) + arg0 + ) + +;; definition for function matrix-inverse-of-rot-trans! +(defun matrix-inverse-of-rot-trans! ((arg0 matrix) (arg1 matrix)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf8 :class vf) + ) + (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) + (matrix-transpose! arg0 arg1) + (.lvf vf1 (&-> arg0 vector 0 quad)) + (.lvf vf2 (&-> arg0 vector 1 quad)) + (.lvf vf3 (&-> arg0 vector 2 quad)) + (.sub.vf vf1 vf1 vf1 :mask #b1000) + (.sub.vf vf2 vf2 vf2 :mask #b1000) + (.sub.vf vf3 vf3 vf3 :mask #b1000) + (.lvf vf8 (&-> arg1 vector 3 quad)) + (.mul.x.vf acc vf1 vf8) + (.add.mul.y.vf acc vf2 vf8 acc) + (.add.mul.z.vf vf4 vf3 vf8 acc) + (.sub.vf vf4 vf0 vf4) + (.mov.vf vf4 vf0 :mask #b1000) + (.svf (&-> arg0 vector 0 quad) vf1) + (.svf (&-> arg0 vector 1 quad) vf2) + (.svf (&-> arg0 vector 2 quad) vf3) + (.svf (&-> arg0 vector 3 quad) vf4) + arg0 + ) + ) + +;; definition for function matrix-4x4-inverse! +;; WARN: Bad vector register dependency: vf3 +;; WARN: Bad vector register dependency: vf4 +;; WARN: Bad vector register dependency: vf5 +(defun matrix-4x4-inverse! ((arg0 matrix) (arg1 matrix)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + (vf14 :class vf) + (vf15 :class vf) + (vf16 :class vf) + (vf17 :class vf) + (vf18 :class vf) + (vf19 :class vf) + (vf2 :class vf) + (vf20 :class vf) + (vf23 :class vf) + (vf24 :class vf) + (vf25 :class vf) + (vf26 :class vf) + (vf27 :class vf) + (vf28 :class vf) + (vf29 :class vf) + (vf3 :class vf) + (vf30 :class vf) + (vf31 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + (vf9 :class vf) + ) + (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) + (nop!) + (nop!) + (.lvf vf23 (&-> arg1 vector 0 quad)) + (nop!) + (.lvf vf24 (&-> arg1 vector 1 quad)) + (nop!) + (.lvf vf25 (&-> arg1 vector 2 quad)) + (nop!) + (.lvf vf1 (&-> arg1 vector 3 quad)) + (.mul.x.vf vf7 vf24 vf23) + (nop!) + (.mul.y.vf vf8 vf24 vf23) + (nop!) + (.mul.z.vf vf9 vf24 vf23) + (nop!) + (.mul.x.vf vf10 vf25 vf23) + (nop!) + (.mul.y.vf vf11 vf25 vf23) + (nop!) + (.mul.z.vf vf12 vf25 vf23) + (nop!) + (.mul.x.vf vf13 vf25 vf24) + (nop!) + (.mul.y.vf vf14 vf25 vf24) + (nop!) + (.mul.z.vf vf15 vf25 vf24) + (nop!) + (.mul.z.vf vf26 vf7 vf25 :mask #b10) + (nop!) + (.mul.z.vf vf27 vf11 vf24 :mask #b1) + (nop!) + (.mul.y.vf vf28 vf9 vf25 :mask #b1) + (nop!) + (.mul.z.vf vf29 vf14 vf23 :mask #b1) + (nop!) + (.mul.z.vf vf30 vf8 vf25 :mask #b1) + (nop!) + (.mul.y.vf vf31 vf7 vf25 :mask #b100) + (nop!) + (.add.y.vf vf16 vf27 vf26 :mask #b1) + (nop!) + (.sub.vf vf1 vf0 vf1) + (nop!) + (.add.x.vf vf17 vf29 vf30 :mask #b1) + (nop!) + (.sub.z.vf vf18 vf28 vf31 :mask #b1) + (nop!) + (.sub.y.vf vf23 vf14 vf15 :mask #b100) + (nop!) + (.sub.z.vf vf26 vf15 vf13 :mask #b1) + (nop!) + (.sub.x.vf vf29 vf13 vf14 :mask #b10) + (nop!) + (.sub.vf vf19 vf16 vf17 :mask #b1) + (nop!) + (.sub.z.vf vf24 vf12 vf11 :mask #b10) + (nop!) + (.sub.x.vf vf27 vf10 vf12 :mask #b100) + (nop!) + (.sub.y.vf vf30 vf11 vf10 :mask #b1) + (nop!) + (.add.vf vf20 vf19 vf18 :mask #b1) + (nop!) + (.sub.y.vf vf25 vf8 vf9 :mask #b100) + (nop!) + (.sub.z.vf vf28 vf9 vf7 :mask #b1) + (nop!) + (.sub.x.vf vf31 vf7 vf8 :mask #b10) + (nop!) + (.div.vf Q vf0 vf20 :ftf #b11 :fsf #b0) + (nop!) + (.sub.w.vf vf3 vf3 vf3 :mask #b1000) + (nop!) + (.sub.w.vf vf4 vf4 vf4 :mask #b1000) + (nop!) + (.sub.w.vf vf5 vf5 vf5 :mask #b1000) + (nop!) + (.mov.vf vf6 vf0 :mask #b1000) + (nop!) + (.wait.vf) + (nop!) + (.add.vf vf2 vf0 Q :mask #b1) + (nop!) + (.add.x.vf vf2 vf0 vf2 :mask #b111) + (nop!) + (.mul.z.vf vf3 vf2 vf23 :mask #b1) + (nop!) + (.mul.x.vf vf4 vf2 vf26 :mask #b1) + (nop!) + (.mul.y.vf vf5 vf2 vf29 :mask #b1) + (nop!) + (.mul.y.vf vf3 vf2 vf24 :mask #b10) + (nop!) + (.mul.z.vf vf4 vf2 vf27 :mask #b10) + (nop!) + (.mul.x.vf vf5 vf2 vf30 :mask #b10) + (nop!) + (.mul.z.vf vf3 vf2 vf25 :mask #b100) + (nop!) + (.mul.x.vf vf4 vf2 vf28 :mask #b100) + (nop!) + (.mul.y.vf vf5 vf2 vf31 :mask #b100) + (nop!) + (.mul.x.vf acc vf3 vf1) + (.svf (&-> arg0 vector 0 quad) vf3) + (.add.mul.y.vf acc vf4 vf1 acc) + (.svf (&-> arg0 vector 1 quad) vf4) + (.add.mul.z.vf vf6 vf5 vf1 acc :mask #b111) + (.svf (&-> arg0 vector 2 quad) vf5) + (nop!) + (.svf (&-> arg0 vector 3 quad) vf6) + arg0 + ) + ) + +;; definition for function matrix-translate! +(defun matrix-translate! ((arg0 matrix) (arg1 vector)) + (matrix-identity! arg0) + (set! (-> arg0 data 12) (-> arg1 data 0)) + (set! (-> arg0 data 13) (-> arg1 data 1)) + (set! (-> arg0 data 14) (-> arg1 data 2)) + arg0 + ) + +;; definition for function matrix-translate+! +;; Used lq/sq +(defun matrix-translate+! ((arg0 matrix) (arg1 matrix) (arg2 vector)) + (set! (-> arg0 data 12) (+ (-> arg1 data 12) (-> arg2 data 0))) + (set! (-> arg0 data 13) (+ (-> arg1 data 13) (-> arg2 data 1))) + (set! (-> arg0 data 14) (+ (-> arg1 data 14) (-> arg2 data 2))) + (when (!= arg0 arg1) + (set! (-> arg0 vector 0 quad) (-> arg1 vector 0 quad)) + (set! (-> arg0 vector 1 quad) (-> arg1 vector 1 quad)) + (set! (-> arg0 vector 2 quad) (-> arg1 vector 2 quad)) + ) + arg0 + ) + +;; definition for function matrix-scale! +;; Used lq/sq +(defun matrix-scale! ((arg0 matrix) (arg1 vector)) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) (-> arg1 data 0)) + (set! (-> arg0 data 5) (-> arg1 data 1)) + (set! (-> arg0 data 10) (-> arg1 data 2)) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +;; definition for function scale-matrix! +(defun scale-matrix! ((arg0 matrix) (arg1 vector) (arg2 matrix)) + (rlet ((vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + ) + (.lvf vf4 (&-> arg1 quad)) + (.lvf vf5 (&-> arg2 vector 0 quad)) + (.lvf vf6 (&-> arg2 vector 1 quad)) + (.lvf vf7 (&-> arg2 vector 2 quad)) + (.lvf vf8 (&-> arg2 vector 3 quad)) + (.mul.x.vf vf5 vf5 vf4) + (.mul.y.vf vf6 vf6 vf4) + (.mul.z.vf vf7 vf7 vf4) + (.mul.w.vf vf8 vf8 vf4) + (.svf (&-> arg0 vector 0 quad) vf5) + (.svf (&-> arg0 vector 1 quad) vf6) + (.svf (&-> arg0 vector 2 quad) vf7) + (.svf (&-> arg0 vector 3 quad) vf8) + arg0 + ) + ) + +;; definition for function matrix-inv-scale! +;; Used lq/sq +(defun matrix-inv-scale! ((arg0 matrix) (arg1 vector)) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) (/ 1.0 (-> arg1 data 0))) + (set! (-> arg0 data 5) (/ 1.0 (-> arg1 data 1))) + (set! (-> arg0 data 10) (/ 1.0 (-> arg1 data 2))) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +;; definition for function column-scale-matrix! +(defun column-scale-matrix! ((arg0 matrix) (arg1 vector) (arg2 matrix)) + (rlet ((vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + ) + (.lvf vf4 (&-> arg1 quad)) + (.lvf vf5 (&-> arg2 vector 0 quad)) + (.lvf vf6 (&-> arg2 vector 1 quad)) + (.lvf vf7 (&-> arg2 vector 2 quad)) + (.lvf vf8 (&-> arg2 vector 3 quad)) + (.mul.vf vf5 vf5 vf4) + (.mul.vf vf6 vf6 vf4) + (.mul.vf vf7 vf7 vf4) + (.mul.vf vf8 vf8 vf4) + (.svf (&-> arg0 vector 0 quad) vf5) + (.svf (&-> arg0 vector 1 quad) vf6) + (.svf (&-> arg0 vector 2 quad) vf7) + (.svf (&-> arg0 vector 3 quad) vf8) + arg0 + ) + ) + +;; definition for function matrix-rotate-x! +;; Used lq/sq +(defun matrix-rotate-x! ((arg0 matrix) (arg1 float)) + (let ((f30-0 (sin arg1)) + (f0-0 (cos arg1)) + ) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) 1.0) + (set! (-> arg0 data 5) f0-0) + (set! (-> arg0 data 6) f30-0) + (set! (-> arg0 data 9) (- f30-0)) + (set! (-> arg0 data 10) f0-0) + ) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +;; definition for function matrix-rotate-y! +;; Used lq/sq +(defun matrix-rotate-y! ((arg0 matrix) (arg1 float)) + (let ((f30-0 (sin arg1)) + (f0-0 (cos arg1)) + ) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) f0-0) + (set! (-> arg0 data 2) (- f30-0)) + (set! (-> arg0 data 5) 1.0) + (set! (-> arg0 data 8) f30-0) + (set! (-> arg0 data 10) f0-0) + ) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +;; definition for function matrix-rotate-z! +;; Used lq/sq +(defun matrix-rotate-z! ((arg0 matrix) (arg1 float)) + (let ((f30-0 (sin arg1)) + (f0-0 (cos arg1)) + ) + (set! (-> arg0 vector 0 quad) (the-as uint128 0)) + (set! (-> arg0 vector 1 quad) (the-as uint128 0)) + (set! (-> arg0 vector 2 quad) (the-as uint128 0)) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 data 0) f0-0) + (set! (-> arg0 data 1) f30-0) + (set! (-> arg0 data 4) (- f30-0)) + (set! (-> arg0 data 5) f0-0) + ) + (set! (-> arg0 data 10) 1.0) + (set! (-> arg0 data 15) 1.0) + arg0 + ) + +;; definition for function matrix-rotate-zyx! +;; Used lq/sq +(defun matrix-rotate-zyx! ((arg0 matrix) (arg1 vector)) + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-x! arg0 (-> arg1 data 0)) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-z! gp-0 (-> arg1 data 2)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +;; definition for function matrix-rotate-xyz! +;; Used lq/sq +(defun matrix-rotate-xyz! ((arg0 matrix) (arg1 vector)) + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-z! arg0 (-> arg1 data 2)) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-x! gp-0 (-> arg1 data 0)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +;; definition for function matrix-rotate-zxy! +;; Used lq/sq +(defun matrix-rotate-zxy! ((arg0 matrix) (arg1 vector)) + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-y! arg0 (-> arg1 data 1)) + (matrix-rotate-x! gp-0 (-> arg1 data 0)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-z! gp-0 (-> arg1 data 2)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +;; definition for function matrix-rotate-yxz! +;; Used lq/sq +(defun matrix-rotate-yxz! ((arg0 matrix) (arg1 vector)) + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-z! arg0 (-> arg1 data 2)) + (matrix-rotate-x! gp-0 (-> arg1 data 0)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +;; definition for function matrix-rotate-yzx! +;; Used lq/sq +(defun matrix-rotate-yzx! ((arg0 matrix) (arg1 vector)) + (let ((gp-0 (new 'stack 'matrix))) + (set! (-> gp-0 vector 0 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 1 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 2 quad) (the-as uint128 0)) + (set! (-> gp-0 vector 3 quad) (the-as uint128 0)) + (let ((s5-0 (new 'stack 'matrix))) + (set! (-> s5-0 vector 0 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 1 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 2 quad) (the-as uint128 0)) + (set! (-> s5-0 vector 3 quad) (the-as uint128 0)) + (matrix-rotate-z! arg0 (-> arg1 data 0)) + (matrix-rotate-x! gp-0 (-> arg1 data 2)) + (matrix*! s5-0 gp-0 arg0) + (matrix-rotate-y! gp-0 (-> arg1 data 1)) + (matrix*! arg0 gp-0 s5-0) + ) + ) + arg0 + ) + +;; definition for function matrix-rotate-yxy! +(defun matrix-rotate-yxy! ((arg0 matrix) (arg1 vector)) + (let ((a2-0 (new 'stack 'vector)) + (s5-0 (new 'stack 'vector)) + (s4-0 (new 'stack 'vector)) + ) + (let ((v1-0 a2-0)) + (set! (-> v1-0 data 0) (-> arg1 data 0)) + (set! (-> v1-0 data 1) (- (-> arg1 data 1) (-> arg1 data 2))) + (set! (-> v1-0 data 2) (-> arg1 data 2)) + (set! (-> v1-0 data 3) 1.0) + ) + (vector-sincos! s5-0 s4-0 a2-0) + (let ((f1-1 (-> s4-0 data 1)) + (f0-5 (-> s5-0 data 1)) + (f2-0 (-> s4-0 data 0)) + (f5-0 (-> s5-0 data 0)) + (f3-0 (-> s4-0 data 2)) + (f4-0 (-> s5-0 data 2)) + ) + (set! (-> arg0 data 0) (- (* f1-1 f3-0) (* (* f0-5 f2-0) f4-0))) + (set! (-> arg0 data 1) (* f0-5 f5-0)) + (set! (-> arg0 data 2) (- (+ (* f1-1 f4-0) (* (* f0-5 f2-0) f3-0)))) + (set! (-> arg0 data 3) 0.0) + (set! (-> arg0 data 4) (* f5-0 f4-0)) + (set! (-> arg0 data 5) f2-0) + (set! (-> arg0 data 6) (* f5-0 f3-0)) + (set! (-> arg0 data 7) 0.0) + (set! (-> arg0 data 8) (+ (* f0-5 f3-0) (* (* f1-1 f2-0) f4-0))) + (set! (-> arg0 data 9) (- (* f1-1 f5-0))) + (set! (-> arg0 data 10) (- (* (* f1-1 f2-0) f3-0) (* f0-5 f4-0))) + ) + ) + (set! (-> arg0 data 11) 0.0) + (set! (-> arg0 data 12) 0.0) + (set! (-> arg0 data 13) 0.0) + (set! (-> arg0 data 14) 0.0) + (let ((f0-12 1.0)) + (set! (-> arg0 data 15) f0-12) + (let ((v1-1 f0-12)) + ) + ) + arg0 + ) + +;; definition for function matrix-rotate-yx! +;; Used lq/sq +(defun matrix-rotate-yx! ((arg0 matrix) (arg1 float) (arg2 float)) + (matrix-rotate-y! arg0 arg1) + (let ((t9-1 matrix-rotate-x!) + (a0-2 (new 'stack 'matrix)) + ) + (set! (-> a0-2 vector 0 quad) (the-as uint128 0)) + (set! (-> a0-2 vector 1 quad) (the-as uint128 0)) + (set! (-> a0-2 vector 2 quad) (the-as uint128 0)) + (set! (-> a0-2 vector 3 quad) (the-as uint128 0)) + (let ((a1-2 (t9-1 a0-2 arg2))) + (matrix*! arg0 a1-2 arg0) + ) + ) + arg0 + ) + +;; definition for function matrix-axis-sin-cos-vu! +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function matrix-axis-sin-cos! +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function matrix-axis-angle! +(defun matrix-axis-angle! ((arg0 matrix) (arg1 vector) (arg2 float)) + (matrix-axis-sin-cos! arg0 arg1 (sin arg2) (cos arg2)) + (none) + ) + +;; definition for function matrix-lerp! +(defun matrix-lerp! ((arg0 matrix) (arg1 matrix) (arg2 matrix) (arg3 float)) + (rlet ((vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + (vf9 :class vf) + ) + (.mov vf9 arg3) + (.lvf vf1 (&-> arg1 vector 0 quad)) + (.lvf vf2 (&-> arg1 vector 1 quad)) + (.lvf vf3 (&-> arg1 vector 2 quad)) + (.lvf vf4 (&-> arg1 vector 3 quad)) + (.lvf vf5 (&-> arg2 vector 0 quad)) + (.lvf vf6 (&-> arg2 vector 1 quad)) + (.lvf vf7 (&-> arg2 vector 2 quad)) + (.lvf vf8 (&-> arg2 vector 3 quad)) + (.sub.vf vf5 vf5 vf1) + (.sub.vf vf6 vf6 vf2) + (.sub.vf vf7 vf7 vf3) + (.sub.vf vf8 vf8 vf4) + (.mul.x.vf vf5 vf5 vf9) + (.mul.x.vf vf6 vf6 vf9) + (.mul.x.vf vf7 vf7 vf9) + (.mul.x.vf vf8 vf8 vf9) + (.add.vf vf1 vf1 vf5) + (.add.vf vf2 vf2 vf6) + (.add.vf vf3 vf3 vf7) + (.add.vf vf4 vf4 vf8) + (.svf (&-> arg0 vector 0 quad) vf1) + (.svf (&-> arg0 vector 1 quad) vf2) + (.svf (&-> arg0 vector 2 quad) vf3) + (.svf (&-> arg0 vector 3 quad) vf4) + arg0 + ) + ) + +;; definition for function matrix-3x3-determinant +(defun matrix-3x3-determinant ((arg0 matrix)) + (let ((f8-0 (-> arg0 data 0)) + (f1-0 (-> arg0 data 1)) + (f4-0 (-> arg0 data 2)) + (f2-0 (-> arg0 data 4)) + (f5-0 (-> arg0 data 5)) + (f9-0 (-> arg0 data 6)) + (f3-0 (-> arg0 data 8)) + (f6-0 (-> arg0 data 9)) + (f0-0 (-> arg0 data 10)) + ) + (- + (+ (+ (* (* f8-0 f5-0) f0-0) (* (* f1-0 f9-0) f3-0)) (* (* f4-0 f2-0) f6-0)) + (+ (+ (* (* f8-0 f9-0) f6-0) (* (* f4-0 f5-0) f3-0)) (* (* f1-0 f2-0) f0-0)) + ) + ) + ) + +;; definition for function matrix3-determinant +;; INFO: Return type mismatch int vs float. +(defun matrix3-determinant ((arg0 matrix)) + (local-vars (v0-0 int)) + (rlet ((acc :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + ) + (.lvf vf11 (&-> arg0 vector 1 quad)) + (.lvf vf12 (&-> arg0 vector 2 quad)) + (.lvf vf10 (&-> arg0 vector 0 quad)) + (.outer.product.vf vf13 vf11 vf12) + (.mul.vf vf13 vf13 vf10 :mask #b111) + (.add.y.vf vf13 vf13 vf13 :mask #b1) + (.add.z.vf vf13 vf13 vf13 :mask #b1) + (.mov v0-0 vf13) + (the-as float v0-0) + ) + ) + +;; definition for function matrix-3x3-inverse! +(defun matrix-3x3-inverse! ((arg0 matrix) (arg1 matrix)) + (let ((f0-0 (matrix-3x3-determinant arg1))) + (set! + (-> arg0 data 0) + (/ + (- + (* (-> arg1 data 5) (-> arg1 data 10)) + (* (-> arg1 data 6) (-> arg1 data 9)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 4) + (/ + (- + (* (-> arg1 data 6) (-> arg1 data 8)) + (* (-> arg1 data 4) (-> arg1 data 10)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 8) + (/ + (- + (* (-> arg1 data 4) (-> arg1 data 9)) + (* (-> arg1 data 5) (-> arg1 data 8)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 1) + (/ + (- + (* (-> arg1 data 9) (-> arg1 data 2)) + (* (-> arg1 data 10) (-> arg1 data 1)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 5) + (/ + (- + (* (-> arg1 data 10) (-> arg1 data 0)) + (* (-> arg1 data 8) (-> arg1 data 2)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 9) + (/ + (- + (* (-> arg1 data 8) (-> arg1 data 1)) + (* (-> arg1 data 9) (-> arg1 data 0)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 2) + (/ + (- + (* (-> arg1 data 1) (-> arg1 data 6)) + (* (-> arg1 data 2) (-> arg1 data 5)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 6) + (/ + (- + (* (-> arg1 data 2) (-> arg1 data 4)) + (* (-> arg1 data 0) (-> arg1 data 6)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 10) + (/ + (- + (* (-> arg1 data 0) (-> arg1 data 5)) + (* (-> arg1 data 1) (-> arg1 data 4)) + ) + f0-0 + ) + ) + ) + arg0 + ) + +;; definition for function matrix-3x3-inverse-transpose! +(defun matrix-3x3-inverse-transpose! ((arg0 matrix) (arg1 matrix)) + (let ((f0-0 (matrix-3x3-determinant arg1))) + (set! + (-> arg0 data 0) + (/ + (- + (* (-> arg1 data 5) (-> arg1 data 10)) + (* (-> arg1 data 6) (-> arg1 data 9)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 1) + (/ + (- + (* (-> arg1 data 6) (-> arg1 data 8)) + (* (-> arg1 data 4) (-> arg1 data 10)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 2) + (/ + (- + (* (-> arg1 data 4) (-> arg1 data 9)) + (* (-> arg1 data 5) (-> arg1 data 8)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 4) + (/ + (- + (* (-> arg1 data 9) (-> arg1 data 2)) + (* (-> arg1 data 10) (-> arg1 data 1)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 5) + (/ + (- + (* (-> arg1 data 10) (-> arg1 data 0)) + (* (-> arg1 data 8) (-> arg1 data 2)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 6) + (/ + (- + (* (-> arg1 data 8) (-> arg1 data 1)) + (* (-> arg1 data 9) (-> arg1 data 0)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 8) + (/ + (- + (* (-> arg1 data 1) (-> arg1 data 6)) + (* (-> arg1 data 2) (-> arg1 data 5)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 9) + (/ + (- + (* (-> arg1 data 2) (-> arg1 data 4)) + (* (-> arg1 data 0) (-> arg1 data 6)) + ) + f0-0 + ) + ) + (set! + (-> arg0 data 10) + (/ + (- + (* (-> arg1 data 0) (-> arg1 data 5)) + (* (-> arg1 data 1) (-> arg1 data 4)) + ) + f0-0 + ) + ) + ) + arg0 + ) + +;; definition for function matrix3-inverse-transpose! +(defun matrix3-inverse-transpose! ((arg0 matrix) (arg1 matrix)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf10 :class vf) + (vf11 :class vf) + (vf12 :class vf) + (vf13 :class vf) + (vf14 :class vf) + (vf15 :class vf) + ) + (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) + (.lvf vf10 (&-> arg1 vector 0 quad)) + (.lvf vf11 (&-> arg1 vector 1 quad)) + (.lvf vf12 (&-> arg1 vector 2 quad)) + (.outer.product.vf vf13 vf11 vf12) + (.outer.product.vf vf14 vf12 vf10) + (.mul.vf vf1 vf10 vf13 :mask #b111) + (.outer.product.vf vf15 vf10 vf11) + (.nop.vf) + (.add.y.vf vf1 vf1 vf1 :mask #b1) + (.nop.vf) + (.nop.vf) + (.nop.vf) + (.add.z.vf vf1 vf1 vf1 :mask #b1) + (.nop.vf) + (.nop.vf) + (.nop.vf) + (.div.vf Q vf0 vf1 :ftf #b11 :fsf #b0) + (.wait.vf) + (.mul.vf vf13 vf13 Q) + (.mul.vf vf14 vf14 Q) + (.mul.vf vf15 vf15 Q) + (.nop.vf) + (.nop.vf) + (.svf (&-> arg0 vector 0 quad) vf13) + (.svf (&-> arg0 vector 1 quad) vf14) + (.svf (&-> arg0 vector 2 quad) vf15) + arg0 + ) + ) + +;; definition for function matrix-4x4-determinant +(defun matrix-4x4-determinant ((arg0 matrix)) + (let ((f15-0 (-> arg0 data 0)) + (f14-0 (-> arg0 data 1)) + (f10-0 (-> arg0 data 2)) + (f2-0 (-> arg0 data 3)) + (f9-0 (-> arg0 data 4)) + (f6-0 (-> arg0 data 5)) + (f3-0 (-> arg0 data 6)) + (f11-0 (-> arg0 data 7)) + (f5-0 (-> arg0 data 8)) + (f1-0 (-> arg0 data 9)) + (f8-0 (-> arg0 data 10)) + (f13-0 (-> arg0 data 11)) + (f0-0 (-> arg0 data 12)) + (f7-0 (-> arg0 data 13)) + (f4-0 (-> arg0 data 14)) + (f12-0 (-> arg0 data 15)) + ) + (- + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (* (* (* f15-0 f6-0) f8-0) f12-0) + (* (* (* f15-0 f3-0) f13-0) f7-0) + ) + (* (* (* f15-0 f11-0) f1-0) f4-0) + ) + (* (* (* f14-0 f9-0) f13-0) f4-0) + ) + (* (* (* f14-0 f3-0) f5-0) f4-0) + ) + (* (* (* f14-0 f11-0) f8-0) f0-0) + ) + (* (* (* f10-0 f9-0) f1-0) f12-0) + ) + (* (* (* f10-0 f6-0) f13-0) f0-0) + ) + (* (* (* f10-0 f11-0) f5-0) f7-0) + ) + (* (* (* f2-0 f9-0) f1-0) f4-0) + ) + (* (* (* f2-0 f6-0) f8-0) f0-0) + ) + (* (* (* f2-0 f3-0) f5-0) f7-0) + ) + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (+ + (* (* (* f15-0 f6-0) f13-0) f4-0) + (* (* (* f15-0 f3-0) f1-0) f12-0) + ) + (* (* (* f15-0 f11-0) f8-0) f7-0) + ) + (* (* (* f14-0 f9-0) f8-0) f12-0) + ) + (* (* (* f14-0 f3-0) f13-0) f0-0) + ) + (* (* (* f14-0 f11-0) f5-0) f4-0) + ) + (* (* (* f10-0 f9-0) f13-0) f7-0) + ) + (* (* (* f10-0 f6-0) f5-0) f12-0) + ) + (* (* (* f10-0 f11-0) f1-0) f0-0) + ) + (* (* (* f2-0 f9-0) f8-0) f7-0) + ) + (* (* (* f2-0 f6-0) f5-0) f4-0) + ) + (* (* (* f2-0 f3-0) f1-0) f0-0) + ) + ) + ) + ) + +;; definition for function matrix-4x4-inverse-transpose! +(defun matrix-4x4-inverse-transpose! ((arg0 matrix) (arg1 matrix)) + (let ((f0-0 (matrix-4x4-determinant arg1))) + (let ((f9-0 (-> arg1 data 5)) + (f2-0 (-> arg1 data 6)) + (f5-0 (-> arg1 data 7)) + (f3-0 (-> arg1 data 9)) + (f6-0 (-> arg1 data 10)) + (f10-0 (-> arg1 data 11)) + (f4-0 (-> arg1 data 13)) + (f7-0 (-> arg1 data 14)) + (f1-0 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 0) + (/ + (- + (+ + (+ (* (* f9-0 f6-0) f1-0) (* (* f2-0 f10-0) f4-0)) + (* (* f5-0 f3-0) f7-0) + ) + (+ + (+ (* (* f9-0 f10-0) f7-0) (* (* f5-0 f6-0) f4-0)) + (* (* f2-0 f3-0) f1-0) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-2 (-> arg1 data 4)) + (f2-2 (-> arg1 data 6)) + (f5-2 (-> arg1 data 7)) + (f3-1 (-> arg1 data 8)) + (f6-1 (-> arg1 data 10)) + (f10-1 (-> arg1 data 11)) + (f4-3 (-> arg1 data 12)) + (f7-2 (-> arg1 data 14)) + (f1-6 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 1) + (- + (/ + (- + (+ + (+ (* (* f9-2 f6-1) f1-6) (* (* f2-2 f10-1) f4-3)) + (* (* f5-2 f3-1) f7-2) + ) + (+ + (+ (* (* f9-2 f10-1) f7-2) (* (* f5-2 f6-1) f4-3)) + (* (* f2-2 f3-1) f1-6) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-4 (-> arg1 data 4)) + (f2-4 (-> arg1 data 5)) + (f5-4 (-> arg1 data 7)) + (f3-2 (-> arg1 data 8)) + (f6-2 (-> arg1 data 9)) + (f10-2 (-> arg1 data 11)) + (f4-6 (-> arg1 data 12)) + (f7-4 (-> arg1 data 13)) + (f1-13 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 2) + (/ + (- + (+ + (+ (* (* f9-4 f6-2) f1-13) (* (* f2-4 f10-2) f4-6)) + (* (* f5-4 f3-2) f7-4) + ) + (+ + (+ (* (* f9-4 f10-2) f7-4) (* (* f5-4 f6-2) f4-6)) + (* (* f2-4 f3-2) f1-13) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-6 (-> arg1 data 4)) + (f2-6 (-> arg1 data 5)) + (f5-6 (-> arg1 data 6)) + (f3-3 (-> arg1 data 8)) + (f6-3 (-> arg1 data 9)) + (f10-3 (-> arg1 data 10)) + (f4-9 (-> arg1 data 12)) + (f7-6 (-> arg1 data 13)) + (f1-19 (-> arg1 data 14)) + ) + (set! + (-> arg0 data 3) + (- + (/ + (- + (+ + (+ (* (* f9-6 f6-3) f1-19) (* (* f2-6 f10-3) f4-9)) + (* (* f5-6 f3-3) f7-6) + ) + (+ + (+ (* (* f9-6 f10-3) f7-6) (* (* f5-6 f6-3) f4-9)) + (* (* f2-6 f3-3) f1-19) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-8 (-> arg1 data 1)) + (f2-8 (-> arg1 data 2)) + (f5-8 (-> arg1 data 3)) + (f3-4 (-> arg1 data 9)) + (f6-4 (-> arg1 data 10)) + (f10-4 (-> arg1 data 11)) + (f4-12 (-> arg1 data 13)) + (f7-8 (-> arg1 data 14)) + (f1-26 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 4) + (- + (/ + (- + (+ + (+ (* (* f9-8 f6-4) f1-26) (* (* f2-8 f10-4) f4-12)) + (* (* f5-8 f3-4) f7-8) + ) + (+ + (+ (* (* f9-8 f10-4) f7-8) (* (* f5-8 f6-4) f4-12)) + (* (* f2-8 f3-4) f1-26) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-10 (-> arg1 data 0)) + (f2-10 (-> arg1 data 2)) + (f5-10 (-> arg1 data 3)) + (f3-5 (-> arg1 data 8)) + (f6-5 (-> arg1 data 10)) + (f10-5 (-> arg1 data 11)) + (f4-15 (-> arg1 data 12)) + (f7-10 (-> arg1 data 14)) + (f1-33 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 5) + (/ + (- + (+ + (+ (* (* f9-10 f6-5) f1-33) (* (* f2-10 f10-5) f4-15)) + (* (* f5-10 f3-5) f7-10) + ) + (+ + (+ (* (* f9-10 f10-5) f7-10) (* (* f5-10 f6-5) f4-15)) + (* (* f2-10 f3-5) f1-33) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-12 (-> arg1 data 0)) + (f2-12 (-> arg1 data 1)) + (f5-12 (-> arg1 data 3)) + (f3-6 (-> arg1 data 8)) + (f6-6 (-> arg1 data 9)) + (f10-6 (-> arg1 data 11)) + (f4-18 (-> arg1 data 12)) + (f7-12 (-> arg1 data 13)) + (f1-39 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 6) + (- + (/ + (- + (+ + (+ (* (* f9-12 f6-6) f1-39) (* (* f2-12 f10-6) f4-18)) + (* (* f5-12 f3-6) f7-12) + ) + (+ + (+ (* (* f9-12 f10-6) f7-12) (* (* f5-12 f6-6) f4-18)) + (* (* f2-12 f3-6) f1-39) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-14 (-> arg1 data 0)) + (f2-14 (-> arg1 data 1)) + (f5-14 (-> arg1 data 2)) + (f3-7 (-> arg1 data 8)) + (f6-7 (-> arg1 data 9)) + (f10-7 (-> arg1 data 10)) + (f4-21 (-> arg1 data 12)) + (f7-14 (-> arg1 data 13)) + (f1-46 (-> arg1 data 14)) + ) + (set! + (-> arg0 data 7) + (/ + (- + (+ + (+ (* (* f9-14 f6-7) f1-46) (* (* f2-14 f10-7) f4-21)) + (* (* f5-14 f3-7) f7-14) + ) + (+ + (+ (* (* f9-14 f10-7) f7-14) (* (* f5-14 f6-7) f4-21)) + (* (* f2-14 f3-7) f1-46) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-16 (-> arg1 data 1)) + (f2-16 (-> arg1 data 2)) + (f5-16 (-> arg1 data 3)) + (f3-8 (-> arg1 data 5)) + (f6-8 (-> arg1 data 6)) + (f10-8 (-> arg1 data 7)) + (f4-24 (-> arg1 data 13)) + (f7-16 (-> arg1 data 14)) + (f1-52 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 8) + (/ + (- + (+ + (+ (* (* f9-16 f6-8) f1-52) (* (* f2-16 f10-8) f4-24)) + (* (* f5-16 f3-8) f7-16) + ) + (+ + (+ (* (* f9-16 f10-8) f7-16) (* (* f5-16 f6-8) f4-24)) + (* (* f2-16 f3-8) f1-52) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-18 (-> arg1 data 0)) + (f2-18 (-> arg1 data 2)) + (f5-18 (-> arg1 data 3)) + (f3-9 (-> arg1 data 4)) + (f6-9 (-> arg1 data 6)) + (f10-9 (-> arg1 data 7)) + (f4-27 (-> arg1 data 12)) + (f7-18 (-> arg1 data 14)) + (f1-58 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 9) + (- + (/ + (- + (+ + (+ (* (* f9-18 f6-9) f1-58) (* (* f2-18 f10-9) f4-27)) + (* (* f5-18 f3-9) f7-18) + ) + (+ + (+ (* (* f9-18 f10-9) f7-18) (* (* f5-18 f6-9) f4-27)) + (* (* f2-18 f3-9) f1-58) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-20 (-> arg1 data 0)) + (f2-20 (-> arg1 data 1)) + (f5-20 (-> arg1 data 3)) + (f3-10 (-> arg1 data 4)) + (f6-10 (-> arg1 data 5)) + (f10-10 (-> arg1 data 7)) + (f4-30 (-> arg1 data 12)) + (f7-20 (-> arg1 data 13)) + (f1-65 (-> arg1 data 15)) + ) + (set! + (-> arg0 data 10) + (/ + (- + (+ + (+ (* (* f9-20 f6-10) f1-65) (* (* f2-20 f10-10) f4-30)) + (* (* f5-20 f3-10) f7-20) + ) + (+ + (+ (* (* f9-20 f10-10) f7-20) (* (* f5-20 f6-10) f4-30)) + (* (* f2-20 f3-10) f1-65) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-22 (-> arg1 data 0)) + (f2-22 (-> arg1 data 1)) + (f5-22 (-> arg1 data 2)) + (f3-11 (-> arg1 data 4)) + (f6-11 (-> arg1 data 5)) + (f10-11 (-> arg1 data 6)) + (f4-33 (-> arg1 data 12)) + (f7-22 (-> arg1 data 13)) + (f1-71 (-> arg1 data 14)) + ) + (set! + (-> arg0 data 11) + (- + (/ + (- + (+ + (+ (* (* f9-22 f6-11) f1-71) (* (* f2-22 f10-11) f4-33)) + (* (* f5-22 f3-11) f7-22) + ) + (+ + (+ (* (* f9-22 f10-11) f7-22) (* (* f5-22 f6-11) f4-33)) + (* (* f2-22 f3-11) f1-71) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-24 (-> arg1 data 1)) + (f2-24 (-> arg1 data 2)) + (f5-24 (-> arg1 data 3)) + (f3-12 (-> arg1 data 5)) + (f6-12 (-> arg1 data 6)) + (f10-12 (-> arg1 data 7)) + (f4-36 (-> arg1 data 9)) + (f7-24 (-> arg1 data 10)) + (f1-78 (-> arg1 data 11)) + ) + (set! + (-> arg0 data 12) + (- + (/ + (- + (+ + (+ (* (* f9-24 f6-12) f1-78) (* (* f2-24 f10-12) f4-36)) + (* (* f5-24 f3-12) f7-24) + ) + (+ + (+ (* (* f9-24 f10-12) f7-24) (* (* f5-24 f6-12) f4-36)) + (* (* f2-24 f3-12) f1-78) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f9-26 (-> arg1 data 0)) + (f2-26 (-> arg1 data 2)) + (f5-26 (-> arg1 data 3)) + (f3-13 (-> arg1 data 4)) + (f6-13 (-> arg1 data 6)) + (f10-13 (-> arg1 data 7)) + (f4-39 (-> arg1 data 8)) + (f7-26 (-> arg1 data 10)) + (f1-85 (-> arg1 data 11)) + ) + (set! + (-> arg0 data 13) + (/ + (- + (+ + (+ (* (* f9-26 f6-13) f1-85) (* (* f2-26 f10-13) f4-39)) + (* (* f5-26 f3-13) f7-26) + ) + (+ + (+ (* (* f9-26 f10-13) f7-26) (* (* f5-26 f6-13) f4-39)) + (* (* f2-26 f3-13) f1-85) + ) + ) + f0-0 + ) + ) + ) + (let ((f9-28 (-> arg1 data 0)) + (f2-28 (-> arg1 data 1)) + (f5-28 (-> arg1 data 3)) + (f3-14 (-> arg1 data 4)) + (f6-14 (-> arg1 data 5)) + (f10-14 (-> arg1 data 7)) + (f4-42 (-> arg1 data 8)) + (f7-28 (-> arg1 data 9)) + (f1-91 (-> arg1 data 11)) + ) + (set! + (-> arg0 data 14) + (- + (/ + (- + (+ + (+ (* (* f9-28 f6-14) f1-91) (* (* f2-28 f10-14) f4-42)) + (* (* f5-28 f3-14) f7-28) + ) + (+ + (+ (* (* f9-28 f10-14) f7-28) (* (* f5-28 f6-14) f4-42)) + (* (* f2-28 f3-14) f1-91) + ) + ) + f0-0 + ) + ) + ) + ) + (let ((f8-60 (-> arg1 data 0)) + (f1-98 (-> arg1 data 1)) + (f5-30 (-> arg1 data 2)) + (f2-30 (-> arg1 data 4)) + (f6-15 (-> arg1 data 5)) + (f9-30 (-> arg1 data 6)) + (f4-45 (-> arg1 data 8)) + (f7-30 (-> arg1 data 9)) + (f3-15 (-> arg1 data 10)) + ) + (set! + (-> arg0 data 15) + (/ + (- + (+ + (+ (* (* f8-60 f6-15) f3-15) (* (* f1-98 f9-30) f4-45)) + (* (* f5-30 f2-30) f7-30) + ) + (+ + (+ (* (* f8-60 f9-30) f7-30) (* (* f5-30 f6-15) f4-45)) + (* (* f1-98 f2-30) f3-15) + ) + ) + f0-0 + ) + ) + ) + ) + arg0 + ) + +;; definition for function matrix-y-angle +(defun matrix-y-angle ((arg0 matrix)) + (let ((v1-0 (&-> arg0 data 8))) + (atan (-> v1-0 0) (-> v1-0 2)) + ) + ) + +;; definition for method 9 of type matrix +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; failed to figure out what this is: +(none) + diff --git a/test/decompiler/reference/vector-h_REF.gc b/test/decompiler/reference/vector-h_REF.gc index 56fd388aa1..e3bfb9c692 100644 --- a/test/decompiler/reference/vector-h_REF.gc +++ b/test/decompiler/reference/vector-h_REF.gc @@ -849,8 +849,8 @@ (rlet ((vf1 :class vf) (vf2 :class vf) ) - (.lvf vf1 arg0) - (.lvf vf2 arg1) + (.lvf vf1 (&-> arg0 quad)) + (.lvf vf2 (&-> arg1 quad)) (.mul.vf vf1 vf1 vf2) (.add.y.vf vf1 vf1 vf1 :mask #b1) (.add.z.vf vf1 vf1 vf1 :mask #b1) @@ -895,8 +895,8 @@ (vf3 :class vf) ) (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) - (.lvf vf1 arg0) - (.lvf vf2 arg1) + (.lvf vf1 (&-> arg0 quad)) + (.lvf vf2 (&-> arg1 quad)) (.mul.vf vf1 vf1 vf2) (.add.w.vf vf3 vf0 vf0 :mask #b1) (.mul.x.vf acc vf3 vf1 :mask #b1) @@ -917,10 +917,10 @@ ) (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) (.mov.vf vf6 vf0 :mask #b1000) - (.lvf vf4 arg1) - (.lvf vf5 arg2) + (.lvf vf4 (&-> arg1 quad)) + (.lvf vf5 (&-> arg2 quad)) (.add.vf vf6 vf4 vf5 :mask #b111) - (.svf arg0 vf6) + (.svf (&-> arg0 quad) vf6) arg0 ) ) @@ -933,11 +933,11 @@ (vf6 :class vf) ) (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) - (.lvf vf4 arg1) - (.lvf vf5 arg2) + (.lvf vf4 (&-> arg1 quad)) + (.lvf vf5 (&-> arg2 quad)) (.mov.vf vf6 vf0 :mask #b1000) (.sub.vf vf6 vf4 vf5 :mask #b111) - (.svf arg0 vf6) + (.svf (&-> arg0 quad) vf6) arg0 ) ) @@ -953,7 +953,7 @@ (defun vector-reset! ((arg0 vector)) (rlet ((vf0 :class vf)) (.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0)) - (.svf arg0 vf0) + (.svf (&-> arg0 quad) vf0) arg0 ) ) diff --git a/test/decompiler/test_FormBeforeExpressions.cpp b/test/decompiler/test_FormBeforeExpressions.cpp index 717ae5dc73..084df07407 100644 --- a/test/decompiler/test_FormBeforeExpressions.cpp +++ b/test/decompiler/test_FormBeforeExpressions.cpp @@ -11,8 +11,9 @@ TEST_F(FormRegressionTest, StringTest) { "L101:\n" " jr ra\n" " daddu sp, sp, r0"; - auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), false, false, "", - {{"L100", "testing-string"}, {"L101", "testing-string-2"}}); + TestSettings settings; + settings.strings = {{"L100", "testing-string"}, {"L101", "testing-string-2"}}; + auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), settings); EXPECT_EQ(test->file.get_goal_string_by_label(test->file.get_label_by_name("L100")), "testing-string"); diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp index 92db303ec3..65920bf9ae 100644 --- a/test/decompiler/test_FormExpressionBuild.cpp +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -2282,8 +2282,8 @@ TEST_F(FormRegressionTest, ExprPrintName) { " )\n" " )"; test_with_expr(func, type, expected, false, "", {}, - parse_cast_json("[\t\t[24, \"a1\", \"symbol\"],\n" - "\t\t[39, \"a0\", \"symbol\"]]")); + "[\t\t[24, \"a1\", \"symbol\"],\n" + "\t\t[39, \"a0\", \"symbol\"]]"); } TEST_F(FormRegressionTest, ExprProfileBarMethod9) { diff --git a/test/decompiler/test_FormExpressionBuild2.cpp b/test/decompiler/test_FormExpressionBuild2.cpp new file mode 100644 index 0000000000..978803d28a --- /dev/null +++ b/test/decompiler/test_FormExpressionBuild2.cpp @@ -0,0 +1,59 @@ +#include "gtest/gtest.h" +#include "FormRegressionTest.h" + +using namespace decompiler; + +TEST_F(FormRegressionTest, MatrixPMult) { + 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" + " daddiu s5, sp, 16\n" + " sq r0, 0(s5)\n" + " sq r0, 16(s5)\n" + " sq r0, 32(s5)\n" + " sq r0, 48(s5)\n" + " lw t9, matrix*!(s7)\n" + " or a0, s5, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lq v1, 0(s5)\n" + " sq v1, 0(gp)\n" + " lq v1, 16(s5)\n" + " sq v1, 16(gp)\n" + " lq v1, 32(s5)\n" + " sq v1, 32(gp)\n" + " lq v1, 48(s5)\n" + " sq v1, 48(gp)\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"; + std::string type = "(function matrix matrix matrix matrix)"; + std::string expected = + "(begin\n" + " (let ((s5-0 (new (quote stack) (quote matrix))))\n" + " (set! (-> s5-0 vector 0 quad) (the-as uint128 0))\n" + " (set! (-> s5-0 vector 1 quad) (the-as uint128 0))\n" + " (set! (-> s5-0 vector 2 quad) (the-as uint128 0))\n" + " (set! (-> s5-0 vector 3 quad) (the-as uint128 0))\n" + " (matrix*! s5-0 arg1 arg2)\n" + " (set! (-> arg0 vector 0 quad) (-> s5-0 vector 0 quad))\n" + " (set! (-> arg0 vector 1 quad) (-> s5-0 vector 1 quad))\n" + " (set! (-> arg0 vector 2 quad) (-> s5-0 vector 2 quad))\n" + " (set! (-> arg0 vector 3 quad) (-> s5-0 vector 3 quad))\n" + " )\n" + " arg0\n" + " )"; + test_with_stack_vars(func, type, expected, + "[\n" + " [16, \"matrix\"]\n" + " ]"); +} \ No newline at end of file diff --git a/test/decompiler/test_FormExpressionBuildLong.cpp b/test/decompiler/test_FormExpressionBuildLong.cpp index 697da1132e..84b7e765a8 100644 --- a/test/decompiler/test_FormExpressionBuildLong.cpp +++ b/test/decompiler/test_FormExpressionBuildLong.cpp @@ -687,21 +687,21 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { {"L336", "~A"}, {"L335", " ~A"}, {"L334", ")"}}, - parse_cast_json("[" - "\t\t[23, \"gp\", \"(array int32)\"],\n" - "\t\t[43, \"gp\", \"(array uint32)\"],\n" - "\t\t[63, \"gp\", \"(array int64)\"],\n" - "\t\t[83, \"gp\", \"(array uint64)\"],\n" - "\t\t[102, \"gp\", \"(array int8)\"],\n" - "\t\t[121, \"gp\", \"(array uint8)\"],\n" - "\t\t[141, \"gp\", \"(array int16)\"],\n" - "\t\t[161, \"gp\", \"(array uint16)\"],\n" - "\t\t[186, \"gp\", \"(array uint128)\"],\n" - "\t\t[204, \"gp\", \"(array int32)\"],\n" - "\t\t[223, \"gp\", \"(array float)\"],\n" - "\t\t[232, \"gp\", \"(array float)\"],\n" - "\t\t[249, \"gp\", \"(array basic)\"],\n" - "\t\t[258, \"gp\", \"(array basic)\"]]")); + "[" + "\t\t[23, \"gp\", \"(array int32)\"],\n" + "\t\t[43, \"gp\", \"(array uint32)\"],\n" + "\t\t[63, \"gp\", \"(array int64)\"],\n" + "\t\t[83, \"gp\", \"(array uint64)\"],\n" + "\t\t[102, \"gp\", \"(array int8)\"],\n" + "\t\t[121, \"gp\", \"(array uint8)\"],\n" + "\t\t[141, \"gp\", \"(array int16)\"],\n" + "\t\t[161, \"gp\", \"(array uint16)\"],\n" + "\t\t[186, \"gp\", \"(array uint128)\"],\n" + "\t\t[204, \"gp\", \"(array int32)\"],\n" + "\t\t[223, \"gp\", \"(array float)\"],\n" + "\t\t[232, \"gp\", \"(array float)\"],\n" + "\t\t[249, \"gp\", \"(array basic)\"],\n" + "\t\t[258, \"gp\", \"(array basic)\"]]"); } TEST_F(FormRegressionTest, ExprArrayMethod3) { @@ -1266,18 +1266,18 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { {"L327", "~T [~D] #x~X~%"}, {"L326", "~T [~D] ~f~%"}, {"L325", "~T [~D] ~A~%"}}, - parse_cast_json("[\t\t[44, \"gp\", \"(array int32)\"],\n" - "\t\t[62, \"gp\", \"(array uint32)\"],\n" - "\t\t[80, \"gp\", \"(array int64)\"],\n" - "\t\t[98, \"gp\", \"(array uint64)\"],\n" - "\t\t[115, \"gp\", \"(array int8)\"],\n" - "\t\t[132, \"gp\", \"(array int8)\"],\n" - "\t\t[150, \"gp\", \"(array int16)\"],\n" - "\t\t[168, \"gp\", \"(array uint16)\"],\n" - "\t\t[191, \"gp\", \"(array uint128)\"],\n" - "\t\t[207, \"gp\", \"(array int32)\"],\n" - "\t\t[226, \"gp\", \"(array float)\"],\n" - "\t\t[243, \"gp\", \"(array basic)\"]]")); + "[\t\t[44, \"gp\", \"(array int32)\"],\n" + "\t\t[62, \"gp\", \"(array uint32)\"],\n" + "\t\t[80, \"gp\", \"(array int64)\"],\n" + "\t\t[98, \"gp\", \"(array uint64)\"],\n" + "\t\t[115, \"gp\", \"(array int8)\"],\n" + "\t\t[132, \"gp\", \"(array int8)\"],\n" + "\t\t[150, \"gp\", \"(array int16)\"],\n" + "\t\t[168, \"gp\", \"(array uint16)\"],\n" + "\t\t[191, \"gp\", \"(array uint128)\"],\n" + "\t\t[207, \"gp\", \"(array int32)\"],\n" + "\t\t[226, \"gp\", \"(array float)\"],\n" + "\t\t[243, \"gp\", \"(array basic)\"]]"); } TEST_F(FormRegressionTest, ExprValid) { diff --git a/test/decompiler/test_gkernel_decomp.cpp b/test/decompiler/test_gkernel_decomp.cpp index 547503362a..5662654853 100644 --- a/test/decompiler/test_gkernel_decomp.cpp +++ b/test/decompiler/test_gkernel_decomp.cpp @@ -371,7 +371,7 @@ TEST_F(FormRegressionTest, ExprMethod0Thread) { " (the-as cpu-thread (the-as object obj))\n" " )"; test_with_expr(func, type, expected, false, "cpu-thread", {}, - parse_cast_json("[[[13, 28], \"v0\", \"cpu-thread\"]]"), + "[[[13, 28], \"v0\", \"cpu-thread\"]]", "{\"vars\":{\"v0-0\":[\"obj\", \"cpu-thread\"]}}"); } @@ -686,8 +686,8 @@ TEST_F(FormRegressionTest, ExprMethod0Process) { " (the-as process v0-0)\n" " )"; test_with_expr(func, type, expected, false, "process", {}, - parse_cast_json("[\t\t[12, \"a0\", \"int\"],\n" - "\t\t[[13, 43], \"v0\", \"process\"]]")); + "[\t\t[12, \"a0\", \"int\"],\n" + "\t\t[[13, 43], \"v0\", \"process\"]]"); } TEST_F(FormRegressionTest, ExprInspectProcessHeap) { @@ -751,8 +751,8 @@ TEST_F(FormRegressionTest, ExprInspectProcessHeap) { " #f\n" " )"; test_with_expr(func, type, expected, false, "", {}, - parse_cast_json("[\t\t[[4,11], \"s5\", \"basic\"],\n" - "\t\t[[17,20], \"s5\", \"pointer\"]]"), + "[\t\t[[4,11], \"s5\", \"basic\"],\n" + "\t\t[[17,20], \"s5\", \"pointer\"]]", "{\"vars\":{\"s5-0\":[\"obj\", \"pointer\"]}}"); } @@ -1123,8 +1123,8 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPool) { func, type, expected, false, "dead-pool", {{"L315", "WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%"}, {"L314", "WARNING: ~A ~A could not be allocated, because ~A was empty.~%"}}, - parse_cast_json("[\t\t[24, \"v1\", \"(pointer process-tree)\"],\n" - "\t\t[[30,39], \"s4\", \"(pointer process-tree)\"]]")); + "[\t\t[24, \"v1\", \"(pointer process-tree)\"],\n" + "\t\t[[30,39], \"s4\", \"(pointer process-tree)\"]]"); } TEST_F(FormRegressionTest, ExprMethod15DeadPool) { @@ -1299,11 +1299,10 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) { " (set! (-> obj heap top-base) (-> obj heap top))\n" " obj\n" " )"; - test_with_expr( - func, type, expected, false, "dead-pool-heap", {}, - parse_cast_json("[\t\t[60, \"v0\", \"int\"],\n" - "\t\t[61, \"a0\", \"pointer\"], [61, \"v0\", \"dead-pool-heap\"]]"), - "{\"vars\":{\"v0-0\":[\"obj\", \"dead-pool-heap\"]}}"); + test_with_expr(func, type, expected, false, "dead-pool-heap", {}, + "[\t\t[60, \"v0\", \"int\"],\n" + "\t\t[61, \"a0\", \"pointer\"], [61, \"v0\", \"dead-pool-heap\"]]", + "{\"vars\":{\"v0-0\":[\"obj\", \"dead-pool-heap\"]}}"); } TEST_F(FormRegressionTest, ExprMethod22DeadPoolHeap) { @@ -1426,9 +1425,9 @@ TEST_F(FormRegressionTest, ExprMethod21DeadPoolHeap) { " )\n" " )"; test_with_expr(func, type, expected, false, "", {}, - parse_cast_json("[\t\t[5, \"v1\", \"pointer\"],\n" - "\t\t[13, \"a0\", \"pointer\"],\n" - "\t\t[25, \"v1\", \"pointer\"]]")); + "[\t\t[5, \"v1\", \"pointer\"],\n" + "\t\t[13, \"a0\", \"pointer\"],\n" + "\t\t[25, \"v1\", \"pointer\"]]"); } TEST_F(FormRegressionTest, ExprMethod3DeadPoolHeap) { @@ -1623,7 +1622,7 @@ TEST_F(FormRegressionTest, ExprMethod5DeadPoolHeap) { std::string expected = "(+ (the-as int (- -4 (the-as int arg0))) (the-as int (-> arg0 heap top)))"; test_with_expr(func, type, expected, false, "", {}, - parse_cast_json("[[3, \"v1\", \"int\"], [3, \"a0\", \"int\"]]")); + "[[3, \"v1\", \"int\"], [3, \"a0\", \"int\"]]"); } TEST_F(FormRegressionTest, ExprMethod19DeadPoolHeap) { diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index a6a705454a..99a0dab0b7 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -14,30 +14,18 @@ const std::unordered_set g_object_files_to_decompile = { "gcommon", "gstring-h", "gkernel-h", "gkernel", /*"pskernel",*/ "gstring", "dgo-h", "gstate", "types-h", "vu1-macros", "math", "vector-h", "bounding-box-h", "matrix-h", "quaternion-h", "euler-h", "transform-h", "geometry-h", - "trigonometry-h", + "trigonometry-h", /* transformq-h */ "matrix", /* gap */ "bounding-box"}; // the object files to check against a reference in test/decompiler/reference const std::vector g_object_files_to_check_against_reference = { "gcommon", // NOTE: this file needs work, but adding it for now just to test the framework. - "gstring-h", - "gkernel-h", - "gkernel", - "gstring", - "dgo-h", - "gstate", - "types-h", - "vu1-macros", - "math", - "vector-h", - "bounding-box-h", - "matrix-h", - "quaternion-h", - "euler-h", - "transform-h", - "geometry-h", - "trigonometry-h", + "gstring-h", "gkernel-h", "gkernel", "gstring", "dgo-h", "gstate", "types-h", "vu1-macros", + "math", "vector-h", "bounding-box-h", "matrix-h", "quaternion-h", "euler-h", "transform-h", + "geometry-h", "trigonometry-h", + /* transformq-h, */ + "matrix", /* gap */ "bounding-box"}; // the functions we expect the decompiler to skip @@ -66,6 +54,10 @@ const std::unordered_set expected_skip_in_decompiler = { // bounding-box "(method 9 bounding-box)", // handwritten asm loop "(method 14 bounding-box)", // handwritten asm loop + // matrix + "(method 9 matrix)", // handwritten asm loop + "matrix-axis-sin-cos!", + "matrix-axis-sin-cos-vu!", }; const std::unordered_set skip_in_compiling = { @@ -100,6 +92,10 @@ const std::unordered_set skip_in_compiling = { "(method 3 vector)", // this function appears twice, which confuses the compiler. "vector-dot", // fpu acc "vector4-dot", // fpu acc + + /// MATRIX + "matrix-transpose!", // unsupported asm ops + "matrix-4x4-inverse!", // compiler fails to regalloc this... }; // default location for the data. It can be changed with a command line argument.