Implemented jal function lookup
This commit is contained in:
parent
8a0f0da0cc
commit
84fd433dcc
|
@ -4,6 +4,8 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
inline uint32_t byteswap(uint32_t val) {
|
inline uint32_t byteswap(uint32_t val) {
|
||||||
|
@ -24,8 +26,12 @@ namespace RecompPort {
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
std::vector<RecompPort::Function> functions;
|
||||||
|
std::unordered_map<uint32_t, std::vector<size_t>> functions_by_vram;
|
||||||
|
};
|
||||||
|
|
||||||
bool recompile_function(const Function& func, std::string_view output_path);
|
bool recompile_function(const Context& context, const Function& func, std::string_view output_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
21
recomp.h
21
recomp.h
|
@ -3,11 +3,23 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if 0 // treat GPRs as 32-bit, should be better codegen
|
||||||
|
typedef uint32_t gpr;
|
||||||
|
|
||||||
|
#define SIGNED(val) \
|
||||||
|
((int32_t)(val))
|
||||||
|
#else
|
||||||
|
typedef uint64_t gpr;
|
||||||
|
|
||||||
|
#define SIGNED(val) \
|
||||||
|
((int64_t)(val))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ADD32(a, b) \
|
#define ADD32(a, b) \
|
||||||
((uint64_t)(int32_t)((a) + (b)))
|
((gpr)(int32_t)((a) + (b)))
|
||||||
|
|
||||||
#define SUB32(a, b) \
|
#define SUB32(a, b) \
|
||||||
((uint64_t)(int32_t)((a) - (b)))
|
((gpr)(int32_t)((a) - (b)))
|
||||||
|
|
||||||
#define MEM_D(offset, reg) \
|
#define MEM_D(offset, reg) \
|
||||||
(*(int64_t*)((rdram) + (((reg) + (offset)) ^ 3)))
|
(*(int64_t*)((rdram) + (((reg) + (offset)) ^ 3)))
|
||||||
|
@ -36,6 +48,9 @@
|
||||||
#define S64(val) \
|
#define S64(val) \
|
||||||
((int64_t)(val))
|
((int64_t)(val))
|
||||||
|
|
||||||
|
#define U64(val) \
|
||||||
|
((uint64_t)(val))
|
||||||
|
|
||||||
#define MUL_S(val1, val2) \
|
#define MUL_S(val1, val2) \
|
||||||
((val1) * (val2))
|
((val1) * (val2))
|
||||||
|
|
||||||
|
@ -66,8 +81,6 @@
|
||||||
#define TRUNC_W_D(val) \
|
#define TRUNC_W_D(val) \
|
||||||
((int32_t)(val))
|
((int32_t)(val))
|
||||||
|
|
||||||
typedef uint64_t gpr;
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
double d;
|
double d;
|
||||||
struct {
|
struct {
|
||||||
|
|
32
src/main.cpp
32
src/main.cpp
|
@ -231,6 +231,9 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ELFIO::elfio elf_file;
|
ELFIO::elfio elf_file;
|
||||||
|
RabbitizerConfig_Cfg.pseudos.pseudoMove = false;
|
||||||
|
RabbitizerConfig_Cfg.pseudos.pseudoBeqz = false;
|
||||||
|
RabbitizerConfig_Cfg.pseudos.pseudoBnez = false;
|
||||||
|
|
||||||
auto exit_failure = [] (const std::string& error_str) {
|
auto exit_failure = [] (const std::string& error_str) {
|
||||||
fmt::print(stderr, error_str);
|
fmt::print(stderr, error_str);
|
||||||
|
@ -282,8 +285,8 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
fmt::print("Num symbols: {}\n", symbols.get_symbols_num());
|
fmt::print("Num symbols: {}\n", symbols.get_symbols_num());
|
||||||
|
|
||||||
std::vector<RecompPort::Function> functions{};
|
RecompPort::Context context{};
|
||||||
functions.reserve(1024);
|
context.functions.reserve(1024);
|
||||||
|
|
||||||
for (int sym_index = 0; sym_index < symbols.get_symbols_num(); sym_index++) {
|
for (int sym_index = 0; sym_index < symbols.get_symbols_num(); sym_index++) {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -298,33 +301,36 @@ int main(int argc, char** argv) {
|
||||||
symbols.get_symbol(sym_index, name, value, size, bind, type,
|
symbols.get_symbol(sym_index, name, value, size, bind, type,
|
||||||
section_index, other);
|
section_index, other);
|
||||||
|
|
||||||
// Check if this symbol is a function
|
// Check if this symbol is a function or has no type (like a regular glabel would)
|
||||||
if (type == ELFIO::STT_FUNC) {
|
// Symbols with no type have a dummy entry created so that their symbol can be looked up for function calls
|
||||||
|
if (type == ELFIO::STT_FUNC || (type == ELFIO::STT_NOTYPE && section_index < section_rom_addrs.size())) {
|
||||||
auto section_rom_addr = section_rom_addrs[section_index];
|
auto section_rom_addr = section_rom_addrs[section_index];
|
||||||
auto section_offset = value - elf_file.sections[section_index]->get_address();
|
auto section_offset = value - elf_file.sections[section_index]->get_address();
|
||||||
const uint32_t* words = reinterpret_cast<const uint32_t*>(elf_file.sections[section_index]->get_data() + section_offset);
|
const uint32_t* words = reinterpret_cast<const uint32_t*>(elf_file.sections[section_index]->get_data() + section_offset);
|
||||||
functions.emplace_back(
|
uint32_t vram = static_cast<uint32_t>(value);
|
||||||
static_cast<uint32_t>(value),
|
uint32_t num_instructions = type == ELFIO::STT_FUNC ? size / 4 : 0;
|
||||||
|
context.functions_by_vram[vram].push_back(context.functions.size());
|
||||||
|
context.functions.emplace_back(
|
||||||
|
vram,
|
||||||
static_cast<uint32_t>(section_offset + section_rom_addr),
|
static_cast<uint32_t>(section_offset + section_rom_addr),
|
||||||
std::span{ reinterpret_cast<const uint32_t*>(words), size / 4 },
|
std::span{ words, num_instructions },
|
||||||
std::move(name)
|
std::move(name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::print("Function count: {}\n", functions.size());
|
fmt::print("Function count: {}\n", context.functions.size());
|
||||||
|
|
||||||
//#pragma omp parallel for
|
//#pragma omp parallel for
|
||||||
for (size_t i = 0; i < functions.size(); i++) {
|
for (size_t i = 0; i < context.functions.size(); i++) {
|
||||||
const auto& func = functions[i];
|
const auto& func = context.functions[i];
|
||||||
if (!ignored_funcs.contains(func.name)) {
|
if (!ignored_funcs.contains(func.name) && func.words.size() != 0) {
|
||||||
if (RecompPort::recompile_function(func, "out/" + func.name + ".c") == false) {
|
if (RecompPort::recompile_function(context, func, "out/" + func.name + ".c") == false) {
|
||||||
fmt::print(stderr, "Error recompiling {}\n", func.name);
|
fmt::print(stderr, "Error recompiling {}\n", func.name);
|
||||||
std::exit(EXIT_FAILURE);
|
std::exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//RecompPort::recompile_function(functions.back(), "test.c");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ std::string_view ctx_gpr_prefix(int reg) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool process_instruction(size_t instr_index, const std::vector<rabbitizer::InstructionCpu>& instructions, std::ofstream& output_file, bool indent, bool emit_link_branch, int link_branch_index, bool& needs_link_branch, bool& is_branch_likely) {
|
bool process_instruction(const RecompPort::Context& context, size_t instr_index, const std::vector<rabbitizer::InstructionCpu>& instructions, std::ofstream& output_file, bool indent, bool emit_link_branch, int link_branch_index, bool& needs_link_branch, bool& is_branch_likely) {
|
||||||
const auto& instr = instructions[instr_index];
|
const auto& instr = instructions[instr_index];
|
||||||
needs_link_branch = false;
|
needs_link_branch = false;
|
||||||
is_branch_likely = false;
|
is_branch_likely = false;
|
||||||
|
@ -25,7 +25,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
if (instr.isBranch() || instr.getUniqueId() == InstrId::cpu_j) {
|
if (instr.isBranch() || instr.getUniqueId() == InstrId::cpu_j) {
|
||||||
fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("L_{:08X}", (uint32_t)instr.getBranchVramGeneric())));
|
fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("L_{:08X}", (uint32_t)instr.getBranchVramGeneric())));
|
||||||
} else if (instr.getUniqueId() == InstrId::cpu_jal) {
|
} else if (instr.getUniqueId() == InstrId::cpu_jal) {
|
||||||
fmt::print(output_file, " // {}\n", instr.disassemble(0, "func"));
|
fmt::print(output_file, " // {}\n", instr.disassemble(0, fmt::format("0x{:08X}", (uint32_t)instr.getBranchVramGeneric())));
|
||||||
} else {
|
} else {
|
||||||
fmt::print(output_file, " // {}\n", instr.disassemble(0));
|
fmt::print(output_file, " // {}\n", instr.disassemble(0));
|
||||||
}
|
}
|
||||||
|
@ -45,12 +45,27 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
fmt::print(output_file, " ");
|
fmt::print(output_file, " ");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto print_unconditional_branch = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts ...args) {
|
||||||
|
if (instr_index < instructions.size() - 1) {
|
||||||
|
bool dummy_needs_link_branch;
|
||||||
|
bool dummy_is_branch_likely;
|
||||||
|
process_instruction(context, instr_index + 1, instructions, output_file, false, false, link_branch_index, dummy_needs_link_branch, dummy_is_branch_likely);
|
||||||
|
}
|
||||||
|
print_indent();
|
||||||
|
fmt::print(output_file, fmt_str, args...);
|
||||||
|
if (needs_link_branch) {
|
||||||
|
fmt::print(output_file, ";\n goto after_{};\n", link_branch_index);
|
||||||
|
} else {
|
||||||
|
fmt::print(output_file, ";\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auto print_branch = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts ...args) {
|
auto print_branch = [&]<typename... Ts>(fmt::format_string<Ts...> fmt_str, Ts ...args) {
|
||||||
fmt::print(output_file, "{{\n ");
|
fmt::print(output_file, "{{\n ");
|
||||||
if (instr_index < instructions.size() - 1) {
|
if (instr_index < instructions.size() - 1) {
|
||||||
bool dummy_needs_link_branch;
|
bool dummy_needs_link_branch;
|
||||||
bool dummy_is_branch_likely;
|
bool dummy_is_branch_likely;
|
||||||
process_instruction(instr_index + 1, instructions, output_file, true, false, link_branch_index, dummy_needs_link_branch, dummy_is_branch_likely);
|
process_instruction(context, instr_index + 1, instructions, output_file, true, false, link_branch_index, dummy_needs_link_branch, dummy_is_branch_likely);
|
||||||
}
|
}
|
||||||
fmt::print(output_file, " ");
|
fmt::print(output_file, " ");
|
||||||
fmt::print(output_file, fmt_str, args...);
|
fmt::print(output_file, fmt_str, args...);
|
||||||
|
@ -122,37 +137,38 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
print_line("{}{} = S32({}{}) << ({}{} & 31)", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs);
|
print_line("{}{} = S32({}{}) << ({}{} & 31)", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_sra:
|
case InstrId::cpu_sra:
|
||||||
print_line("{}{} = S32(S64({}{}) >> {})", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, sa);
|
print_line("{}{} = S32(SIGNED({}{}) >> {})", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, sa);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_srav:
|
case InstrId::cpu_srav:
|
||||||
print_line("{}{} = S32(S64({}{}) >> ({}{} & 31)", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs);
|
print_line("{}{} = S32(SIGNED({}{}) >> ({}{} & 31))", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_srl:
|
case InstrId::cpu_srl:
|
||||||
print_line("{}{} = S32(U32({}{}) >> {})", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, sa);
|
print_line("{}{} = S32(U32({}{}) >> {})", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, sa);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_srlv:
|
case InstrId::cpu_srlv:
|
||||||
print_line("{}{} = S32(U32({}{}) >> ({}{} & 31)", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs);
|
print_line("{}{} = S32(U32({}{}) >> ({}{} & 31))", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_slt:
|
case InstrId::cpu_slt:
|
||||||
print_line("{}{} = S64({}{}) < S64({}{}) ? 1 : 0", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_line("{}{} = SIGNED({}{}) < SIGNED({}{}) ? 1 : 0", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_slti:
|
case InstrId::cpu_slti:
|
||||||
print_line("{}{} = S64({}{}) < {:#X} ? 1 : 0", ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, (int16_t)imm);
|
print_line("{}{} = SIGNED({}{}) < {:#X} ? 1 : 0", ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, (int16_t)imm);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_sltu:
|
case InstrId::cpu_sltu:
|
||||||
print_line("{}{} = U64({}{}) < U64({}{}) ? 1 : 0", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_line("{}{} = {}{} < {}{} ? 1 : 0", ctx_gpr_prefix(rd), rd, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_sltiu:
|
case InstrId::cpu_sltiu:
|
||||||
print_line("{}{} = U64({}{}) < {:#X} ? 1 : 0", ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, (int16_t)imm);
|
print_line("{}{} = {}{} < {:#X} ? 1 : 0", ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, (int16_t)imm);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_mult:
|
case InstrId::cpu_mult:
|
||||||
print_line("uint64_t result = S64({}{}) * S64({}{}); lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_line("uint64_t result = S64({}{}) * S64({}{}); lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_multu:
|
case InstrId::cpu_multu:
|
||||||
print_line("uint64_t result = {}{} * {}{}; lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_line("uint64_t result = U64({}{}) * U64({}{}); lo = S32(result >> 0); hi = S32(result >> 32)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_div:
|
case InstrId::cpu_div:
|
||||||
print_line("lo = S32(S64({}{}) / S64({}{})); hi = S32(S64({}{}) % S64({}{}))", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
// Cast to 64-bits before division to prevent artihmetic exception for s32(0x80000000) / -1
|
||||||
|
print_line("lo = S32(S64(S32({}{})) / S64(S32({}{}))); hi = S32(S64(S32({}{})) % S64(S32({}{})))", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_divu:
|
case InstrId::cpu_divu:
|
||||||
print_line("lo = S32(U32({}{}) / U32({}{})); hi = S32(U32({}{}) % U32({}{}))", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_line("lo = S32(U32({}{}) / U32({}{})); hi = S32(U32({}{}) % U32({}{}))", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt, ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
|
@ -219,26 +235,65 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
|
|
||||||
// Branches
|
// Branches
|
||||||
case InstrId::cpu_jal:
|
case InstrId::cpu_jal:
|
||||||
needs_link_branch = true;
|
{
|
||||||
print_indent();
|
uint32_t target_func_vram = instr.getBranchVramGeneric();
|
||||||
// TODO lookup function name
|
const auto matching_funcs_find = context.functions_by_vram.find(target_func_vram);
|
||||||
print_branch("{}(rdram, ctx)", "func");
|
if (matching_funcs_find == context.functions_by_vram.end()) {
|
||||||
|
fmt::print(stderr, "No function found for jal target: 0x{:08X}\n", target_func_vram);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto& matching_funcs_vec = matching_funcs_find->second;
|
||||||
|
size_t real_func_index;
|
||||||
|
bool ambiguous;
|
||||||
|
// If there is more than one corresponding function, look for any that have a nonzero size
|
||||||
|
if (matching_funcs_vec.size() > 1) {
|
||||||
|
size_t nonzero_func_index = (size_t)-1;
|
||||||
|
bool found_nonzero_func = false;
|
||||||
|
for (size_t cur_func_index : matching_funcs_vec) {
|
||||||
|
const auto& cur_func = context.functions[cur_func_index];
|
||||||
|
if (cur_func.words.size() != 0) {
|
||||||
|
if (found_nonzero_func) {
|
||||||
|
ambiguous = true;
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_jalr:
|
}
|
||||||
|
found_nonzero_func = true;
|
||||||
|
nonzero_func_index = cur_func_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
real_func_index = nonzero_func_index;
|
||||||
|
ambiguous = false;
|
||||||
|
} else {
|
||||||
|
real_func_index = matching_funcs_vec.front();
|
||||||
|
ambiguous = false;
|
||||||
|
}
|
||||||
|
if (ambiguous) {
|
||||||
|
fmt::print(stderr, "Ambiguous jal target: 0x{:08X}\n", target_func_vram);
|
||||||
|
for (size_t cur_func_index : matching_funcs_vec) {
|
||||||
|
const auto& cur_func = context.functions[cur_func_index];
|
||||||
|
fmt::print(stderr, " {}\n", cur_func.name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
needs_link_branch = true;
|
needs_link_branch = true;
|
||||||
print_indent();
|
print_unconditional_branch("{}(rdram, ctx)", context.functions[real_func_index].name);
|
||||||
// TODO index global function table
|
break;
|
||||||
print_branch("{}(rdram, ctx)", "func_reg");
|
}
|
||||||
|
case InstrId::cpu_jalr:
|
||||||
|
// jalr can only be handled with $ra as the return address register
|
||||||
|
if (rd != (int)rabbitizer::Registers::Cpu::GprO32::GPR_O32_ra) {
|
||||||
|
fmt::print(stderr, "Invalid return address reg for jalr: f{}\n", rd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
needs_link_branch = true;
|
||||||
|
print_unconditional_branch("LOOKUP_FUNC({}{})(rdram, ctx)", ctx_gpr_prefix(rs), rs);
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_j:
|
case InstrId::cpu_j:
|
||||||
case InstrId::cpu_b:
|
case InstrId::cpu_b:
|
||||||
print_indent();
|
print_unconditional_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_jr:
|
case InstrId::cpu_jr:
|
||||||
print_indent();
|
|
||||||
if (rs == (int)rabbitizer::Registers::Cpu::GprO32::GPR_O32_ra) {
|
if (rs == (int)rabbitizer::Registers::Cpu::GprO32::GPR_O32_ra) {
|
||||||
print_branch("return");
|
print_unconditional_branch("return");
|
||||||
} else {
|
} else {
|
||||||
// TODO jump table handling
|
// TODO jump table handling
|
||||||
}
|
}
|
||||||
|
@ -248,7 +303,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case InstrId::cpu_bne:
|
case InstrId::cpu_bne:
|
||||||
print_indent();
|
print_indent();
|
||||||
print_branch_condition("if (S32({}{}) != S32({}{}))", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_branch_condition("if ({}{} != {}{})", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_beql:
|
case InstrId::cpu_beql:
|
||||||
|
@ -256,17 +311,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case InstrId::cpu_beq:
|
case InstrId::cpu_beq:
|
||||||
print_indent();
|
print_indent();
|
||||||
print_branch_condition("if (S32({}{}) == S32({}{}))", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
print_branch_condition("if ({}{} == {}{})", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_bnez:
|
|
||||||
print_indent();
|
|
||||||
print_branch_condition("if (S32({}{}) != 0)", ctx_gpr_prefix(rs), rs);
|
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_beqz:
|
|
||||||
print_indent();
|
|
||||||
print_branch_condition("if (S32({}{}) == 0)", ctx_gpr_prefix(rs), rs);
|
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_bgezl:
|
case InstrId::cpu_bgezl:
|
||||||
|
@ -274,7 +319,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case InstrId::cpu_bgez:
|
case InstrId::cpu_bgez:
|
||||||
print_indent();
|
print_indent();
|
||||||
print_branch_condition("if (S32({}{}) >= 0)", ctx_gpr_prefix(rs), rs);
|
print_branch_condition("if (SIGNED({}{}) >= 0)", ctx_gpr_prefix(rs), rs);
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_bgtzl:
|
case InstrId::cpu_bgtzl:
|
||||||
|
@ -282,7 +327,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case InstrId::cpu_bgtz:
|
case InstrId::cpu_bgtz:
|
||||||
print_indent();
|
print_indent();
|
||||||
print_branch_condition("if (S32({}{}) > 0)", ctx_gpr_prefix(rs), rs);
|
print_branch_condition("if (SIGNED({}{}) > 0)", ctx_gpr_prefix(rs), rs);
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_blezl:
|
case InstrId::cpu_blezl:
|
||||||
|
@ -290,7 +335,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case InstrId::cpu_blez:
|
case InstrId::cpu_blez:
|
||||||
print_indent();
|
print_indent();
|
||||||
print_branch_condition("if (S32({}{}) <= 0)", ctx_gpr_prefix(rs), rs);
|
print_branch_condition("if (SIGNED({}{}) <= 0)", ctx_gpr_prefix(rs), rs);
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_bltzl:
|
case InstrId::cpu_bltzl:
|
||||||
|
@ -298,7 +343,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case InstrId::cpu_bltz:
|
case InstrId::cpu_bltz:
|
||||||
print_indent();
|
print_indent();
|
||||||
print_branch_condition("if (S32({}{}) < 0)", ctx_gpr_prefix(rs), rs);
|
print_branch_condition("if (SIGNED({}{}) < 0)", ctx_gpr_prefix(rs), rs);
|
||||||
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
print_branch("goto L_{:08X}", (uint32_t)instr.getBranchVramGeneric());
|
||||||
break;
|
break;
|
||||||
case InstrId::cpu_break:
|
case InstrId::cpu_break:
|
||||||
|
@ -639,7 +684,7 @@ bool process_instruction(size_t instr_index, const std::vector<rabbitizer::Instr
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecompPort::recompile_function(const RecompPort::Function& func, std::string_view output_path) {
|
bool RecompPort::recompile_function(const RecompPort::Context& context, const RecompPort::Function& func, std::string_view output_path) {
|
||||||
fmt::print("Recompiling {}\n", func.name);
|
fmt::print("Recompiling {}\n", func.name);
|
||||||
std::vector<rabbitizer::InstructionCpu> instructions;
|
std::vector<rabbitizer::InstructionCpu> instructions;
|
||||||
|
|
||||||
|
@ -692,7 +737,7 @@ bool RecompPort::recompile_function(const RecompPort::Function& func, std::strin
|
||||||
++cur_label;
|
++cur_label;
|
||||||
}
|
}
|
||||||
// Process the current instruction and check for errors
|
// Process the current instruction and check for errors
|
||||||
if (process_instruction(instr_index, instructions, output_file, false, needs_link_branch, num_link_branches, needs_link_branch, is_branch_likely) == false) {
|
if (process_instruction(context, instr_index, instructions, output_file, false, needs_link_branch, num_link_branches, needs_link_branch, is_branch_likely) == false) {
|
||||||
fmt::print(stderr, "Error in recompilation, clearing {}\n", output_path);
|
fmt::print(stderr, "Error in recompilation, clearing {}\n", output_path);
|
||||||
output_file.clear();
|
output_file.clear();
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue