mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2025-05-14 08:12:19 +00:00
Initial implementation of unary operation table
This commit is contained in:
parent
347a792f80
commit
81f95a42e4
1 changed files with 52 additions and 31 deletions
|
@ -31,6 +31,7 @@ enum class UnaryOpType {
|
|||
Lui,
|
||||
Mask5, // Mask to 5 bits
|
||||
Mask6, // Mask to 5 bits
|
||||
ToInt32, // Functionally equivalent to ToS32, only exists for parity with old codegen
|
||||
};
|
||||
|
||||
enum class BinaryOpType {
|
||||
|
@ -78,6 +79,8 @@ enum class Operand {
|
|||
ImmS16, // 16-bit immediate, signed
|
||||
Sa, // Shift amount
|
||||
Sa32, // Shift amount plus 32
|
||||
Hi,
|
||||
Lo,
|
||||
|
||||
Base = Rs, // Alias for Rs for loads
|
||||
};
|
||||
|
@ -101,6 +104,10 @@ struct BinaryOp {
|
|||
|
||||
const std::unordered_map<InstrId, UnaryOp> unary_ops {
|
||||
{ InstrId::cpu_lui, { UnaryOpType::Lui, Operand::Rt, Operand::ImmU16 } },
|
||||
{ InstrId::cpu_mthi, { UnaryOpType::None, Operand::Hi, Operand::Rs } },
|
||||
{ InstrId::cpu_mtlo, { UnaryOpType::None, Operand::Lo, Operand::Rs } },
|
||||
{ InstrId::cpu_mfhi, { UnaryOpType::None, Operand::Rd, Operand::Hi } },
|
||||
{ InstrId::cpu_mflo, { UnaryOpType::None, Operand::Rd, Operand::Lo } },
|
||||
};
|
||||
|
||||
const std::unordered_map<InstrId, BinaryOp> binary_ops {
|
||||
|
@ -188,6 +195,7 @@ class CGenerator {
|
|||
public:
|
||||
CGenerator() = default;
|
||||
void process_binary_op(std::ostream& output_file, const BinaryOp& op, const InstructionContext& ctx);
|
||||
void process_unary_op(std::ostream& output_file, const UnaryOp& op, const InstructionContext& ctx);
|
||||
private:
|
||||
void get_operand_string(Operand operand, UnaryOpType operation, const InstructionContext& context, std::string& operand_string);
|
||||
void get_notation(BinaryOpType op_type, std::string& func_string, std::string& infix_string);
|
||||
|
@ -283,6 +291,12 @@ void CGenerator::get_operand_string(Operand operand, UnaryOpType operation, cons
|
|||
case Operand::Sa32:
|
||||
operand_string = fmt::format("({} + 32)", context.sa);
|
||||
break;
|
||||
case Operand::Hi:
|
||||
operand_string = "hi";
|
||||
break;
|
||||
case Operand::Lo:
|
||||
operand_string = "lo";
|
||||
break;
|
||||
}
|
||||
switch (operation) {
|
||||
case UnaryOpType::None:
|
||||
|
@ -306,8 +320,7 @@ void CGenerator::get_operand_string(Operand operand, UnaryOpType operation, cons
|
|||
assert(false);
|
||||
break;
|
||||
case UnaryOpType::Lui:
|
||||
assert(false);
|
||||
// operand_string = "S32(" + operand_string + ")";
|
||||
operand_string = "S32(" + operand_string + " << 16)";
|
||||
break;
|
||||
case UnaryOpType::Mask5:
|
||||
operand_string = "(" + operand_string + " & 31)";
|
||||
|
@ -315,6 +328,9 @@ void CGenerator::get_operand_string(Operand operand, UnaryOpType operation, cons
|
|||
case UnaryOpType::Mask6:
|
||||
operand_string = "(" + operand_string + " & 63)";
|
||||
break;
|
||||
case UnaryOpType::ToInt32:
|
||||
operand_string = "(int32_t)" + operand_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,6 +374,17 @@ void CGenerator::process_binary_op(std::ostream& output_file, const BinaryOp& op
|
|||
}
|
||||
}
|
||||
|
||||
void CGenerator::process_unary_op(std::ostream& output_file, const UnaryOp& op, const InstructionContext& ctx) {
|
||||
// Thread local variables to prevent allocations when possible.
|
||||
// TODO these thread locals probably don't actually help right now, so figure out a better way to prevent allocations.
|
||||
thread_local std::string output{};
|
||||
thread_local std::string input{};
|
||||
bool is_infix;
|
||||
get_operand_string(op.output, UnaryOpType::None, ctx, output);
|
||||
get_operand_string(op.input, op.operation, ctx, input);
|
||||
fmt::print(output_file, "{} = {};\n", output, input);
|
||||
}
|
||||
|
||||
// Major TODO, this function grew very organically and needs to be cleaned up. Ideally, it'll get split up into some sort of lookup table grouped by similar instruction types.
|
||||
bool process_instruction(const RecompPort::Context& context, const RecompPort::Config& config, const RecompPort::Function& func, const RecompPort::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, std::span<std::vector<uint32_t>> static_funcs_out) {
|
||||
const auto& section = context.sections[func.section_index];
|
||||
|
@ -694,9 +721,6 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
|||
break;
|
||||
}
|
||||
// Arithmetic
|
||||
case InstrId::cpu_lui:
|
||||
print_line("{}{} = S32({} << 16)", ctx_gpr_prefix(rt), rt, unsigned_imm_string);
|
||||
break;
|
||||
case InstrId::cpu_add:
|
||||
case InstrId::cpu_addu:
|
||||
{
|
||||
|
@ -737,18 +761,6 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
|||
case InstrId::cpu_ddivu:
|
||||
print_line("DDIVU(U64({}{}), U64({}{}), &lo, &hi)", ctx_gpr_prefix(rs), rs, ctx_gpr_prefix(rt), rt);
|
||||
break;
|
||||
case InstrId::cpu_mflo:
|
||||
print_line("{}{} = lo", ctx_gpr_prefix(rd), rd);
|
||||
break;
|
||||
case InstrId::cpu_mfhi:
|
||||
print_line("{}{} = hi", ctx_gpr_prefix(rd), rd);
|
||||
break;
|
||||
case InstrId::cpu_mtlo:
|
||||
print_line("lo = {}{}", ctx_gpr_prefix(rs), rs);
|
||||
break;
|
||||
case InstrId::cpu_mthi:
|
||||
print_line("hi = {}{}", ctx_gpr_prefix(rs), rs);
|
||||
break;
|
||||
// Stores
|
||||
case InstrId::cpu_sd:
|
||||
print_line("SD({}{}, {}, {}{})", ctx_gpr_prefix(rt), rt, signed_imm_string, ctx_gpr_prefix(base), base);
|
||||
|
@ -1367,9 +1379,6 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
|||
break;
|
||||
}
|
||||
|
||||
auto find_it = binary_ops.find(instr.getUniqueId());
|
||||
if (find_it != binary_ops.end()) {
|
||||
CGenerator generator{};
|
||||
InstructionContext instruction_context{};
|
||||
instruction_context.rd = rd;
|
||||
instruction_context.rs = rs;
|
||||
|
@ -1380,8 +1389,20 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
|||
instruction_context.ft = ft;
|
||||
instruction_context.cop1_cs = cop1_cs;
|
||||
instruction_context.imm16 = imm;
|
||||
|
||||
auto find_binary_it = binary_ops.find(instr.getUniqueId());
|
||||
if (find_binary_it != binary_ops.end()) {
|
||||
CGenerator generator{};
|
||||
print_indent();
|
||||
generator.process_binary_op(output_file, find_it->second, instruction_context);
|
||||
generator.process_binary_op(output_file, find_binary_it->second, instruction_context);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
auto find_unary_it = unary_ops.find(instr.getUniqueId());
|
||||
if (find_unary_it != unary_ops.end()) {
|
||||
CGenerator generator{};
|
||||
print_indent();
|
||||
generator.process_unary_op(output_file, find_unary_it->second, instruction_context);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue