diff --git a/decompiler/Disasm/InstructionParser.cpp b/decompiler/Disasm/InstructionParser.cpp index f01ab0247c..aa1db16f1a 100644 --- a/decompiler/Disasm/InstructionParser.cpp +++ b/decompiler/Disasm/InstructionParser.cpp @@ -45,7 +45,8 @@ InstructionParser::InstructionParser() { InstructionKind::MFLO, InstructionKind::MFHI, InstructionKind::MTLO1, InstructionKind::MFLO1, InstructionKind::SYNCL, InstructionKind::PCPYUD, InstructionKind::PEXTUW, InstructionKind::POR, InstructionKind::VMOVE, - InstructionKind::VSUB, InstructionKind::LQC2, InstructionKind::SQC2}) { + InstructionKind::VSUB, InstructionKind::LQC2, InstructionKind::SQC2, + InstructionKind::MULAS, InstructionKind::MADDAS}) { auto& info = gOpcodeInfo[int(i)]; if (info.defined) { m_opcode_name_lookup[info.name] = int(i); diff --git a/decompiler/Function/CfgVtx.cpp b/decompiler/Function/CfgVtx.cpp index fed54285bd..5fa13eddcb 100644 --- a/decompiler/Function/CfgVtx.cpp +++ b/decompiler/Function/CfgVtx.cpp @@ -121,6 +121,12 @@ std::string CfgVtx::links_to_string() { result += " prev: " + prev->to_string() + "\n"; } + result += " start: " + std::to_string(get_first_block_id()) + "\n"; + + if (end_branch.asm_branch) { + result += " ASM BRANCH\n"; + } + if (!pred.empty()) { result += " preds:\n"; for (auto* x : pred) { @@ -332,10 +338,17 @@ std::string Break::to_string() const { } goos::Object Break::to_form() const { - std::vector forms = {pretty_print::to_symbol("break"), - pretty_print::to_symbol(std::to_string(dest_block_id)), - body->to_form(), unreachable_block->to_form()}; - return pretty_print::build_list(forms); + if (unreachable_block) { + std::vector forms = {pretty_print::to_symbol("break"), + pretty_print::to_symbol(std::to_string(dest_block_id)), + body->to_form(), unreachable_block->to_form()}; + return pretty_print::build_list(forms); + } else { + std::vector forms = {pretty_print::to_symbol("break"), + pretty_print::to_symbol(std::to_string(dest_block_id)), + body->to_form(), pretty_print::to_symbol("no-unreachable")}; + return pretty_print::build_list(forms); + } } int Break::get_first_block_id() const { @@ -537,6 +550,11 @@ bool ControlFlowGraph::is_until_loop(CfgVtx* b1, CfgVtx* b2) { return false; assert(!b1->end_branch.has_branch); + if (!b2->has_pred(b1)) { + fmt::print("Graph error {} (s {}) should have pred {} (s {})\n", b2->to_string(), + b2->get_first_block_id(), b1->to_string(), b1->get_first_block_id()); + } + assert(b2->has_pred(b1)); if (b2->pred.size() != 1) return false; @@ -730,7 +748,7 @@ bool ControlFlowGraph::find_infinite_loop() { bool found = false; for_each_top_level_vtx([&](CfgVtx* vtx) { - if (vtx->succ_branch == vtx && !vtx->succ_ft) { + if (vtx->succ_branch == vtx && !vtx->succ_ft && !vtx->end_branch.asm_branch) { auto inf = alloc(); inf->block = vtx; inf->pred = vtx->pred; @@ -806,7 +824,7 @@ bool ControlFlowGraph::find_goto_end() { for_each_top_level_vtx([&](CfgVtx* vtx) { auto* b0 = vtx; auto* b1 = vtx->next; - if (is_goto_end_and_unreachable(b0, b1)) { + if (is_goto_end_and_unreachable(b0, b1) && !b0->end_branch.asm_branch) { replaced = true; auto* new_goto = alloc(); @@ -959,7 +977,9 @@ bool ControlFlowGraph::find_goto_not_end() { for_each_top_level_vtx([&](CfgVtx* vtx) { auto* b0 = vtx; auto* b1 = vtx->next; - if (is_goto_not_end_and_unreachable(b0, b1)) { + + // this can't work on asm branches because the structuring will fail. + if (is_goto_not_end_and_unreachable(b0, b1) && b0 && !b0->end_branch.asm_branch) { replaced = true; auto* new_goto = alloc(); @@ -1051,6 +1071,339 @@ bool ControlFlowGraph::is_sequence(CfgVtx* b0, CfgVtx* b1, bool allow_self_loops return true; } +bool debug_asm_branch = false; +/*! + * This is a weird and special pass that takes something like: + * B0 + * asm branch + * B1 + * + * and merges B0B1 into a single block with a + */ +bool ControlFlowGraph::clean_up_asm_branches() { + bool replaced = false; + for_each_top_level_vtx([&](CfgVtx* vtx) { + auto* b0 = vtx; + auto* b1 = vtx->next; + if (!b1) { + return true; + } + + if (!b0->end_branch.asm_branch) { + return true; + } + + // don't want to combine two with an incoming edge in between. + if (b1->pred.size() > 1) { + return true; + } else { + if (b1->pred.size() == 1 && !b1->has_pred(b1->prev)) { + return true; + } + } + + if (b0->end_branch.branch_likely) { + auto* bds = b1; + b1 = bds->next; + if (!b1) { + return true; + } + + if (debug_asm_branch) { + fmt::print("Looks like asm likely branch: {} {} to {}\n", b0->to_string(), bds->to_string(), + b1->to_string()); + } + + auto* b0_seq = dynamic_cast(b0); + auto* b1_seq = dynamic_cast(b1); + if (!b0_seq && !b1_seq) { + // build new sequence + replaced = true; + + m_blocks.at(bds->succ_branch->get_first_block_id())->needs_label = true; + + auto* new_seq = alloc(); + new_seq->seq.push_back(b0); + new_seq->seq.push_back(bds); + new_seq->seq.push_back(b1); + + for (auto* new_pred : b0->pred) { + if (debug_asm_branch) { + fmt::print(" pred {}\n", new_pred->to_string()); + } + new_pred->replace_succ_and_check(b0, new_seq); + } + new_seq->pred = b0->pred; + + if (b0->succ_branch) { + b0->succ_branch->replace_preds_with_and_check({b0}, nullptr); + } + + if (bds->succ_branch) { + // likely delay slots "branch" in this graph. + bds->succ_branch->replace_preds_with_and_check({bds}, nullptr); + } + + for (auto* new_succ : b1->succs()) { + new_succ->replace_pred_and_check(b1, new_seq); + } + new_seq->succ_ft = b1->succ_ft; + new_seq->succ_branch = b1->succ_branch; + + new_seq->prev = b0->prev; + if (new_seq->prev) { + new_seq->prev->next = new_seq; + } + new_seq->next = b1->next; + if (new_seq->next) { + new_seq->next->prev = new_seq; + } + + b0->parent_claim(new_seq); + bds->parent_claim(new_seq); + b1->parent_claim(new_seq); + new_seq->end_branch = b1->end_branch; + + return false; + } else if (b0_seq && b1_seq) { + replaced = true; + m_blocks.at(bds->succ_branch->get_first_block_id())->needs_label = true; + auto* seq = dynamic_cast(b0); + assert(seq); + + auto* old_seq = dynamic_cast(b1); + assert(old_seq); + + if (b0->succ_branch) { + b0->succ_branch->replace_preds_with_and_check({b0}, nullptr); + } + + if (bds->succ_branch) { + // likely delay slots "branch" in this graph. + bds->succ_branch->replace_preds_with_and_check({bds}, nullptr); + } + + seq->seq.push_back(bds); + + for (auto* x : old_seq->seq) { + x->parent_claim(seq); + seq->seq.push_back(x); + } + + for (auto* x : old_seq->succs()) { + // printf("fix preds of %s\n", x->to_string().c_str()); + x->replace_pred_and_check(old_seq, seq); + } + seq->succ_branch = old_seq->succ_branch; + seq->succ_ft = old_seq->succ_ft; + seq->end_branch = old_seq->end_branch; + seq->next = old_seq->next; + if (seq->next) { + seq->next->prev = seq; + } + + // todo - proper trash? + old_seq->parent_claim(seq); + bds->parent_claim(seq); + + return false; + } + + else { + lg::error("unhandled sequences in clean_up_asm_branches likely seq: {} {}", !!b0_seq, + !!b1_seq); + } + + } else { + if (debug_asm_branch) { + fmt::print("Looks like asm normal branch: {} to {}\n", b0->to_string(), b1->to_string()); + } + auto* b0_seq = dynamic_cast(b0); + auto* b1_seq = dynamic_cast(b1); + + if (!b0_seq && !b1_seq) { + if (debug_asm_branch) { + fmt::print("[combo nn] {} and {}\n", b0->get_first_block_id(), b1->get_first_block_id()); + } + // build new sequence + replaced = true; + m_blocks.at(b0->succ_branch->get_first_block_id())->needs_label = true; + + auto* new_seq = alloc(); + new_seq->seq.push_back(b0); + new_seq->seq.push_back(b1); + + for (auto* new_pred : b0->pred) { + new_pred->replace_succ_and_check(b0, new_seq); + } + new_seq->pred = b0->pred; + + if (b0->succ_branch) { + b0->succ_branch->replace_preds_with_and_check({b0}, nullptr); + } + + for (auto* new_succ : b1->succs()) { + if (debug_asm_branch) { + fmt::print("changing {}'s pred {} to seq. bc: {}", new_succ->to_string(), + b1->to_string(), new_succ->pred.size()); + } + new_succ->replace_pred_and_check(b1, new_seq); + if (debug_asm_branch) { + fmt::print(" ac: {}\n", new_succ->pred.size()); + } + } + new_seq->succ_ft = b1->succ_ft; + + if (b1->succ_branch && debug_asm_branch) { + fmt::print("combining {} and {} into a sequence, succ {}\n", b0->get_first_block_id(), + b1->get_first_block_id(), b1->succ_branch->get_first_block_id()); + } + + new_seq->succ_branch = b1->succ_branch; + + new_seq->prev = b0->prev; + if (new_seq->prev) { + new_seq->prev->next = new_seq; + } + new_seq->next = b1->next; + if (new_seq->next) { + new_seq->next->prev = new_seq; + } + + b0->parent_claim(new_seq); + b1->parent_claim(new_seq); + + if (new_seq->succ_branch) { + assert(!new_seq->succ_branch->parent); + } + + new_seq->end_branch = b1->end_branch; + return false; + } else if (b0_seq && !b1_seq) { + if (debug_asm_branch) { + fmt::print("[combo sn] {} and {}\n", b0->get_first_block_id(), b1->get_first_block_id()); + fmt::print("expanding sequence: {} (s {}) to include {}\n", b0_seq->to_string(), + b0_seq->get_first_block_id(), b1->get_first_block_id()); + } + if (b1->succ_ft) { + if (debug_asm_branch) { + fmt::print(" b1 succ_ft is {}\n", b1->succ_ft->to_string()); + } + assert(b1->succ_ft->has_pred(b1)); + } + replaced = true; + m_blocks.at(b0->succ_branch->get_first_block_id())->needs_label = true; + auto* seq = dynamic_cast(b0); + assert(seq); + + seq->seq.push_back(b1); + + if (b0->succ_branch) { + if (debug_asm_branch) { + fmt::print("succ {} has {} preds parent: {}\n", b0->succ_branch->get_first_block_id(), + b0->succ_branch->pred.size(), !!b0->succ_branch->parent); + } + b0->succ_branch->replace_preds_with_and_check({b0}, nullptr); + if (debug_asm_branch) { + fmt::print("OKOK\n"); + } + } + + for (auto* new_succ : b1->succs()) { + if (debug_asm_branch) { + fmt::print("fixing up succ {}\n", new_succ->to_string()); + } + new_succ->replace_pred_and_check(b1, b0); + } + + if (b1->succ_ft) { + assert(b1->succ_ft->has_pred(b0)); + } + + if (b1->succ_ft) { + assert(b1->succ_ft->has_pred(b0)); + } + + // try + + seq->succ_ft = b1->succ_ft; + seq->succ_branch = b1->succ_branch; + if (b1->succ_branch) { + assert(!b1->succ_branch->parent); + } + + if (seq->succ_branch && debug_asm_branch) { + fmt::print(" new sb: {}\n", seq->succ_branch->get_first_block_id()); + } + seq->next = b1->next; + if (seq->next) { + seq->next->prev = seq; + } + + b1->parent_claim(seq); + if (seq->succ_branch) { + assert(!seq->succ_branch->parent); + } + seq->end_branch = b1->end_branch; + return false; + } else if (b0_seq && b1_seq) { + if (debug_asm_branch) { + fmt::print("[combo ss] {} and {}\n", b0->get_first_block_id(), b1->get_first_block_id()); + fmt::print(" {} and {}\n", b0->to_string(), b1->to_string()); + } + + // printf("make seq type 3 %s %s\n", b0->to_string().c_str(), b1->to_string().c_str()); + replaced = true; + m_blocks.at(b0->succ_branch->get_first_block_id())->needs_label = true; + auto* seq = dynamic_cast(b0); + assert(seq); + + auto* old_seq = dynamic_cast(b1); + assert(old_seq); + + if (b0->succ_branch) { + if (debug_asm_branch) { + fmt::print(" sbp: {}\n", !!b0->succ_branch->parent); + fmt::print(" sb: {}\n", b0->succ_branch->to_string()); + } + b0->succ_branch->replace_preds_with_and_check({b0}, nullptr); + } + + for (auto* x : old_seq->seq) { + x->parent_claim(seq); + seq->seq.push_back(x); + } + + for (auto* x : old_seq->succs()) { + // printf("fix preds of %s\n", x->to_string().c_str()); + x->replace_pred_and_check(old_seq, seq); + } + seq->succ_branch = old_seq->succ_branch; + seq->succ_branch = b1->succ_branch; + if (seq->succ_branch && debug_asm_branch) { + fmt::print(" DS new sb: {}\n", seq->succ_branch->get_first_block_id()); + } + seq->succ_ft = old_seq->succ_ft; + seq->end_branch = old_seq->end_branch; + seq->next = old_seq->next; + if (seq->next) { + seq->next->prev = seq; + } + + // todo - proper trash? + old_seq->parent_claim(seq); + + return false; + } else { + lg::error("unhandled sequences in clean_up_asm_branches seq: {} {}", !!b0_seq, !!b1_seq); + } + } + + return true; // keep looking + }); + return replaced; +} + bool ControlFlowGraph::is_sequence_of_non_sequences(CfgVtx* b0, CfgVtx* b1, bool allow_self_loops) { if (!b0 || !b1) return false; @@ -1826,6 +2179,10 @@ bool ControlFlowGraph::find_short_circuits() { return true; } + if (vtx->end_branch.asm_branch) { + return true; + } + // set up the first entry: ShortCircuit::Entry candidate = {vtx, vtx->next}; CfgVtx* end = vtx->next->succ_branch; @@ -2085,13 +2442,49 @@ CfgVtx::DelaySlotKind get_delay_slot(const Instruction& i) { } } +namespace { +/*! + * Is this instruction possible in the delay slot, without using inline assembly? + */ +bool branch_delay_asm(const Instruction& i) { + if (is_nop(i)) { + // nop can be used as a delay + return false; + } else if (is_gpr_3(i, InstructionKind::OR, {}, Register(Reg::GPR, Reg::S7), + Register(Reg::GPR, Reg::R0))) { + // set false is used in ifs, etc + return false; + } else if (is_gpr_2_imm_int(i, InstructionKind::DADDIU, {}, Register(Reg::GPR, Reg::S7), 8)) { + // set true is used in sc + return false; + } else if (is_gpr_3(i, InstructionKind::OR, {}, {}, Register(Reg::GPR, Reg::R0))) { + // set var to var + return false; + } else if (is_gpr_3(i, InstructionKind::DSLLV, {}, {}, {})) { + // shift trick + return false; + } else if (is_gpr_3(i, InstructionKind::DSUBU, {}, Register(Reg::GPR, Reg::R0), {})) { + // abs trick + return false; + } else if (i.kind == InstructionKind::LW && + (i.get_src(0).is_sym("binteger") || i.get_src(0).is_sym("pair"))) { + // rtype trick + return false; + } else { + return true; + } +} +} // namespace + /*! * Build and resolve a Control Flow Graph as much as possible. */ -std::shared_ptr build_cfg(const LinkedObjectFile& file, - int seg, - Function& func, - const CondWithElseLengthHack& cond_with_else_hack) { +std::shared_ptr build_cfg( + const LinkedObjectFile& file, + int seg, + Function& func, + const CondWithElseLengthHack& cond_with_else_hack, + const std::unordered_set& blocks_ending_in_asm_br) { // fmt::print("START {}\n", func.guessed_name.to_string()); auto cfg = std::make_shared(); @@ -2105,8 +2498,6 @@ std::shared_ptr build_cfg(const LinkedObjectFile& file, cfg->exit()->pred.push_back(blocks.back()); blocks.back()->succ_ft = cfg->exit(); - // todo - early returns! - // set up succ / pred for (int i = 0; i < int(func.basic_blocks.size()); i++) { auto& b = func.basic_blocks[i]; @@ -2234,6 +2625,57 @@ std::shared_ptr build_cfg(const LinkedObjectFile& file, } } + for (int i = 0; i < int(func.basic_blocks.size()); i++) { + auto& bb = func.basic_blocks[i]; + auto& b = blocks.at(i); + + if (bb.end_word == bb.start_word) { + continue; // zero sized block, there is no branch here. + } + + if (blocks_ending_in_asm_br.find(i) != blocks_ending_in_asm_br.end()) { + b->end_branch.asm_branch = true; + if (debug_asm_branch) { + fmt::print("OVERRIDE asm branch at block {}\n", i); + } + continue; + } + + // room for at least a likely branch, try that first. + int likely_branch_idx = bb.end_word - 1; + assert(likely_branch_idx >= bb.start_word); + auto& likely_branch_candidate = func.instructions.at(likely_branch_idx); + + if (is_branch(likely_branch_candidate, true)) { + // likely branch! + auto following = func.instructions.at(likely_branch_idx + 1); + if (branch_delay_asm(following)) { + b->end_branch.asm_branch = true; + if (debug_asm_branch) { + fmt::print("LIKELY ASM BRANCH: {} and {}\n", + likely_branch_candidate.to_string(file.labels), + following.to_string(file.labels)); + } + } + } + + if (bb.end_word - bb.start_word >= 2) { + int idx = bb.end_word - 2; + assert(idx >= bb.start_word); + auto& branch_candidate = func.instructions.at(idx); + auto& delay_slot_candidate = func.instructions.at(idx + 1); + if (is_branch(branch_candidate, false)) { + if (branch_delay_asm(delay_slot_candidate)) { + b->end_branch.asm_branch = true; + if (debug_asm_branch) { + fmt::print("NORMAL ASM BRANCH: {} and {}\n", branch_candidate.to_string(file.labels), + delay_slot_candidate.to_string(file.labels)); + } + } + } + } + } + cfg->flag_early_exit(func.basic_blocks); bool changed = true; @@ -2272,6 +2714,10 @@ std::shared_ptr build_cfg(const LinkedObjectFile& file, changed = changed || cfg->find_cond_w_empty_else(); } + if (!changed) { + changed = changed || cfg->clean_up_asm_branches(); + } + if (!changed) { changed = changed || cfg->find_infinite_continue(); if (changed && !complained_about_weird_gotos) { diff --git a/decompiler/Function/CfgVtx.h b/decompiler/Function/CfgVtx.h index 8e3ac8b3c2..12064a1975 100644 --- a/decompiler/Function/CfgVtx.h +++ b/decompiler/Function/CfgVtx.h @@ -86,6 +86,7 @@ class CfgVtx { bool has_branch = false; // does the block end in a branch (any kind)? bool branch_likely = false; // does the block end in a likely branch? bool branch_always = false; // does the branch always get taken? + bool asm_branch = false; // is this an inline assembly branch? DelaySlotKind kind = DelaySlotKind::NO_BRANCH; } end_branch; @@ -331,6 +332,7 @@ class ControlFlowGraph { bool find_goto_end(); bool find_infinite_loop(); bool find_goto_not_end(); + bool clean_up_asm_branches(); /*! * Apply a function f to each top-level vertex. @@ -387,6 +389,7 @@ class Function; std::shared_ptr build_cfg(const LinkedObjectFile& file, int seg, Function& func, - const CondWithElseLengthHack& cond_with_else_hack); + const CondWithElseLengthHack& cond_with_else_hack, + const std::unordered_set& blocks_ending_in_asm_br); } // namespace decompiler #endif // JAK_DISASSEMBLER_CFGVTX_H diff --git a/decompiler/IR2/AtomicOp.cpp b/decompiler/IR2/AtomicOp.cpp index 626b10132c..fbfb1b508b 100644 --- a/decompiler/IR2/AtomicOp.cpp +++ b/decompiler/IR2/AtomicOp.cpp @@ -300,6 +300,8 @@ std::string get_simple_expression_op_name(SimpleExpression::Kind kind) { return "vector-float*!2"; case SimpleExpression::Kind::SUBU_L32_S7: return "subu-s7"; + case SimpleExpression::Kind::VECTOR_3_DOT: + return "vec3dot"; default: assert(false); return {}; @@ -357,6 +359,8 @@ int get_simple_expression_arg_count(SimpleExpression::Kind kind) { return 3; case SimpleExpression::Kind::SUBU_L32_S7: return 1; + case SimpleExpression::Kind::VECTOR_3_DOT: + return 2; default: assert(false); return -1; @@ -1370,6 +1374,17 @@ void BranchOp::collect_vars(RegAccessSet& vars) const { // AsmBranchOp ///////////////////////////// +AsmBranchOp::AsmBranchOp(bool likely, + IR2_Condition condition, + int label, + AtomicOp* branch_delay, + int my_idx) + : AtomicOp(my_idx), + m_likely(likely), + m_condition(std::move(condition)), + m_label(label), + m_branch_delay(branch_delay) {} + AsmBranchOp::AsmBranchOp(bool likely, IR2_Condition condition, int label, @@ -1379,7 +1394,9 @@ AsmBranchOp::AsmBranchOp(bool likely, m_likely(likely), m_condition(std::move(condition)), m_label(label), - m_branch_delay(std::move(branch_delay)) {} + m_branch_delay_sp(branch_delay) { + m_branch_delay = m_branch_delay_sp.get(); +} goos::Object AsmBranchOp::to_form(const std::vector& labels, const Env& env) const { @@ -1393,7 +1410,10 @@ goos::Object AsmBranchOp::to_form(const std::vector& labels, forms.push_back(m_condition.to_form(labels, env)); forms.push_back(pretty_print::to_symbol(labels.at(m_label).name)); - forms.push_back(m_branch_delay->to_form(labels, env)); + + if (m_branch_delay) { + forms.push_back(m_branch_delay->to_form(labels, env)); + } return pretty_print::build_list(forms); } @@ -1419,23 +1439,28 @@ RegisterAccess AsmBranchOp::get_set_destination() const { void AsmBranchOp::update_register_info() { m_condition.get_regs(&m_read_regs); - m_branch_delay->update_register_info(); - for (auto x : m_branch_delay->read_regs()) { - m_read_regs.push_back(x); - } + if (m_branch_delay) { + m_branch_delay->update_register_info(); - for (auto x : m_branch_delay->write_regs()) { - m_write_regs.push_back(x); - } + for (auto x : m_branch_delay->read_regs()) { + m_read_regs.push_back(x); + } - for (auto x : m_branch_delay->clobber_regs()) { - m_clobber_regs.push_back(x); + for (auto x : m_branch_delay->write_regs()) { + m_write_regs.push_back(x); + } + + for (auto x : m_branch_delay->clobber_regs()) { + m_clobber_regs.push_back(x); + } } } void AsmBranchOp::collect_vars(RegAccessSet& vars) const { m_condition.collect_vars(vars); - m_branch_delay->collect_vars(vars); + if (m_branch_delay) { + m_branch_delay->collect_vars(vars); + } } ///////////////////////////// @@ -1489,9 +1514,9 @@ void SpecialOp::update_register_info() { return; case Kind::SUSPEND: // todo - confirm this is true. - // the suspend operation is written in a way where it doesn't use temporaries to make the call - // but the actual suspend operation doesn't seem to preserve temporaries. Maybe the plan was - // to save temp registers at some point, but they later gave up on this? + // the suspend operation is written in a way where it doesn't use temporaries to make the + // call but the actual suspend operation doesn't seem to preserve temporaries. Maybe the + // plan was to save temp registers at some point, but they later gave up on this? clobber_temps(); return; default: @@ -1540,11 +1565,12 @@ RegisterAccess CallOp::get_set_destination() const { } void CallOp::update_register_info() { - // throw std::runtime_error("CallOp::update_register_info cannot be done until types are known"); + // throw std::runtime_error("CallOp::update_register_info cannot be done until types are + // known"); m_read_regs.push_back(Register(Reg::GPR, Reg::T9)); - // previously, if the type analysis succeeds, it would remove this if the function doesn't return - // a value. however, this turned out to be not quite right because GOAL internally thinks that all - // functions return a value. + // previously, if the type analysis succeeds, it would remove this if the function doesn't + // return a value. however, this turned out to be not quite right because GOAL internally thinks + // that all functions return a value. m_write_regs.push_back(Register(Reg::GPR, Reg::V0)); clobber_temps(); } diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index a93a8fd916..ff777be427 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -227,6 +227,7 @@ class SimpleExpression { VECTOR_MINUS, VECTOR_FLOAT_PRODUCT, SUBU_L32_S7, // use SUBU X, src0, s7 to check if lower 32-bits are s7. + VECTOR_3_DOT, }; // how many arguments? @@ -559,6 +560,7 @@ class BranchOp : public AtomicOp { const IR2_Condition& condition() const { return m_condition; } ConditionElement* get_condition_as_form(FormPool& pool, const Env& env) const; bool likely() const { return m_likely; } + int label_id() const { return m_label; } private: bool m_likely = false; @@ -572,11 +574,14 @@ class BranchOp : public AtomicOp { */ class AsmBranchOp : public AtomicOp { public: + AsmBranchOp(bool likely, IR2_Condition condition, int label, AtomicOp* branch_delay, int my_idx); + AsmBranchOp(bool likely, IR2_Condition condition, int label, std::shared_ptr branch_delay, 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; @@ -587,12 +592,17 @@ class AsmBranchOp : public AtomicOp { const Env& env, DecompilerTypeSystem& dts) override; void collect_vars(RegAccessSet& vars) const override; + bool is_likely() const { return m_likely; } + const IR2_Condition& condition() const { return m_condition; } + int label_id() const { return m_label; } + AtomicOp* branch_delay() { return m_branch_delay; } private: bool m_likely = false; IR2_Condition m_condition; int m_label = -1; - std::shared_ptr m_branch_delay; + AtomicOp* m_branch_delay; + std::shared_ptr m_branch_delay_sp; }; /*! diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index 2a80fccd4d..577a3fc8ec 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -728,7 +728,7 @@ FormElement* BranchOp::get_as_form(FormPool& pool, const Env&) const { } FormElement* SpecialOp::get_as_form(FormPool& pool, const Env&) const { - return pool.alloc_element(this); + return pool.alloc_element(const_cast(this)); } FormElement* CallOp::get_as_form(FormPool& pool, const Env& env) const { @@ -764,11 +764,18 @@ FormElement* ConditionalMoveFalseOp::get_as_form(FormPool& pool, const Env&) con } FormElement* FunctionEndOp::get_as_form(FormPool& pool, const Env&) const { - return pool.alloc_element(this); + return pool.alloc_element(const_cast(this)); } -FormElement* AsmBranchOp::get_as_form(FormPool& pool, const Env&) const { - return pool.alloc_element(this); +FormElement* AsmBranchOp::get_as_form(FormPool& pool, const Env& env) const { + if (m_branch_delay) { + auto delay = m_branch_delay->get_as_form(pool, env); + auto delay_form = pool.alloc_single_form(nullptr, delay); + return pool.alloc_element(const_cast(this), delay_form, + m_likely); + } else { + return pool.alloc_element(const_cast(this)); + } } FormElement* StackSpillLoadOp::get_as_form(FormPool& pool, const Env& env) const { diff --git a/decompiler/IR2/AtomicOpTypeAnalysis.cpp b/decompiler/IR2/AtomicOpTypeAnalysis.cpp index ece5f5086e..72c22fb753 100644 --- a/decompiler/IR2/AtomicOpTypeAnalysis.cpp +++ b/decompiler/IR2/AtomicOpTypeAnalysis.cpp @@ -202,6 +202,8 @@ TP_Type SimpleExpression::get_type(const TypeState& input, return TP_Type::make_from_ts("vector"); case Kind::SUBU_L32_S7: return TP_Type::make_from_ts("int"); + case Kind::VECTOR_3_DOT: + return TP_Type::make_from_ts("float"); default: throw std::runtime_error("Simple expression cannot get_type: " + to_form(env.file->labels, env).print()); @@ -491,10 +493,31 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input, rd_in.stride = arg1_type.get_multiplier(); rd_in.offset = 0; rd_in.base_type = arg0_type.typespec(); - auto rd = dts.ts.reverse_field_lookup(rd_in); + auto rd = dts.ts.reverse_field_multi_lookup(rd_in); - if (rd.success) { - return TP_Type::make_from_ts(coerce_to_reg_type(rd.result_type)); + for (int i = 0; i < (int)rd.results.size(); i++) { + if (rd.results.at(i).has_variable_token()) { + return TP_Type::make_from_ts(coerce_to_reg_type(rd.results.at(i).result_type)); + break; + } + } + } + + if (m_kind == Kind::ADD && arg1_type.kind == TP_Type::Kind::TYPESPEC && + arg1_type.typespec().base_type() == "inline-array" && + arg0_type.kind == TP_Type::Kind::PRODUCT_WITH_CONSTANT) { + FieldReverseLookupInput rd_in; + rd_in.deref = std::nullopt; + rd_in.stride = arg0_type.get_multiplier(); + rd_in.offset = 0; + rd_in.base_type = arg1_type.typespec(); + auto rd = dts.ts.reverse_field_multi_lookup(rd_in); + + for (int i = 0; i < (int)rd.results.size(); i++) { + if (rd.results.at(i).has_variable_token()) { + return TP_Type::make_from_ts(coerce_to_reg_type(rd.results.at(i).result_type)); + break; + } } } @@ -558,6 +581,20 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input, return TP_Type::make_from_ts(TypeSpec("int")); } + if (m_kind == Kind::RIGHT_SHIFT_LOGIC && arg0_type.typespec() == TypeSpec("float") && + arg1_type.is_integer_constant(63)) { + // + return TP_Type::make_from_ts(TypeSpec("int")); + } + + if (m_kind == Kind::OR && arg0_type.typespec() == TypeSpec("float") && + arg1_type.typespec() == TypeSpec("float")) { + env.func->warnings.general_warning("Using logior on floats"); + // returning int instead of uint because they like to use the float sign bit as an integer sign + // bit. + return TP_Type::make_from_ts(TypeSpec("float")); + } + throw std::runtime_error(fmt::format("Cannot get_type_int2: {}, args {} and {}", to_form(env.file->labels, env).print(), arg0_type.print(), arg1_type.print())); @@ -1149,7 +1186,9 @@ TypeState AsmBranchOp::propagate_types_internal(const TypeState& input, // for now, just make everything uint TypeState output = input; for (auto x : m_write_regs) { - output.get(x) = TP_Type::make_from_ts("uint"); + if (x.allowed_local_gpr()) { + output.get(x) = TP_Type::make_from_ts("uint"); + } } return output; } diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index 195003703b..b5959f974d 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -33,7 +33,8 @@ std::string FormElement::to_string(const Env& env) const { } void FormElement::push_to_stack(const Env& env, FormPool&, FormStack&) { - throw std::runtime_error("push_to_stack not implemented for " + to_string(env)); + throw std::runtime_error(fmt::format("push_to_stack not implemented for {}: {}", to_string(env), + typeid(*this).name())); } goos::Object FormElement::to_form_as_condition_internal(const Env& env) const { @@ -494,7 +495,7 @@ void SetFormFormElement::get_modified_regs(RegSet& regs) const { // AtomicOpElement ///////////////////////////// -AtomicOpElement::AtomicOpElement(const AtomicOp* op) : m_op(op) {} +AtomicOpElement::AtomicOpElement(AtomicOp* op) : m_op(op) {} goos::Object AtomicOpElement::to_form_internal(const Env& env) const { return m_op->to_form(env.file->labels, env); @@ -520,6 +521,137 @@ void AtomicOpElement::get_modified_regs(RegSet& regs) const { } } +///////////////////////////// +// AsmBranchElement +///////////////////////////// + +AsmBranchElement::AsmBranchElement(AsmBranchOp* branch_op, Form* branch_delay, bool likely) + : m_branch_op(branch_op), m_branch_delay(branch_delay), m_likely(likely) { + m_branch_delay->parent_element = this; +} + +goos::Object AsmBranchElement::to_form_internal(const Env& env) const { + auto f = m_branch_op->to_form(env.file->labels, env); + return pretty_print::build_list(f, m_branch_delay->to_form(env)); // temp hack +} + +void AsmBranchElement::apply(const std::function& f) { + f(this); + m_branch_delay->apply(f); +} + +void AsmBranchElement::apply_form(const std::function& f) { + m_branch_delay->apply_form(f); +} + +void AsmBranchElement::collect_vars(RegAccessSet& vars, bool recursive) const { + if (recursive) { + m_branch_delay->collect_vars(vars, recursive); + } + m_branch_op->collect_vars(vars); +} + +void AsmBranchElement::get_modified_regs(RegSet& regs) const { + m_branch_delay->get_modified_regs(regs); + for (auto r : m_branch_op->write_regs()) { + regs.insert(r); + } + + for (auto r : m_branch_op->clobber_regs()) { + regs.insert(r); + } +} + +///////////////////////////// +// TranslatedAsmBranch +///////////////////////////// + +TranslatedAsmBranch::TranslatedAsmBranch(Form* branch_condition, + Form* branch_delay, + int label_id, + bool likely) + : m_branch_condition(branch_condition), + m_branch_delay(branch_delay), + m_label_id(label_id), + m_likely(likely) { + if (m_branch_delay) { + m_branch_delay->parent_element = this; + } + + m_branch_condition->parent_element = this; +} + +goos::Object TranslatedAsmBranch::to_form_internal(const Env& env) const { + // auto& cfg = env.func->cfg; + auto& label = env.file->labels.at(m_label_id); + int instr_in_function = (label.offset / 4 - env.func->start_word); + + int block_id = -20; + if (instr_in_function == env.func->basic_blocks.back().end_word) { + block_id = env.func->basic_blocks.size() - 1; + } else { + int atomic_op_in_function = + env.func->ir2.atomic_ops->instruction_to_atomic_op.at(instr_in_function); + auto& ao = env.func->ir2.atomic_ops; + + for (int i = 0; i < (int)ao->block_id_to_first_atomic_op.size(); i++) { + if (ao->block_id_to_first_atomic_op.at(i) == atomic_op_in_function) { + block_id = i; + break; + } + } + } + + assert(block_id >= 0); + + if (m_branch_delay) { + std::vector list = { + pretty_print::to_symbol("b!"), m_branch_condition->to_form(env), + pretty_print::to_symbol(fmt::format("cfg-{}", block_id)), + pretty_print::to_symbol(m_likely ? ":likely-delay" : ":delay"), + m_branch_delay->to_form(env)}; + + return pretty_print::build_list(list); + } else { + std::vector list = {pretty_print::to_symbol("b!"), + m_branch_condition->to_form(env), + pretty_print::to_symbol(fmt::format("cfg-{}", block_id))}; + + return pretty_print::build_list(list); + } +} + +void TranslatedAsmBranch::apply(const std::function& f) { + f(this); + m_branch_condition->apply(f); + if (m_branch_delay) { + m_branch_delay->apply(f); + } +} + +void TranslatedAsmBranch::apply_form(const std::function& f) { + m_branch_condition->apply_form(f); + if (m_branch_delay) { + m_branch_delay->apply_form(f); + } +} + +void TranslatedAsmBranch::collect_vars(RegAccessSet& vars, bool recursive) const { + if (recursive) { + m_branch_condition->collect_vars(vars, recursive); + if (m_branch_delay) { + m_branch_delay->collect_vars(vars, recursive); + } + } +} + +void TranslatedAsmBranch::get_modified_regs(RegSet& regs) const { + m_branch_condition->get_modified_regs(regs); + if (m_branch_delay) { + m_branch_delay->get_modified_regs(regs); + } +} + ///////////////////////////// // AsmOpElement ///////////////////////////// @@ -1550,6 +1682,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) { return "vector-float*!"; case FixedOperatorKind::L32_NOT_FALSE_CBOOL: return "l32-false-check"; + case FixedOperatorKind::VECTOR_3_DOT: + return "vector-dot"; default: assert(false); return ""; diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 27695eb2f1..825be58966 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -207,6 +207,11 @@ class SimpleExpressionElement : public FormElement { FormStack& stack, std::vector* result, bool allow_side_effects); + void update_from_stack_vector_3_dot(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects); const SimpleExpression& expr() const { return m_expr; } @@ -408,7 +413,7 @@ class SetFormFormElement : public FormElement { */ class AtomicOpElement : public FormElement { public: - explicit AtomicOpElement(const AtomicOp* op); + explicit AtomicOpElement(AtomicOp* op); 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; @@ -416,9 +421,43 @@ class AtomicOpElement : public FormElement { void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; void get_modified_regs(RegSet& regs) const override; const AtomicOp* op() const { return m_op; } + AtomicOp* op() { return m_op; } private: - const AtomicOp* m_op; + AtomicOp* m_op = nullptr; // not const because of asm likely merging +}; + +class AsmBranchElement : public FormElement { + public: + AsmBranchElement(AsmBranchOp* branch_op, Form* branch_delay, bool likely); + 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 push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; + void get_modified_regs(RegSet& regs) const override; + + private: + AsmBranchOp* m_branch_op = nullptr; + Form* m_branch_delay = nullptr; + bool m_likely = false; +}; + +class TranslatedAsmBranch : public FormElement { + public: + TranslatedAsmBranch(Form* branch_condition, Form* branch_delay, int label_id, bool likely); + 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 push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; + void get_modified_regs(RegSet& regs) const override; + + private: + Form* m_branch_condition = nullptr; + Form* m_branch_delay = nullptr; + int m_label_id = -1; + bool m_likely = false; }; /*! @@ -559,6 +598,7 @@ class BranchElement : public FormElement { 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; const BranchOp* op() const { return m_op; } private: diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 4fa712e680..ae0b889f48 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -789,9 +789,19 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env, rd_in.stride = arg1_type.get_multiplier(); rd_in.offset = 0; rd_in.base_type = arg0_type.typespec(); - auto rd = env.dts->ts.reverse_field_lookup(rd_in); + auto rd = env.dts->ts.reverse_field_multi_lookup(rd_in); + int idx_of_success = -1; + if (rd.success) { + for (int i = 0; i < (int)rd.results.size(); i++) { + if (rd.results.at(i).has_variable_token()) { + idx_of_success = i; + break; + } + } + } - if (rd.success && rd.has_variable_token()) { + if (idx_of_success >= 0) { + auto& rd_ok = rd.results.at(idx_of_success); auto arg1_matcher = Matcher::match_or( {Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::MULTIPLICATION), {Matcher::any(0), Matcher::integer(rd_in.stride)}), @@ -801,7 +811,7 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env, if (match_result.matched) { bool used_index = false; std::vector tokens; - for (auto& tok : rd.tokens) { + for (auto& tok : rd_ok.tokens) { if (tok.kind == FieldReverseLookupOutput::Token::Kind::VAR_IDX) { assert(!used_index); used_index = true; @@ -811,7 +821,55 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env, } } assert(used_index); - result->push_back(pool.alloc_element(args.at(0), rd.addr_of, tokens)); + result->push_back(pool.alloc_element(args.at(0), rd_ok.addr_of, tokens)); + return; + } else { + throw std::runtime_error("Failed to match product_with_constant inline array access."); + } + } + } else if (arg0_type.kind == TP_Type::Kind::PRODUCT_WITH_CONSTANT && + arg1_type.kind == TP_Type::Kind::TYPESPEC && + arg1_type.typespec().base_type() == "inline-array") { + FieldReverseLookupInput rd_in; + rd_in.deref = std::nullopt; + rd_in.stride = arg0_type.get_multiplier(); + rd_in.offset = 0; + rd_in.base_type = arg1_type.typespec(); + auto rd = env.dts->ts.reverse_field_multi_lookup(rd_in); + int idx_of_success = -1; + if (rd.success) { + for (int i = 0; i < (int)rd.results.size(); i++) { + if (rd.results.at(i).has_variable_token()) { + idx_of_success = i; + break; + } + } + } + // fmt::print("here {} {} {}\n", rd_in.base_type.print(), rd.success, + // rd.has_variable_token()); + + if (idx_of_success >= 0) { + auto& rd_ok = rd.results.at(idx_of_success); + auto arg0_matcher = Matcher::match_or( + {Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::MULTIPLICATION), + {Matcher::any(0), Matcher::integer(rd_in.stride)}), + Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::MULTIPLICATION), + {Matcher::integer(rd_in.stride), Matcher::any(0)})}); + auto match_result = match(arg0_matcher, args.at(0)); + if (match_result.matched) { + bool used_index = false; + std::vector tokens; + for (auto& tok : rd_ok.tokens) { + if (tok.kind == FieldReverseLookupOutput::Token::Kind::VAR_IDX) { + assert(!used_index); + used_index = true; + tokens.push_back(DerefToken::make_int_expr(match_result.maps.forms.at(0))); + } else { + tokens.push_back(to_token(tok)); + } + } + assert(used_index); + result->push_back(pool.alloc_element(args.at(1), rd_ok.addr_of, tokens)); return; } else { throw std::runtime_error("Failed to match product_with_constant inline array access."); @@ -1032,6 +1090,27 @@ void SimpleExpressionElement::update_from_stack_vector_float_product( result->push_back(new_form); } +void SimpleExpressionElement::update_from_stack_vector_3_dot(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) { + std::vector popped_args = pop_to_forms({m_expr.get_arg(0).var(), m_expr.get_arg(1).var()}, + env, pool, stack, allow_side_effects); + + for (int i = 0; i < 2; i++) { + auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg()); + if (arg_type.typespec() != TypeSpec("vector")) { + popped_args.at(i) = cast_form(popped_args.at(i), TypeSpec("vector"), pool, env); + } + } + + auto new_form = pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::VECTOR_3_DOT), + std::vector{popped_args.at(0), popped_args.at(1)}); + result->push_back(new_form); +} + void SimpleExpressionElement::update_from_stack_copy_first_int_2(const Env& env, FixedOperatorKind kind, FormPool& pool, @@ -1675,6 +1754,9 @@ void SimpleExpressionElement::update_from_stack(const Env& env, case SimpleExpression::Kind::SUBU_L32_S7: update_from_stack_subu_l32_s7(env, pool, stack, result, allow_side_effects); break; + case SimpleExpression::Kind::VECTOR_3_DOT: + update_from_stack_vector_3_dot(env, pool, stack, result, allow_side_effects); + break; default: throw std::runtime_error( fmt::format("SimpleExpressionElement::update_from_stack NYI for {}", to_string(env))); @@ -3239,6 +3321,13 @@ FormElement* ConditionElement::make_generic(const Env& env, casted); } + case IR2_Condition::Kind::FLOAT_GREATER_THAN: { + // never emitted by normal branch conditions + auto casted = make_casts_if_needed(source_forms, types, TypeSpec("float"), pool, env); + return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::GT), + casted); + } + default: throw std::runtime_error("ConditionElement::make_generic NYI for kind " + get_condition_kind_name(m_kind)); @@ -3317,7 +3406,11 @@ void ConditionElement::update_from_stack(const Env& env, } else { source_types.push_back(TypeSpec("int")); } - } else { + } else if (m_src[i]->is_sym_val() && m_src[i]->get_str() == "#f") { + source_types.push_back(TypeSpec("symbol")); + } + + else { throw std::runtime_error("Unsupported atom in ConditionElement::update_from_stack"); } } @@ -3604,6 +3697,18 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& s return; } + auto as_branch = dynamic_cast(m_op); + if (as_branch && !as_branch->is_likely()) { + // this is a bit of a hack, but we go AsmBranchOp -> AsmBranchElement -> TranslatedAsmBranch + auto delay = as_branch->branch_delay(); + assert(delay); + // this might not be enough - we may need to back up to the cfg builder and do something there. + auto del = pool.alloc_single_element_form(nullptr, delay); + auto be = pool.alloc_element(as_branch, del, false); + be->push_to_stack(env, pool, stack); + return; + } + throw std::runtime_error("Cannot push atomic op to stack: " + m_op->to_string(env)); } @@ -3626,6 +3731,77 @@ void GenericElement::update_from_stack(const Env& env, result->push_back(this); } +void AsmBranchElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + // create a condition element + RegSet consumed; + if (env.has_reg_use()) { + consumed = env.reg_use().op.at(m_branch_op->op_id()).consumes; + } + std::optional vars[2]; + for (int i = 0; i < get_condition_num_args(m_branch_op->condition().kind()); i++) { + vars[i] = m_branch_op->condition().src(i); + } + auto ce = pool.alloc_element(m_branch_op->condition().kind(), vars[0], vars[1], + consumed, false); + + // and update it from the stack. + std::vector ce_updated; + ce->update_from_stack(env, pool, stack, &ce_updated, true); + + auto branch_condition = pool.alloc_sequence_form(nullptr, ce_updated); + + auto op = pool.alloc_element( + branch_condition, m_branch_delay, m_branch_op->label_id(), m_branch_op->is_likely()); + // fmt::print("rewrote as {}\n", op->to_string(env)); + stack.push_form_element(op, true); +} + +void BranchElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + // These will appear if we have an asm-branch that looked like a normal branch. + // create a condition element + RegSet consumed; + if (env.has_reg_use()) { + consumed = env.reg_use().op.at(m_op->op_id()).consumes; + } + std::optional vars[2]; + for (int i = 0; i < get_condition_num_args(m_op->condition().kind()); i++) { + vars[i] = m_op->condition().src(i); + } + auto ce = pool.alloc_element(m_op->condition().kind(), vars[0], vars[1], + consumed, false); + + // and update it from the stack. + std::vector ce_updated; + ce->update_from_stack(env, pool, stack, &ce_updated, true); + + auto branch_condition = pool.alloc_sequence_form(nullptr, ce_updated); + + Form* branch_delay = nullptr; + switch (m_op->branch_delay().kind()) { + case IR2_BranchDelay::Kind::NOP: { + branch_delay = nullptr; + } break; + case IR2_BranchDelay::Kind::SET_REG_REG: { + auto src = m_op->branch_delay().var(1); + auto dst = m_op->branch_delay().var(0); + + auto src_form = + pool.alloc_single_element_form(nullptr, SimpleAtom::make_var(src)); + + branch_delay = pool.alloc_single_element_form( + nullptr, dst, src_form, true, env.get_variable_type(src, true)); + } break; + default: + throw std::runtime_error("Unhandled branch delay in BranchElement::push_to_stack: " + + m_op->to_string(env)); + } + + auto op = pool.alloc_element(branch_condition, branch_delay, + m_op->label_id(), m_op->likely()); + // fmt::print("rewrote (non-asm) as {}\n", op->to_string(env)); + stack.push_form_element(op, true); +} + void GenericElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { (void)env; (void)pool; @@ -3643,7 +3819,8 @@ void DynamicMethodAccess::update_from_stack(const Env& env, std::vector* result, bool allow_side_effects) { mark_popped(); - auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects); + // auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects); + auto new_val = pop_to_forms({m_source}, env, pool, stack, allow_side_effects).at(0); auto reg0_matcher = Matcher::match_or({Matcher::any_reg(0), Matcher::cast("uint", Matcher::any_reg(0))}); auto reg1_matcher = @@ -3740,6 +3917,8 @@ void ArrayFieldAccess::update_with_val(Form* new_val, Matcher::fixed_op(FixedOperatorKind::ADDITION_PTR, {mult_matcher, reg0_matcher})}); match_result = match(matcher, new_val); if (!match_result.matched) { + result->push_back(this); + return; fmt::print("power {}\n", power_of_two); throw std::runtime_error( "Couldn't match ArrayFieldAccess (stride power of 2, 0 offset) values: " + @@ -3875,7 +4054,7 @@ void ArrayFieldAccess::update_from_stack(const Env& env, std::vector* result, bool allow_side_effects) { mark_popped(); - auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects); + auto new_val = pop_to_forms({m_source}, env, pool, stack, allow_side_effects).at(0); update_with_val(new_val, env, pool, result, allow_side_effects); } diff --git a/decompiler/IR2/IR2_common.h b/decompiler/IR2/IR2_common.h index a670d554a2..6a302a927c 100644 --- a/decompiler/IR2/IR2_common.h +++ b/decompiler/IR2/IR2_common.h @@ -152,6 +152,7 @@ enum class FixedOperatorKind { VECTOR_MINUS, VECTOR_FLOAT_PRODUCT, L32_NOT_FALSE_CBOOL, + VECTOR_3_DOT, INVALID }; diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index e9fcdfb2ce..ab6782faa1 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -733,7 +733,7 @@ void ObjectFileDB::analyze_functions_ir1(const Config& config) { // run analysis // build a control flow graph, just looking at branch instructions. - func.cfg = build_cfg(data.linked_data, segment_id, func, {}); + func.cfg = build_cfg(data.linked_data, segment_id, func, {}, {}); // convert individual basic blocks to sequences of IR Basic Ops for (auto& block : func.basic_blocks) { diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index 49b7eb766a..01280eb11d 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -219,7 +219,15 @@ void ObjectFileDB::ir2_basic_block_pass(const Config& config) { if (lookup != config.hacks.cond_with_else_len_by_func_name.end()) { hack = lookup->second; } - func.cfg = build_cfg(data.linked_data, segment_id, func, hack); + + std::unordered_set asm_br_blocks; + auto asm_lookup = + config.hacks.blocks_ending_in_asm_branch_by_func_name.find(func.guessed_name.to_string()); + if (asm_lookup != config.hacks.blocks_ending_in_asm_branch_by_func_name.end()) { + asm_br_blocks = asm_lookup->second; + } + + func.cfg = build_cfg(data.linked_data, segment_id, func, hack, asm_br_blocks); if (!func.cfg->is_fully_resolved()) { lg::warn("Function {} from {} failed to build control flow graph!", func.guessed_name.to_string(), data.to_unique_name()); diff --git a/decompiler/analysis/atomic_op_builder.cpp b/decompiler/analysis/atomic_op_builder.cpp index 3ebcad4490..b8802092c2 100644 --- a/decompiler/analysis/atomic_op_builder.cpp +++ b/decompiler/analysis/atomic_op_builder.cpp @@ -299,6 +299,8 @@ std::unique_ptr make_asm_op(const Instruction& i0, int idx) { case InstructionKind::MULAS: case InstructionKind::MADDAS: case InstructionKind::MADDS: + case InstructionKind::MSUBAS: + case InstructionKind::MSUBS: case InstructionKind::ADDAS: // Moves / Loads / Stores @@ -361,6 +363,14 @@ std::unique_ptr make_asm_op(const Instruction& i0, int idx) { } } +std::unique_ptr convert_1_allow_asm(const Instruction& i0, int idx) { + auto as_normal = convert_1(i0, idx, false); + if (as_normal) { + return as_normal; + } + return make_asm_op(i0, idx); +} + //////////////////////// // Branch Helpers //////////////////////// @@ -407,7 +417,11 @@ std::unique_ptr make_branch(const IR2_Condition& condition, if (branch_delay.is_known()) { return std::make_unique(likely, condition, dest_label, branch_delay, my_idx); } else { - auto delay_op = std::shared_ptr(convert_1(delay, my_idx, false)); + auto delay_op = std::shared_ptr(convert_1_allow_asm(delay, my_idx)); + if (!delay_op) { + throw std::runtime_error( + fmt::format("Failed to convert branch delay slot instruction for branch at {}", my_idx)); + } return std::make_unique(likely, condition, dest_label, delay_op, my_idx); } } @@ -421,6 +435,14 @@ std::unique_ptr make_branch_no_delay(const IR2_Condition& condition, return std::make_unique(likely, condition, dest_label, delay, my_idx); } +std::unique_ptr make_asm_branch_no_delay(const IR2_Condition& condition, + bool likely, + int dest_label, + int my_idx) { + assert(likely); + return std::make_unique(likely, condition, dest_label, nullptr, my_idx); +} + /////////////////////// // OP 1 Conversions ////////////////////// @@ -880,6 +902,23 @@ std::unique_ptr convert_1(const Instruction& i0, int idx, bool hint_in // OP 2 Conversions ////////////////////// +std::unique_ptr convert_fp_branch_asm(const Instruction& i0, + const Instruction& i1, + IR2_Condition::Kind kind, + int idx) { + if (i1.kind == InstructionKind::BC1TL || i1.kind == InstructionKind::BC1FL) { + IR2_Condition condition(kind, make_src_atom(i0.get_src(0).get_reg(), idx), + make_src_atom(i0.get_src(1).get_reg(), idx)); + if (i1.kind == InstructionKind::BC1FL) { + condition.invert(); + } + // return make_branch(condition, i2, false, i1.get_src(0).get_label(), idx); + return make_asm_branch_no_delay(condition, true, i1.get_src(0).get_label(), idx); + } + + return nullptr; +} + std::unique_ptr convert_division_2(const Instruction& i0, const Instruction& i1, int idx, @@ -1071,6 +1110,8 @@ std::unique_ptr convert_2(const Instruction& i0, const Instruction& i1 return convert_slt_2(i0, i1, idx, true); case InstructionKind::SLTU: return convert_slt_2(i0, i1, idx, false); + case InstructionKind::CLTS: + return convert_fp_branch_asm(i0, i1, IR2_Condition::Kind::FLOAT_LESS_THAN, idx); default: return nullptr; } @@ -1605,6 +1646,98 @@ std::unique_ptr convert_6(const Instruction& i0, return nullptr; } +bool is_lwc(const Instruction& instr, int offset) { + return instr.kind == InstructionKind::LWC1 && instr.get_src(0).is_imm(offset); +} + +// 9 instructions +std::unique_ptr convert_vector3_dot(const Instruction* instrs, int idx) { + // lwc1 f0, 0(a0) + if (!is_lwc(instrs[0], 0)) { + return nullptr; + } + auto t0 = instrs[0].get_dst(0).get_reg(); + + // lwc1 f1, 4(a0) + if (!is_lwc(instrs[1], 4)) { + return nullptr; + } + auto t1 = instrs[1].get_dst(0).get_reg(); + + // lwc1 f2, 8(a0) + if (!is_lwc(instrs[2], 8)) { + return nullptr; + } + auto t2 = instrs[2].get_dst(0).get_reg(); + + // lwc1 f3, 0(v1) + if (!is_lwc(instrs[3], 0)) { + return nullptr; + } + auto t3 = instrs[3].get_dst(0).get_reg(); + + // lwc1 f4, 4(v1) + if (!is_lwc(instrs[4], 4)) { + return nullptr; + } + auto t4 = instrs[4].get_dst(0).get_reg(); + + // lwc1 f5, 8(v1) + if (!is_lwc(instrs[5], 8)) { + return nullptr; + } + auto t5 = instrs[5].get_dst(0).get_reg(); + + auto src0 = instrs[0].get_src(1).get_reg(); + auto src1 = instrs[3].get_src(1).get_reg(); + if (instrs[1].get_src(1).get_reg() != src0) { + return nullptr; + } + if (instrs[2].get_src(1).get_reg() != src0) { + return nullptr; + } + if (instrs[4].get_src(1).get_reg() != src1) { + return nullptr; + } + if (instrs[5].get_src(1).get_reg() != src1) { + return nullptr; + } + + // mula.s f0, f3 + if (instrs[6].kind != InstructionKind::MULAS || instrs[6].get_src(0).get_reg() != t0 || + instrs[6].get_src(1).get_reg() != t3) { + return nullptr; + } + + // madda.s f1, f4 + if (instrs[7].kind != InstructionKind::MADDAS || instrs[7].get_src(0).get_reg() != t1 || + instrs[7].get_src(1).get_reg() != t4) { + return nullptr; + } + + // madd.s f0, f2, f5 + if (instrs[8].kind != InstructionKind::MADDS || instrs[8].get_src(0).get_reg() != t2 || + instrs[8].get_src(1).get_reg() != t5) { + return nullptr; + } + + auto dst = instrs[8].get_dst(0).get_reg(); + + return std::make_unique( + make_dst_var(dst, idx), + SimpleExpression(SimpleExpression::Kind::VECTOR_3_DOT, make_src_atom(src0, idx), + make_src_atom(src1, idx)), + idx); +} + +std::unique_ptr convert_9(const Instruction* instrs, int idx) { + auto as_vector3_dot = convert_vector3_dot(instrs, idx); + if (as_vector3_dot) { + return as_vector3_dot; + } + return nullptr; +} + } // namespace /*! @@ -1637,7 +1770,15 @@ int convert_block_to_atomic_ops(int begin_idx, warnings.warn_sq_lq(); } - if (n_instr >= 6) { + if (n_instr >= 9) { + op = convert_9(&instr[0], op_idx); + if (op) { + converted = true; + length = 9; + } + } + + if (!converted && n_instr >= 6) { // try 6 instructions op = convert_6(instr[0], instr[1], instr[2], instr[3], instr[4], instr[5], op_idx); if (op) { @@ -1702,7 +1843,8 @@ int convert_block_to_atomic_ops(int begin_idx, if (!converted) { // failed! - throw std::runtime_error("Failed to convert " + instr->to_string(labels)); + throw std::runtime_error( + fmt::format("Failed to convert ({} instrs) {}\n", n_instr, instr->to_string(labels))); // lg::die("Failed to convert instruction {} to an atomic op", // instr->to_string(labels)); } diff --git a/decompiler/analysis/cfg_builder.cpp b/decompiler/analysis/cfg_builder.cpp index dea94079ac..a10a021d0e 100644 --- a/decompiler/analysis/cfg_builder.cpp +++ b/decompiler/analysis/cfg_builder.cpp @@ -178,7 +178,7 @@ void clean_up_return_final(const Function& f, ReturnElement* ir) { /*! * Remove the branch in a break (really return-from nonfunction scope) */ -void clean_up_break(FormPool& pool, BreakElement* ir) { +void clean_up_break(FormPool& pool, BreakElement* ir, const Env&) { auto jump_to_end = get_condition_branch(ir->return_code); assert(jump_to_end.first); assert(jump_to_end.first->op()->branch_delay().kind() == IR2_BranchDelay::Kind::NOP); @@ -192,7 +192,7 @@ void clean_up_break(FormPool& pool, BreakElement* ir) { } } -void clean_up_break_final(const Function& f, BreakElement* ir) { +void clean_up_break_final(const Function& f, BreakElement* ir, const Env& env) { EmptyElement* dead_empty = dynamic_cast(ir->dead_code->try_as_single_element()); if (dead_empty) { ir->dead_code = nullptr; @@ -210,6 +210,13 @@ void clean_up_break_final(const Function& f, BreakElement* ir) { } } + if (!dead) { + if (ir->dead_code->to_string(env) == "(nop!)") { + ir->dead_code = nullptr; + return; + } + } + if (!dead) { lg::error("failed to recognize dead code after break, got {}", ir->dead_code->to_string(f.ir2.env)); @@ -1379,6 +1386,31 @@ bool contains(const std::vector& vec, const T& val) { } } // namespace +/*! + * Push x to output (can be a Form or std::vector). + * Will take of grouping the delay slots for likely asm branches into a single operation. + */ +template +void push_back_form_regroup_asm_likely_branches(T* output, FormElement* x, Function& f) { + std::vector hack_temp; + + if (output->size() > 0) { + auto back_as_asm = dynamic_cast(output->back()); + if (back_as_asm) { + auto back_as_branch = dynamic_cast(back_as_asm->op()); + if (back_as_branch && back_as_branch->is_likely()) { + auto& pool = *f.ir2.form_pool; + auto elt = pool.alloc_element(back_as_branch, + pool.alloc_single_form(nullptr, x), true); + output->pop_back(); + output->push_back(elt); + return; + } + } + } + output->push_back(x); +} + template void convert_and_inline(FormPool& pool, Function& f, const BlockVtx* as_block, T* output) { auto start_op = f.ir2.atomic_ops->block_id_to_first_atomic_op.at(as_block->block_id); @@ -1436,7 +1468,8 @@ void convert_and_inline(FormPool& pool, Function& f, const BlockVtx* as_block, T } if (add) { add_map.push_back(output->size()); - output->push_back(op); + // output->push_back(op); + push_back_form_regroup_asm_likely_branches(output, op, f); } else { add_map.push_back(-1); } @@ -1465,7 +1498,8 @@ void insert_cfg_into_list(FormPool& pool, } else { auto ir = cfg_to_ir(pool, f, vtx); for (auto x : ir->elts()) { - output->push_back(x); + push_back_form_regroup_asm_likely_branches(output, x, f); + // output->push_back(x); } } } @@ -1643,7 +1677,7 @@ Form* cfg_to_ir_helper(FormPool& pool, Function& f, const CfgVtx* vtx) { auto result = pool.alloc_single_element_form( nullptr, cfg_to_ir(pool, f, cvtx->body), cfg_to_ir_allow_null(pool, f, cvtx->unreachable_block), cvtx->dest_block_id); - clean_up_break(pool, dynamic_cast(result->try_as_single_element())); + clean_up_break(pool, dynamic_cast(result->try_as_single_element()), f.ir2.env); return result; } else if (dynamic_cast(vtx)) { return pool.alloc_single_element_form(nullptr); @@ -1739,7 +1773,7 @@ void build_initial_forms(Function& function) { auto as_break = dynamic_cast(form); if (as_break) { - clean_up_break_final(function, as_break); + clean_up_break_final(function, as_break, function.ir2.env); } }); diff --git a/decompiler/config.cpp b/decompiler/config.cpp index 57c31c2bba..dccb5f247a 100644 --- a/decompiler/config.cpp +++ b/decompiler/config.cpp @@ -162,6 +162,9 @@ Config read_config_file(const std::string& path_to_config_file) { hacks_json.at("types_with_bad_inspect_methods").get>(); config.hacks.reject_cond_to_value = hacks_json.at("aggressively_reject_cond_to_value_rewrite") .get>(); + config.hacks.blocks_ending_in_asm_branch_by_func_name = + hacks_json.at("blocks_ending_in_asm_branch") + .get>>(); for (auto& entry : hacks_json.at("cond_with_else_max_lengths")) { auto func_name = entry.at(0).get(); diff --git a/decompiler/config.h b/decompiler/config.h index 3a87be4328..c7af0b1be0 100644 --- a/decompiler/config.h +++ b/decompiler/config.h @@ -59,6 +59,7 @@ struct DecompileHacks { std::unordered_set pair_functions_by_name; std::unordered_map cond_with_else_len_by_func_name; std::unordered_set reject_cond_to_value; + std::unordered_map> blocks_ending_in_asm_branch_by_func_name; }; struct Config { diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 7cab1bf422..c872859908 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -1727,11 +1727,11 @@ ) (deftype vector (structure) - ((data float 4 :do-not-decompile :score -9999 :offset-assert 0) - (x float :offset 0) + ((x float :offset 0) (y float :offset 4) (z float :offset 8) (w float :offset 12) + (data float 4 :score -9999 :offset 0) (quad uint128 :offset 0) ) :method-count-assert 9 @@ -2100,7 +2100,7 @@ (deftype curve (structure) ((cverts pointer :offset-assert 0) (num-cverts int32 :offset-assert 4) - (knots pointer :offset-assert 8) + (knots (inline-array vector) :offset-assert 8) (num-knots int32 :offset-assert 12) (length float :offset-assert 16) ) @@ -2224,7 +2224,7 @@ (define-extern atan (function float float float)) (define-extern matrix-4x4-determinant (function matrix float)) (define-extern matrix-3x3-determinant (function matrix float)) -(define-extern matrix-axis-sin-cos! (function matrix vector float float none)) +(define-extern matrix-axis-sin-cos! (function matrix vector float float matrix)) (define-extern sin (function float float)) (define-extern cos (function float float)) (define-extern matrix-rotate-y! (function matrix float matrix)) @@ -2381,16 +2381,16 @@ ;; - Functions -(define-extern curve-length function) -(define-extern curve-get-pos! function) + + (define-extern vector-vector-distance-squared (function vector vector float)) -(define-extern curve-evaluate! (function vector float int int vector int int)) + (define-extern vector-vector-distance (function vector vector float)) -(define-extern circle-circle-xz-intersect (function vector vector vector vector int)) +(define-extern circle-circle-xz-intersect (function sphere sphere vector vector int)) (define-extern vector-normalize-copy! (function vector vector float vector)) (define-extern forward-up->quaternion (function quaternion vector vector quaternion)) -(define-extern matrix-from-two-vectors-partial-linear! (function matrix vector vector float float none)) -(define-extern matrix-from-two-vectors-max-angle! (function matrix vector vector none)) +(define-extern matrix-from-two-vectors-partial-linear! (function matrix vector vector float matrix)) +(define-extern matrix-from-two-vectors-max-angle! (function matrix vector vector float matrix)) (define-extern vector-negate! (function vector vector vector)) (define-extern vector-normalize-ret-len! (function vector float float)) (define-extern vector-flatten! (function vector vector vector vector)) @@ -2408,30 +2408,35 @@ (define-extern vector-segment-distance-point! (function vector vector vector vector float)) (define-extern vector-line-distance (function vector vector vector float)) (define-extern vector-line-distance-point! (function vector vector vector vector float)) -(define-extern vector-orient-by-quat! (function vector vector vector vector)) +(define-extern vector-orient-by-quat! (function vector vector quaternion vector)) (define-extern forward-up-nopitch->quaternion (function quaternion vector vector quaternion)) (define-extern quaternion-from-two-vectors! (function quaternion vector vector quaternion)) -(define-extern matrix-from-two-vectors! (function matrix vector vector none)) -(define-extern matrix-from-two-vectors-max-angle-partial! (function matrix vector vector float float none)) -(define-extern matrix-remove-z-rot (function matrix matrix)) -(define-extern matrix-rot-diff! (function matrix matrix matrix float)) -(define-extern quaternion-seek (function quaternion quaternion quaternion float quaternion)) -(define-extern vector-deg-seek (function vector vector vector none)) +(define-extern matrix-from-two-vectors! (function matrix vector vector matrix)) +(define-extern matrix-from-two-vectors-max-angle-partial! (function matrix vector vector float float matrix)) +(define-extern matrix-remove-z-rot (function matrix matrix matrix)) +(define-extern matrix-rot-diff! (function vector matrix matrix float)) +(define-extern quaternion-seek (function quaternion quaternion quaternion float float quaternion)) +(define-extern vector-deg-seek (function vector vector vector float vector)) (define-extern vector-deg-slerp (function vector vector vector float vector)) -(define-extern vector-vector-deg-slerp! function) ;; stack spills! +(define-extern vector-vector-deg-slerp! (function vector vector vector float vector vector)) ;; stack spills! (define-extern normal-of-plane (function vector vector vector vector vector)) (define-extern vector-3pt-cross! (function vector vector vector vector vector)) -(define-extern closest-pt-in-triangle function) ;; asm branches +(define-extern closest-pt-in-triangle (function vector vector matrix vector none)) ;; asm branches (define-extern point-in-triangle-cross (function vector vector vector vector vector symbol)) (define-extern point-in-plane-<-point+normal! (function vector vector vector vector)) (define-extern circle-test (function none)) -(define-extern vector-circle-tangent-new function) -(define-extern vector-circle-tangent function) -(define-extern find-knot-span function) -(define-extern calculate-basis-functions-vector! function) -(define-extern curve-copy! function) -(define-extern curve-closest-point function) -(define-extern vector-plane-distance function) +(define-extern vector-circle-tangent-new (function vector vector vector vector none)) +(define-extern vector-circle-tangent (function vector vector vector vector none)) +(define-extern find-knot-span (function int int float (inline-array vector) int)) +(define-extern calculate-basis-functions-vector! (function (pointer float) int float (pointer float) (pointer float))) + +(define-extern curve-closest-point (function curve vector float float int float float)) +(define-extern vector-plane-distance (function vector plane vector float)) + +(define-extern curve-get-pos! (function vector float curve vector)) +(define-extern curve-evaluate! (function vector float pointer int (inline-array vector) int vector)) +(define-extern curve-length (function curve float)) +(define-extern curve-copy! (function curve curve curve)) ;; ---------------------- @@ -15051,7 +15056,7 @@ (define-extern add-debug-light (function symbol bucket-id light vector string symbol)) (define-extern add-debug-text-3d (function symbol bucket-id string vector rgba vector2h symbol)) (define-extern add-debug-x (function symbol bucket-id vector rgba symbol)) -(define-extern add-debug-curve (function symbol bucket-id pointer int vector int rgba symbol)) +(define-extern add-debug-curve (function symbol bucket-id pointer int (inline-array vector) int rgba symbol)) (define-extern add-debug-sphere (function symbol bucket-id vector float rgba symbol)) (define-extern get-debug-text-3d (function debug-text-3d)) (define-extern internal-draw-debug-text-3d (function bucket-id string vector rgba vector2h pointer)) diff --git a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc index 8bfb69910d..8480cdc103 100644 --- a/decompiler/config/jak1_ntsc_black_label/hacks.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/hacks.jsonc @@ -69,11 +69,7 @@ "matrix-axis-sin-cos-vu!", // geometry - "curve-evaluate!", // BUG: cfg fails, suspected weird gotos "circle-circle-xz-intersect", // F: asm branching - "closest-pt-in-triangle", // F: asm branching - "find-knot-span", // ?? - "vector-segment-distance-point!", // trigonometry "exp", // BUG: cfg is wrong. @@ -493,5 +489,16 @@ "ERROR: dma tag has data in reserved bits ~X~%": 0, "#: value of symbol ~A in task-controls is not a task-control~%": 0 + }, + + "blocks_ending_in_asm_branch": { + "closest-pt-in-triangle": [17], + + // this one is all asm branches + "circle-circle-xz-intersect": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], + + "find-knot-span": [0, 1, 2, 3, 5, 6, 7, 8, 9], + + "curve-evaluate!": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] } } diff --git a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc index b509b93fc1..856e044138 100644 --- a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc @@ -551,7 +551,7 @@ "main": [["L230", "_lambda_", true]], - "geometry": [["L125", "float", true]], + "geometry": [["L125", "float", true], ["L126", "float", true], ["L112", "(pointer float)", true, 4]], "level": [ ["L452", "_auto_", true], diff --git a/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc b/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc index 973fd278cd..2b59a2f189 100644 --- a/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/stack_structures.jsonc @@ -468,5 +468,46 @@ "(method 9 game-info)": [[16, "event-message-block"]], "(method 9 continue-point)": [[16, "vector"]], "(method 9 game-save)": [[16, "file-stream"]], - "(method 10 game-save)": [[16, "file-stream"]] + "(method 10 game-save)": [[16, "file-stream"]], + "vector-vector-deg-slerp!": [ + [16, "vector"], + [32, "vector"], + [48, "quaternion"], + [64, "quaternion"], + [80, "quaternion"], + [96, "vector"] + ], + + "closest-pt-in-triangle": [ + [16, "vector"], + [32, "vector"], + [48, "vector"] + ], + + "vector-circle-tangent-new": [ + [16, "sphere"], + [32, "vector"], + [48, "vector"] + ], + + "vector-circle-tangent": [ + [16, "sphere"], + [32, "vector"], + [48, "vector"], + [64, "vector"] + ], + + "vector-plane-distance": [ + [16, "vector"] + ], + + "curve-length": [ + [16, "vector"], + [32, "vector"] + ], + + "curve-closest-point": [ + [16, "vector"], + [32, "vector"] + ] } diff --git a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc index cac7c0acb4..51468f2dd1 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc @@ -1018,5 +1018,10 @@ [21, "t9", "(function int int int int int)"] ], + "calculate-basis-functions-vector!": [ + [[8, 20], "v1", "(pointer float)"], + [[0, 60], "f1", "float"] + ], + "placeholder-do-not-add-below": [] } diff --git a/goal_src/engine/data/res.gc b/goal_src/engine/data/res.gc index a60c72bf6c..7103f93646 100644 --- a/goal_src/engine/data/res.gc +++ b/goal_src/engine/data/res.gc @@ -711,7 +711,7 @@ This is updated from the entity system used in Crash 2, which had most of these (set! curve-data (get-property-data obj knots-name 'exact time (the pointer #f) (& knots-tag) *res-static-buf*)) (when curve-data - (set! (-> curve-target knots) curve-data) + (set! (-> curve-target knots) (the (inline-array vector) curve-data)) (set! (-> curve-target num-knots) (the int (-> knots-tag elt-count))) (set! result #t) ) diff --git a/goal_src/engine/debug/debug.gc b/goal_src/engine/debug/debug.gc index 0834ab3b36..83ac3ff0e6 100644 --- a/goal_src/engine/debug/debug.gc +++ b/goal_src/engine/debug/debug.gc @@ -1304,7 +1304,7 @@ ) ) -(defun-debug add-debug-curve ((arg0 symbol) (arg1 bucket-id) (arg2 pointer) (arg3 int) (arg4 vector) (arg5 int) (arg6 rgba)) +(defun-debug add-debug-curve ((arg0 symbol) (arg1 bucket-id) (arg2 pointer) (arg3 int) (arg4 (inline-array vector)) (arg5 int) (arg6 rgba)) (local-vars (sv-48 vector) (sv-64 int) (sv-80 int)) (if (not arg0) (return #f) @@ -1313,14 +1313,14 @@ (set! sv-48 (new 'stack-no-clear 'vector)) (set! (-> sv-48 quad) (the-as uint128 0)) (set! sv-64 (* arg3 4)) - (curve-evaluate! sv-48 (-> arg4 x) (the-as int arg2) arg3 arg4 arg5) + (curve-evaluate! sv-48 (-> arg4 0 x) arg2 arg3 arg4 arg5) (set! sv-80 0) (while (< sv-80 sv-64) (set! (-> s0-0 quad) (-> sv-48 quad)) (curve-evaluate! sv-48 (/ (the float (+ sv-80 1)) (the float sv-64)) - (the-as int arg2) + arg2 arg3 arg4 arg5 @@ -1339,7 +1339,7 @@ arg1 (-> arg2 cverts) (-> arg2 num-cverts) - (the-as vector (-> arg2 knots)) + (-> arg2 knots) (-> arg2 num-knots) arg3 ) diff --git a/goal_src/engine/geometry/geometry-h.gc b/goal_src/engine/geometry/geometry-h.gc index 7ff447eecf..0b990e70a5 100644 --- a/goal_src/engine/geometry/geometry-h.gc +++ b/goal_src/engine/geometry/geometry-h.gc @@ -10,7 +10,7 @@ (deftype curve (structure) ((cverts pointer :offset-assert 0) (num-cverts int32 :offset-assert 4) - (knots pointer :offset-assert 8) + (knots (inline-array vector) :offset-assert 8) (num-knots int32 :offset-assert 12) (length float :offset-assert 16) ) diff --git a/goal_src/engine/geometry/geometry.gc b/goal_src/engine/geometry/geometry.gc index 415901542d..40ba57b42a 100644 --- a/goal_src/engine/geometry/geometry.gc +++ b/goal_src/engine/geometry/geometry.gc @@ -113,28 +113,1228 @@ (.svf (&-> dst quad) vf3) ;; dst is now the normal part of src - (let ((f0-0 (vector-length dst)) ;; length of normal - (f1-1 (vector-dot dst plane-normal))) ;; ?? this is always zero. - (let* ((f1-2 f1-1) - ;; f1-3 = .02 * length of normal. f1-2 is always zero here - (f1-3 (- (* 0.02 f0-0) f1-2)) + (let* ((f0-0 (vector-length dst)) ;; len of normal component + (f1-1 (vector-dot dst plane-normal)) ;; always zero? + ;; f1-3 = .02 * length of normal. f1-2 is always zero here + (f1-2 (- (* 0.02 f0-0) f1-1)) + ) + + ;; scale down and limit the normal component + (vector+float*! dst dst plane-normal (fmin 16384.0 (* 16.0 f1-2))) + ) + ) + ) + +(defun vector-segment-distance-point! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (local-vars (v0-0 float) (v1-0 float) (v1-1 float)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + ) + (init-vf0-vector) + (nop!) + (.lvf vf3 (&-> arg1 quad)) + (.lvf vf4 (&-> arg2 quad)) + (.lvf vf5 (&-> arg0 quad)) + (.sub.vf vf1 vf4 vf3) + (.sub.vf vf6 vf5 vf3) + (.mul.vf vf2 vf1 vf1) + (.mul.x.vf acc vf0 vf2 :mask #b1000) + (.add.mul.y.vf acc vf0 vf2 acc :mask #b1000) + (.add.mul.z.vf vf2 vf0 vf2 acc :mask #b1000) + (.sqrt.vf Q vf2 :ftf #b11) + (.wait.vf) + (.add.vf vf2 vf0 Q :mask #b1) + (.nop.vf) + (.nop.vf) + (.div.vf Q vf0 vf2 :fsf #b11 :ftf #b0) + (.mov v1-0 vf2) + (let ((f2-0 v1-0)) + (.wait.vf) + (.mul.vf vf1 vf1 Q) + (.mul.vf vf7 vf1 vf6) + (let ((f1-0 0.0)) + (.add.y.vf vf7 vf7 vf7 :mask #b1) + (.add.z.vf vf7 vf7 vf7 :mask #b1) + (.mov v1-1 vf7) + (let ((f0-0 v1-1)) + (b! (< f0-0 f1-0) cfg-4 :likely-delay (set! f0-0 f1-0)) + (b! (< f2-0 f0-0) cfg-4 :likely-delay (set! f0-0 f2-0)) + (label cfg-4) + (let ((v1-2 f0-0)) + (.mov vf7 v1-2) + ) + ) + ) + ) + (.mul.x.vf vf1 vf1 vf7) + (b! (= arg3 #f) cfg-6 :delay (.mov.vf vf8 vf0 :mask #b1000)) + (.add.vf vf8 vf3 vf1 :mask #b111) + (.svf (&-> arg3 quad) vf8) + (label cfg-6) + (.sub.vf vf2 vf6 vf1) + (.mul.vf vf2 vf2 vf2) + (.mul.x.vf acc vf0 vf2 :mask #b1000) + (.add.mul.y.vf acc vf0 vf2 acc :mask #b1000) + (.add.mul.z.vf vf2 vf0 vf2 acc :mask #b1000) + (.sqrt.vf Q vf2 :ftf #b11) + (.wait.vf) + (.add.vf vf2 vf0 Q :mask #b1) + (.nop.vf) + (.mov v0-0 vf2) + v0-0 + ) + ) + +(defun vector-line-distance ((arg0 vector) (arg1 vector) (arg2 vector)) + (let* ((a1-3 (vector-normalize! (vector-! (new-stack-vector0) arg2 arg1) 1.0)) + (gp-1 (vector-! (new-stack-vector0) arg0 arg1)) + (f0-1 (vector-dot a1-3 gp-1)) + (v1-3 (vector-float*! (new-stack-vector0) a1-3 f0-1)) + ) + (vector-length (vector-! (new-stack-vector0) gp-1 v1-3)) + ) + ) + +(defun vector-line-distance-point! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (let* ((a1-3 (vector-normalize! (vector-! (new-stack-vector0) arg2 arg1) 1.0)) + (s4-1 (vector-! (new-stack-vector0) arg0 arg1)) + (f0-1 (vector-dot a1-3 s4-1)) + (v1-4 (vector-float*! (new-stack-vector0) a1-3 f0-1)) + ) + (if arg3 + (vector+! arg3 arg1 v1-4) + ) + (vector-length (vector-! (new-stack-vector0) s4-1 v1-4)) + ) + ) + +(defun vector-orient-by-quat! ((arg0 vector) (arg1 vector) (arg2 quaternion)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> arg2 vec quad)) + (.lvf vf6 (&-> arg1 quad)) + (.add.vf vf5 vf1 vf1) + (.add.w.vf vf2 vf0 vf1 :mask #b1) + (.add.z.vf vf2 vf0 vf1 :mask #b10) + (.sub.y.vf vf2 vf0 vf1 :mask #b100) + (.sub.w.vf vf2 vf0 vf0 :mask #b1000) + (.sub.z.vf vf3 vf0 vf1 :mask #b1) + (.add.w.vf vf3 vf0 vf1 :mask #b10) + (.add.x.vf vf3 vf0 vf1 :mask #b100) + (.sub.w.vf vf3 vf0 vf0 :mask #b1000) + (.add.y.vf vf4 vf0 vf1 :mask #b1) + (.sub.x.vf vf4 vf0 vf1 :mask #b10) + (.add.w.vf vf4 vf0 vf1 :mask #b100) + (.sub.w.vf vf4 vf0 vf0 :mask #b1000) + (.outer.product.vf vf2 vf5 vf2) + (.outer.product.vf vf3 vf5 vf3) + (.outer.product.vf vf4 vf5 vf4) + (.add.w.vf vf2 vf2 vf0 :mask #b1) + (.add.w.vf vf3 vf3 vf0 :mask #b10) + (.add.w.vf vf4 vf4 vf0 :mask #b100) + (.mul.w.vf acc vf0 vf6) + (.add.mul.x.vf acc vf2 vf6 acc) + (.add.mul.y.vf acc vf3 vf6 acc) + (.add.mul.z.vf vf6 vf4 vf6 acc) + (.svf (&-> arg0 quad) vf6) + arg0 + ) + ) + +(defun forward-down->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + (vector-normalize-copy! (-> arg0 vector 2) arg1 1.0) + (vector-cross! (the-as vector (-> arg0 vector)) (-> arg0 vector 2) arg2) + (vector-normalize! (the-as vector (-> arg0 vector)) 1.0) + (vector-cross! (-> arg0 vector 1) arg1 (the-as vector (-> arg0 vector))) + (vector-normalize! (-> arg0 vector 1) 1.0) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 vector 0 w) 0.0) + (set! (-> arg0 vector 1 w) 0.0) + (set! (-> arg0 vector 2 w) 0.0) + (set! (-> arg0 vector 3 w) 1.0) + arg0 + ) + +(defun forward-down-nopitch->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + (vector-normalize-copy! (-> arg0 vector 1) arg2 1.0) + (vector-negate! (-> arg0 vector 1) (-> arg0 vector 1)) + (vector-cross! (the-as vector (-> arg0 vector)) (-> arg0 vector 1) arg1) + (vector-normalize! (the-as vector (-> arg0 vector)) 1.0) + (vector-cross! + (-> arg0 vector 2) + (the-as vector (-> arg0 vector)) + (-> arg0 vector 1) + ) + (vector-normalize! (-> arg0 vector 2) 1.0) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 vector 0 w) 0.0) + (set! (-> arg0 vector 1 w) 0.0) + (set! (-> arg0 vector 2 w) 0.0) + (set! (-> arg0 vector 3 w) 1.0) + arg0 + ) + +(defun forward-up-nopitch->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + (forward-down-nopitch->inv-matrix arg0 arg1 (vector-negate! (new-stack-vector0) arg2)) + ) + +(defun forward-up-nopitch->quaternion ((arg0 quaternion) (arg1 vector) (arg2 vector)) + (matrix->quaternion arg0 (forward-up-nopitch->inv-matrix (new-stack-matrix0) arg1 arg2)) + ) + +(defun forward-up->quaternion ((arg0 quaternion) (arg1 vector) (arg2 vector)) + (matrix->quaternion arg0 + (forward-down->inv-matrix + (new-stack-matrix0) + arg1 + (vector-negate! (new 'stack-no-clear 'vector) arg2) + ) + ) + ) + +(defun quaternion-from-two-vectors! ((arg0 quaternion) (arg1 vector) (arg2 vector)) + (let* ((s5-0 (vector-cross! (new-stack-vector0) arg1 arg2)) + (f0-0 (vector-length s5-0)) + (f1-1 (vector-dot arg1 arg2)) + ) + (let ((f0-1 (/ (sqrtf (* 0.5 (- 1.0 f1-1))) f0-0))) + (set! (-> arg0 x) (* (-> s5-0 x) f0-1)) + (set! (-> arg0 y) (* (-> s5-0 y) f0-1)) + (set! (-> arg0 z) (* (-> s5-0 z) f0-1)) + ) + (set! (-> arg0 w) (sqrtf (* 0.5 (+ 1.0 f1-1)))) + ) + arg0 + ) + +(defun quaternion-from-two-vectors-max-angle! ((arg0 quaternion) (arg1 vector) (arg2 vector) (arg3 float)) + (let* ((s5-0 (vector-cross! (new-stack-vector0) arg1 arg2)) + (f30-0 (vector-length s5-0)) + (f26-0 (vector-dot arg1 arg2)) + (f28-0 (sqrtf (* 0.5 (- 1.0 f26-0)))) + ) + (let ((f0-5 (sin (* 0.5 arg3)))) + (cond + ((< f0-5 f28-0) + (set! f28-0 f0-5) + (set! (-> arg0 w) (cos (* 0.5 arg3))) + ) + (else + (set! (-> arg0 w) (sqrtf (* 0.5 (+ 1.0 f26-0)))) + ) + ) + ) + (let ((f0-12 (/ f28-0 f30-0))) + (set! (-> arg0 x) (* (-> s5-0 x) f0-12)) + (set! (-> arg0 y) (* (-> s5-0 y) f0-12)) + (set! (-> arg0 z) (* (-> s5-0 z) f0-12)) + ) + ) + arg0 + ) + +(defun matrix-from-two-vectors! ((arg0 matrix) (arg1 vector) (arg2 vector)) + (let* ((a1-3 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f0-1 (vector-dot arg1 arg2)) + (f1-0 1.0) + (f2-0 f0-1) + (f1-2 (sqrtf (- f1-0 (* f2-0 f2-0)))) + ) + (matrix-axis-sin-cos! arg0 a1-3 f1-2 f0-1) + ) + ) + +(defun matrix-from-two-vectors-max-angle! ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float)) + (let + ((s4-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f30-0 (vector-dot arg1 arg2)) + (f28-0 (cos arg3)) + ) + (cond + ((< f30-0 f28-0) + (matrix-axis-sin-cos! arg0 s4-1 (sin arg3) f28-0) + ) + (else + ;; todo looks bad because of inline (square x) + (let ((t9-5 matrix-axis-sin-cos!) + (a0-6 arg0) + (a1-4 s4-1) + (f0-1 1.0) + (f1-0 f30-0) ) - ;; scale down and limit the normal component - (vector+float*! dst dst plane-normal (fmin 16384.0 (* 16.0 f1-3))) + (t9-5 a0-6 a1-4 (sqrtf (- f0-1 (* f1-0 f1-0))) f30-0) + ) + ) + ) + ) + ) + +(defun matrix-from-two-vectors-max-angle-partial! ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float) (arg4 float)) + (let* ((s4-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f28-0 (vector-dot arg1 arg2)) + (f30-0 (cos arg3)) + (f0-2 (+ 1.0 (* (+ -1.0 f28-0) arg4))) + ) + (cond + ((< f0-2 f30-0) + (matrix-axis-sin-cos! arg0 s4-1 (sin arg3) f30-0) + ) + (else + ;; todo looks bad because of inline (square x) + (let ((t9-5 matrix-axis-sin-cos!) + (a0-6 arg0) + (a1-4 s4-1) + (f1-3 1.0) + (f2-1 f0-2) + ) + (t9-5 a0-6 a1-4 (sqrtf (- f1-3 (* f2-1 f2-1))) f0-2) + ) + ) + ) + ) + ) + +(defun matrix-from-two-vectors-partial-linear! ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float)) + (let ((gp-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f0-1 (vector-dot arg1 arg2)) + ) + (cond + ((< 0.9999 (fabs f0-1)) + (matrix-identity! arg0) + ) + (else + (let* ((f0-4 (cos (* arg3 (acos f0-1)))) + (t9-5 matrix-axis-sin-cos!) + (a0-6 arg0) + (f1-1 1.0) + (f2-1 f0-4) + ) + (t9-5 a0-6 gp-1 (sqrtf (- f1-1 (* f2-1 f2-1))) f0-4) + ) + ) + ) + ) + ) + +(defun matrix-remove-z-rot ((arg0 matrix) (arg1 matrix)) + (let ((s4-0 (new-stack-vector0))) + 0.0 + 0.0 + (let ((s5-0 (new-stack-matrix0))) + (vector-negate! s4-0 (the-as vector arg1)) + (vector-flatten! s4-0 s4-0 (-> arg0 vector 2)) + (vector-normalize! s4-0 1.0) + (let ((f30-0 (vector-dot (-> arg0 vector 1) s4-0))) + (when (< f30-0 0.99999) + (vector-cross! s4-0 (-> arg0 vector 1) s4-0) + (let ((f0-4 (vector-length s4-0))) + (if (< 0.0 (vector-dot s4-0 (-> arg0 vector 2))) + (set! f0-4 (- f0-4)) + ) + (matrix-axis-sin-cos! s5-0 (-> arg0 vector 2) f0-4 f30-0) + ) + (matrix*! arg0 arg0 s5-0) + ) + ) + ) + ) + arg0 + ) + +(defun matrix-rot-diff! ((arg0 vector) (arg1 matrix) (arg2 matrix)) + (let ((s3-0 (new-stack-quaternion0)) + (s2-0 (new-stack-quaternion0)) + (s5-0 (new-stack-quaternion0)) + ) + 0.0 + (matrix->quaternion s3-0 arg1) + (matrix->quaternion s2-0 arg2) + (quaternion-conjugate! s5-0 s3-0) + (quaternion*! s5-0 s2-0 s5-0) + (quaternion-normalize! s5-0) + (if (< (-> s5-0 w) 0.0) + (quaternion-negate! s5-0 s5-0) + ) + (let ((f30-1 (* 2.0 (acos (-> s5-0 w))))) + (set! (-> arg0 quad) (-> s5-0 vec quad)) + (vector-negate! arg0 arg0) + (if (= (vector-normalize-ret-len! arg0 1.0) 0.0) + (set! (-> arg0 y) 1.0) + ) + f30-1 + ) + ) + ) + + +(defun quaternion-seek ((arg0 quaternion) (arg1 quaternion) (arg2 quaternion) (arg3 float) (arg4 float)) + (let ((s5-0 (new-stack-matrix0)) + (s4-0 (new-stack-matrix0)) + ) + (quaternion->matrix s5-0 arg1) + (quaternion->matrix s4-0 arg2) + (let ((s2-1 (new-stack-quaternion0))) + (quaternion-from-two-vectors-max-angle! + s2-1 + (-> s5-0 vector 2) + (-> s4-0 vector 2) + arg4 + ) + (quaternion-normalize! (quaternion*! arg0 arg0 s2-1)) + ) + ) + ) + +(defun vector-deg-seek ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float)) + (let ((s4-0 (new-stack-matrix0))) + (matrix-from-two-vectors-max-angle! s4-0 arg1 arg2 arg3) + (vector-matrix*! arg0 arg1 s4-0) + ) + ) + +(defun vector-deg-slerp ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float)) + (cond + ((>= 0.0 arg3) + (set! (-> arg0 quad) (-> arg1 quad)) + arg0 + ) + ((>= arg3 1.0) + (set! (-> arg0 quad) (-> arg2 quad)) + arg0 + ) + (else + (let ((s1-0 (new-stack-matrix0))) + (let + ((s2-0 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg1 1.0)) + (a2-3 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg2 1.0)) + ) + (matrix-from-two-vectors-partial-linear! s1-0 s2-0 a2-3 arg3) + ) + (vector-matrix*! arg0 arg1 s1-0) + ) + ) + ) + ) + +(defun vector-vector-deg-slerp! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float) (arg4 vector)) + (local-vars (sv-112 (function float float float float))) + (cond + ((>= 0.0 arg3) + (set! (-> arg0 quad) (-> arg1 quad)) + ) + ((>= arg3 1.0) + (set! (-> arg0 quad) (-> arg2 quad)) + ) + (else + (let* + ((s0-0 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg1 1.0)) + (s1-0 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg2 1.0)) + (s0-1 (forward-up->quaternion (new 'stack-no-clear 'quaternion) s0-0 arg4)) + (a2-5 (forward-up->quaternion (new 'stack-no-clear 'quaternion) s1-0 arg4)) + (a1-6 (quaternion-slerp! (new 'stack-no-clear 'quaternion) s0-1 a2-5 arg3)) + (s2-1 vector-normalize-copy!) + (s1-1 arg0) + (s0-2 (vector-z-quaternion! (new 'stack-no-clear 'vector) a1-6)) + ) + (set! sv-112 lerp) + (let ((s3-1 (vector-length arg1)) + (a1-7 (vector-length arg2)) + ) + (s2-1 s1-1 s0-2 (sv-112 s3-1 a1-7 arg3)) + ) + ) + ) + ) + arg0 + ) + +(defun normal-of-plane ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (init-vf0-vector) + (.lvf vf3 (&-> arg2 quad)) + (.lvf vf1 (&-> arg1 quad)) + (.lvf vf2 (&-> arg3 quad)) + (.sub.vf vf1 vf3 vf1) + (.sub.vf vf2 vf3 vf2) + (.outer.product.vf vf4 vf2 vf1) + (.mul.vf vf5 vf4 vf4) + (.add.y.vf vf5 vf5 vf5 :mask #b1) + (.add.z.vf vf5 vf5 vf5 :mask #b1) + (.isqrt.vf Q vf0 vf5 :fsf #b11 :ftf #b0) + (.mov.vf vf4 vf0 :mask #b1000) + (.wait.vf) + (.mul.vf vf4 vf4 Q :mask #b111) + (.nop.vf) + (.nop.vf) + (.svf (&-> arg0 quad) vf4) + arg0 + ) + ) + +(defun vector-3pt-cross! ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> arg1 quad)) + (.lvf vf2 (&-> arg2 quad)) + (.lvf vf3 (&-> arg3 quad)) + (.add.x.vf vf4 vf0 vf0 :mask #b1000) + (.sub.vf vf2 vf2 vf1) + (.sub.vf vf3 vf3 vf1) + (.outer.product.vf vf4 vf2 vf3) + (.svf (&-> arg0 quad) vf4) + arg0 + ) + ) + +(defun closest-pt-in-triangle ((arg0 vector) (arg1 vector) (arg2 matrix) (arg3 vector)) + "arg2 is probably the triangle" + ;; (declare (print-asm)) + (local-vars + (v1-0 uint) + (v1-4 uint) + (v1-5 uint) + (v1-6 uint) + (v1-7 uint) + (v1-10 uint) + (a0-1 uint) + (a1-1 uint) + ) + (rlet ((acc :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) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + (vf9 :class vf) + ) + (init-vf0-vector) + (nop!) + (nop!) + (.lvf vf3 (&-> arg2 vector 1 quad)) + (nop!) + (.lvf vf4 (&-> arg2 vector 2 quad)) + (nop!) + (.lvf vf5 (&-> arg1 quad)) + (.sub.vf vf6 vf3 vf4) + (.lvf vf2 (&-> arg2 vector 0 quad)) + (.sub.vf vf7 vf3 vf5) + (.lvf vf1 (&-> arg3 quad)) + (.sub.vf vf8 vf3 vf2) + (.sub.vf vf9 vf5 vf4) + (.sub.vf vf10 vf5 vf2) + (.outer.product.vf vf14 vf7 vf8) + (.outer.product.vf vf15 vf6 vf7) + (.mul.vf vf11 vf14 vf1) + (.outer.product.vf vf16 vf9 vf10) + (.mul.vf vf12 vf15 vf1) + (.add.x.vf vf11 vf11 vf11 :mask #b10) + (.mul.vf vf13 vf16 vf1) + (.add.x.vf vf12 vf12 vf12 :mask #b10) + (.add.x.vf vf13 vf13 vf13 :mask #b10) + (.add.z.vf vf11 vf11 vf11 :mask #b10) + (.add.z.vf vf12 vf12 vf12 :mask #b10) + (.add.z.vf vf13 vf13 vf13 :mask #b10) + ;; note: these types were changed to uint to make this copy 64 bits. + (.mov v1-0 vf11) + (.mov a1-1 vf12) + (.mov a0-1 vf13) + (let* ((v1-1 (shr (the-as int v1-0) 63)) + (a1-2 (shr (the-as int a1-1) 63)) + (a0-2 (shr (the-as int a0-1) 63)) + (a1-3 (* a1-2 2)) + (a0-3 (* a0-2 4)) + (v1-3 (logior (logior v1-1 a1-3) a0-3)) + ) + (b! (nonzero? v1-3) cfg-3 :delay (set! v1-4 (the-as uint (+ v1-3 -1)))) + ) + (.sub.vf vf17 vf5 vf2) + (.mov.vf vf18 vf0 :mask #b1000) + (.outer.product.vf vf18 vf17 vf1) + (.outer.product.vf vf18 vf1 vf18) + (.add.vf vf18 vf18 vf2 :mask #b111) + (b! #t cfg-24 :delay (.svf (&-> arg0 quad) vf18)) + (nop!) + (label cfg-3) + (b! (nonzero? v1-4) cfg-6 :delay (set! v1-5 (the-as uint (+ v1-4 -1)))) + (vector-segment-distance-point! + arg1 + (the-as vector (-> arg2 vector)) + (-> arg2 vector 1) + arg0 + ) + (goto cfg-24) + (label cfg-6) + (b! (nonzero? v1-5) cfg-9 :delay (set! v1-6 (the-as uint (+ v1-5 -1)))) + (vector-segment-distance-point! + arg1 + (-> arg2 vector 1) + (-> arg2 vector 2) + arg0 + ) + (goto cfg-24) + (label cfg-9) + (b! (nonzero? v1-6) cfg-14 :delay (set! v1-7 (the-as uint (+ v1-6 -1)))) + (let ((f30-0 (vector-segment-distance-point! + arg1 + (-> arg2 vector 1) + (the-as vector (-> arg2 vector)) + arg0 + ) + ) + (s3-0 (new 'stack-no-clear 'vector)) + ) + (if (< (vector-segment-distance-point! + arg1 + (-> arg2 vector 1) + (-> arg2 vector 2) + s3-0 + ) + f30-0 + ) + (set! (-> arg0 quad) (-> s3-0 quad)) + ) + ) + (goto cfg-24) + (label cfg-14) + (b! (nonzero? v1-7) cfg-17 :delay (set! v1-10 (the-as uint (+ v1-7 -1)))) + (vector-segment-distance-point! + arg1 + (-> arg2 vector 2) + (the-as vector (-> arg2 vector)) + arg0 + ) + (goto cfg-24) + (label cfg-17) + (b! (nonzero? v1-10) cfg-22) + (let ((f30-1 (vector-segment-distance-point! + arg1 + (the-as vector (-> arg2 vector)) + (-> arg2 vector 1) + arg0 + ) + ) + (s3-1 (new 'stack-no-clear 'vector)) + ) + (if (< (vector-segment-distance-point! + arg1 + (the-as vector (-> arg2 vector)) + (-> arg2 vector 2) + s3-1 + ) + f30-1 + ) + (set! (-> arg0 quad) (-> s3-1 quad)) + ) + ) + (goto cfg-24) + (label cfg-22) + (let ((f30-2 (vector-segment-distance-point! + arg1 + (-> arg2 vector 2) + (the-as vector (-> arg2 vector)) + arg0 + ) + ) + (s3-2 (new 'stack-no-clear 'vector)) + ) + (if (< (vector-segment-distance-point! + arg1 + (-> arg2 vector 2) + (-> arg2 vector 1) + s3-2 + ) + f30-2 + ) + (set! (-> arg0 quad) (-> s3-2 quad)) + ) + ) + (label cfg-24) + 0 + (none) + ) + ) + +(defun point-in-triangle-cross ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector) (arg4 vector)) + (local-vars (v1-0 int) (a0-1 int) (a1-1 int)) + (rlet ((acc :class vf) + (vf1 :class vf) + (vf10 :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) + ) + (.lvf vf3 (&-> arg3 quad)) + (.lvf vf4 (&-> arg4 quad)) + (.lvf vf5 (&-> arg0 quad)) + (.lvf vf2 (&-> arg2 quad)) + (.lvf vf1 (&-> arg1 quad)) + (.sub.vf vf6 vf3 vf4) + (.sub.vf vf7 vf3 vf5) + (.sub.vf vf8 vf3 vf2) + (.sub.vf vf9 vf5 vf4) + (.sub.vf vf10 vf5 vf2) + (.outer.product.vf vf2 vf6 vf7) + (.outer.product.vf vf3 vf7 vf8) + (.outer.product.vf vf4 vf9 vf10) + (.mul.vf vf2 vf2 vf1) + (.mul.vf vf3 vf3 vf1) + (.nop.vf) + (.mul.vf vf4 vf4 vf1) + (.add.x.vf vf2 vf2 vf2 :mask #b10) + (.add.x.vf vf3 vf3 vf3 :mask #b10) + (.add.x.vf vf4 vf4 vf4 :mask #b10) + (.nop.vf) + (.add.z.vf vf2 vf2 vf2 :mask #b10) + (.add.z.vf vf3 vf3 vf3 :mask #b10) + (.add.z.vf vf4 vf4 vf4 :mask #b10) + (.nop.vf) + (.mov a0-1 vf2) + (.mov a1-1 vf3) + (.mov v1-0 vf4) + (>= (the-as int (logior (logior a0-1 a1-1) v1-0)) 0) + ) + ) + +(defun point-in-plane-<-point+normal! ((arg0 vector) (arg1 vector) (arg2 vector)) + (let ((f0-3 (+ (+ (* (-> arg2 x) (-> arg1 x)) (* (-> arg2 y) (-> arg1 y))) + (* (-> arg2 z) (-> arg1 z)) + ) + ) + ) + (set! (-> arg0 w) 1.0) + (let ((f1-7 (fabs (-> arg2 x))) + (f2-3 (fabs (-> arg2 y))) + (f3-1 (fabs (-> arg2 z))) + ) + (cond + ((and (< f2-3 f1-7) (< f3-1 f1-7)) + (set! (-> arg0 y) (+ 4096.0 (-> arg1 y))) + (set! (-> arg0 z) (+ 4096.0 (-> arg1 z))) + (set! (-> arg0 x) + (/ (+ (- (- (* (-> arg2 y) (-> arg0 y))) (* (-> arg2 z) (-> arg0 z))) f0-3) (-> arg2 x)) + ) + ) + (else + (cond + ((and (< f1-7 f2-3) (< f3-1 f2-3)) + (set! (-> arg0 x) (+ 4096.0 (-> arg1 x))) + (set! (-> arg0 z) (+ 4096.0 (-> arg1 z))) + (set! (-> arg0 y) + (/ (- (- f0-3 (* (-> arg2 x) (-> arg0 x))) (* (-> arg2 z) (-> arg0 z))) (-> arg2 y)) + ) + ) + (else + (set! (-> arg0 x) (+ 4096.0 (-> arg1 x))) + (set! (-> arg0 y) (+ 4096.0 (-> arg1 y))) + (set! (-> arg0 z) + (/ (+ (- (- (* (-> arg2 x) (-> arg0 x))) (* (-> arg2 y) (-> arg0 y))) f0-3) (-> arg2 z)) + ) + ) + ) + ) + ) + ) + ) + arg0 + ) + + +(defun circle-circle-xz-intersect ((arg0 sphere) (arg1 sphere) (arg2 vector) (arg3 vector)) + ;; this function is unused and really complicated, so not implementing it for now. + (format 0 "circle-circle-xz-intersect~%") + (crash!) + 0 + ) + +(defun circle-test () + "Test the circle-circle-xz-intersect function." + ;; doesn't work because circle-circle-xz-intersect hasn't been ported. + (let ((s4-0 (new 'stack 'sphere)) + (a1-2 (new 'stack 'sphere)) + (s5-0 (new-stack-vector0)) + (gp-0 (new-stack-vector0)) + ) + (let ((v1-3 s4-0)) + (set! (-> v1-3 x) 0.0) + (set! (-> v1-3 y) 0.0) + (set! (-> v1-3 z) 0.0) + (set! (-> v1-3 w) 1.0) + ) + (let ((v1-4 a1-2)) + (set! (-> v1-4 x) 100.0) + (set! (-> v1-4 y) 0.0) + (set! (-> v1-4 z) 0.0) + (set! (-> v1-4 w) 10000.0) + ) + (let ((a2-1 (circle-circle-xz-intersect s4-0 a1-2 s5-0 gp-0))) + (format #t "res = ~d~%" a2-1) + ) + (format #t "(~f, ~f)~%" (-> s5-0 x) (-> s5-0 z)) + (format #t "(~f, ~f)~%" (-> gp-0 x) (-> gp-0 z)) + ) + (none) + ) + + +(defun vector-circle-tangent-new ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + "Unused." + (rlet ((Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (init-vf0-vector) + (let ((a1-2 (new 'stack 'sphere))) + (set! (-> (new 'stack-no-clear 'vector) quad) (the-as uint128 0)) + (set! (-> (new 'stack-no-clear 'vector) quad) (the-as uint128 0)) + (let ((v1-3 0.5)) + (.lvf vf3 (&-> arg1 quad)) + (.mov vf2 v1-3) + ) + (.lvf vf4 (&-> arg0 quad)) + (.add.vf vf1 vf3 vf4) + (.sub.vf vf5 vf4 vf3) + (.mul.x.vf vf1 vf1 vf2) + (.mul.x.vf vf5 vf5 vf2) + (.mul.vf vf5 vf5 vf5 :mask #b101) + (.add.z.vf vf5 vf5 vf5 :mask #b1) + (.sqrt.vf Q vf5 :ftf #b0) + (.wait.vf) + (.mul.vf vf1 vf0 Q :mask #b1000) + (.nop.vf) + (.nop.vf) + (.svf (&-> a1-2 quad) vf1) + (circle-circle-xz-intersect (the-as sphere arg1) a1-2 arg2 arg3) + ) + 0 + (none) + ) + ) + +(defun vector-circle-tangent ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + "Also unused." + (let* ((s3-1 (vector-! (the-as vector (new 'stack-no-clear 'sphere)) arg1 arg0)) + (f0-0 (vector-xz-length s3-1)) + (f28-0 (acos (/ (-> arg1 w) f0-0))) + ) + (cond + ((>= 546.13336 f28-0) ;; 2/15 of a meter... + (set! (-> arg2 x) (- (-> arg0 x) (-> s3-1 z))) + (set! (-> arg2 y) 0.0) + (set! (-> arg2 z) (+ (-> arg0 z) (-> s3-1 x))) + (set! (-> arg3 x) (+ (-> arg0 x) (-> s3-1 z))) + (set! (-> arg3 y) 0.0) + (set! (-> arg3 z) (- (-> arg0 z) (-> s3-1 x))) + ) + (else + (let ((f0-15 (atan (-> s3-1 z) (-> s3-1 x))) + (f30-0 (- (-> arg1 w))) + (s3-2 (new 'stack-no-clear 'vector)) + ) + (let ((s2-1 (new 'stack-no-clear 'vector))) + (let ((a2-1 (new 'stack-no-clear 'vector))) + (set! (-> a2-1 x) (- f0-15 f28-0)) + (set! (-> a2-1 y) (+ f0-15 f28-0)) + (vector-sincos! s3-2 s2-1 a2-1) + ) + (set! (-> arg2 x) (+ (-> arg1 x) (* f30-0 (-> s2-1 x)))) + (set! (-> arg2 z) (+ (-> arg1 z) (* f30-0 (-> s3-2 x)))) + (set! (-> arg3 x) (+ (-> arg1 x) (* f30-0 (-> s2-1 y)))) + ) + (set! (-> arg3 z) (+ (-> arg1 z) (* f30-0 (-> s3-2 y)))) + ) + ) + ) + ) + 0 + (none) + ) + +(defun find-knot-span ((arg0 int) (arg1 int) (arg2 float) (arg3 (inline-array vector))) + "Binary serach over knots to find which contains the value float in (arg0 arg1). Unused." + (local-vars (v0-0 int)) + + ;; if the knot after this, is exactly target value, return that. + (b! (= arg2 (-> arg3 (+ arg0 1))) cfg-11 :delay (set! v0-0 arg0)) + + ;; convert to int? + (let ((v1-3 (the int arg2))) + (let* ((a2-1 (+ v1-3 3)) + ;;(t0-1 (+ (* a2-1 4) (the-as int arg3))) + (t0-1 (&-> arg3 0 data a2-1)) + ;;(f1-2 (dynamic-array-field-access t0-1 PLACEHOLDER)) + (f1-2 (-> t0-1 0)) + (f2-0 (-> t0-1 1)) + ) + (b! (> f1-2 arg2) cfg-4) + (b! (>= arg2 f2-0) cfg-4 :delay (set! v0-0 a2-1)) + ) + + ;; don't think this is hit normally. + (b! #t cfg-11) + + ;; loop setup + (label cfg-4) + (let ((a1-1 arg1) ;; current + (a0-1 (+ arg0 1)) ;; next + ) + + ;; loop top + (label cfg-5) + + (let ((a2-3 (/ (+ a1-1 a0-1) 2))) + (let ((t0-3 (&-> arg3 0 data a2-3))) + (print-type t0-3) + (b! (>= arg2 (-> t0-3 0)) cfg-7) + (b! #t cfg-5 :delay (set! a0-1 a2-3)) + (label cfg-7) + (b! (< arg2 (-> t0-3 1)) cfg-9) + ) + (b! #t cfg-5 :delay (set! a1-1 a2-3)) + (label cfg-9) + (set! v0-0 a2-3) + ) + ) + (b! (= v0-0 v1-3) cfg-11) + ) + (nop!) + (nop!) + (label cfg-11) + v0-0 + ) + +(defun calculate-basis-functions-vector! ((arg0 (pointer float)) (arg1 int) (arg2 float) (arg3 (pointer float))) + (local-vars (v1-0 int) (v1-1 object)) + ;;(.sll v1-0 arg1 2) + (set! v1-0 (* 4 arg1)) ;; originally used 32-bit asm + (let ((a1-1 #x3f800000) + (f3-0 arg2) + ) + ;;(.addu v1-1 arg3 v1-0) + (set! v1-1 (&+ arg3 v1-0)) + (let* ((f1-0 (the-as float a1-1)) ;; trick to load float constant. + (f5-0 f1-0) + ) + 0.0 + 0.0 + (let* ((f0-2 (-> (the-as (pointer float) v1-1) 0)) + (f2-0 (-> (the-as (pointer float) v1-1) 1)) + (f0-3 (- f3-0 f0-2)) + (f4-0 (- f2-0 f3-0)) + (f10-0 (/ f1-0 (+ f4-0 f0-3))) + (f2-2 (-> (the-as (pointer float) v1-1) -1)) + (f8-0 (-> (the-as (pointer float) v1-1) 2)) + (f2-3 (- f3-0 f2-2)) + (f9-0 (+ f4-0 f2-3)) + (f6-0 (-> (the-as (pointer float) v1-1) -2)) + (f7-0 (-> (the-as (pointer float) v1-1) 3)) + (f9-1 (/ f1-0 f9-0)) + (f5-1 (* f5-0 f10-0)) + (f11-0 (* f4-0 f5-1)) + (f10-1 (* f0-3 f5-1)) + (f5-2 (- f8-0 f3-0)) + (f8-1 (* f11-0 f9-1)) + (f11-1 (/ f1-0 (+ f5-2 f0-3))) + (f9-3 (* f4-0 f8-1)) + (f8-2 (* f2-3 f8-1)) + (f11-2 (* f10-1 f11-1)) + (f10-3 (+ (* f5-2 f11-2) f8-2)) + (f8-3 (* f0-3 f11-2)) + (f6-1 (- f3-0 f6-0)) + (f3-1 (- f7-0 f3-0)) + (f7-3 (* f9-3 (/ f1-0 (+ f4-0 f6-1)))) + (f4-1 (* f4-0 f7-3)) + (f6-2 (* f6-1 f7-3)) + (f7-6 (* f10-3 (/ f1-0 (+ f5-2 f2-3)))) + (f5-4 (+ (* f5-2 f7-6) f6-2)) + (f2-4 (* f2-3 f7-6)) + (f1-2 (* f8-3 (the-as float (/ f1-0 (+ f3-1 f0-3))))) + (f2-5 (+ (* f3-1 f1-2) f2-4)) + (f0-4 (* f0-3 f1-2)) + ) + (set! (-> arg0 0) f4-1) + (set! (-> arg0 1) f5-4) + (set! (-> arg0 2) f2-5) + (set! (-> arg0 3) f0-4) + ) + ) + ) + arg0 + ) + +(defun curve-evaluate! ((arg0 vector) (arg1 float) (arg2 pointer) (arg3 int) (arg4 (inline-array vector)) (arg5 int)) + (local-vars (v1-7 int) (v1-8 int) (v1-10 float) (s3-0 int)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + ) + (init-vf0-vector) + (let ((s4-0 (new 'static 'array float 4 0.0 0.0 0.0 0.0))) + 0 + (let* ((f0-0 (-> arg4 0 x)) + (f1-0 (-> (&-> arg4 0 data (+ arg5 -1)) 0)) + (a2-1 (fmax (fmin (* arg1 f1-0) f1-0) f0-0)) + ) + (let* ((a1-1 (+ arg5 -5)) + (a3-1 3) + (f0-2 a2-1) + (v1-5 arg4) + (f0-3 f0-2) + ) + (b! (= f0-3 (-> (&-> v1-5 0 data (+ a1-1 1)) 0)) + cfg-11 + :delay (set! s3-0 a1-1) + ) + (let ((a0-4 (the int f0-3))) + (let* ((t1-1 (+ a0-4 3)) + (t2-1 (&-> v1-5 0 data t1-1)) + (f1-4 (-> t2-1 0)) + (f2-3 (-> t2-1 1)) + ) + (b! (> f1-4 f0-3) cfg-4) + (b! (>= f0-3 f2-3) cfg-4 :delay (set! s3-0 t1-1)) + ) + (b! #t cfg-11) + (label cfg-4) + (let ((a3-2 a3-1) + (a1-2 (+ a1-1 1)) + ) + (label cfg-5) + (let ((t1-3 (/ (+ a3-2 a1-2) 2))) + (let ((t2-3 (&-> v1-5 0 data t1-3))) + (b! (>= f0-3 (-> t2-3 0)) cfg-7) + (b! #t cfg-5 :delay (set! a1-2 t1-3)) + (label cfg-7) + (b! (< f0-3 (-> t2-3 1)) cfg-9) + ) + (b! #t cfg-5 :delay (set! a3-2 t1-3)) + (label cfg-9) + (set! s3-0 t1-3) + ) + ) + (b! (= s3-0 a0-4) cfg-11) + ) + ) + (nop!) + (nop!) + (label cfg-11) + (calculate-basis-functions-vector! + s4-0 + s3-0 + a2-1 + (the-as (pointer float) arg4) + ) + ) + ;;(.addiu v1-7 s3-0 -3) + (set! v1-7 (- s3-0 3)) + (.lvf vf6 s4-0) + ) + ;;(.sll v1-8 v1-7 4) + (set! v1-8 (* v1-7 16)) + (.add.x.vf vf1 vf0 vf0 :mask #b1000) + (let ((v1-9 (+ v1-8 (the-as int arg2)))) + (nop!) + (nop!) + (.lvf vf2 (&-> (the-as (pointer int128) v1-9))) + (nop!) + (.lvf vf3 (+ v1-9 16)) + (nop!) + (.lvf vf4 (+ v1-9 32)) + (nop!) + (.lvf vf5 (+ v1-9 48)) + ) + (.mul.x.vf acc vf2 vf6) + (nop!) + (.add.mul.y.vf acc vf3 vf6 acc :mask #b111) + (nop!) + (.add.mul.z.vf acc vf4 vf6 acc :mask #b111) + (nop!) + (.add.mul.w.vf vf1 vf5 vf6 acc :mask #b111) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (.svf (&-> arg0 quad) vf1) + (.mov v1-10 vf1) + arg0 + ) + ) + +(defun curve-get-pos! ((arg0 vector) (arg1 float) (arg2 curve)) + (curve-evaluate! + arg0 + arg1 + (-> arg2 cverts) + (-> arg2 num-cverts) + (-> arg2 knots) + (-> arg2 num-knots) + ) + ) + +(defun curve-length ((arg0 curve)) + (let ((s5-0 (new-stack-vector0)) + (s4-0 (new-stack-vector0)) + (s3-0 (* 3 (-> arg0 num-cverts))) + (f30-0 0.0) + ) + (curve-evaluate! + s4-0 + (-> arg0 knots 0 x) + (-> arg0 cverts) + (-> arg0 num-cverts) + (-> arg0 knots) + (-> arg0 num-knots) + ) + (dotimes (s2-0 s3-0) + (set! (-> s5-0 quad) (-> s4-0 quad)) + (curve-evaluate! + s4-0 + (/ (the float (+ s2-0 1)) (the float s3-0)) + (-> arg0 cverts) + (-> arg0 num-cverts) + (-> arg0 knots) + (-> arg0 num-knots) + ) + (+! f30-0 (vector-vector-distance s5-0 s4-0)) + ) + f30-0 + ) + ) + +(defun curve-copy! ((arg0 curve) (arg1 curve)) + (set! (-> arg0 cverts) (-> arg1 cverts)) + (set! (-> arg0 num-cverts) (-> arg1 num-cverts)) + (set! (-> arg0 knots) (-> arg1 knots)) + (set! (-> arg0 num-knots) (-> arg1 num-knots)) + (set! (-> arg0 length) (-> arg1 length)) + arg0 + ) + +(defun curve-closest-point ((arg0 curve) (arg1 vector) (arg2 float) (arg3 float) (arg4 int) (arg5 float)) + (local-vars (sv-48 float)) + (set! sv-48 arg3) + (let ((s3-0 arg4) + (gp-0 arg5) + (f30-0 (curve-length arg0)) + (s2-0 (new 'stack-no-clear 'vector)) + (s1-0 (new 'stack-no-clear 'vector)) + ) + 0.0 + 0.0 + 0.0 + 0.0 + (let ((f28-0 0.5)) + 0.0 + (if (< 0.0 sv-48) + (set! f28-0 (/ sv-48 f30-0)) + ) + (let* ((s0-1 (- arg2 (/ gp-0 f30-0))) + (f26-0 (- s0-1 f28-0)) + (f24-0 (+ s0-1 f28-0)) + ) + (curve-get-pos! s2-0 f26-0 arg0) + (curve-get-pos! s1-0 f24-0 arg0) + (let ((f22-0 (vector-vector-distance-squared s2-0 arg1)) + (f20-0 (vector-vector-distance-squared s1-0 arg1)) + ) + (while (> s3-0 0) + (+! s3-0 -1) + (set! f28-0 (* 0.5 f28-0)) + (let ((v1-4 (cond + ((< f22-0 f20-0) + (curve-get-pos! s1-0 s0-1 arg0) + (set! f20-0 (vector-vector-distance-squared s1-0 arg1)) + (set! f24-0 s0-1) + (- s0-1 f28-0) + ) + (else + (curve-get-pos! s2-0 s0-1 arg0) + (set! f22-0 (vector-vector-distance-squared s2-0 arg1)) + (set! f26-0 s0-1) + (+ s0-1 f28-0) + ) + ) + ) + ) + (set! s0-1 (fmin 1.0 (fmax 0.0 v1-4))) + ) + ) + (+ (if (< f22-0 f20-0) + f26-0 + f24-0 + ) + (/ gp-0 f30-0) + ) + ) ) ) ) ) -;; TODO vector-segment-distance-point! - -;; TODO - temporary for lights.gc -(define-extern vector-deg-slerp (function vector vector vector float vector)) -;; TODO - temporary for transformq.gc -(define-extern forward-up-nopitch->quaternion (function quaternion vector vector quaternion)) -(define-extern forward-up->quaternion (function quaternion vector vector quaternion)) -(define-extern vector-flatten! (function vector vector vector vector)) - -;; TODO -(define-extern vector-3pt-cross! (function vector vector vector vector vector)) -(define-extern curve-evaluate! (function vector float int int vector int int)) +(defun vector-plane-distance ((arg0 vector) (arg1 plane) (arg2 vector)) + (vector-dot + (vector-! (new 'stack-no-clear 'vector) arg0 (the-as vector (&-> arg1 x))) + arg2 + ) + ) diff --git a/goal_src/engine/math/matrix.gc b/goal_src/engine/math/matrix.gc index f96358f09e..469e2d7378 100644 --- a/goal_src/engine/math/matrix.gc +++ b/goal_src/engine/math/matrix.gc @@ -1001,7 +1001,7 @@ (matrix-identity! dst) (label end) ) - (none) + dst ) (defun matrix-axis-angle! ((dst matrix) (axis vector) (angle-deg float)) diff --git a/goal_src/engine/math/quaternion.gc b/goal_src/engine/math/quaternion.gc index 885ea5664f..a7cb848d34 100644 --- a/goal_src/engine/math/quaternion.gc +++ b/goal_src/engine/math/quaternion.gc @@ -976,25 +976,6 @@ ) ) -;; (local-vars (f0-1 float)) -;; (let ((gp-0 acos)) -;; (let* ((s5-0 (vector-z-quaternion! (new 'stack 'vector) arg0)) -;; (v1-1 (vector-z-quaternion! (new 'stack 'vector) arg1)) -;; (f0-0 (-> s5-0 data 0)) -;; (f1-0 (-> s5-0 data 1)) -;; (f2-0 (-> s5-0 data 2)) -;; (f3-0 (-> v1-1 data 0)) -;; (f4-0 (-> v1-1 data 1)) -;; (f5-0 (-> v1-1 data 2)) -;; ) -;; (.mula.s f0-0 f3-0) -;; (.madda.s f1-0 f4-0) -;; (.madd.s f0-1 f2-0 f5-0) -;; ) -;; (gp-0 f0-1) -;; ) - - (defun quaternion-rotate-y-to-vector! ((arg0 quaternion) (arg1 quaternion) (arg2 quaternion) (arg3 float)) (let ((s5-0 (new 'stack-no-clear 'quaternion))) (let ((t9-0 vector-xz-normalize!) diff --git a/goal_src/engine/math/vector-h.gc b/goal_src/engine/math/vector-h.gc index 147a71d53f..01430d9e92 100644 --- a/goal_src/engine/math/vector-h.gc +++ b/goal_src/engine/math/vector-h.gc @@ -296,11 +296,11 @@ ;; Vector of 4 floats. Shortened to "vector" because it is commonly used. (deftype vector (structure) - ((data float 4 :do-not-decompile :score -9999 :offset-assert 0) - (x float :offset 0) + ((x float :offset 0) (y float :offset 4) (z float :offset 8) (w float :offset 12) + (data float 4 :do-not-decompile :score -9999 :offset 0) (quad uint128 :offset 0) ) :method-count-assert 9 @@ -714,3 +714,9 @@ (defun-extern vector+float*! vector vector vector float vector) (defun-extern vector-normalize! vector float vector) (defun-extern vector-float*! vector vector float vector) +(define-extern vector-normalize-copy! (function vector vector float vector)) +(define-extern vector-cross! (function vector vector vector vector)) +(define-extern vector-negate! (function vector vector vector)) +(define-extern vector-normalize-ret-len! (function vector float float)) +(define-extern vector-vector-distance (function vector vector float)) +(define-extern vector-vector-distance-squared (function vector vector float)) diff --git a/goal_src/kernel/gcommon.gc b/goal_src/kernel/gcommon.gc index 223ac5d24e..2136ca5ede 100644 --- a/goal_src/kernel/gcommon.gc +++ b/goal_src/kernel/gcommon.gc @@ -1365,3 +1365,21 @@ ;; Copies the contents of a gpr to a cop0 (system control) register (fake-asm .mtc0 dest src) ) + + +;;;;;;;;;;;;;;;;;;;;;;;; +;; Branch Macro +;;;;;;;;;;;;;;;;;;;;;;;; + +(defmacro b! (pred destination &key (delay '()) &key (likely-delay '())) + "Branch!" + ;; evaluate the predicate + `(let ((should-branch ,pred)) + ;; normal delay slot: + ,delay + (when should-branch + ,likely-delay + (goto ,destination) + ) + ) + ) diff --git a/scripts/decomp_progress.py b/scripts/decomp_progress.py index 3ff0cb75da..c63dde71e7 100644 --- a/scripts/decomp_progress.py +++ b/scripts/decomp_progress.py @@ -6,9 +6,9 @@ import argparse ### Script to track decompilation progress. ### Example usage: python3 scripts/decomp_progress.py ~/jak-project/goal_src -def get_goal_files(root_dir): +def get_goal_files(root_dir, ext = "*.gc"): """Get all GOAL source files under root_dir.""" - return [goal_file for file in os.walk(root_dir) for goal_file in glob.glob(os.path.join(file[0], '*.gc'))] + return [goal_file for file in os.walk(root_dir) for goal_file in glob.glob(os.path.join(file[0], ext))] def lines_in_file(file_path): @@ -41,10 +41,17 @@ def main(): args = parser.parse_args() all_files = get_goal_files(args.goal_src) + ref_files = get_goal_files(args.goal_src + "/../test/", "*_REF.gc") + + ref_files_no_ext = [os.path.basename(fn)[:-7] for fn in ref_files] + + + file_stats = [] total_gc_files = 0 excluded_files = {"game_dgos.gc", "all_files.gc", "goal-lib.gc", "ocean-trans-tables.gc", "ocean-frames.gc", "ocean-tables.gc"} + modified = set() for fn in all_files: short_name = os.path.basename(fn) @@ -60,8 +67,18 @@ def main(): continue file_stats.append((short_name, line_count)) + modified.add(short_name[:-3]) + file_stats.sort(key=lambda x: x[1]) + + missing_ref_files = modified - set(ref_files_no_ext) + + print("Missing ref files:") + for fn in missing_ref_files: + print(" {}".format(fn)) + + print_table(file_stats, total_gc_files) diff --git a/test/decompiler/FormRegressionTest.cpp b/test/decompiler/FormRegressionTest.cpp index d2dba22108..ffaba73a7a 100644 --- a/test/decompiler/FormRegressionTest.cpp +++ b/test/decompiler/FormRegressionTest.cpp @@ -149,7 +149,7 @@ std::unique_ptr FormRegressionTest::make_function( // analyze function prologue/epilogue test->func.analyze_prologue(test->file); // build control flow graph - test->func.cfg = build_cfg(test->file, 0, test->func, {}); + 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()); diff --git a/test/decompiler/reference/decompiler-macros.gc b/test/decompiler/reference/decompiler-macros.gc index dbd622b9ca..b89a5bdbd0 100644 --- a/test/decompiler/reference/decompiler-macros.gc +++ b/test/decompiler/reference/decompiler-macros.gc @@ -113,4 +113,17 @@ ;; otherwise don't ignore it. `(define ,name (lambda :name ,name :behavior ,process-type ,bindings ,@body)) ) - ) \ No newline at end of file + ) + +(defmacro b! (pred destination &key (delay '()) &key (likely-delay '())) + "Branch!" + ;; evaluate the predicate + `(let ((should-branch ,pred)) + ;; normal delay slot: + ,delay + (when should-branch + ,likely-delay + (goto ,destination) + ) + ) + ) diff --git a/test/decompiler/reference/engine/geometry/geometry-h_REF.gc b/test/decompiler/reference/engine/geometry/geometry-h_REF.gc index 42633a19dc..e166aa7053 100644 --- a/test/decompiler/reference/engine/geometry/geometry-h_REF.gc +++ b/test/decompiler/reference/engine/geometry/geometry-h_REF.gc @@ -3,11 +3,11 @@ ;; definition of type curve (deftype curve (structure) - ((cverts pointer :offset-assert 0) - (num-cverts int32 :offset-assert 4) - (knots pointer :offset-assert 8) - (num-knots int32 :offset-assert 12) - (length float :offset-assert 16) + ((cverts pointer :offset-assert 0) + (num-cverts int32 :offset-assert 4) + (knots (inline-array vector) :offset-assert 8) + (num-knots int32 :offset-assert 12) + (length float :offset-assert 16) ) :method-count-assert 9 :size-assert #x14 diff --git a/test/decompiler/reference/engine/geometry/geometry_REF.gc b/test/decompiler/reference/engine/geometry/geometry_REF.gc new file mode 100644 index 0000000000..f9c065dd51 --- /dev/null +++ b/test/decompiler/reference/engine/geometry/geometry_REF.gc @@ -0,0 +1,1488 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for function vector-flatten! +(defun vector-flatten! ((dst vector) (src vector) (plane-normal vector)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) + (.svf (&-> dst quad) vf3) + dst + ) + ) + +;; definition for function vector-reflect! +(defun vector-reflect! ((dst vector) (src vector) (plane-normal vector)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) + (.add.vf acc vf3 vf3 :mask #b111) + (.sub.mul.w.vf vf3 vf1 vf0 acc :mask #b111) + (.svf (&-> dst quad) vf3) + dst + ) + ) + +;; definition for function vector-reflect-flat! +(defun vector-reflect-flat! ((dst vector) (src vector) (plane-normal vector)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) + (.add.vf vf3 vf3 vf2 :mask #b111) + (.svf (&-> dst quad) vf3) + dst + ) + ) + +;; definition for function vector-reflect-true-flat! +(defun + vector-reflect-true-flat! + ((dst vector) (src vector) (plane-normal vector)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) + (.svf (&-> dst quad) vf3) + dst + ) + ) + +;; definition for function vector-reflect-flat-above! +(defun + vector-reflect-flat-above! + ((dst vector) (src vector) (plane-normal vector)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> src quad)) + (.lvf vf2 (&-> plane-normal quad)) + (.mov.vf vf3 vf0 :mask #b1000) + (.outer.product.vf vf3 vf1 vf2) + (.outer.product.vf vf3 vf2 vf3) + (.svf (&-> dst quad) vf3) + (let* ((f0-0 (vector-length dst)) + (f1-1 (vector-dot dst plane-normal)) + (f1-2 (- (* 0.02 f0-0) f1-1)) + ) + (vector+float*! dst dst plane-normal (fmin 16384.0 (* 16.0 f1-2))) + ) + ) + ) + +;; definition for function vector-segment-distance-point! +(defun + vector-segment-distance-point! + ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (local-vars (v0-0 float) (v1-0 float) (v1-1 float)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + ) + (init-vf0-vector) + (nop!) + (.lvf vf3 (&-> arg1 quad)) + (.lvf vf4 (&-> arg2 quad)) + (.lvf vf5 (&-> arg0 quad)) + (.sub.vf vf1 vf4 vf3) + (.sub.vf vf6 vf5 vf3) + (.mul.vf vf2 vf1 vf1) + (.mul.x.vf acc vf0 vf2 :mask #b1000) + (.add.mul.y.vf acc vf0 vf2 acc :mask #b1000) + (.add.mul.z.vf vf2 vf0 vf2 acc :mask #b1000) + (.sqrt.vf Q vf2 :ftf #b11) + (.wait.vf) + (.add.vf vf2 vf0 Q :mask #b1) + (.nop.vf) + (.nop.vf) + (.div.vf Q vf0 vf2 :fsf #b11 :ftf #b0) + (.mov v1-0 vf2) + (let ((f2-0 v1-0)) + (.wait.vf) + (.mul.vf vf1 vf1 Q) + (.mul.vf vf7 vf1 vf6) + (let ((f1-0 0.0)) + (.add.y.vf vf7 vf7 vf7 :mask #b1) + (.add.z.vf vf7 vf7 vf7 :mask #b1) + (.mov v1-1 vf7) + (let ((f0-0 v1-1)) + (b! (< f0-0 f1-0) cfg-4 :likely-delay (set! f0-0 f1-0)) + (b! (< f2-0 f0-0) cfg-4 :likely-delay (set! f0-0 f2-0)) + (label cfg-4) + (let ((v1-2 f0-0)) + (.mov vf7 v1-2) + ) + ) + ) + ) + (.mul.x.vf vf1 vf1 vf7) + (b! (= arg3 #f) cfg-6 :delay (.mov.vf vf8 vf0 :mask #b1000)) + (.add.vf vf8 vf3 vf1 :mask #b111) + (.svf (&-> arg3 quad) vf8) + (label cfg-6) + (.sub.vf vf2 vf6 vf1) + (.mul.vf vf2 vf2 vf2) + (.mul.x.vf acc vf0 vf2 :mask #b1000) + (.add.mul.y.vf acc vf0 vf2 acc :mask #b1000) + (.add.mul.z.vf vf2 vf0 vf2 acc :mask #b1000) + (.sqrt.vf Q vf2 :ftf #b11) + (.wait.vf) + (.add.vf vf2 vf0 Q :mask #b1) + (.nop.vf) + (.mov v0-0 vf2) + v0-0 + ) + ) + +;; definition for function vector-line-distance +;; Used lq/sq +(defun vector-line-distance ((arg0 vector) (arg1 vector) (arg2 vector)) + (let* ((a1-3 (vector-normalize! (vector-! (new-stack-vector0) arg2 arg1) 1.0)) + (gp-1 (vector-! (new-stack-vector0) arg0 arg1)) + (f0-1 (vector-dot a1-3 gp-1)) + (v1-3 (vector-float*! (new-stack-vector0) a1-3 f0-1)) + ) + (vector-length (vector-! (new-stack-vector0) gp-1 v1-3)) + ) + ) + +;; definition for function vector-line-distance-point! +;; Used lq/sq +(defun + vector-line-distance-point! + ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (let* ((a1-3 (vector-normalize! (vector-! (new-stack-vector0) arg2 arg1) 1.0)) + (s4-1 (vector-! (new-stack-vector0) arg0 arg1)) + (f0-1 (vector-dot a1-3 s4-1)) + (v1-4 (vector-float*! (new-stack-vector0) a1-3 f0-1)) + ) + (if arg3 + (vector+! arg3 arg1 v1-4) + ) + (vector-length (vector-! (new-stack-vector0) s4-1 v1-4)) + ) + ) + +;; definition for function vector-orient-by-quat! +(defun vector-orient-by-quat! ((arg0 vector) (arg1 vector) (arg2 quaternion)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> arg2 vec quad)) + (.lvf vf6 (&-> arg1 quad)) + (.add.vf vf5 vf1 vf1) + (.add.w.vf vf2 vf0 vf1 :mask #b1) + (.add.z.vf vf2 vf0 vf1 :mask #b10) + (.sub.y.vf vf2 vf0 vf1 :mask #b100) + (.sub.w.vf vf2 vf0 vf0 :mask #b1000) + (.sub.z.vf vf3 vf0 vf1 :mask #b1) + (.add.w.vf vf3 vf0 vf1 :mask #b10) + (.add.x.vf vf3 vf0 vf1 :mask #b100) + (.sub.w.vf vf3 vf0 vf0 :mask #b1000) + (.add.y.vf vf4 vf0 vf1 :mask #b1) + (.sub.x.vf vf4 vf0 vf1 :mask #b10) + (.add.w.vf vf4 vf0 vf1 :mask #b100) + (.sub.w.vf vf4 vf0 vf0 :mask #b1000) + (.outer.product.vf vf2 vf5 vf2) + (.outer.product.vf vf3 vf5 vf3) + (.outer.product.vf vf4 vf5 vf4) + (.add.w.vf vf2 vf2 vf0 :mask #b1) + (.add.w.vf vf3 vf3 vf0 :mask #b10) + (.add.w.vf vf4 vf4 vf0 :mask #b100) + (.mul.w.vf acc vf0 vf6) + (.add.mul.x.vf acc vf2 vf6 acc) + (.add.mul.y.vf acc vf3 vf6 acc) + (.add.mul.z.vf vf6 vf4 vf6 acc) + (.svf (&-> arg0 quad) vf6) + arg0 + ) + ) + +;; definition for function forward-down->inv-matrix +;; Used lq/sq +(defun forward-down->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + (vector-normalize-copy! (-> arg0 vector 2) arg1 1.0) + (vector-cross! (the-as vector (-> arg0 vector)) (-> arg0 vector 2) arg2) + (vector-normalize! (the-as vector (-> arg0 vector)) 1.0) + (vector-cross! (-> arg0 vector 1) arg1 (the-as vector (-> arg0 vector))) + (vector-normalize! (-> arg0 vector 1) 1.0) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 vector 0 w) 0.0) + (set! (-> arg0 vector 1 w) 0.0) + (set! (-> arg0 vector 2 w) 0.0) + (set! (-> arg0 vector 3 w) 1.0) + arg0 + ) + +;; definition for function forward-down-nopitch->inv-matrix +;; Used lq/sq +(defun + forward-down-nopitch->inv-matrix + ((arg0 matrix) (arg1 vector) (arg2 vector)) + (vector-normalize-copy! (-> arg0 vector 1) arg2 1.0) + (vector-negate! (-> arg0 vector 1) (-> arg0 vector 1)) + (vector-cross! (the-as vector (-> arg0 vector)) (-> arg0 vector 1) arg1) + (vector-normalize! (the-as vector (-> arg0 vector)) 1.0) + (vector-cross! + (-> arg0 vector 2) + (the-as vector (-> arg0 vector)) + (-> arg0 vector 1) + ) + (vector-normalize! (-> arg0 vector 2) 1.0) + (set! (-> arg0 vector 3 quad) (the-as uint128 0)) + (set! (-> arg0 vector 0 w) 0.0) + (set! (-> arg0 vector 1 w) 0.0) + (set! (-> arg0 vector 2 w) 0.0) + (set! (-> arg0 vector 3 w) 1.0) + arg0 + ) + +;; definition for function forward-up-nopitch->inv-matrix +;; Used lq/sq +(defun forward-up-nopitch->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) + (forward-down-nopitch->inv-matrix + arg0 + arg1 + (vector-negate! (new-stack-vector0) arg2) + ) + ) + +;; definition for function forward-up-nopitch->quaternion +;; Used lq/sq +(defun + forward-up-nopitch->quaternion + ((arg0 quaternion) (arg1 vector) (arg2 vector)) + (matrix->quaternion + arg0 + (forward-up-nopitch->inv-matrix (new-stack-matrix0) arg1 arg2) + ) + ) + +;; definition for function forward-up->quaternion +;; Used lq/sq +(defun forward-up->quaternion ((arg0 quaternion) (arg1 vector) (arg2 vector)) + (matrix->quaternion + arg0 + (forward-down->inv-matrix + (new-stack-matrix0) + arg1 + (vector-negate! (new 'stack-no-clear 'vector) arg2) + ) + ) + ) + +;; definition for function quaternion-from-two-vectors! +;; Used lq/sq +(defun + quaternion-from-two-vectors! + ((arg0 quaternion) (arg1 vector) (arg2 vector)) + (let* ((s5-0 (vector-cross! (new-stack-vector0) arg1 arg2)) + (f0-0 (vector-length s5-0)) + (f1-1 (vector-dot arg1 arg2)) + ) + (let ((f0-1 (/ (sqrtf (* 0.5 (- 1.0 f1-1))) f0-0))) + (set! (-> arg0 x) (* (-> s5-0 x) f0-1)) + (set! (-> arg0 y) (* (-> s5-0 y) f0-1)) + (set! (-> arg0 z) (* (-> s5-0 z) f0-1)) + ) + (set! (-> arg0 w) (sqrtf (* 0.5 (+ 1.0 f1-1)))) + ) + arg0 + ) + +;; definition for function quaternion-from-two-vectors-max-angle! +;; Used lq/sq +(defun + quaternion-from-two-vectors-max-angle! + ((arg0 quaternion) (arg1 vector) (arg2 vector) (arg3 float)) + (let* ((s5-0 (vector-cross! (new-stack-vector0) arg1 arg2)) + (f30-0 (vector-length s5-0)) + (f26-0 (vector-dot arg1 arg2)) + (f28-0 (sqrtf (* 0.5 (- 1.0 f26-0)))) + ) + (let ((f0-5 (sin (* 0.5 arg3)))) + (cond + ((< f0-5 f28-0) + (set! f28-0 f0-5) + (set! (-> arg0 w) (cos (* 0.5 arg3))) + ) + (else + (set! (-> arg0 w) (sqrtf (* 0.5 (+ 1.0 f26-0)))) + ) + ) + ) + (let ((f0-12 (/ f28-0 f30-0))) + (set! (-> arg0 x) (* (-> s5-0 x) f0-12)) + (set! (-> arg0 y) (* (-> s5-0 y) f0-12)) + (set! (-> arg0 z) (* (-> s5-0 z) f0-12)) + ) + ) + arg0 + ) + +;; definition for function matrix-from-two-vectors! +;; Used lq/sq +(defun matrix-from-two-vectors! ((arg0 matrix) (arg1 vector) (arg2 vector)) + (let* + ((a1-3 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f0-1 (vector-dot arg1 arg2)) + (f1-0 1.0) + (f2-0 f0-1) + (f1-2 (sqrtf (- f1-0 (* f2-0 f2-0)))) + ) + (matrix-axis-sin-cos! arg0 a1-3 f1-2 f0-1) + ) + ) + +;; definition for function matrix-from-two-vectors-max-angle! +;; Used lq/sq +(defun + matrix-from-two-vectors-max-angle! + ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float)) + (let + ((s4-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f30-0 (vector-dot arg1 arg2)) + (f28-0 (cos arg3)) + ) + (cond + ((< f30-0 f28-0) + (matrix-axis-sin-cos! arg0 s4-1 (sin arg3) f28-0) + ) + (else + (let ((t9-5 matrix-axis-sin-cos!) + (a0-6 arg0) + (a1-4 s4-1) + (f0-1 1.0) + (f1-0 f30-0) + ) + (t9-5 a0-6 a1-4 (sqrtf (- f0-1 (* f1-0 f1-0))) f30-0) + ) + ) + ) + ) + ) + +;; definition for function matrix-from-two-vectors-max-angle-partial! +;; Used lq/sq +(defun + matrix-from-two-vectors-max-angle-partial! + ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float) (arg4 float)) + (let* + ((s4-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f28-0 (vector-dot arg1 arg2)) + (f30-0 (cos arg3)) + (f0-2 (+ 1.0 (* (+ -1.0 f28-0) arg4))) + ) + (cond + ((< f0-2 f30-0) + (matrix-axis-sin-cos! arg0 s4-1 (sin arg3) f30-0) + ) + (else + (let ((t9-5 matrix-axis-sin-cos!) + (a0-6 arg0) + (a1-4 s4-1) + (f1-3 1.0) + (f2-1 f0-2) + ) + (t9-5 a0-6 a1-4 (sqrtf (- f1-3 (* f2-1 f2-1))) f0-2) + ) + ) + ) + ) + ) + +;; definition for function matrix-from-two-vectors-partial-linear! +;; Used lq/sq +(defun + matrix-from-two-vectors-partial-linear! + ((arg0 matrix) (arg1 vector) (arg2 vector) (arg3 float)) + (let + ((gp-1 (vector-normalize! (vector-cross! (new-stack-vector0) arg2 arg1) 1.0)) + (f0-1 (vector-dot arg1 arg2)) + ) + (cond + ((< 0.9999 (fabs f0-1)) + (matrix-identity! arg0) + ) + (else + (let* ((f0-4 (cos (* arg3 (acos f0-1)))) + (t9-5 matrix-axis-sin-cos!) + (a0-6 arg0) + (f1-1 1.0) + (f2-1 f0-4) + ) + (t9-5 a0-6 gp-1 (sqrtf (- f1-1 (* f2-1 f2-1))) f0-4) + ) + ) + ) + ) + ) + +;; definition for function matrix-remove-z-rot +;; Used lq/sq +(defun matrix-remove-z-rot ((arg0 matrix) (arg1 matrix)) + (let ((s4-0 (new-stack-vector0))) + 0.0 + 0.0 + (let ((s5-0 (new-stack-matrix0))) + (vector-negate! s4-0 (the-as vector arg1)) + (vector-flatten! s4-0 s4-0 (-> arg0 vector 2)) + (vector-normalize! s4-0 1.0) + (let ((f30-0 (vector-dot (-> arg0 vector 1) s4-0))) + (when (< f30-0 0.99999) + (vector-cross! s4-0 (-> arg0 vector 1) s4-0) + (let ((f0-4 (vector-length s4-0))) + (if (< 0.0 (vector-dot s4-0 (-> arg0 vector 2))) + (set! f0-4 (- f0-4)) + ) + (matrix-axis-sin-cos! s5-0 (-> arg0 vector 2) f0-4 f30-0) + ) + (matrix*! arg0 arg0 s5-0) + ) + ) + ) + ) + arg0 + ) + +;; definition for function matrix-rot-diff! +;; Used lq/sq +(defun matrix-rot-diff! ((arg0 vector) (arg1 matrix) (arg2 matrix)) + (let ((s3-0 (new-stack-quaternion0)) + (s2-0 (new-stack-quaternion0)) + (s5-0 (new-stack-quaternion0)) + ) + 0.0 + (matrix->quaternion s3-0 arg1) + (matrix->quaternion s2-0 arg2) + (quaternion-conjugate! s5-0 s3-0) + (quaternion*! s5-0 s2-0 s5-0) + (quaternion-normalize! s5-0) + (if (< (-> s5-0 w) 0.0) + (quaternion-negate! s5-0 s5-0) + ) + (let ((f30-1 (* 2.0 (acos (-> s5-0 w))))) + (set! (-> arg0 quad) (-> s5-0 vec quad)) + (vector-negate! arg0 arg0) + (if (= (vector-normalize-ret-len! arg0 1.0) 0.0) + (set! (-> arg0 y) 1.0) + ) + f30-1 + ) + ) + ) + +;; definition for function quaternion-seek +;; Used lq/sq +(defun + quaternion-seek + ((arg0 quaternion) + (arg1 quaternion) + (arg2 quaternion) + (arg3 float) + (arg4 float) + ) + (let ((s5-0 (new-stack-matrix0)) + (s4-0 (new-stack-matrix0)) + ) + (quaternion->matrix s5-0 arg1) + (quaternion->matrix s4-0 arg2) + (let ((s2-1 (new-stack-quaternion0))) + (quaternion-from-two-vectors-max-angle! + s2-1 + (-> s5-0 vector 2) + (-> s4-0 vector 2) + arg4 + ) + (quaternion-normalize! (quaternion*! arg0 arg0 s2-1)) + ) + ) + ) + +;; definition for function vector-deg-seek +;; Used lq/sq +(defun vector-deg-seek ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float)) + (let ((s4-0 (new-stack-matrix0))) + (matrix-from-two-vectors-max-angle! s4-0 arg1 arg2 arg3) + (vector-matrix*! arg0 arg1 s4-0) + ) + ) + +;; definition for function vector-deg-slerp +;; Used lq/sq +(defun vector-deg-slerp ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float)) + (cond + ((>= 0.0 arg3) + (set! (-> arg0 quad) (-> arg1 quad)) + arg0 + ) + ((>= arg3 1.0) + (set! (-> arg0 quad) (-> arg2 quad)) + arg0 + ) + (else + (let ((s1-0 (new-stack-matrix0))) + (let + ((s2-0 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg1 1.0)) + (a2-3 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg2 1.0)) + ) + (matrix-from-two-vectors-partial-linear! s1-0 s2-0 a2-3 arg3) + ) + (vector-matrix*! arg0 arg1 s1-0) + ) + ) + ) + ) + +;; definition for function vector-vector-deg-slerp! +;; Used lq/sq +(defun + vector-vector-deg-slerp! + ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 float) (arg4 vector)) + (local-vars (sv-112 (function float float float float))) + (cond + ((>= 0.0 arg3) + (set! (-> arg0 quad) (-> arg1 quad)) + ) + ((>= arg3 1.0) + (set! (-> arg0 quad) (-> arg2 quad)) + ) + (else + (let* + ((s0-0 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg1 1.0)) + (s1-0 (vector-normalize-copy! (new 'stack-no-clear 'vector) arg2 1.0)) + (s0-1 + (forward-up->quaternion (new 'stack-no-clear 'quaternion) s0-0 arg4) + ) + (a2-5 + (forward-up->quaternion (new 'stack-no-clear 'quaternion) s1-0 arg4) + ) + (a1-6 + (quaternion-slerp! (new 'stack-no-clear 'quaternion) s0-1 a2-5 arg3) + ) + (s2-1 vector-normalize-copy!) + (s1-1 arg0) + (s0-2 (vector-z-quaternion! (new 'stack-no-clear 'vector) a1-6)) + ) + (set! sv-112 lerp) + (let ((s3-1 (vector-length arg1)) + (a1-7 (vector-length arg2)) + ) + (s2-1 s1-1 s0-2 (sv-112 s3-1 a1-7 arg3)) + ) + ) + ) + ) + arg0 + ) + +;; definition for function normal-of-plane +(defun normal-of-plane ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (rlet ((acc :class vf) + (Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (init-vf0-vector) + (.lvf vf3 (&-> arg2 quad)) + (.lvf vf1 (&-> arg1 quad)) + (.lvf vf2 (&-> arg3 quad)) + (.sub.vf vf1 vf3 vf1) + (.sub.vf vf2 vf3 vf2) + (.outer.product.vf vf4 vf2 vf1) + (.mul.vf vf5 vf4 vf4) + (.add.y.vf vf5 vf5 vf5 :mask #b1) + (.add.z.vf vf5 vf5 vf5 :mask #b1) + (.isqrt.vf Q vf0 vf5 :fsf #b11 :ftf #b0) + (.mov.vf vf4 vf0 :mask #b1000) + (.wait.vf) + (.mul.vf vf4 vf4 Q :mask #b111) + (.nop.vf) + (.nop.vf) + (.svf (&-> arg0 quad) vf4) + arg0 + ) + ) + +;; definition for function vector-3pt-cross! +(defun + vector-3pt-cross! + ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + ) + (init-vf0-vector) + (.lvf vf1 (&-> arg1 quad)) + (.lvf vf2 (&-> arg2 quad)) + (.lvf vf3 (&-> arg3 quad)) + (.add.x.vf vf4 vf0 vf0 :mask #b1000) + (.sub.vf vf2 vf2 vf1) + (.sub.vf vf3 vf3 vf1) + (.outer.product.vf vf4 vf2 vf3) + (.svf (&-> arg0 quad) vf4) + arg0 + ) + ) + +;; definition for function closest-pt-in-triangle +;; INFO: Return type mismatch int vs none. +;; Used lq/sq +(defun + closest-pt-in-triangle + ((arg0 vector) (arg1 vector) (arg2 matrix) (arg3 vector)) + (local-vars + (v1-0 float) + (v1-4 uint) + (v1-5 uint) + (v1-6 uint) + (v1-7 uint) + (v1-10 uint) + (a0-1 float) + (a1-1 float) + ) + (rlet ((acc :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) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + (vf7 :class vf) + (vf8 :class vf) + (vf9 :class vf) + ) + (init-vf0-vector) + (nop!) + (nop!) + (.lvf vf3 (&-> arg2 vector 1 quad)) + (nop!) + (.lvf vf4 (&-> arg2 vector 2 quad)) + (nop!) + (.lvf vf5 (&-> arg1 quad)) + (.sub.vf vf6 vf3 vf4) + (.lvf vf2 (&-> arg2 vector 0 quad)) + (.sub.vf vf7 vf3 vf5) + (.lvf vf1 (&-> arg3 quad)) + (.sub.vf vf8 vf3 vf2) + (.sub.vf vf9 vf5 vf4) + (.sub.vf vf10 vf5 vf2) + (.outer.product.vf vf14 vf7 vf8) + (.outer.product.vf vf15 vf6 vf7) + (.mul.vf vf11 vf14 vf1) + (.outer.product.vf vf16 vf9 vf10) + (.mul.vf vf12 vf15 vf1) + (.add.x.vf vf11 vf11 vf11 :mask #b10) + (.mul.vf vf13 vf16 vf1) + (.add.x.vf vf12 vf12 vf12 :mask #b10) + (.add.x.vf vf13 vf13 vf13 :mask #b10) + (.add.z.vf vf11 vf11 vf11 :mask #b10) + (.add.z.vf vf12 vf12 vf12 :mask #b10) + (.add.z.vf vf13 vf13 vf13 :mask #b10) + (.mov v1-0 vf11) + (.mov a1-1 vf12) + (.mov a0-1 vf13) + (let* ((v1-1 (shr (the-as int v1-0) 63)) + (a1-2 (shr (the-as int a1-1) 63)) + (a0-2 (shr (the-as int a0-1) 63)) + (a1-3 (* a1-2 2)) + (a0-3 (* a0-2 4)) + (v1-3 (logior (logior v1-1 a1-3) a0-3)) + ) + (b! (nonzero? v1-3) cfg-3 :delay (set! v1-4 (the-as uint (+ v1-3 -1)))) + ) + (.sub.vf vf17 vf5 vf2) + (.mov.vf vf18 vf0 :mask #b1000) + (.outer.product.vf vf18 vf17 vf1) + (.outer.product.vf vf18 vf1 vf18) + (.add.vf vf18 vf18 vf2 :mask #b111) + (b! #t cfg-24 :delay (.svf (&-> arg0 quad) vf18)) + (nop!) + (label cfg-3) + (b! (nonzero? v1-4) cfg-6 :delay (set! v1-5 (the-as uint (+ v1-4 -1)))) + (begin + (vector-segment-distance-point! + arg1 + (the-as vector (-> arg2 vector)) + (-> arg2 vector 1) + arg0 + ) + (goto cfg-24) + ) + (label cfg-6) + (b! (nonzero? v1-5) cfg-9 :delay (set! v1-6 (the-as uint (+ v1-5 -1)))) + (begin + (vector-segment-distance-point! + arg1 + (-> arg2 vector 1) + (-> arg2 vector 2) + arg0 + ) + (goto cfg-24) + ) + (label cfg-9) + (b! (nonzero? v1-6) cfg-14 :delay (set! v1-7 (the-as uint (+ v1-6 -1)))) + (begin + (let + ((f30-0 + (vector-segment-distance-point! + arg1 + (-> arg2 vector 1) + (the-as vector (-> arg2 vector)) + arg0 + ) + ) + (s3-0 (new 'stack-no-clear 'vector)) + ) + (if + (< + (vector-segment-distance-point! + arg1 + (-> arg2 vector 1) + (-> arg2 vector 2) + s3-0 + ) + f30-0 + ) + (set! (-> arg0 quad) (-> s3-0 quad)) + ) + ) + (goto cfg-24) + ) + (label cfg-14) + (b! (nonzero? v1-7) cfg-17 :delay (set! v1-10 (the-as uint (+ v1-7 -1)))) + (begin + (vector-segment-distance-point! + arg1 + (-> arg2 vector 2) + (the-as vector (-> arg2 vector)) + arg0 + ) + (goto cfg-24) + ) + (label cfg-17) + (b! (nonzero? v1-10) cfg-22) + (begin + (let + ((f30-1 + (vector-segment-distance-point! + arg1 + (the-as vector (-> arg2 vector)) + (-> arg2 vector 1) + arg0 + ) + ) + (s3-1 (new 'stack-no-clear 'vector)) + ) + (if + (< + (vector-segment-distance-point! + arg1 + (the-as vector (-> arg2 vector)) + (-> arg2 vector 2) + s3-1 + ) + f30-1 + ) + (set! (-> arg0 quad) (-> s3-1 quad)) + ) + ) + (goto cfg-24) + ) + (label cfg-22) + (let + ((f30-2 + (vector-segment-distance-point! + arg1 + (-> arg2 vector 2) + (the-as vector (-> arg2 vector)) + arg0 + ) + ) + (s3-2 (new 'stack-no-clear 'vector)) + ) + (if + (< + (vector-segment-distance-point! + arg1 + (-> arg2 vector 2) + (-> arg2 vector 1) + s3-2 + ) + f30-2 + ) + (set! (-> arg0 quad) (-> s3-2 quad)) + ) + ) + (label cfg-24) + 0 + (none) + ) + ) + +;; definition for function point-in-triangle-cross +;; WARN: Using logior on floats +;; WARN: Using logior on floats +(defun + point-in-triangle-cross + ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector) (arg4 vector)) + (local-vars (v1-0 float) (a0-1 float) (a1-1 float)) + (rlet ((acc :class vf) + (vf1 :class vf) + (vf10 :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) + ) + (.lvf vf3 (&-> arg3 quad)) + (.lvf vf4 (&-> arg4 quad)) + (.lvf vf5 (&-> arg0 quad)) + (.lvf vf2 (&-> arg2 quad)) + (.lvf vf1 (&-> arg1 quad)) + (.sub.vf vf6 vf3 vf4) + (.sub.vf vf7 vf3 vf5) + (.sub.vf vf8 vf3 vf2) + (.sub.vf vf9 vf5 vf4) + (.sub.vf vf10 vf5 vf2) + (.outer.product.vf vf2 vf6 vf7) + (.outer.product.vf vf3 vf7 vf8) + (.outer.product.vf vf4 vf9 vf10) + (.mul.vf vf2 vf2 vf1) + (.mul.vf vf3 vf3 vf1) + (.nop.vf) + (.mul.vf vf4 vf4 vf1) + (.add.x.vf vf2 vf2 vf2 :mask #b10) + (.add.x.vf vf3 vf3 vf3 :mask #b10) + (.add.x.vf vf4 vf4 vf4 :mask #b10) + (.nop.vf) + (.add.z.vf vf2 vf2 vf2 :mask #b10) + (.add.z.vf vf3 vf3 vf3 :mask #b10) + (.add.z.vf vf4 vf4 vf4 :mask #b10) + (.nop.vf) + (.mov a0-1 vf2) + (.mov a1-1 vf3) + (.mov v1-0 vf4) + (>= + (the-as int (logior (logior a0-1 (the-as uint a1-1)) (the-as uint v1-0))) + 0 + ) + ) + ) + +;; definition for function point-in-plane-<-point+normal! +(defun point-in-plane-<-point+normal! ((arg0 vector) (arg1 vector) (arg2 vector)) + (let + ((f0-3 + (+ + (+ (* (-> arg2 x) (-> arg1 x)) (* (-> arg2 y) (-> arg1 y))) + (* (-> arg2 z) (-> arg1 z)) + ) + ) + ) + (set! (-> arg0 w) 1.0) + (let ((f1-7 (fabs (-> arg2 x))) + (f2-3 (fabs (-> arg2 y))) + (f3-1 (fabs (-> arg2 z))) + ) + (cond + ((and (< f2-3 f1-7) (< f3-1 f1-7)) + (set! (-> arg0 y) (+ 4096.0 (-> arg1 y))) + (set! (-> arg0 z) (+ 4096.0 (-> arg1 z))) + (set! + (-> arg0 x) + (/ + (+ (- (- (* (-> arg2 y) (-> arg0 y))) (* (-> arg2 z) (-> arg0 z))) f0-3) + (-> arg2 x) + ) + ) + ) + (else + (cond + ((and (< f1-7 f2-3) (< f3-1 f2-3)) + (set! (-> arg0 x) (+ 4096.0 (-> arg1 x))) + (set! (-> arg0 z) (+ 4096.0 (-> arg1 z))) + (set! + (-> arg0 y) + (/ + (- (- f0-3 (* (-> arg2 x) (-> arg0 x))) (* (-> arg2 z) (-> arg0 z))) + (-> arg2 y) + ) + ) + ) + (else + (set! (-> arg0 x) (+ 4096.0 (-> arg1 x))) + (set! (-> arg0 y) (+ 4096.0 (-> arg1 y))) + (set! + (-> arg0 z) + (/ + (+ + (- (- (* (-> arg2 x) (-> arg0 x))) (* (-> arg2 y) (-> arg0 y))) + f0-3 + ) + (-> arg2 z) + ) + ) + ) + ) + ) + ) + ) + ) + arg0 + ) + +;; definition for function circle-circle-xz-intersect +;; ERROR: function was not converted to expressions. Cannot decompile. + +;; definition for function circle-test +;; INFO: Return type mismatch object vs none. +;; Used lq/sq +(defun circle-test () + (let ((s4-0 (new 'stack 'sphere)) + (a1-2 (new 'stack 'sphere)) + (s5-0 (new-stack-vector0)) + (gp-0 (new-stack-vector0)) + ) + (let ((v1-3 s4-0)) + (set! (-> v1-3 x) 0.0) + (set! (-> v1-3 y) 0.0) + (set! (-> v1-3 z) 0.0) + (set! (-> v1-3 w) 1.0) + ) + (let ((v1-4 a1-2)) + (set! (-> v1-4 x) 100.0) + (set! (-> v1-4 y) 0.0) + (set! (-> v1-4 z) 0.0) + (set! (-> v1-4 w) 10000.0) + ) + (let ((a2-1 (circle-circle-xz-intersect s4-0 a1-2 s5-0 gp-0))) + (format #t "res = ~d~%" a2-1) + ) + (format #t "(~f, ~f)~%" (-> s5-0 x) (-> s5-0 z)) + (format #t "(~f, ~f)~%" (-> gp-0 x) (-> gp-0 z)) + ) + (none) + ) + +;; definition for function vector-circle-tangent-new +;; INFO: Return type mismatch int vs none. +;; Used lq/sq +(defun + vector-circle-tangent-new + ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (rlet ((Q :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + ) + (init-vf0-vector) + (let ((a1-2 (new 'stack 'sphere))) + (set! (-> (new 'stack-no-clear 'vector) quad) (the-as uint128 0)) + (set! (-> (new 'stack-no-clear 'vector) quad) (the-as uint128 0)) + (let ((v1-3 0.5)) + (.lvf vf3 (&-> arg1 quad)) + (.mov vf2 v1-3) + ) + (.lvf vf4 (&-> arg0 quad)) + (.add.vf vf1 vf3 vf4) + (.sub.vf vf5 vf4 vf3) + (.mul.x.vf vf1 vf1 vf2) + (.mul.x.vf vf5 vf5 vf2) + (.mul.vf vf5 vf5 vf5 :mask #b101) + (.add.z.vf vf5 vf5 vf5 :mask #b1) + (.sqrt.vf Q vf5 :ftf #b0) + (.wait.vf) + (.mul.vf vf1 vf0 Q :mask #b1000) + (.nop.vf) + (.nop.vf) + (.svf (&-> a1-2 quad) vf1) + (circle-circle-xz-intersect (the-as sphere arg1) a1-2 arg2 arg3) + ) + 0 + (none) + ) + ) + +;; definition for function vector-circle-tangent +;; INFO: Return type mismatch int vs none. +(defun + vector-circle-tangent + ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector)) + (let* + ((s3-1 (vector-! (the-as vector (new 'stack-no-clear 'sphere)) arg1 arg0)) + (f0-0 (vector-xz-length s3-1)) + (f28-0 (acos (/ (-> arg1 w) f0-0))) + ) + (cond + ((>= 546.13336 f28-0) + (set! (-> arg2 x) (- (-> arg0 x) (-> s3-1 z))) + (set! (-> arg2 y) 0.0) + (set! (-> arg2 z) (+ (-> arg0 z) (-> s3-1 x))) + (set! (-> arg3 x) (+ (-> arg0 x) (-> s3-1 z))) + (set! (-> arg3 y) 0.0) + (set! (-> arg3 z) (- (-> arg0 z) (-> s3-1 x))) + ) + (else + (let ((f0-15 (atan (-> s3-1 z) (-> s3-1 x))) + (f30-0 (- (-> arg1 w))) + (s3-2 (new 'stack-no-clear 'vector)) + ) + (let ((s2-1 (new 'stack-no-clear 'vector))) + (let ((a2-1 (new 'stack-no-clear 'vector))) + (set! (-> a2-1 x) (- f0-15 f28-0)) + (set! (-> a2-1 y) (+ f0-15 f28-0)) + (vector-sincos! s3-2 s2-1 a2-1) + ) + (set! (-> arg2 x) (+ (-> arg1 x) (* f30-0 (-> s2-1 x)))) + (set! (-> arg2 z) (+ (-> arg1 z) (* f30-0 (-> s3-2 x)))) + (set! (-> arg3 x) (+ (-> arg1 x) (* f30-0 (-> s2-1 y)))) + ) + (set! (-> arg3 z) (+ (-> arg1 z) (* f30-0 (-> s3-2 y)))) + ) + ) + ) + ) + 0 + (none) + ) + +;; definition for function find-knot-span +(defun + find-knot-span + ((arg0 int) (arg1 int) (arg2 float) (arg3 (inline-array vector))) + (local-vars (v0-0 int)) + (b! + (= arg2 (-> (&-> arg3 0 data (+ arg0 1)) 0)) + cfg-11 + :delay + (set! v0-0 arg0) + ) + (let ((v1-3 (the int arg2))) + (let* ((a2-1 (+ v1-3 3)) + (t0-1 (&-> arg3 0 data a2-1)) + (f1-2 (-> t0-1 0)) + (f2-0 (-> t0-1 1)) + ) + (b! (> f1-2 arg2) cfg-4) + (b! (>= arg2 f2-0) cfg-4 :delay (set! v0-0 a2-1)) + ) + (b! #t cfg-11) + (label cfg-4) + (let ((a1-1 arg1) + (a0-1 (+ arg0 1)) + ) + (label cfg-5) + (let ((a2-3 (/ (+ a1-1 a0-1) 2))) + (let ((t0-3 (&-> arg3 0 data a2-3))) + (b! (>= arg2 (-> t0-3 0)) cfg-7) + (b! #t cfg-5 :delay (set! a0-1 a2-3)) + (label cfg-7) + (b! (< arg2 (-> t0-3 1)) cfg-9) + ) + (b! #t cfg-5 :delay (set! a1-1 a2-3)) + (label cfg-9) + (set! v0-0 a2-3) + ) + ) + (b! (= v0-0 v1-3) cfg-11) + ) + (nop!) + (nop!) + (label cfg-11) + v0-0 + ) + +;; definition for function calculate-basis-functions-vector! +;; WARN: Unsupported inline assembly instruction kind - [sll v1, a1, 2] +;; WARN: Unsupported inline assembly instruction kind - [addu v1, a3, v1] +(defun + calculate-basis-functions-vector! + ((arg0 (pointer float)) (arg1 int) (arg2 float) (arg3 (pointer float))) + (local-vars (v1-0 int) (v1-1 object)) + (.sll v1-0 arg1 2) + (let ((a1-1 #x3f800000) + (f3-0 arg2) + ) + (.addu v1-1 arg3 v1-0) + (let* ((f1-0 (the-as float (gpr->fpr a1-1))) + (f5-0 f1-0) + ) + 0.0 + 0.0 + (let* ((f0-2 (-> (the-as (pointer float) v1-1) 0)) + (f2-0 (-> (the-as (pointer float) v1-1) 1)) + (f0-3 (- f3-0 f0-2)) + (f4-0 (- f2-0 f3-0)) + (f10-0 (/ f1-0 (+ f4-0 f0-3))) + (f2-2 (-> (the-as (pointer float) v1-1) -1)) + (f8-0 (-> (the-as (pointer float) v1-1) 2)) + (f2-3 (- f3-0 f2-2)) + (f9-0 (+ f4-0 f2-3)) + (f6-0 (-> (the-as (pointer float) v1-1) -2)) + (f7-0 (-> (the-as (pointer float) v1-1) 3)) + (f9-1 (/ f1-0 f9-0)) + (f5-1 (* f5-0 f10-0)) + (f11-0 (* f4-0 f5-1)) + (f10-1 (* f0-3 f5-1)) + (f5-2 (- f8-0 f3-0)) + (f8-1 (* f11-0 f9-1)) + (f11-1 (/ f1-0 (+ f5-2 f0-3))) + (f9-3 (* f4-0 f8-1)) + (f8-2 (* f2-3 f8-1)) + (f11-2 (* f10-1 f11-1)) + (f10-3 (+ (* f5-2 f11-2) f8-2)) + (f8-3 (* f0-3 f11-2)) + (f6-1 (- f3-0 f6-0)) + (f3-1 (- f7-0 f3-0)) + (f7-3 (* f9-3 (/ f1-0 (+ f4-0 f6-1)))) + (f4-1 (* f4-0 f7-3)) + (f6-2 (* f6-1 f7-3)) + (f7-6 (* f10-3 (/ f1-0 (+ f5-2 f2-3)))) + (f5-4 (+ (* f5-2 f7-6) f6-2)) + (f2-4 (* f2-3 f7-6)) + (f1-2 (* f8-3 (the-as float (/ f1-0 (+ f3-1 f0-3))))) + (f2-5 (+ (* f3-1 f1-2) f2-4)) + (f0-4 (* f0-3 f1-2)) + ) + (set! (-> arg0 0) f4-1) + (set! (-> arg0 1) f5-4) + (set! (-> arg0 2) f2-5) + (set! (-> arg0 3) f0-4) + ) + ) + ) + arg0 + ) + +;; definition for function curve-evaluate! +;; WARN: Unsupported inline assembly instruction kind - [addiu v1, s3, -3] +;; WARN: Unsupported inline assembly instruction kind - [sll v1, v1, 4] +(defun + curve-evaluate! + ((arg0 vector) + (arg1 float) + (arg2 pointer) + (arg3 int) + (arg4 (inline-array vector)) + (arg5 int) + ) + (local-vars (v1-7 int) (v1-8 int) (v1-10 float) (s3-0 int)) + (rlet ((acc :class vf) + (vf0 :class vf) + (vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + (vf5 :class vf) + (vf6 :class vf) + ) + (init-vf0-vector) + (let ((s4-0 (new 'static 'array float 4 0.0 0.0 0.0 0.0))) + 0 + (let* ((f0-0 (-> arg4 0 x)) + (f1-0 (-> (&-> arg4 0 data (+ arg5 -1)) 0)) + (a2-1 (fmax (fmin (* arg1 f1-0) f1-0) f0-0)) + ) + (let* ((a1-1 (+ arg5 -5)) + (a3-1 3) + (f0-2 a2-1) + (v1-5 arg4) + (f0-3 f0-2) + ) + (b! + (= f0-3 (-> (&-> v1-5 0 data (+ a1-1 1)) 0)) + cfg-11 + :delay + (set! s3-0 a1-1) + ) + (let ((a0-4 (the int f0-3))) + (let* ((t1-1 (+ a0-4 3)) + (t2-1 (&-> v1-5 0 data t1-1)) + (f1-4 (-> t2-1 0)) + (f2-3 (-> t2-1 1)) + ) + (b! (> f1-4 f0-3) cfg-4) + (b! (>= f0-3 f2-3) cfg-4 :delay (set! s3-0 t1-1)) + ) + (b! #t cfg-11) + (label cfg-4) + (let ((a3-2 a3-1) + (a1-2 (+ a1-1 1)) + ) + (label cfg-5) + (let ((t1-3 (/ (+ a3-2 a1-2) 2))) + (let ((t2-3 (&-> v1-5 0 data t1-3))) + (b! (>= f0-3 (-> t2-3 0)) cfg-7) + (b! #t cfg-5 :delay (set! a1-2 t1-3)) + (label cfg-7) + (b! (< f0-3 (-> t2-3 1)) cfg-9) + ) + (b! #t cfg-5 :delay (set! a3-2 t1-3)) + (label cfg-9) + (set! s3-0 t1-3) + ) + ) + (b! (= s3-0 a0-4) cfg-11) + ) + ) + (nop!) + (nop!) + (label cfg-11) + (calculate-basis-functions-vector! + s4-0 + s3-0 + a2-1 + (the-as (pointer float) arg4) + ) + ) + (.addiu v1-7 s3-0 -3) + (.lvf vf6 s4-0) + ) + (.sll v1-8 v1-7 4) + (.add.x.vf vf1 vf0 vf0 :mask #b1000) + (let ((v1-9 (+ v1-8 (the-as int arg2)))) + (nop!) + (nop!) + (.lvf vf2 (&-> (the-as (pointer int128) v1-9))) + (nop!) + (.lvf vf3 (+ v1-9 16)) + (nop!) + (.lvf vf4 (+ v1-9 32)) + (nop!) + (.lvf vf5 (+ v1-9 48)) + ) + (.mul.x.vf acc vf2 vf6) + (nop!) + (.add.mul.y.vf acc vf3 vf6 acc :mask #b111) + (nop!) + (.add.mul.z.vf acc vf4 vf6 acc :mask #b111) + (nop!) + (.add.mul.w.vf vf1 vf5 vf6 acc :mask #b111) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (nop!) + (.svf (&-> arg0 quad) vf1) + (.mov v1-10 vf1) + arg0 + ) + ) + +;; definition for function curve-get-pos! +(defun curve-get-pos! ((arg0 vector) (arg1 float) (arg2 curve)) + (curve-evaluate! + arg0 + arg1 + (-> arg2 cverts) + (-> arg2 num-cverts) + (-> arg2 knots) + (-> arg2 num-knots) + ) + ) + +;; definition for function curve-length +;; Used lq/sq +(defun curve-length ((arg0 curve)) + (let ((s5-0 (new-stack-vector0)) + (s4-0 (new-stack-vector0)) + (s3-0 (* 3 (-> arg0 num-cverts))) + (f30-0 0.0) + ) + (curve-evaluate! + s4-0 + (-> arg0 knots 0 x) + (-> arg0 cverts) + (-> arg0 num-cverts) + (-> arg0 knots) + (-> arg0 num-knots) + ) + (dotimes (s2-0 s3-0) + (set! (-> s5-0 quad) (-> s4-0 quad)) + (curve-evaluate! + s4-0 + (/ (the float (+ s2-0 1)) (the float s3-0)) + (-> arg0 cverts) + (-> arg0 num-cverts) + (-> arg0 knots) + (-> arg0 num-knots) + ) + (+! f30-0 (vector-vector-distance s5-0 s4-0)) + ) + f30-0 + ) + ) + +;; definition for function curve-copy! +(defun curve-copy! ((arg0 curve) (arg1 curve)) + (set! (-> arg0 cverts) (-> arg1 cverts)) + (set! (-> arg0 num-cverts) (-> arg1 num-cverts)) + (set! (-> arg0 knots) (-> arg1 knots)) + (set! (-> arg0 num-knots) (-> arg1 num-knots)) + (set! (-> arg0 length) (-> arg1 length)) + arg0 + ) + +;; definition for function curve-closest-point +;; WARN: Stack slot offset 48 signed mismatch +;; WARN: Stack slot offset 48 signed mismatch +;; WARN: Stack slot offset 48 signed mismatch +;; WARN: Stack slot offset 48 signed mismatch +;; WARN: Stack slot offset 48 signed mismatch +;; WARN: Stack slot offset 48 signed mismatch +;; INFO: Return type mismatch float vs object. +(defun + curve-closest-point + ((arg0 curve) (arg1 vector) (arg2 float) (arg3 float) (arg4 int) (arg5 float)) + (local-vars (sv-48 float)) + (set! sv-48 arg3) + (let ((s3-0 arg4) + (gp-0 arg5) + (f30-0 (curve-length arg0)) + (s2-0 (new 'stack-no-clear 'vector)) + (s1-0 (new 'stack-no-clear 'vector)) + ) + 0.0 + 0.0 + 0.0 + 0.0 + (let ((f28-0 0.5)) + 0.0 + (if (< 0.0 sv-48) + (set! f28-0 (/ sv-48 f30-0)) + ) + (let* ((s0-1 (- arg2 (/ gp-0 f30-0))) + (f26-0 (- s0-1 f28-0)) + (f24-0 (+ s0-1 f28-0)) + ) + (curve-get-pos! s2-0 f26-0 arg0) + (curve-get-pos! s1-0 f24-0 arg0) + (let ((f22-0 (vector-vector-distance-squared s2-0 arg1)) + (f20-0 (vector-vector-distance-squared s1-0 arg1)) + ) + (while (> s3-0 0) + (+! s3-0 -1) + (set! f28-0 (* 0.5 f28-0)) + (let ((v1-4 (cond + ((< f22-0 f20-0) + (curve-get-pos! s1-0 s0-1 arg0) + (set! f20-0 (vector-vector-distance-squared s1-0 arg1)) + (set! f24-0 s0-1) + (- s0-1 f28-0) + ) + (else + (curve-get-pos! s2-0 s0-1 arg0) + (set! f22-0 (vector-vector-distance-squared s2-0 arg1)) + (set! f26-0 s0-1) + (+ s0-1 f28-0) + ) + ) + ) + ) + (set! s0-1 (fmin 1.0 (fmax 0.0 v1-4))) + ) + ) + (+ (if (< f22-0 f20-0) + f26-0 + f24-0 + ) + (/ gp-0 f30-0) + ) + ) + ) + ) + ) + ) + +;; definition for function vector-plane-distance +(defun vector-plane-distance ((arg0 vector) (arg1 plane) (arg2 vector)) + (vector-dot + (vector-! (new 'stack-no-clear 'vector) arg0 (the-as vector (&-> arg1 x))) + arg2 + ) + ) + + + + diff --git a/test/decompiler/reference/engine/math/matrix_REF.gc b/test/decompiler/reference/engine/math/matrix_REF.gc index 37cae577b8..041359c519 100644 --- a/test/decompiler/reference/engine/math/matrix_REF.gc +++ b/test/decompiler/reference/engine/math/matrix_REF.gc @@ -785,6 +785,7 @@ ;; ERROR: function was not converted to expressions. Cannot decompile. ;; definition for function matrix-axis-angle! +;; INFO: Return type mismatch matrix vs none. (defun matrix-axis-angle! ((dst matrix) (axis vector) (angle-deg float)) (matrix-axis-sin-cos! dst axis (sin angle-deg) (cos angle-deg)) (none) diff --git a/test/decompiler/reference/engine/math/quaternion_REF.gc b/test/decompiler/reference/engine/math/quaternion_REF.gc index 11260fa508..6965e17f9d 100644 --- a/test/decompiler/reference/engine/math/quaternion_REF.gc +++ b/test/decompiler/reference/engine/math/quaternion_REF.gc @@ -598,18 +598,9 @@ ) ;; definition for function matrix-with-scale->quaternion -;; WARN: Unsupported inline assembly instruction kind - [mula.s f0, f3] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f1, f4] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f0, f2, f5] -;; WARN: Unsupported inline assembly instruction kind - [mula.s f1, f4] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f2, f5] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f1, f3, f6] -;; WARN: Unsupported inline assembly instruction kind - [mula.s f2, f5] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f3, f6] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f2, f4, f7] ;; Used lq/sq (defun matrix-with-scale->quaternion ((arg0 quaternion) (arg1 matrix)) - (local-vars (a1-4 float) (f0-1 float) (f1-2 float) (f2-3 float)) + (local-vars (a1-4 float)) (rlet ((vf1 :class vf) (vf2 :class vf) (vf3 :class vf) @@ -619,50 +610,31 @@ (vf7 :class vf) ) (let ((v1-0 (new-stack-matrix0))) - (let* ((a3-0 (-> arg1 vector)) - (a2-0 (-> arg1 vector)) - (f0-0 (-> a3-0 0 x)) - (f1-0 (-> a3-0 0 y)) - (f2-0 (-> a3-0 0 z)) - (f3-0 (-> a2-0 0 x)) - (f4-0 (-> a2-0 0 y)) - (f5-0 (-> a2-0 0 z)) - ) - (.mula.s f0-0 f3-0) - (.madda.s f1-0 f4-0) - (.madd.s f0-1 f2-0 f5-0) - ) - (let ((f0-2 f0-1)) - (let* ((a3-1 (-> arg1 vector 1)) - (a2-2 (-> arg1 vector 1)) - ) - (set! f1-2 (vector-dot a3-1 a2-2)) + (let* + ((f0-1 + (vector-dot + (the-as vector (-> arg1 vector)) + (the-as vector (-> arg1 vector)) + ) + ) + (f1-1 (vector-dot (-> arg1 vector 1) (-> arg1 vector 1))) + (f2-1 (vector-dot (-> arg1 vector 2) (-> arg1 vector 2))) + (f0-3 (/ 1.0 (sqrtf f0-1))) + (f1-3 (/ 1.0 (sqrtf f1-1))) + (f2-3 (/ 1.0 (sqrtf f2-1))) ) - (let ((f1-3 f1-2)) - (let* ((a3-2 (-> arg1 vector 2)) - (a2-4 (-> arg1 vector 2)) - ) - (set! f2-3 (vector-dot a3-2 a2-4)) - ) - (let* ((f2-4 f2-3) - (f0-4 (/ 1.0 (sqrtf f0-2))) - (f1-5 (/ 1.0 (sqrtf f1-3))) - (f2-6 (/ 1.0 (sqrtf f2-4))) - ) - (.lvf vf1 (&-> arg1 vector 0 quad)) - (.lvf vf2 (&-> arg1 vector 1 quad)) - (.lvf vf3 (&-> arg1 vector 2 quad)) - (.lvf vf4 (&-> arg1 vector 3 quad)) - (let ((a1-1 f0-4)) - (.mov vf5 a1-1) - ) - (let ((a1-2 f1-5)) - (.mov vf6 a1-2) - ) - (let ((a1-3 f2-6)) - (.mov vf7 a1-3) - ) - ) + (.lvf vf1 (&-> arg1 vector 0 quad)) + (.lvf vf2 (&-> arg1 vector 1 quad)) + (.lvf vf3 (&-> arg1 vector 2 quad)) + (.lvf vf4 (&-> arg1 vector 3 quad)) + (let ((a1-1 f0-3)) + (.mov vf5 a1-1) + ) + (let ((a1-2 f1-3)) + (.mov vf6 a1-2) + ) + (let ((a1-3 f2-3)) + (.mov vf7 a1-3) ) ) (.mul.x.vf vf1 vf1 vf5) @@ -1021,18 +993,12 @@ ) ;; definition for function quaternion-delta-y -;; WARN: Unsupported inline assembly instruction kind - [mula.s f0, f3] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f1, f4] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f0, f2, f5] (defun quaternion-delta-y ((arg0 quaternion) (arg1 quaternion)) - (local-vars (f0-1 float)) - (let ((gp-0 acos)) - (let* ((s5-0 (vector-z-quaternion! (new 'stack-no-clear 'vector) arg0)) - (v1-1 (vector-z-quaternion! (new 'stack-no-clear 'vector) arg1)) - ) - (set! f0-1 (vector-dot s5-0 v1-1)) + (acos + (vector-dot + (vector-z-quaternion! (new 'stack-no-clear 'vector) arg0) + (vector-z-quaternion! (new 'stack-no-clear 'vector) arg1) ) - (gp-0 f0-1) ) ) diff --git a/test/decompiler/reference/engine/math/vector-h_REF.gc b/test/decompiler/reference/engine/math/vector-h_REF.gc index b5639beccf..31d7694ab9 100644 --- a/test/decompiler/reference/engine/math/vector-h_REF.gc +++ b/test/decompiler/reference/engine/math/vector-h_REF.gc @@ -433,12 +433,12 @@ ;; definition of type vector (deftype vector (structure) - ((data float 4 :offset-assert 0) - (x float :offset 0) - (y float :offset 4) - (z float :offset 8) - (w float :offset 12) - (quad uint128 :offset 0) + ((x float :offset 0) + (y float :offset 4) + (z float :offset 8) + (w float :offset 12) + (data float 4 :offset 0) + (quad uint128 :offset 0) ) :method-count-assert 9 :size-assert #x10 @@ -820,23 +820,8 @@ ) ;; definition for function vector-dot -;; WARN: Unsupported inline assembly instruction kind - [mula.s f0, f3] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f1, f4] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f0, f2, f5] (defun vector-dot ((arg0 vector) (arg1 vector)) - (local-vars (f0-1 float)) - (let ((f0-0 (-> arg0 x)) - (f1-0 (-> arg0 y)) - (f2-0 (-> arg0 z)) - (f3-0 (-> arg1 x)) - (f4-0 (-> arg1 y)) - (f5-0 (-> arg1 z)) - ) - (.mula.s f0-0 f3-0) - (.madda.s f1-0 f4-0) - (.madd.s f0-1 f2-0 f5-0) - ) - f0-1 + (vector-dot arg0 arg1) ) ;; definition for function vector-dot-vu diff --git a/test/decompiler/reference/engine/target/joint-mod-h_REF.gc b/test/decompiler/reference/engine/target/joint-mod-h_REF.gc index 3e05f5f4b1..c9c1065de2 100644 --- a/test/decompiler/reference/engine/target/joint-mod-h_REF.gc +++ b/test/decompiler/reference/engine/target/joint-mod-h_REF.gc @@ -367,12 +367,9 @@ ;; definition for function joint-mod-look-at-handler ;; INFO: Return type mismatch int vs none. -;; WARN: Unsupported inline assembly instruction kind - [mula.s f1, f4] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f2, f5] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f1, f3, f6] ;; Used lq/sq (defun joint-mod-look-at-handler ((csp cspace) (xform transformq)) - (local-vars (f1-12 float) (sv-48 vector) (sv-52 vector) (sv-56 vector)) + (local-vars (sv-48 vector) (sv-52 vector) (sv-56 vector)) (let ((gp-0 (the-as joint-mod (-> csp param1)))) (cspace<-parented-transformq-joint! csp xform) (set! @@ -468,10 +465,7 @@ ) ) ) - (let* ((v1-22 sv-52)) - (set! f1-12 (vector-dot s3-2 v1-22)) - ) - (if (< f1-12 0.1) + (if (< (vector-dot s3-2 sv-52) 0.1) (set! f0-21 0.0) ) (set! @@ -518,12 +512,9 @@ ;; definition for function joint-mod-world-look-at-handler ;; INFO: Return type mismatch int vs none. -;; WARN: Unsupported inline assembly instruction kind - [mula.s f1, f4] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f2, f5] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f1, f3, f6] ;; Used lq/sq (defun joint-mod-world-look-at-handler ((arg0 cspace) (arg1 transformq)) - (local-vars (f1-14 float) (sv-48 vector) (sv-52 vector) (sv-56 vector)) + (local-vars (sv-48 vector) (sv-52 vector) (sv-56 vector)) (let ((gp-0 (the-as joint-mod (-> arg0 param1)))) (let ((s5-0 (-> arg0 bone transform))) (cspace<-parented-transformq-joint! arg0 arg1) @@ -606,10 +597,7 @@ ) ) ) - (let* ((v1-14 sv-52)) - (set! f1-14 (vector-dot s4-4 v1-14)) - ) - (if (< f1-14 0.1) + (if (< (vector-dot s4-4 sv-52) 0.1) (set! f0-20 0.0) ) (set! @@ -792,12 +780,8 @@ ) ;; definition for function joint-mod-wheel-callback -;; WARN: Unsupported inline assembly instruction kind - [mula.s f0, f3] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f1, f4] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f0, f2, f5] ;; Used lq/sq (defun joint-mod-wheel-callback ((arg0 cspace) (arg1 transformq)) - (local-vars (f0-3 float)) (let ((s4-0 (the-as joint-mod-wheel (-> arg0 param1)))) (let ((v1-1 (-> s4-0 process root)) (s1-0 (new-stack-vector0)) @@ -810,14 +794,13 @@ (vector<-cspace! s1-0 arg0) (vector-! s3-0 s1-0 (-> s4-0 last-position)) (set! (-> s4-0 last-position quad) (-> s1-0 quad)) - (set! f0-3 (vector-dot s2-0 s3-0)) - ) - (let* ((f0-4 f0-3) - (f1-1 65536.0) - (f2-2 (* 6.28318 (-> s4-0 wheel-radius))) - (f0-5 (* (* f1-1 (/ 1.0 f2-2)) f0-4)) - ) - (set! (-> s4-0 angle) (+ (-> s4-0 angle) f0-5)) + (let* ((f0-3 (vector-dot s2-0 s3-0)) + (f1-0 65536.0) + (f2-1 (* 6.28318 (-> s4-0 wheel-radius))) + (f0-4 (* (* f1-0 (/ 1.0 f2-1)) f0-3)) + ) + (set! (-> s4-0 angle) (+ (-> s4-0 angle) f0-4)) + ) ) (quaternion-vector-angle! (-> arg1 quat) diff --git a/test/decompiler/test_FormExpressionBuild2.cpp b/test/decompiler/test_FormExpressionBuild2.cpp index be07d49dbd..5e06e84c6b 100644 --- a/test/decompiler/test_FormExpressionBuild2.cpp +++ b/test/decompiler/test_FormExpressionBuild2.cpp @@ -1526,4 +1526,100 @@ TEST_F(FormRegressionTest, Method23Trsqv) { std::string expected = "(vector-y-angle (vector-! (new 'stack-no-clear 'vector) arg1 (-> arg0 trans)))"; test_with_stack_structures(func, type, expected, R"([[16, "vector"]])"); +} + +TEST_F(FormRegressionTest, VectorLineDistance) { + std::string func = + "sll r0, r0, 0\n" + "\n" + " daddiu sp, sp, -128\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " sq s4, 80(sp)\n" + " sq s5, 96(sp)\n" + " sq gp, 112(sp)\n" + " or s5, a0, r0\n" + " or s4, a1, r0\n" + " lw t9, vector-normalize!(s7)\n" + " daddiu a0, sp, 16\n" + " sq r0, 0(a0)\n" + " or v1, a2, r0\n" + " or a1, s4, r0\n" + " lqc2 vf4, 0(v1)\n" + " lqc2 vf5, 0(a1)\n" + " vmove.w vf6, vf0\n" + " vsub.xyz vf6, vf4, vf5\n" + " sqc2 vf6, 0(a0)\n" + //" lw a1, L125(fp)\n" + " or a1, r0, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or a1, v0, r0\n" + " daddiu gp, sp, 32\n" + " sq r0, 0(gp)\n" + " lqc2 vf4, 0(s5)\n" + " lqc2 vf5, 0(s4)\n" + " vmove.w vf6, vf0\n" + " vsub.xyz vf6, vf4, vf5\n" + " sqc2 vf6, 0(gp)\n" + " or a0, a1, r0\n" + " or v1, gp, r0\n" + " lwc1 f0, 0(a0)\n" + " lwc1 f1, 4(a0)\n" + " lwc1 f2, 8(a0)\n" + " lwc1 f3, 0(v1)\n" + " lwc1 f4, 4(v1)\n" + " lwc1 f5, 8(v1)\n" + " mula.s f0, f3\n" + " madda.s f1, f4\n" + " madd.s f0, f2, f5\n" + " mfc1 v1, f0\n" + " mtc1 f0, v1\n" + " lw t9, vector-float*!(s7)\n" + " daddiu a0, sp, 48\n" + " sq r0, 0(a0)\n" + " mfc1 a2, f0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + " lw t9, vector-length(s7)\n" + " daddiu a0, sp, 64\n" + " sq r0, 0(a0)\n" + " lqc2 vf4, 0(gp)\n" + " lqc2 vf5, 0(v1)\n" + " vmove.w vf6, vf0\n" + " vsub.xyz vf6, vf4, vf5\n" + " sqc2 vf6, 0(a0)\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " lq gp, 112(sp)\n" + " lq s5, 96(sp)\n" + " lq s4, 80(sp)\n" + " jr ra\n" + " daddiu sp, sp, 128\n" + " sll r0, r0, 0\n" + " sll r0, r0, 0\n"; + std::string type = "(function vector vector vector float)"; + std::string expected = + "(let*\n" + " ((a1-3\n" + " (vector-normalize!\n" + " (vector-! (new-stack-vector0) arg2 arg1)\n" + " (the-as float 0)\n" + " )\n" + " )\n" + " (gp-1 (vector-! (new-stack-vector0) arg0 arg1))\n" + " (f0-1 (vector-dot a1-3 gp-1))\n" + " (v1-3 (vector-float*! (new-stack-vector0) a1-3 f0-1))\n" + " )\n" + " (vector-length (vector-! (new-stack-vector0) gp-1 v1-3))\n" + " )"; + test_with_stack_structures(func, type, expected, + R"([[16, "vector"], [32, "vector"], [48, "vector"], [64, "vector"]])"); } \ No newline at end of file diff --git a/test/offline/offline_test_main.cpp b/test/offline/offline_test_main.cpp index 5d46e7c7d3..56d624aed6 100644 --- a/test/offline/offline_test_main.cpp +++ b/test/offline/offline_test_main.cpp @@ -50,6 +50,8 @@ const std::unordered_set g_functions_expected_to_reject = { // matrix "(method 9 matrix)", // handwritten asm loop "matrix-axis-sin-cos!", "matrix-axis-sin-cos-vu!", + // geometry + "circle-circle-xz-intersect", // unused not bothering // dma-h "dma-count-until-done", // dma asm loop "dma-sync-with-count", "dma-send-no-scratch", "dma-sync-fast", @@ -117,12 +119,8 @@ const std::unordered_set g_functions_to_skip_compiling = { /// VECTOR-H "(method 3 vector)", // this function appears twice, which confuses the compiler. - "vector-dot", // fpu acc "vector4-dot", // fpu acc - // quaternion - "matrix-with-scale->quaternion", // fpu-acc - "(method 3 profile-frame)", // double definition. // dma-disasm @@ -143,6 +141,11 @@ const std::unordered_set g_functions_to_skip_compiling = { "vector-deg-diff", "vector-degi", + // geometry + "calculate-basis-functions-vector!", // asm requiring manual rewrite + "curve-evaluate!", // asm requiring manual rewrite + "point-in-triangle-cross", // logior on floats manual fixup + // asm "invalidate-cache-line", diff --git a/third-party/googletest b/third-party/googletest index adeef19294..7153098229 160000 --- a/third-party/googletest +++ b/third-party/googletest @@ -1 +1 @@ -Subproject commit adeef192947fbc0f68fa14a6c494c8df32177508 +Subproject commit 7153098229e88295f9655ff1d3b0e2fa9eada5f8