From c7543aa99b8220581966b48d57084c5f320d85f6 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Wed, 2 Oct 2024 23:05:39 -0400 Subject: [PATCH] Split Negate operation into NegateFloat and NegateDouble, added support for custom recompiler backends --- include/n64recomp.h | 6 ++++-- include/operations.h | 5 ++--- src/cgenerator.cpp | 11 ++++------- src/luajitgenerator.cpp | 11 ++++------- src/operations.cpp | 4 ++-- src/recompilation.cpp | 26 ++++++++++++-------------- 6 files changed, 28 insertions(+), 35 deletions(-) diff --git a/include/n64recomp.h b/include/n64recomp.h index b197910..5b7b245 100644 --- a/include/n64recomp.h +++ b/include/n64recomp.h @@ -520,8 +520,10 @@ namespace N64Recomp { } }; - bool recompile_function(const Context& context, const Function& func, std::ofstream& output_file, std::span> static_funcs, bool tag_reference_relocs); - bool recompile_function_luajit(const Context& context, const Function& func, std::ofstream& output_file, std::span> static_funcs, bool tag_reference_relocs); + 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_luajit(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); enum class ModSymbolsError { Good, diff --git a/include/operations.h b/include/operations.h index 5cb407e..abca35b 100644 --- a/include/operations.h +++ b/include/operations.h @@ -28,13 +28,12 @@ namespace N64Recomp { ToU32, ToS64, ToU64, - NegateS32, - NegateS64, Lui, Mask5, // Mask to 5 bits Mask6, // Mask to 5 bits ToInt32, // Functionally equivalent to ToS32, only exists for parity with old codegen - Negate, + NegateFloat, + NegateDouble, AbsFloat, AbsDouble, SqrtFloat, diff --git a/src/cgenerator.cpp b/src/cgenerator.cpp index f919049..e1c2f15 100644 --- a/src/cgenerator.cpp +++ b/src/cgenerator.cpp @@ -223,12 +223,6 @@ void N64Recomp::CGenerator::get_operand_string(Operand operand, UnaryOpType oper case UnaryOpType::ToU64: // Nothing to do here, they're already U64 break; - case UnaryOpType::NegateS32: - assert(false); - break; - case UnaryOpType::NegateS64: - assert(false); - break; case UnaryOpType::Lui: operand_string = "S32(" + operand_string + " << 16)"; break; @@ -241,7 +235,10 @@ void N64Recomp::CGenerator::get_operand_string(Operand operand, UnaryOpType oper case UnaryOpType::ToInt32: operand_string = "(int32_t)" + operand_string; break; - case UnaryOpType::Negate: + case UnaryOpType::NegateFloat: + operand_string = "-" + operand_string; + break; + case UnaryOpType::NegateDouble: operand_string = "-" + operand_string; break; case UnaryOpType::AbsFloat: diff --git a/src/luajitgenerator.cpp b/src/luajitgenerator.cpp index 021eb28..00821d8 100644 --- a/src/luajitgenerator.cpp +++ b/src/luajitgenerator.cpp @@ -224,12 +224,6 @@ void N64Recomp::LuajitGenerator::get_operand_string(Operand operand, UnaryOpType case UnaryOpType::ToU64: // Nothing to do here, they're already U64 break; - case UnaryOpType::NegateS32: - assert(false); - break; - case UnaryOpType::NegateS64: - assert(false); - break; case UnaryOpType::Lui: operand_string = "S32(bit.lshift(" + operand_string + "), 16ULL)"; break; @@ -239,7 +233,10 @@ void N64Recomp::LuajitGenerator::get_operand_string(Operand operand, UnaryOpType case UnaryOpType::Mask6: operand_string = "(bit.band(" + operand_string + "), 63ULL)"; break; - case UnaryOpType::Negate: + case UnaryOpType::NegateFloat: + operand_string = "-" + operand_string; + break; + case UnaryOpType::NegateDouble: operand_string = "-" + operand_string; break; case UnaryOpType::AbsFloat: diff --git a/src/operations.cpp b/src/operations.cpp index e3b372c..40526c2 100644 --- a/src/operations.cpp +++ b/src/operations.cpp @@ -12,8 +12,8 @@ namespace N64Recomp { // Float operations { InstrId::cpu_mov_s, { UnaryOpType::None, Operand::Fd, Operand::Fs, true } }, { InstrId::cpu_mov_d, { UnaryOpType::None, Operand::FdDouble, Operand::FsDouble, true } }, - { InstrId::cpu_neg_s, { UnaryOpType::Negate, Operand::Fd, Operand::Fs, true, true } }, - { InstrId::cpu_neg_d, { UnaryOpType::Negate, Operand::FdDouble, Operand::FsDouble, true, true } }, + { InstrId::cpu_neg_s, { UnaryOpType::NegateFloat, Operand::Fd, Operand::Fs, true, true } }, + { InstrId::cpu_neg_d, { UnaryOpType::NegateDouble, Operand::FdDouble, Operand::FsDouble, true, true } }, { InstrId::cpu_abs_s, { UnaryOpType::AbsFloat, Operand::Fd, Operand::Fs, true, true } }, { InstrId::cpu_abs_d, { UnaryOpType::AbsDouble, Operand::FdDouble, Operand::FsDouble, true, true } }, { InstrId::cpu_sqrt_s, { UnaryOpType::SqrtFloat, Operand::Fd, Operand::Fs, true, true } }, diff --git a/src/recompilation.cpp b/src/recompilation.cpp index 7b2383c..b2a19b0 100644 --- a/src/recompilation.cpp +++ b/src/recompilation.cpp @@ -110,7 +110,7 @@ std::string_view ctx_gpr_prefix(int reg) { } template -bool process_instruction(GeneratorType& generator, const N64Recomp::Context& context, const N64Recomp::Function& func, const N64Recomp::FunctionStats& stats, const std::unordered_set& skipped_insns, size_t instr_index, const std::vector& instructions, std::ofstream& output_file, bool indent, bool emit_link_branch, int link_branch_index, size_t reloc_index, bool& needs_link_branch, bool& is_branch_likely, bool tag_reference_relocs, std::span> static_funcs_out) { +bool process_instruction(GeneratorType& generator, const N64Recomp::Context& context, const N64Recomp::Function& func, const N64Recomp::FunctionStats& stats, const std::unordered_set& skipped_insns, size_t instr_index, const std::vector& instructions, std::ostream& output_file, bool indent, bool emit_link_branch, int link_branch_index, size_t reloc_index, bool& needs_link_branch, bool& is_branch_likely, bool tag_reference_relocs, std::span> static_funcs_out) { using namespace N64Recomp; const auto& section = context.sections[func.section_index]; @@ -260,16 +260,6 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con return true; }; - auto print_func_call_lookup = [&](uint32_t target_vram) { - if (!process_delay_slot(false)) { - return false; - } - print_indent(); - generator.emit_function_call_lookup(target_vram); - print_link_branch(); - return true; - }; - auto print_func_call_by_address = [&generator, reloc_target_section_offset, reloc_section, reloc_reference_symbol, reloc_type, &context, §ion, &func, &static_funcs_out, &needs_link_branch, &print_indent, &process_delay_slot, &output_file, &print_link_branch] (uint32_t target_func_vram, bool tail_call = false, bool indent = false) { @@ -364,6 +354,7 @@ 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(); return true; @@ -379,6 +370,7 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con print_indent(); print_indent(); generator.emit_goto(fmt::format("L_{:08X}", branch_target)); + // TODO check if this link branch ever exists. if (needs_link_branch) { print_indent(); print_indent(); @@ -704,6 +696,8 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con auto find_conditional_branch_it = conditional_branch_ops.find(instr.getUniqueId()); if (find_conditional_branch_it != conditional_branch_ops.end()) { print_indent(); + // TODO combining the branch condition and branch target into one generator call would allow better optimization in the runtime's JIT generator. + // This would require splitting into a conditional jump method and conditional function call method. generator.emit_branch_condition(find_conditional_branch_it->second, instruction_context); print_indent(); @@ -753,7 +747,7 @@ 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::ofstream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { +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) { //fmt::print("Recompiling {}\n", func.name); std::vector instructions; @@ -865,12 +859,16 @@ 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::ofstream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { +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) { CGenerator generator{output_file}; return recompile_function_impl(generator, context, func, output_file, static_funcs_out, tag_reference_relocs); } -bool N64Recomp::recompile_function_luajit(const N64Recomp::Context& context, const N64Recomp::Function& func, std::ofstream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { +bool N64Recomp::recompile_function_luajit(const N64Recomp::Context& context, const N64Recomp::Function& func, std::ostream& output_file, std::span> static_funcs_out, bool tag_reference_relocs) { LuajitGenerator generator{output_file}; 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, 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); +}