| 761 | |
| 762 | template <typename GeneratorType> |
| 763 | bool recompile_function_impl(GeneratorType& generator, const N64Recomp::Context& context, size_t func_index, std::ostream& output_file, std::span<std::vector<uint32_t>> static_funcs_out, bool tag_reference_relocs) { |
| 764 | const N64Recomp::Function& func = context.functions[func_index]; |
| 765 | //fmt::print("Recompiling {}\n", func.name); |
| 766 | std::vector<rabbitizer::InstructionCpu> instructions; |
| 767 | |
| 768 | generator.emit_function_start(func.name, func_index); |
| 769 | |
| 770 | if (context.trace_mode) { |
| 771 | fmt::print(output_file, |
| 772 | " TRACE_ENTRY()\n", |
| 773 | func.name); |
| 774 | } |
| 775 | |
| 776 | // Skip analysis and recompilation of this function is stubbed. |
| 777 | if (!func.stubbed) { |
| 778 | // Use a set to sort and deduplicate labels |
| 779 | std::set<uint32_t> branch_labels; |
| 780 | instructions.reserve(func.words.size()); |
| 781 | |
| 782 | auto hook_find = func.function_hooks.find(-1); |
| 783 | if (hook_find != func.function_hooks.end()) { |
| 784 | fmt::print(output_file, " {}\n", hook_find->second); |
| 785 | } |
| 786 | |
| 787 | // First pass, disassemble each instruction and collect branch labels |
| 788 | uint32_t vram = func.vram; |
| 789 | for (uint32_t word : func.words) { |
| 790 | const auto& instr = instructions.emplace_back(byteswap(word), vram); |
| 791 | |
| 792 | // If this is a branch or a direct jump, add it to the local label list |
| 793 | if (instr.isBranch() || instr.getUniqueId() == rabbitizer::InstrId::UniqueId::cpu_j) { |
| 794 | branch_labels.insert((uint32_t)instr.getBranchVramGeneric()); |
| 795 | } |
| 796 | |
| 797 | // Advance the vram address by the size of one instruction |
| 798 | vram += 4; |
| 799 | } |
| 800 | |
| 801 | // Analyze function |
| 802 | N64Recomp::FunctionStats stats{}; |
| 803 | if (!N64Recomp::analyze_function(context, func, instructions, stats)) { |
| 804 | fmt::print(stderr, "Failed to analyze {}\n", func.name); |
| 805 | output_file.clear(); |
| 806 | return false; |
| 807 | } |
| 808 | |
| 809 | std::unordered_set<uint32_t> jtbl_lw_instructions{}; |
| 810 | |
| 811 | // Add jump table labels into function |
| 812 | for (const auto& jtbl : stats.jump_tables) { |
| 813 | jtbl_lw_instructions.insert(jtbl.lw_vram); |
| 814 | for (uint32_t jtbl_entry : jtbl.entries) { |
| 815 | branch_labels.insert(jtbl_entry); |
| 816 | } |
| 817 | } |
| 818 | |
| 819 | // Second pass, emit code for each instruction and emit labels |
| 820 | auto cur_label = branch_labels.cbegin(); |
no test coverage detected