mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2025-05-14 08:12:19 +00:00
Added CHECK_FR generation to binary operation processing, moved float comparison instructions to binary op table
This commit is contained in:
parent
d91f1cf3a8
commit
43598c65d9
1 changed files with 86 additions and 126 deletions
|
@ -131,6 +131,8 @@ struct BinaryOp {
|
||||||
Operand output;
|
Operand output;
|
||||||
// The input operands.
|
// The input operands.
|
||||||
BinaryOperands operands;
|
BinaryOperands operands;
|
||||||
|
// Whether the FR bit needs to be checked for odd float registers for this instruction.
|
||||||
|
bool check_fr = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConditionalBranchOp {
|
struct ConditionalBranchOp {
|
||||||
|
@ -206,6 +208,34 @@ const std::unordered_map<InstrId, BinaryOp> binary_ops {
|
||||||
// Comparisons (immediate)
|
// Comparisons (immediate)
|
||||||
{ InstrId::cpu_slti, { BinaryOpType::Less, Operand::Rt, {{ UnaryOpType::ToS64, UnaryOpType::None }, { Operand::Rs, Operand::ImmS16 }}} },
|
{ InstrId::cpu_slti, { BinaryOpType::Less, Operand::Rt, {{ UnaryOpType::ToS64, UnaryOpType::None }, { Operand::Rs, Operand::ImmS16 }}} },
|
||||||
{ InstrId::cpu_sltiu, { BinaryOpType::Less, Operand::Rt, {{ UnaryOpType::ToU64, UnaryOpType::None }, { Operand::Rs, Operand::ImmS16 }}} },
|
{ InstrId::cpu_sltiu, { BinaryOpType::Less, Operand::Rt, {{ UnaryOpType::ToU64, UnaryOpType::None }, { Operand::Rs, Operand::ImmS16 }}} },
|
||||||
|
// Float comparisons TODO remaining operations and investigate ordered/unordered and default values
|
||||||
|
{ InstrId::cpu_c_lt_s, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_nge_s, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_olt_s, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_ult_s, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_lt_d, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_nge_d, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_olt_d, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_ult_d, { BinaryOpType::Less, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
|
||||||
|
{ InstrId::cpu_c_le_s, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_ngt_s, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_ole_s, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_ule_s, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_le_d, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_ngt_d, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_ole_d, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_ule_d, { BinaryOpType::LessEq, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
|
||||||
|
{ InstrId::cpu_c_eq_s, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_ueq_s, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_ngl_s, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_seq_s, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::Fs, Operand::Ft }}, true } },
|
||||||
|
{ InstrId::cpu_c_eq_d, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_ueq_d, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
{ InstrId::cpu_c_ngl_d, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
|
/* TODO rename to c_seq_d when fixed in rabbitizer */
|
||||||
|
{ InstrId::cpu_c_deq_d, { BinaryOpType::Equal, Operand::Cop1cs, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::FsDouble, Operand::FtDouble }}, true } },
|
||||||
// Loads
|
// Loads
|
||||||
{ InstrId::cpu_ld, { BinaryOpType::LD, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
{ InstrId::cpu_ld, { BinaryOpType::LD, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
||||||
{ InstrId::cpu_lw, { BinaryOpType::LW, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
{ InstrId::cpu_lw, { BinaryOpType::LW, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
||||||
|
@ -219,7 +249,7 @@ const std::unordered_map<InstrId, BinaryOp> binary_ops {
|
||||||
{ InstrId::cpu_lwl, { BinaryOpType::LWL, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
{ InstrId::cpu_lwl, { BinaryOpType::LWL, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
||||||
{ InstrId::cpu_lwr, { BinaryOpType::LWR, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
{ InstrId::cpu_lwr, { BinaryOpType::LWR, Operand::Rt, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
||||||
{ InstrId::cpu_lwc1, { BinaryOpType::LW, Operand::FtU32L, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
{ InstrId::cpu_lwc1, { BinaryOpType::LW, Operand::FtU32L, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
||||||
{ InstrId::cpu_ldc1, { BinaryOpType::LD, Operand::FtU64, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}} },
|
{ InstrId::cpu_ldc1, { BinaryOpType::LD, Operand::FtU64, {{ UnaryOpType::None, UnaryOpType::None }, { Operand::ImmS16, Operand::Base }}, true } },
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::unordered_map<InstrId, ConditionalBranchOp> conditional_branch_ops {
|
const std::unordered_map<InstrId, ConditionalBranchOp> conditional_branch_ops {
|
||||||
|
@ -265,14 +295,15 @@ struct InstructionContext {
|
||||||
class CGenerator {
|
class CGenerator {
|
||||||
public:
|
public:
|
||||||
CGenerator() = default;
|
CGenerator() = default;
|
||||||
void process_binary_op(std::ostream& output_file, const BinaryOp& op, const InstructionContext& ctx);
|
void process_binary_op(std::ostream& output_file, const BinaryOp& op, const InstructionContext& ctx) const;
|
||||||
void process_unary_op(std::ostream& output_file, const UnaryOp& op, const InstructionContext& ctx);
|
void process_unary_op(std::ostream& output_file, const UnaryOp& op, const InstructionContext& ctx) const;
|
||||||
void emit_branch_condition(std::ostream& output_file, const ConditionalBranchOp& op, const InstructionContext& ctx);
|
void emit_branch_condition(std::ostream& output_file, const ConditionalBranchOp& op, const InstructionContext& ctx) const;
|
||||||
void emit_branch_close(std::ostream& output_file);
|
void emit_branch_close(std::ostream& output_file) const;
|
||||||
|
void emit_check_fr(std::ostream& output_file, int fpr) const;
|
||||||
private:
|
private:
|
||||||
void get_operand_string(Operand operand, UnaryOpType operation, const InstructionContext& context, std::string& operand_string);
|
void get_operand_string(Operand operand, UnaryOpType operation, const InstructionContext& context, std::string& operand_string) const;
|
||||||
void get_binary_expr_string(BinaryOpType type, const BinaryOperands& operands, const InstructionContext& ctx, const std::string& output, std::string& expr_string);
|
void get_binary_expr_string(BinaryOpType type, const BinaryOperands& operands, const InstructionContext& ctx, const std::string& output, std::string& expr_string) const;
|
||||||
void get_notation(BinaryOpType op_type, std::string& func_string, std::string& infix_string);
|
void get_notation(BinaryOpType op_type, std::string& func_string, std::string& infix_string) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BinaryOpFields { std::string func_string; std::string infix_string; };
|
struct BinaryOpFields { std::string func_string; std::string infix_string; };
|
||||||
|
@ -376,7 +407,7 @@ std::string signed_reloc(const InstructionContext& context) {
|
||||||
return "(int16_t)" + unsigned_reloc(context);
|
return "(int16_t)" + unsigned_reloc(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGenerator::get_operand_string(Operand operand, UnaryOpType operation, const InstructionContext& context, std::string& operand_string) {
|
void CGenerator::get_operand_string(Operand operand, UnaryOpType operation, const InstructionContext& context, std::string& operand_string) const {
|
||||||
switch (operand) {
|
switch (operand) {
|
||||||
case Operand::Rd:
|
case Operand::Rd:
|
||||||
operand_string = gpr_to_string(context.rd);
|
operand_string = gpr_to_string(context.rd);
|
||||||
|
@ -503,12 +534,12 @@ void CGenerator::get_operand_string(Operand operand, UnaryOpType operation, cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGenerator::get_notation(BinaryOpType op_type, std::string& func_string, std::string& infix_string) {
|
void CGenerator::get_notation(BinaryOpType op_type, std::string& func_string, std::string& infix_string) const {
|
||||||
func_string = c_op_fields[static_cast<size_t>(op_type)].func_string;
|
func_string = c_op_fields[static_cast<size_t>(op_type)].func_string;
|
||||||
infix_string = c_op_fields[static_cast<size_t>(op_type)].infix_string;
|
infix_string = c_op_fields[static_cast<size_t>(op_type)].infix_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGenerator::get_binary_expr_string(BinaryOpType type, const BinaryOperands& operands, const InstructionContext& ctx, const std::string& output, std::string& expr_string) {
|
void CGenerator::get_binary_expr_string(BinaryOpType type, const BinaryOperands& operands, const InstructionContext& ctx, const std::string& output, std::string& expr_string) const {
|
||||||
thread_local std::string input_a{};
|
thread_local std::string input_a{};
|
||||||
thread_local std::string input_b{};
|
thread_local std::string input_b{};
|
||||||
thread_local std::string func_string{};
|
thread_local std::string func_string{};
|
||||||
|
@ -519,7 +550,7 @@ void CGenerator::get_binary_expr_string(BinaryOpType type, const BinaryOperands&
|
||||||
get_notation(type, func_string, infix_string);
|
get_notation(type, func_string, infix_string);
|
||||||
|
|
||||||
// These cases aren't strictly necessary and are just here for parity with the old recompiler output.
|
// These cases aren't strictly necessary and are just here for parity with the old recompiler output.
|
||||||
if (type == BinaryOpType::Less && !(operands.operands[1] == Operand::Zero && operands.operand_operations[1] == UnaryOpType::None)) {
|
if (type == BinaryOpType::Less && !((operands.operands[1] == Operand::Zero && operands.operand_operations[1] == UnaryOpType::None) || (operands.operands[0] == Operand::Fs || operands.operands[0] == Operand::FsDouble))) {
|
||||||
expr_string = fmt::format("{} {} {} ? 1 : 0", input_a, infix_string, input_b);
|
expr_string = fmt::format("{} {} {} ? 1 : 0", input_a, infix_string, input_b);
|
||||||
}
|
}
|
||||||
else if (type == BinaryOpType::Equal && operands.operands[1] == Operand::Zero && operands.operand_operations[1] == UnaryOpType::None) {
|
else if (type == BinaryOpType::Equal && operands.operands[1] == Operand::Zero && operands.operand_operations[1] == UnaryOpType::None) {
|
||||||
|
@ -555,7 +586,7 @@ void CGenerator::get_binary_expr_string(BinaryOpType type, const BinaryOperands&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGenerator::emit_branch_condition(std::ostream& output_file, const ConditionalBranchOp& op, const InstructionContext& ctx) {
|
void CGenerator::emit_branch_condition(std::ostream& output_file, const ConditionalBranchOp& op, const InstructionContext& ctx) const {
|
||||||
// Thread local variables to prevent allocations when possible.
|
// 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.
|
// TODO these thread locals probably don't actually help right now, so figure out a better way to prevent allocations.
|
||||||
thread_local std::string expr_string{};
|
thread_local std::string expr_string{};
|
||||||
|
@ -563,27 +594,25 @@ void CGenerator::emit_branch_condition(std::ostream& output_file, const Conditio
|
||||||
fmt::print(output_file, "if ({}) {{\n", expr_string);
|
fmt::print(output_file, "if ({}) {{\n", expr_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGenerator::emit_branch_close(std::ostream& output_file) {
|
void CGenerator::emit_branch_close(std::ostream& output_file) const {
|
||||||
fmt::print(output_file, " }}\n");
|
fmt::print(output_file, " }}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGenerator::process_binary_op(std::ostream& output_file, const BinaryOp& op, const InstructionContext& ctx) {
|
void CGenerator::emit_check_fr(std::ostream& output_file, int fpr) const {
|
||||||
|
fmt::print(output_file, "CHECK_FR(ctx, {});\n ", fpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGenerator::process_binary_op(std::ostream& output_file, const BinaryOp& op, const InstructionContext& ctx) const {
|
||||||
// Thread local variables to prevent allocations when possible.
|
// 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.
|
// 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 output{};
|
||||||
thread_local std::string expression{};
|
thread_local std::string expression{};
|
||||||
get_operand_string(op.output, UnaryOpType::None, ctx, output);
|
get_operand_string(op.output, UnaryOpType::None, ctx, output);
|
||||||
get_binary_expr_string(op.type, op.operands, ctx, output, expression);
|
get_binary_expr_string(op.type, op.operands, ctx, output, expression);
|
||||||
|
|
||||||
// TODO remove this after the refactor is done, temporary hack to match the old recompiler output.
|
|
||||||
if (op.type == BinaryOpType::LD && op.output == Operand::FtU64) {
|
|
||||||
fmt::print(output_file, "CHECK_FR(ctx, {});\n ", ctx.ft);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print(output_file, "{} = {};\n", output, expression);
|
fmt::print(output_file, "{} = {};\n", output, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGenerator::process_unary_op(std::ostream& output_file, const UnaryOp& op, const InstructionContext& ctx) {
|
void CGenerator::process_unary_op(std::ostream& output_file, const UnaryOp& op, const InstructionContext& ctx) const {
|
||||||
// Thread local variables to prevent allocations when possible.
|
// 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.
|
// 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 output{};
|
||||||
|
@ -1148,109 +1177,6 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
print_line("SD(ctx->f{}.u64, {}, {}{})", ft, signed_imm_string, ctx_gpr_prefix(base), base);
|
print_line("SD(ctx->f{}.u64, {}, {}{})", ft, signed_imm_string, ctx_gpr_prefix(base), base);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Cop1 compares
|
|
||||||
// TODO allow NaN in ordered and unordered float comparisons, default to a compare result of 1 for ordered and 0 for unordered if a NaN is present
|
|
||||||
case InstrId::cpu_c_lt_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl < ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_olt_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl < ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ult_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl < ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_lt_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d < ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_olt_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d < ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ult_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d < ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_le_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ole_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ule_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_le_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d <= ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ole_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d <= ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ule_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d <= ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_eq_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl == ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ueq_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl == ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ngl_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl == ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_seq_s:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.fl == ctx->f{}.fl", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_eq_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d == ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ueq_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d == ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_ngl_d:
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d == ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
case InstrId::cpu_c_deq_d: // TODO rename to c_seq_d when fixed in rabbitizer
|
|
||||||
print_line("CHECK_FR(ctx, {})", fs);
|
|
||||||
print_line("CHECK_FR(ctx, {})", ft);
|
|
||||||
print_line("c1cs = ctx->f{}.d == ctx->f{}.d", fs, ft);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Cop1 arithmetic
|
// Cop1 arithmetic
|
||||||
case InstrId::cpu_mov_s:
|
case InstrId::cpu_mov_s:
|
||||||
print_line("CHECK_FR(ctx, {})", fd);
|
print_line("CHECK_FR(ctx, {})", fd);
|
||||||
|
@ -1491,11 +1417,45 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C
|
||||||
instruction_context.reloc_type = reloc_type;
|
instruction_context.reloc_type = reloc_type;
|
||||||
instruction_context.reloc_section_index = func.section_index; // TODO allow relocs to other sections?
|
instruction_context.reloc_section_index = func.section_index; // TODO allow relocs to other sections?
|
||||||
instruction_context.reloc_target_section_offset = reloc_target_section_offset;
|
instruction_context.reloc_target_section_offset = reloc_target_section_offset;
|
||||||
|
|
||||||
|
auto do_check_fr = [](std::ostream& output_file, const CGenerator& generator, const InstructionContext& ctx, Operand operand) {
|
||||||
|
switch (operand) {
|
||||||
|
case Operand::Fd:
|
||||||
|
case Operand::FdDouble:
|
||||||
|
case Operand::FdU32L:
|
||||||
|
case Operand::FdU32H:
|
||||||
|
case Operand::FdU64:
|
||||||
|
generator.emit_check_fr(output_file, ctx.fd);
|
||||||
|
break;
|
||||||
|
case Operand::Fs:
|
||||||
|
case Operand::FsDouble:
|
||||||
|
case Operand::FsU32L:
|
||||||
|
case Operand::FsU32H:
|
||||||
|
case Operand::FsU64:
|
||||||
|
generator.emit_check_fr(output_file, ctx.fs);
|
||||||
|
break;
|
||||||
|
case Operand::Ft:
|
||||||
|
case Operand::FtDouble:
|
||||||
|
case Operand::FtU32L:
|
||||||
|
case Operand::FtU32H:
|
||||||
|
case Operand::FtU64:
|
||||||
|
generator.emit_check_fr(output_file, ctx.ft);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auto find_binary_it = binary_ops.find(instr.getUniqueId());
|
auto find_binary_it = binary_ops.find(instr.getUniqueId());
|
||||||
if (find_binary_it != binary_ops.end()) {
|
if (find_binary_it != binary_ops.end()) {
|
||||||
print_indent();
|
print_indent();
|
||||||
generator.process_binary_op(output_file, find_binary_it->second, instruction_context);
|
const BinaryOp& op = find_binary_it->second;
|
||||||
|
|
||||||
|
if (op.check_fr) {
|
||||||
|
do_check_fr(output_file, generator, instruction_context, op.operands.operands[0]);
|
||||||
|
do_check_fr(output_file, generator, instruction_context, op.operands.operands[1]);
|
||||||
|
do_check_fr(output_file, generator, instruction_context, op.output);
|
||||||
|
}
|
||||||
|
|
||||||
|
generator.process_binary_op(output_file, op, instruction_context);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue