Handle tail calls in the middle of functions

This commit is contained in:
angie 2024-05-14 16:22:00 -04:00
parent be29c979c8
commit a5eaea94cb
3 changed files with 39 additions and 6 deletions

16
.vscode/c_cpp_properties.json vendored Normal file
View file

@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"intelliSenseMode": "linux-clang-x64",
"cStandard": "c17",
"cppStandard": "c++20",
}
],
"version": 4
}

View file

@ -503,7 +503,6 @@ std::unordered_set<std::string> ignored_funcs {
// libgcc math routines (these throw off the recompiler)
"__divdi3",
"__udivdi3",
"__moddi3",
// ido math routines
@ -626,6 +625,7 @@ std::unordered_set<std::string> renamed_funcs{
"flush_window",
"__muldi3",
"__udivdi3",
"__umoddi3",
"div64_64",
"div64_32",

View file

@ -124,7 +124,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
fmt::print(output_file, ";\n }}\n");
};
auto print_func_call = [&](uint32_t target_func_vram) {
auto print_func_call = [&](uint32_t target_func_vram, bool link_branch = true) {
const auto matching_funcs_find = context.functions_by_vram.find(target_func_vram);
std::string jal_target_name;
uint32_t section_vram_start = section.ram_addr;
@ -190,7 +190,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
return false;
}
}
needs_link_branch = true;
needs_link_branch = link_branch;
print_unconditional_branch("{}(rdram, ctx)", jal_target_name);
return true;
};
@ -511,7 +511,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
{
uint32_t branch_target = instr.getBranchVramGeneric();
if (branch_target == instr_vram) {
print_line("void pause_self(uint8_t *rdram); pause_self(rdram)");
print_line("pause_self(rdram)");
}
// Check if the branch is within this function
else if (branch_target >= func.vram && branch_target < func_vram_end) {
@ -522,6 +522,23 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
fmt::print("Tail call in {}\n", func.name);
print_func_call(branch_target);
}
// This may be a tail call in the middle of the control flow due to a previous check
// For example:
// ```c
// void test() {
// if (SOME_CONDITION) {
// do_a();
// } else {
// do_b();
// }
// }
// ```
// FIXME: how to deal with static functions?
else if (context.functions_by_vram.find(branch_target) != context.functions_by_vram.end()) {
fmt::print("Tail call in {}\n", func.name);
print_func_call(branch_target, false);
print_line("return");
}
else {
fmt::print(stderr, "Unhandled branch in {} at 0x{:08X} to 0x{:08X}\n", func.name, instr_vram, branch_target);
return false;