MCPcopy Create free account
hub / github.com/N64Recomp/N64Recomp / emit_switch

Method emit_switch

LiveRecomp/live_generator.cpp:1589–1649  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1587}
1588
1589void N64Recomp::LiveGenerator::emit_switch(const Context& recompiler_context, const JumpTable& jtbl, int reg) const {
1590 // Populate the switch's labels.
1591 std::vector<std::string> cur_labels{};
1592 cur_labels.resize(jtbl.entries.size());
1593 for (size_t i = 0; i < cur_labels.size(); i++) {
1594 cur_labels[i] = fmt::format("L_{:08X}", jtbl.entries[i]);
1595 }
1596 context->switch_jump_labels.emplace_back(std::move(cur_labels));
1597
1598 // Allocate the jump table.
1599 std::unique_ptr<void* []> cur_jump_table = std::make_unique<void* []>(jtbl.entries.size());
1600
1601 /// Codegen
1602
1603 // Load the jump target register. The lw instruction was patched into an addiu, so this holds
1604 // the address of the jump table entry instead of the actual jump target.
1605 sljit_emit_op1(compiler, SLJIT_MOV, Registers::arithmetic_temp1, 0, SLJIT_MEM1(Registers::ctx), get_gpr_context_offset(reg));
1606 // Subtract the jump table's address from the jump target to get the jump table addend.
1607 // Sign extend the jump table address to 64 bits so that the entire register's contents are used instead of just the lower 32 bits.
1608 const auto& jtbl_section = recompiler_context.sections[jtbl.section_index];
1609 if (jtbl_section.relocatable) {
1610 // Make a dummy instruction context to pass to `load_relocated_address`.
1611 InstructionContext dummy_context{};
1612
1613 // Get the relocated address of the jump table.
1614 uint32_t section_offset = jtbl.vram - jtbl_section.ram_addr;
1615
1616 // Get the section index to use for relocation at runtime.
1617 uint16_t reloc_section_index = jtbl.section_index;
1618 if (!inputs.original_section_indices.empty()) {
1619 reloc_section_index = inputs.original_section_indices[reloc_section_index];
1620 }
1621
1622 // Populate the necessary fields of the dummy context and load the relocated address into temp2.
1623 dummy_context.reloc_section_index = reloc_section_index;
1624 dummy_context.reloc_target_section_offset = section_offset;
1625 load_relocated_address(dummy_context, Registers::arithmetic_temp2);
1626
1627 // Subtract the relocated jump table start address from the loaded address.
1628 sljit_emit_op2(compiler, SLJIT_SUB, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp2, 0);
1629 }
1630 else {
1631 sljit_emit_op2(compiler, SLJIT_SUB, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp1, 0, SLJIT_IMM, (sljit_sw)((int32_t)jtbl.vram));
1632 }
1633
1634 // Bounds check the addend. If it's greater than or equal to the jump table size (entries * sizeof(u32)) then jump to the switch error.
1635 sljit_jump* switch_error_jump = sljit_emit_cmp(compiler, SLJIT_GREATER_EQUAL, Registers::arithmetic_temp1, 0, SLJIT_IMM, jtbl.entries.size() * sizeof(uint32_t));
1636 context->switch_error_jumps.emplace_back(SwitchErrorJump{.instr_vram = jtbl.jr_vram, .jtbl_vram = jtbl.vram, .jump = switch_error_jump});
1637
1638 // Multiply the jump table addend by 2 to get the addend for the real jump table. (4 bytes per entry to 8 bytes per entry).
1639 sljit_emit_op2(compiler, SLJIT_ADD, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp1, 0);
1640 // Load the real jump table address.
1641 sljit_emit_op1(compiler, SLJIT_MOV, Registers::arithmetic_temp2, 0, SLJIT_IMM, (sljit_sw)cur_jump_table.get());
1642 // Load the real jump entry.
1643 sljit_emit_op1(compiler, SLJIT_MOV, Registers::arithmetic_temp1, 0, SLJIT_MEM2(Registers::arithmetic_temp1, Registers::arithmetic_temp2), 0);
1644 // Jump to the loaded entry.
1645 sljit_emit_ijump(compiler, SLJIT_JUMP, Registers::arithmetic_temp1, 0);
1646

Callers

nothing calls this directly

Calls 1

get_gpr_context_offsetFunction · 0.85

Tested by

no test coverage detected