Split Negate operation into NegateFloat and NegateDouble, added support for custom recompiler backends

This commit is contained in:
Mr-Wiseguy 2024-10-02 23:05:39 -04:00
parent c54855b05d
commit 485a9e14c9
6 changed files with 28 additions and 35 deletions

View file

@ -517,8 +517,10 @@ namespace N64Recomp {
}
};
bool recompile_function(const Context& context, const Function& func, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs, bool tag_reference_relocs);
bool recompile_function_luajit(const Context& context, const Function& func, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs, bool tag_reference_relocs);
class Generator;
bool recompile_function(const Context& context, const Function& func, std::ostream& output_file, std::span<std::vector<uint32_t>> static_funcs, bool tag_reference_relocs);
bool recompile_function_luajit(const Context& context, const Function& func, std::ostream& output_file, std::span<std::vector<uint32_t>> static_funcs, bool tag_reference_relocs);
bool recompile_function_custom(Generator& generator, const Context& context, const Function& func, std::ostream& output_file, std::span<std::vector<uint32_t>> static_funcs_out, bool tag_reference_relocs);
enum class ModSymbolsError {
Good,

View file

@ -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,

View file

@ -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:

View file

@ -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:

View file

@ -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 } },

View file

@ -110,7 +110,7 @@ std::string_view ctx_gpr_prefix(int reg) {
}
template <typename GeneratorType>
bool process_instruction(GeneratorType& generator, const N64Recomp::Context& context, const N64Recomp::Function& func, const N64Recomp::FunctionStats& stats, const std::unordered_set<uint32_t>& skipped_insns, size_t instr_index, const std::vector<rabbitizer::InstructionCpu>& 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<std::vector<uint32_t>> static_funcs_out) {
bool process_instruction(GeneratorType& generator, const N64Recomp::Context& context, const N64Recomp::Function& func, const N64Recomp::FunctionStats& stats, const std::unordered_set<uint32_t>& skipped_insns, size_t instr_index, const std::vector<rabbitizer::InstructionCpu>& 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<std::vector<uint32_t>> 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, &section, &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 <typename GeneratorType>
bool recompile_function_impl(GeneratorType& generator, const N64Recomp::Context& context, const N64Recomp::Function& func, std::ofstream& output_file, std::span<std::vector<uint32_t>> 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<std::vector<uint32_t>> static_funcs_out, bool tag_reference_relocs) {
//fmt::print("Recompiling {}\n", func.name);
std::vector<rabbitizer::InstructionCpu> instructions;
@ -859,12 +853,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<std::vector<uint32_t>> 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<std::vector<uint32_t>> 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<std::vector<uint32_t>> 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<std::vector<uint32_t>> 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<std::vector<uint32_t>> static_funcs_out, bool tag_reference_relocs) {
return recompile_function_impl(generator, context, func, output_file, static_funcs_out, tag_reference_relocs);
}