From a5eaea94cbc8b2c7c79ebff1b89b2e4d5c19ac2a Mon Sep 17 00:00:00 2001 From: angie Date: Tue, 14 May 2024 16:22:00 -0400 Subject: [PATCH] Handle tail calls in the middle of functions --- .vscode/c_cpp_properties.json | 16 ++++++++++++++++ src/main.cpp | 2 +- src/recompilation.cpp | 27 ++++++++++++++++++++++----- 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 .vscode/c_cpp_properties.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..2e8c75f --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -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 +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4cab9e1..88e11ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -503,7 +503,6 @@ std::unordered_set ignored_funcs { // libgcc math routines (these throw off the recompiler) "__divdi3", - "__udivdi3", "__moddi3", // ido math routines @@ -626,6 +625,7 @@ std::unordered_set renamed_funcs{ "flush_window", "__muldi3", + "__udivdi3", "__umoddi3", "div64_64", "div64_32", diff --git a/src/recompilation.cpp b/src/recompilation.cpp index 8c5bf4e..32c7ac7 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -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; }; @@ -492,7 +492,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C case InstrId::cpu_swr: print_line("do_swr(rdram, {}, {}{}, {}{})", signed_imm_string, ctx_gpr_prefix(base), base, ctx_gpr_prefix(rt), rt); break; - + // Branches case InstrId::cpu_jal: print_func_call(instr.getBranchVramGeneric()); @@ -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; @@ -536,7 +553,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C [instr_vram](const RecompPort::JumpTable& jtbl) { return jtbl.jr_vram == instr_vram; }); - + if (jtbl_find_result != stats.jump_tables.end()) { const RecompPort::JumpTable& cur_jtbl = *jtbl_find_result; bool dummy_needs_link_branch, dummy_is_branch_likely;