| 113 | |
| 114 | template <typename GeneratorType> |
| 115 | bool process_instruction(GeneratorType& generator, const N64Recomp::Context& context, const N64Recomp::Function& func, size_t func_index, const N64Recomp::FunctionStats& stats, const std::unordered_set<uint32_t>& jtbl_lw_instructions, size_t instr_index, const std::vector<rabbitizer::InstructionCpu>& instructions, std::ostream& output_file, bool indent, bool emit_link_branch, int link_branch_index, size_t reloc_index, bool& needs_link_branch, bool& is_branch_likely, bool tag_reference_relocs, std::span<std::vector<uint32_t>> static_funcs_out) { |
| 116 | using namespace N64Recomp; |
| 117 | |
| 118 | const auto& section = context.sections[func.section_index]; |
| 119 | const auto& instr = instructions[instr_index]; |
| 120 | needs_link_branch = false; |
| 121 | is_branch_likely = false; |
| 122 | uint32_t instr_vram = instr.getVram(); |
| 123 | InstrId instr_id = instr.getUniqueId(); |
| 124 | |
| 125 | auto print_indent = [&]() { |
| 126 | fmt::print(output_file, " "); |
| 127 | }; |
| 128 | |
| 129 | auto hook_find = func.function_hooks.find(instr_index); |
| 130 | if (hook_find != func.function_hooks.end()) { |
| 131 | fmt::print(output_file, " {}\n", hook_find->second); |
| 132 | if (indent) { |
| 133 | print_indent(); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | // Output a comment with the original instruction |
| 138 | print_indent(); |
| 139 | if (instr.isBranch() || instr_id == InstrId::cpu_j) { |
| 140 | generator.emit_comment(fmt::format("0x{:08X}: {}", instr_vram, instr.disassemble(0, fmt::format("L_{:08X}", (uint32_t)instr.getBranchVramGeneric())))); |
| 141 | } else if (instr_id == InstrId::cpu_jal) { |
| 142 | generator.emit_comment(fmt::format("0x{:08X}: {}", instr_vram, instr.disassemble(0, fmt::format("0x{:08X}", (uint32_t)instr.getBranchVramGeneric())))); |
| 143 | } else { |
| 144 | generator.emit_comment(fmt::format("0x{:08X}: {}", instr_vram, instr.disassemble(0))); |
| 145 | } |
| 146 | |
| 147 | // Replace loads for jump table entries into addiu. This leaves the jump table entry's address in the output register |
| 148 | // instead of the entry's value, which can then be used to determine the offset from the start of the jump table. |
| 149 | if (jtbl_lw_instructions.contains(instr_vram)) { |
| 150 | assert(instr_id == InstrId::cpu_lw); |
| 151 | instr_id = InstrId::cpu_addiu; |
| 152 | } |
| 153 | |
| 154 | N64Recomp::RelocType reloc_type = N64Recomp::RelocType::R_MIPS_NONE; |
| 155 | bool has_reloc = false; |
| 156 | uint32_t reloc_section = 0; |
| 157 | uint32_t reloc_target_section_offset = 0; |
| 158 | size_t reloc_reference_symbol = (size_t)-1; |
| 159 | |
| 160 | uint32_t func_vram_end = func.vram + func.words.size() * sizeof(func.words[0]); |
| 161 | |
| 162 | uint16_t imm = instr.Get_immediate(); |
| 163 | |
| 164 | // Check if this instruction has a reloc. |
| 165 | if (section.relocs.size() > 0 && section.relocs[reloc_index].address == instr_vram) { |
| 166 | has_reloc = true; |
| 167 | // Get the reloc data for this instruction |
| 168 | const auto& reloc = section.relocs[reloc_index]; |
| 169 | reloc_section = reloc.target_section; |
| 170 | |
| 171 | // Check if the relocation references a relocatable section. |
| 172 | bool target_relocatable = false; |
no test coverage detected