From 898de82da71ec264184e09a78eb0b21ea9cea703 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Mon, 7 Oct 2024 00:15:11 -0400 Subject: [PATCH] Implemented calling internal functions in live recompiler, added bltzal/bltzall to branch operations --- LiveRecomp/live_generator.cpp | 82 ++++++++++++++++-- LiveRecomp/live_recompiler_test.cpp | 123 ++++++++++++++++++++------- OfflineModRecomp/main.cpp | 3 +- include/recompiler/context.h | 4 +- include/recompiler/generator.h | 10 ++- include/recompiler/live_recompiler.h | 34 +++++++- src/cgenerator.cpp | 11 ++- src/main.cpp | 29 ++++--- src/operations.cpp | 2 + src/recompilation.cpp | 28 +++--- 10 files changed, 246 insertions(+), 80 deletions(-) diff --git a/LiveRecomp/live_generator.cpp b/LiveRecomp/live_generator.cpp index 94ff815..9dad0c5 100644 --- a/LiveRecomp/live_generator.cpp +++ b/LiveRecomp/live_generator.cpp @@ -31,17 +31,78 @@ namespace Registers { constexpr int float_temp = SLJIT_FR0; } +struct InnerCall { + size_t target_func_index; + sljit_jump* jump; +}; + +struct ReferenceSymbolCall { + uint16_t reference; +}; + struct N64Recomp::LiveGeneratorContext { std::unordered_map labels; std::unordered_map> pending_jumps; + std::vector func_labels; + std::vector inner_calls; sljit_jump* cur_branch_jump; }; -N64Recomp::LiveGenerator::LiveGenerator(sljit_compiler* compiler) : compiler(compiler) { +N64Recomp::LiveGenerator::LiveGenerator(size_t num_funcs) : compiler(compiler) { + compiler = sljit_create_compiler(NULL); context = std::make_unique(); + context->func_labels.resize(num_funcs); } -N64Recomp::LiveGenerator::~LiveGenerator() {} +N64Recomp::LiveGenerator::~LiveGenerator() { + if (compiler != nullptr) { + sljit_free_compiler(compiler); + compiler = nullptr; + } +} + +N64Recomp::LiveGeneratorOutput N64Recomp::LiveGenerator::finish() { + LiveGeneratorOutput ret{}; + ret.good = true; + + // Populate all the pending inner function calls. + for (const InnerCall& call : context->inner_calls) { + sljit_label* target_func_label = context->func_labels[call.target_func_index]; + + // Generation isn't valid if the target function wasn't recompiled. + if (target_func_label == nullptr) { + return { }; + } + + sljit_set_label(call.jump, target_func_label); + } + + // Generate the code. + ret.code = sljit_generate_code(compiler, 0, NULL); + ret.code_size = sljit_get_generated_code_size(compiler); + ret.functions.resize(context->func_labels.size()); + + // Get the function addresses. + for (size_t func_index = 0; func_index < ret.functions.size(); func_index++) { + sljit_label* func_label = context->func_labels[func_index]; + + // If the function wasn't recompiled, don't populate its address. + if (func_label != nullptr) { + ret.functions[func_index] = reinterpret_cast(sljit_get_label_addr(func_label)); + } + } + + sljit_free_compiler(compiler); + compiler = nullptr; + + return ret; +} + +N64Recomp::LiveGeneratorOutput::~LiveGeneratorOutput() { + if (code != nullptr) { + sljit_free_code(code, nullptr); + } +} constexpr int get_gpr_context_offset(int gpr_index) { return offsetof(recomp_context, r0) + sizeof(recomp_context::r0) * gpr_index; @@ -638,7 +699,8 @@ void N64Recomp::LiveGenerator::process_store_op(const StoreOp& op, const Instruc } } -void N64Recomp::LiveGenerator::emit_function_start(const std::string& function_name) const { +void N64Recomp::LiveGenerator::emit_function_start(const std::string& function_name, size_t func_index) const { + context->func_labels[func_index] = sljit_emit_label(compiler); sljit_emit_enter(compiler, 0, SLJIT_ARGS2V(P, P), 4, 5, 0); sljit_emit_op2(compiler, SLJIT_SUB, Registers::rdram, 0, Registers::rdram, 0, SLJIT_IMM, 0xFFFFFFFF80000000); } @@ -655,10 +717,18 @@ void N64Recomp::LiveGenerator::emit_function_call_by_register(int reg) const { assert(false); } -void N64Recomp::LiveGenerator::emit_function_call_by_name(const std::string& func_name) const { +void N64Recomp::LiveGenerator::emit_function_call_reference_symbol(const Context& context, uint16_t section_index, size_t symbol_index) const { + const N64Recomp::ReferenceSymbol& sym = context.get_reference_symbol(section_index, symbol_index); assert(false); } +void N64Recomp::LiveGenerator::emit_function_call(const Context& recompiler_context, size_t function_index) const { + sljit_emit_op2(compiler, SLJIT_ADD, SLJIT_R0, 0, Registers::rdram, 0, SLJIT_IMM, 0xFFFFFFFF80000000); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R1, 0, Registers::ctx, 0); + sljit_jump* call_jump = sljit_emit_call(compiler, SLJIT_CALL, SLJIT_ARGS2V(P, P)); + context->inner_calls.emplace_back(InnerCall{ .target_func_index = function_index, .jump = call_jump }); +} + void N64Recomp::LiveGenerator::emit_goto(const std::string& target) const { sljit_jump* jump = sljit_emit_jump(compiler, SLJIT_JUMP); // Check if the label already exists. @@ -996,7 +1066,7 @@ void N64Recomp::LiveGenerator::emit_comment(const std::string& comment) const { // Nothing to do here. } -bool N64Recomp::recompile_function_live(LiveGenerator& generator, const Context& context, const Function& func, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { - return recompile_function_custom(generator, context, func, output_file, static_funcs_out, tag_reference_relocs); +bool N64Recomp::recompile_function_live(LiveGenerator& generator, const Context& context, size_t function_index, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { + return recompile_function_custom(generator, context, function_index, output_file, static_funcs_out, tag_reference_relocs); } diff --git a/LiveRecomp/live_recompiler_test.cpp b/LiveRecomp/live_recompiler_test.cpp index 5d62ded..329d8a4 100644 --- a/LiveRecomp/live_recompiler_test.cpp +++ b/LiveRecomp/live_recompiler_test.cpp @@ -54,6 +54,7 @@ enum class TestError { Success, FailedToOpenInput, FailedToRecompile, + UnknownStructType, DataDifference }; @@ -84,6 +85,7 @@ TestStats run_test(const std::filesystem::path& tests_dir, const std::string& te uint32_t data_length = read_u32_swap(file_data, 0x10); uint32_t text_address = read_u32_swap(file_data, 0x14); uint32_t data_address = read_u32_swap(file_data, 0x18); + uint32_t next_struct_address = read_u32_swap(file_data, 0x1C); recomp_context ctx{}; @@ -105,55 +107,107 @@ TestStats run_test(const std::filesystem::path& tests_dir, const std::string& te context.sections[0].executable = true; context.section_functions.resize(context.sections.size()); - // Get the function's instruction words. - std::vector text_words{}; - text_words.resize(text_length / sizeof(uint32_t)); - for (size_t i = 0; i < text_words.size(); i++) { - text_words[i] = read_u32(context.rom, text_offset + i * sizeof(uint32_t)); + size_t start_func_index; + uint32_t function_desc_address = 0; + + // Read any extra structs. + while (next_struct_address != 0) { + uint32_t cur_struct_address = next_struct_address; + uint32_t struct_type = read_u32_swap(context.rom, next_struct_address + 0x00); + next_struct_address = read_u32_swap(context.rom, next_struct_address + 0x04); + + switch (struct_type) { + case 1: // Function desc + function_desc_address = cur_struct_address; + break; + default: + printf("Unknown struct type %u\n", struct_type); + return { TestError::UnknownStructType }; + } } - // Add the function to the context. - context.functions_by_vram[text_address].emplace_back(context.functions.size()); - context.section_functions.emplace_back(context.functions.size()); - context.sections[0].function_addrs.emplace_back(text_address); - context.functions.emplace_back( - text_address, - text_offset, - text_words, - "test_func", - 0 - ); + // Check if a function description exists. + if (function_desc_address == 0) { + // No function description, so treat the whole thing as one function. + + // Get the function's instruction words. + std::vector text_words{}; + text_words.resize(text_length / sizeof(uint32_t)); + for (size_t i = 0; i < text_words.size(); i++) { + text_words[i] = read_u32(context.rom, text_offset + i * sizeof(uint32_t)); + } + + // Add the function to the context. + context.functions_by_vram[text_address].emplace_back(context.functions.size()); + context.section_functions.emplace_back(context.functions.size()); + context.sections[0].function_addrs.emplace_back(text_address); + context.functions.emplace_back( + text_address, + text_offset, + text_words, + "test_func", + 0 + ); + start_func_index = 0; + } + else { + // Use the function description. + uint32_t num_funcs = read_u32_swap(context.rom, function_desc_address + 0x08); + start_func_index = read_u32_swap(context.rom, function_desc_address + 0x0C); + + for (size_t func_index = 0; func_index < num_funcs; func_index++) { + uint32_t cur_func_address = read_u32_swap(context.rom, function_desc_address + 0x10 + 0x00 + 0x08 * func_index); + uint32_t cur_func_length = read_u32_swap(context.rom, function_desc_address + 0x10 + 0x04 + 0x08 * func_index); + uint32_t cur_func_offset = cur_func_address - text_address + text_offset; + + // Get the function's instruction words. + std::vector text_words{}; + text_words.resize(cur_func_length / sizeof(uint32_t)); + for (size_t i = 0; i < text_words.size(); i++) { + text_words[i] = read_u32(context.rom, cur_func_offset + i * sizeof(uint32_t)); + } + + // Add the function to the context. + context.functions_by_vram[cur_func_address].emplace_back(context.functions.size()); + context.section_functions.emplace_back(context.functions.size()); + context.sections[0].function_addrs.emplace_back(cur_func_address); + context.functions.emplace_back( + cur_func_address, + cur_func_offset, + std::move(text_words), + "test_func_" + std::to_string(func_index), + 0 + ); + } + } std::vector> dummy_static_funcs{}; auto before_codegen = std::chrono::system_clock::now(); - // Create the sljit compiler and generator. - sljit_compiler* compiler = sljit_create_compiler(NULL); - N64Recomp::LiveGenerator generator{ compiler }; - std::ostringstream dummy_ostream{}; + // Create the sljit compiler and the generator. + N64Recomp::LiveGenerator generator{ context.functions.size() }; - //sljit_emit_op0(compiler, SLJIT_BREAKPOINT); + for (size_t func_index = 0; func_index < context.functions.size(); func_index++) { + std::ostringstream dummy_ostream{}; - if (!N64Recomp::recompile_function_live(generator, context, context.functions[0], dummy_ostream, dummy_static_funcs, true)) { - return { TestError::FailedToRecompile }; + //sljit_emit_op0(compiler, SLJIT_BREAKPOINT); + + if (!N64Recomp::recompile_function_live(generator, context, func_index, dummy_ostream, dummy_static_funcs, true)) { + return { TestError::FailedToRecompile }; + } } - // Finish up code generation. - void* code = sljit_generate_code(compiler, 0, NULL); - size_t code_size = sljit_get_generated_code_size(compiler); - - sljit_free_compiler(compiler); + // Generate the code. + N64Recomp::LiveGeneratorOutput output = generator.finish(); auto after_codegen = std::chrono::system_clock::now(); auto before_execution = std::chrono::system_clock::now(); // Run the generated code. - typedef void (recomp_func_t)(uint8_t* rdram, recomp_context* ctx); - ((recomp_func_t*)code)(rdram.data(), &ctx); - - sljit_free_code(code, nullptr); + ctx.r29 = 0xFFFFFFFF80000000 + rdram.size() - 0x10; // Set the stack pointer. + output.functions[start_func_index](rdram.data(), &ctx); auto after_execution = std::chrono::system_clock::now(); @@ -175,7 +229,7 @@ TestStats run_test(const std::filesystem::path& tests_dir, const std::string& te ret.error = TestError::Success; ret.codegen_microseconds = std::chrono::duration_cast(after_codegen - before_codegen).count(); ret.execution_microseconds = std::chrono::duration_cast(after_execution - before_execution).count(); - ret.code_size = code_size; + ret.code_size = output.code_size; return ret; } @@ -214,6 +268,9 @@ int main(int argc, const char** argv) { case TestError::FailedToRecompile: printf(" Failed to recompile\n"); break; + case TestError::UnknownStructType: + printf(" Unknown additional data struct type in test data\n"); + break; case TestError::DataDifference: printf(" Output data did not match, dumped to file\n"); break; diff --git a/OfflineModRecomp/main.cpp b/OfflineModRecomp/main.cpp index 02ef166..29e5232 100644 --- a/OfflineModRecomp/main.cpp +++ b/OfflineModRecomp/main.cpp @@ -221,8 +221,7 @@ int main(int argc, const char** argv) { // Perform a second pass for recompiling all the functions. for (size_t func_index = 0; func_index < mod_context.functions.size(); func_index++) { - auto& func = mod_context.functions[func_index]; - if (!N64Recomp::recompile_function(mod_context, func, output_file, static_funcs_by_section, true)) { + if (!N64Recomp::recompile_function(mod_context, func_index, output_file, static_funcs_by_section, true)) { output_file.close(); std::error_code ec; std::filesystem::remove(output_file_path, ec); diff --git a/include/recompiler/context.h b/include/recompiler/context.h index 95e1921..b335849 100644 --- a/include/recompiler/context.h +++ b/include/recompiler/context.h @@ -521,8 +521,8 @@ namespace N64Recomp { }; class Generator; - bool recompile_function(const Context& context, const Function& func, std::ostream& output_file, std::span> static_funcs, bool tag_reference_relocs); - bool recompile_function_custom(Generator& generator, const Context& context, const Function& func, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs); + bool recompile_function(const Context& context, size_t function_index, std::ostream& output_file, std::span> static_funcs, bool tag_reference_relocs); + bool recompile_function_custom(Generator& generator, const Context& context, size_t function_index, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs); enum class ModSymbolsError { Good, diff --git a/include/recompiler/generator.h b/include/recompiler/generator.h index b084e16..fa0acf0 100644 --- a/include/recompiler/generator.h +++ b/include/recompiler/generator.h @@ -30,11 +30,12 @@ namespace N64Recomp { virtual void process_binary_op(const BinaryOp& op, const InstructionContext& ctx) const = 0; virtual void process_unary_op(const UnaryOp& op, const InstructionContext& ctx) const = 0; virtual void process_store_op(const StoreOp& op, const InstructionContext& ctx) const = 0; - virtual void emit_function_start(const std::string& function_name) const = 0; + virtual void emit_function_start(const std::string& function_name, size_t func_index) const = 0; virtual void emit_function_end() const = 0; virtual void emit_function_call_lookup(uint32_t addr) const = 0; virtual void emit_function_call_by_register(int reg) const = 0; - virtual void emit_function_call_by_name(const std::string& func_name) const = 0; + virtual void emit_function_call_reference_symbol(const Context& context, uint16_t section_index, size_t symbol_index) const = 0; + virtual void emit_function_call(const Context& context, size_t function_index) const = 0; virtual void emit_goto(const std::string& target) const = 0; virtual void emit_label(const std::string& label_name) const = 0; virtual void emit_variable_declaration(const std::string& var_name, int reg) const = 0; @@ -65,11 +66,12 @@ namespace N64Recomp { void process_binary_op(const BinaryOp& op, const InstructionContext& ctx) const final; void process_unary_op(const UnaryOp& op, const InstructionContext& ctx) const final; void process_store_op(const StoreOp& op, const InstructionContext& ctx) const final; - void emit_function_start(const std::string& function_name) const final; + void emit_function_start(const std::string& function_name, size_t func_index) const final; void emit_function_end() const final; void emit_function_call_lookup(uint32_t addr) const final; void emit_function_call_by_register(int reg) const final; - void emit_function_call_by_name(const std::string& func_name) const final; + void emit_function_call_reference_symbol(const Context& context, uint16_t section_index, size_t symbol_index) const final; + void emit_function_call(const Context& context, size_t function_index) const final; void emit_goto(const std::string& target) const final; void emit_label(const std::string& label_name) const final; void emit_variable_declaration(const std::string& var_name, int reg) const final; diff --git a/include/recompiler/live_recompiler.h b/include/recompiler/live_recompiler.h index 8773542..365e37b 100644 --- a/include/recompiler/live_recompiler.h +++ b/include/recompiler/live_recompiler.h @@ -2,23 +2,49 @@ #define __LIVE_RECOMPILER_H__ #include "recompiler/generator.h" +#include "recomp.h" struct sljit_compiler; namespace N64Recomp { struct LiveGeneratorContext; + struct LiveGeneratorOutput { + LiveGeneratorOutput() = default; + LiveGeneratorOutput(const LiveGeneratorOutput& rhs) = delete; + LiveGeneratorOutput(LiveGeneratorOutput&& rhs) { *this = std::move(rhs); } + LiveGeneratorOutput& operator=(const LiveGeneratorOutput& rhs) = delete; + LiveGeneratorOutput& operator=(LiveGeneratorOutput&& rhs) { + good = rhs.good; + functions = std::move(rhs.functions); + code = rhs.code; + code_size = rhs.code_size; + + rhs.good = false; + rhs.code = nullptr; + rhs.code_size = 0; + + return *this; + } + ~LiveGeneratorOutput(); + bool good = false; + std::vector functions; + void* code; + size_t code_size; + }; class LiveGenerator final : public Generator { public: - LiveGenerator(sljit_compiler* compiler); + LiveGenerator(size_t num_funcs); ~LiveGenerator(); + LiveGeneratorOutput finish(); void process_binary_op(const BinaryOp& op, const InstructionContext& ctx) const final; void process_unary_op(const UnaryOp& op, const InstructionContext& ctx) const final; void process_store_op(const StoreOp& op, const InstructionContext& ctx) const final; - void emit_function_start(const std::string& function_name) const final; + void emit_function_start(const std::string& function_name, size_t func_index) const final; void emit_function_end() const final; void emit_function_call_lookup(uint32_t addr) const final; void emit_function_call_by_register(int reg) const final; - void emit_function_call_by_name(const std::string& func_name) const final; + void emit_function_call_reference_symbol(const Context& context, uint16_t section_index, size_t symbol_index) const final; + void emit_function_call(const Context& context, size_t function_index) const final; void emit_goto(const std::string& target) const final; void emit_label(const std::string& label_name) const final; void emit_variable_declaration(const std::string& var_name, int reg) const final; @@ -50,7 +76,7 @@ namespace N64Recomp { }; void live_recompiler_init(); - bool recompile_function_live(LiveGenerator& generator, const Context& context, const Function& func, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs); + bool recompile_function_live(LiveGenerator& generator, const Context& context, size_t function_index, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs); } #endif \ No newline at end of file diff --git a/src/cgenerator.cpp b/src/cgenerator.cpp index de7d56a..c5c0ee1 100644 --- a/src/cgenerator.cpp +++ b/src/cgenerator.cpp @@ -362,7 +362,7 @@ void N64Recomp::CGenerator::get_binary_expr_string(BinaryOpType type, const Bina } } -void N64Recomp::CGenerator::emit_function_start(const std::string& function_name) const { +void N64Recomp::CGenerator::emit_function_start(const std::string& function_name, size_t func_index) const { fmt::print(output_file, "RECOMP_FUNC void {}(uint8_t* rdram, recomp_context* ctx) {{\n" // these variables shouldn't need to be preserved across function boundaries, so make them local for more efficient output @@ -384,8 +384,13 @@ void N64Recomp::CGenerator::emit_function_call_by_register(int reg) const { fmt::print(output_file, "LOOKUP_FUNC({})(rdram, ctx);\n", gpr_to_string(reg)); } -void N64Recomp::CGenerator::emit_function_call_by_name(const std::string& func_name) const { - fmt::print(output_file, "{}(rdram, ctx);\n", func_name); +void N64Recomp::CGenerator::emit_function_call_reference_symbol(const Context& context, uint16_t section_index, size_t symbol_index) const { + const N64Recomp::ReferenceSymbol& sym = context.get_reference_symbol(section_index, symbol_index); + fmt::print(output_file, "{}(rdram, ctx);\n", sym.name); +} + +void N64Recomp::CGenerator::emit_function_call(const Context& context, size_t function_index) const { + fmt::print(output_file, "{}(rdram, ctx);\n", context.functions[function_index].name); } void N64Recomp::CGenerator::emit_goto(const std::string& target) const { diff --git a/src/main.cpp b/src/main.cpp index 4e5b27b..8a8fe91 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -111,7 +111,7 @@ bool compare_files(const std::filesystem::path& file1_path, const std::filesyste return std::equal(begin1, std::istreambuf_iterator(), begin2); //Second argument is end-of-range iterator } -bool recompile_single_function(const N64Recomp::Context& context, const N64Recomp::Function& func, const std::string& recomp_include, const std::filesystem::path& output_path, std::span> static_funcs_out) { +bool recompile_single_function(const N64Recomp::Context& context, size_t func_index, const std::string& recomp_include, const std::filesystem::path& output_path, std::span> static_funcs_out) { // Open the temporary output file std::filesystem::path temp_path = output_path; temp_path.replace_extension(".tmp"); @@ -127,7 +127,7 @@ bool recompile_single_function(const N64Recomp::Context& context, const N64Recom "\n", recomp_include); - if (!N64Recomp::recompile_function(context, func, output_file, static_funcs_out, false)) { + if (!N64Recomp::recompile_function(context, func_index, output_file, static_funcs_out, false)) { return false; } @@ -725,7 +725,7 @@ int main(int argc, char** argv) { // Recompile the function. if (config.single_file_output || config.functions_per_output_file > 1) { - result = N64Recomp::recompile_function(context, func, current_output_file, static_funcs_by_section, false); + result = N64Recomp::recompile_function(context, i, current_output_file, static_funcs_by_section, false); if (!config.single_file_output) { cur_file_function_count++; if (cur_file_function_count >= config.functions_per_output_file) { @@ -734,7 +734,7 @@ int main(int argc, char** argv) { } } else { - result = recompile_single_function(context, func, config.recomp_include, config.output_func_path / (func.name + ".c"), static_funcs_by_section); + result = recompile_single_function(context, i, config.recomp_include, config.output_func_path / (func.name + ".c"), static_funcs_by_section); } if (result == false) { fmt::print(stderr, "Error recompiling {}\n", func.name); @@ -797,22 +797,25 @@ int main(int argc, char** argv) { std::vector insn_words((cur_func_end - static_func_addr) / sizeof(uint32_t)); insn_words.assign(func_rom_start, func_rom_start + insn_words.size()); - N64Recomp::Function func { + // Create the new function and add it to the context. + size_t new_func_index = context.functions.size(); + context.functions.emplace_back( static_func_addr, rom_addr, std::move(insn_words), fmt::format("static_{}_{:08X}", section_index, static_func_addr), static_cast(section_index), false - }; + ); + const N64Recomp::Function& new_func = context.functions[new_func_index]; fmt::print(func_header_file, - "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name); + "void {}(uint8_t* rdram, recomp_context* ctx);\n", new_func.name); bool result; - size_t prev_num_statics = static_funcs_by_section[func.section_index].size(); + size_t prev_num_statics = static_funcs_by_section[new_func.section_index].size(); if (config.single_file_output || config.functions_per_output_file > 1) { - result = N64Recomp::recompile_function(context, func, current_output_file, static_funcs_by_section, false); + result = N64Recomp::recompile_function(context, new_func_index, current_output_file, static_funcs_by_section, false); if (!config.single_file_output) { cur_file_function_count++; if (cur_file_function_count >= config.functions_per_output_file) { @@ -821,14 +824,14 @@ int main(int argc, char** argv) { } } else { - result = recompile_single_function(context, func, config.recomp_include, config.output_func_path / (func.name + ".c"), static_funcs_by_section); + result = recompile_single_function(context, new_func_index, config.recomp_include, config.output_func_path / (new_func.name + ".c"), static_funcs_by_section); } // Add any new static functions that were found while recompiling this one. - size_t cur_num_statics = static_funcs_by_section[func.section_index].size(); + size_t cur_num_statics = static_funcs_by_section[new_func.section_index].size(); if (cur_num_statics != prev_num_statics) { for (size_t new_static_index = prev_num_statics; new_static_index < cur_num_statics; new_static_index++) { - uint32_t new_static_vram = static_funcs_by_section[func.section_index][new_static_index]; + uint32_t new_static_vram = static_funcs_by_section[new_func.section_index][new_static_index]; if (!statics_set.contains(new_static_vram)) { statics_set.emplace(new_static_vram); @@ -838,7 +841,7 @@ int main(int argc, char** argv) { } if (result == false) { - fmt::print(stderr, "Error recompiling {}\n", func.name); + fmt::print(stderr, "Error recompiling {}\n", new_func.name); std::exit(EXIT_FAILURE); } } diff --git a/src/operations.cpp b/src/operations.cpp index 718ff0f..ba570e6 100644 --- a/src/operations.cpp +++ b/src/operations.cpp @@ -157,6 +157,8 @@ namespace N64Recomp { { InstrId::cpu_bltzl, { BinaryOpType::Less, {{ UnaryOpType::ToS64, UnaryOpType::None }, { Operand::Rs, Operand::Zero }}, false, true }}, { InstrId::cpu_bgezal, { BinaryOpType::GreaterEq, {{ UnaryOpType::ToS64, UnaryOpType::None }, { Operand::Rs, Operand::Zero }}, true, false }}, { InstrId::cpu_bgezall, { BinaryOpType::GreaterEq, {{ UnaryOpType::ToS64, UnaryOpType::None }, { Operand::Rs, Operand::Zero }}, true, true }}, + { InstrId::cpu_bltzal, { BinaryOpType::Less, {{ UnaryOpType::ToS64, UnaryOpType::None }, { Operand::Rs, Operand::Zero }}, true, false }}, + { InstrId::cpu_bltzall, { BinaryOpType::Less, {{ UnaryOpType::ToS64, UnaryOpType::None }, { Operand::Rs, Operand::Zero }}, true, true }}, { InstrId::cpu_bc1f, { BinaryOpType::Equal, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Cop1cs, Operand::Zero }}, false, false }}, { InstrId::cpu_bc1fl, { BinaryOpType::Equal, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Cop1cs, Operand::Zero }}, false, true }}, { InstrId::cpu_bc1t, { BinaryOpType::NotEqual, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Cop1cs, Operand::Zero }}, false, false }}, diff --git a/src/recompilation.cpp b/src/recompilation.cpp index 114d380..2717545 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -280,6 +280,7 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con // Normal symbol or reference symbol, else { std::string jal_target_name{}; + size_t matched_func_index = (size_t)-1; if (reloc_reference_symbol != (size_t)-1) { const auto& ref_symbol = context.get_reference_symbol(reloc_section, reloc_reference_symbol); @@ -292,11 +293,8 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con fmt::print(stderr, "Function {} uses a MIPS_R_26 addend, which is not supported yet\n", func.name); return false; } - - jal_target_name = ref_symbol.name; } else { - size_t matched_func_index = 0; JalResolutionResult jal_result = resolve_jal(context, func.section_index, target_func_vram, matched_func_index); switch (jal_result) { @@ -331,11 +329,14 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con return false; } print_indent(); - if (call_by_lookup) { + if (reloc_reference_symbol != (size_t)-1) { + generator.emit_function_call_reference_symbol(context, reloc_section, reloc_reference_symbol); + } + else if (call_by_lookup) { generator.emit_function_call_lookup(target_func_vram); } else { - generator.emit_function_call_by_name(jal_target_name); + generator.emit_function_call(context, matched_func_index); } print_link_branch(); } @@ -355,8 +356,8 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con print_indent(); generator.emit_return(); // TODO check if this branch close should exist. - print_indent(); - generator.emit_branch_close(); + // print_indent(); + // generator.emit_branch_close(); return true; } @@ -747,11 +748,12 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con } template -bool recompile_function_impl(GeneratorType& generator, const N64Recomp::Context& context, const N64Recomp::Function& func, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { +bool recompile_function_impl(GeneratorType& generator, const N64Recomp::Context& context, size_t func_index, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { + const N64Recomp::Function& func = context.functions[func_index]; //fmt::print("Recompiling {}\n", func.name); std::vector instructions; - generator.emit_function_start(func.name); + generator.emit_function_start(func.name, func_index); if (context.trace_mode) { fmt::print(output_file, @@ -859,11 +861,11 @@ bool recompile_function_impl(GeneratorType& generator, const N64Recomp::Context& } // Wrap the templated function with CGenerator as the template parameter. -bool N64Recomp::recompile_function(const N64Recomp::Context& context, const N64Recomp::Function& func, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { +bool N64Recomp::recompile_function(const N64Recomp::Context& context, size_t function_index, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { CGenerator generator{output_file}; - return recompile_function_impl(generator, context, func, output_file, static_funcs_out, tag_reference_relocs); + return recompile_function_impl(generator, context, function_index, output_file, static_funcs_out, tag_reference_relocs); } -bool N64Recomp::recompile_function_custom(Generator& generator, const Context& context, const Function& func, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { - return recompile_function_impl(generator, context, func, output_file, static_funcs_out, tag_reference_relocs); +bool N64Recomp::recompile_function_custom(Generator& generator, const Context& context, size_t function_index, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { + return recompile_function_impl(generator, context, function_index, output_file, static_funcs_out, tag_reference_relocs); }