mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-04-27 12:32:00 +00:00
Implement remaining odd float operations in live recompiler (#149)
This commit is contained in:
parent
6e7a5bdb2f
commit
7b8b3c1920
1 changed files with 69 additions and 23 deletions
|
|
@ -238,15 +238,27 @@ constexpr int get_fpr_double_context_offset(int fpr_index) {
|
||||||
return offsetof(recomp_context, f0.d) + sizeof(recomp_context::f0) * fpr_index;
|
return offsetof(recomp_context, f0.d) + sizeof(recomp_context::f0) * fpr_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int get_fpr_u32l_context_offset(int fpr_index) {
|
constexpr bool is_fpr_u32l(N64Recomp::Operand operand) {
|
||||||
|
return
|
||||||
|
operand == N64Recomp::Operand::FdU32L ||
|
||||||
|
operand == N64Recomp::Operand::FsU32L ||
|
||||||
|
operand == N64Recomp::Operand::FtU32L;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void get_fpr_u32l_context_offset(int fpr_index, sljit_compiler* compiler, int odd_float_address_register, sljit_sw& out, sljit_sw& outw) {
|
||||||
if (fpr_index & 1) {
|
if (fpr_index & 1) {
|
||||||
// TODO implement odd floats.
|
assert(compiler != nullptr);
|
||||||
assert(false);
|
// Load ctx->f_odd into the address register.
|
||||||
return -1;
|
sljit_emit_op1(compiler, SLJIT_MOV_P, odd_float_address_register, 0, SLJIT_MEM1(Registers::ctx), offsetof(recomp_context, f_odd));
|
||||||
// return fmt::format("ctx->f_odd[({} - 1) * 2]", fpr_index);
|
// sljit_emit_op0(compiler, SLJIT_BREAKPOINT);
|
||||||
|
out = SLJIT_MEM1(odd_float_address_register);
|
||||||
|
// Set a memory offset of ((fpr_index - 1) * 2) * sizeof(*f_odd).
|
||||||
|
outw = ((fpr_index - 1) * 2) * sizeof(*recomp_context::f_odd);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return offsetof(recomp_context, f0.u32l) + sizeof(recomp_context::f0) * fpr_index;
|
out = SLJIT_MEM1(Registers::ctx);
|
||||||
|
outw = offsetof(recomp_context, f0.u32l) + sizeof(recomp_context::f0) * fpr_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,7 +277,10 @@ void get_gpr_values(int gpr, sljit_sw& out, sljit_sw& outw) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_operand_values(N64Recomp::Operand operand, const N64Recomp::InstructionContext& context, sljit_sw& out, sljit_sw& outw) {
|
bool get_operand_values(N64Recomp::Operand operand, const N64Recomp::InstructionContext& context, sljit_sw& out, sljit_sw& outw,
|
||||||
|
sljit_compiler* compiler, int odd_float_address_register
|
||||||
|
)
|
||||||
|
{
|
||||||
using namespace N64Recomp;
|
using namespace N64Recomp;
|
||||||
|
|
||||||
switch (operand) {
|
switch (operand) {
|
||||||
|
|
@ -303,16 +318,13 @@ bool get_operand_values(N64Recomp::Operand operand, const N64Recomp::Instruction
|
||||||
outw = get_fpr_double_context_offset(context.ft);
|
outw = get_fpr_double_context_offset(context.ft);
|
||||||
break;
|
break;
|
||||||
case Operand::FdU32L:
|
case Operand::FdU32L:
|
||||||
out = SLJIT_MEM1(Registers::ctx);
|
get_fpr_u32l_context_offset(context.fd, compiler, odd_float_address_register, out, outw);
|
||||||
outw = get_fpr_u32l_context_offset(context.fd);
|
|
||||||
break;
|
break;
|
||||||
case Operand::FsU32L:
|
case Operand::FsU32L:
|
||||||
out = SLJIT_MEM1(Registers::ctx);
|
get_fpr_u32l_context_offset(context.fs, compiler, odd_float_address_register, out, outw);
|
||||||
outw = get_fpr_u32l_context_offset(context.fs);
|
|
||||||
break;
|
break;
|
||||||
case Operand::FtU32L:
|
case Operand::FtU32L:
|
||||||
out = SLJIT_MEM1(Registers::ctx);
|
get_fpr_u32l_context_offset(context.ft, compiler, odd_float_address_register, out, outw);
|
||||||
outw = get_fpr_u32l_context_offset(context.ft);
|
|
||||||
break;
|
break;
|
||||||
case Operand::FdU32H:
|
case Operand::FdU32H:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
@ -389,16 +401,30 @@ void N64Recomp::LiveGenerator::process_binary_op(const BinaryOp& op, const Instr
|
||||||
if (outputs_to_zero(op.output, ctx)) {
|
if (outputs_to_zero(op.output, ctx)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Float u32l input operands are not allowed in a binary operation.
|
||||||
|
if (is_fpr_u32l(op.operands.operands[0]) || is_fpr_u32l(op.operands.operands[1])) {
|
||||||
|
assert(false);
|
||||||
|
errored = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A float u32l output operand is only allowed for lwc1, which has an op type of LW.
|
||||||
|
if (is_fpr_u32l(op.output) && op.type != BinaryOpType::LW) {
|
||||||
|
assert(false);
|
||||||
|
errored = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sljit_sw dst;
|
sljit_sw dst;
|
||||||
sljit_sw dstw;
|
sljit_sw dstw;
|
||||||
sljit_sw src1;
|
sljit_sw src1;
|
||||||
sljit_sw src1w;
|
sljit_sw src1w;
|
||||||
sljit_sw src2;
|
sljit_sw src2;
|
||||||
sljit_sw src2w;
|
sljit_sw src2w;
|
||||||
bool output_good = get_operand_values(op.output, ctx, dst, dstw);
|
bool output_good = get_operand_values(op.output, ctx, dst, dstw, compiler, Registers::arithmetic_temp2);
|
||||||
bool input0_good = get_operand_values(op.operands.operands[0], ctx, src1, src1w);
|
bool input0_good = get_operand_values(op.operands.operands[0], ctx, src1, src1w, nullptr, 0);
|
||||||
bool input1_good = get_operand_values(op.operands.operands[1], ctx, src2, src2w);
|
bool input1_good = get_operand_values(op.operands.operands[1], ctx, src2, src2w, nullptr, 0);
|
||||||
|
|
||||||
if (!output_good || !input0_good || !input1_good) {
|
if (!output_good || !input0_good || !input1_good) {
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
@ -866,12 +892,19 @@ void N64Recomp::LiveGenerator::process_unary_op(const UnaryOp& op, const Instruc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A unary op may have a float u32l as the source or destination, but not both.
|
||||||
|
if (is_fpr_u32l(op.input) && is_fpr_u32l(op.output)) {
|
||||||
|
assert(false);
|
||||||
|
errored = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sljit_sw dst;
|
sljit_sw dst;
|
||||||
sljit_sw dstw;
|
sljit_sw dstw;
|
||||||
sljit_sw src;
|
sljit_sw src;
|
||||||
sljit_sw srcw;
|
sljit_sw srcw;
|
||||||
bool output_good = get_operand_values(op.output, ctx, dst, dstw);
|
bool output_good = get_operand_values(op.output, ctx, dst, dstw, compiler, Registers::arithmetic_temp3);
|
||||||
bool input_good = get_operand_values(op.input, ctx, src, srcw);
|
bool input_good = get_operand_values(op.input, ctx, src, srcw, compiler, Registers::arithmetic_temp3);
|
||||||
|
|
||||||
if (!output_good || !input_good) {
|
if (!output_good || !input_good) {
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
@ -1089,7 +1122,13 @@ void N64Recomp::LiveGenerator::process_unary_op(const UnaryOp& op, const Instruc
|
||||||
emit_l_from_d_func(do_floor_l_d);
|
emit_l_from_d_func(do_floor_l_d);
|
||||||
break;
|
break;
|
||||||
case UnaryOpType::None:
|
case UnaryOpType::None:
|
||||||
jit_op = SLJIT_MOV;
|
// Only write 32 bits to the output is a fpr u32l operand.
|
||||||
|
if (is_fpr_u32l(op.output)) {
|
||||||
|
jit_op = SLJIT_MOV32;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
jit_op = SLJIT_MOV;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case UnaryOpType::ToS32:
|
case UnaryOpType::ToS32:
|
||||||
case UnaryOpType::ToInt32:
|
case UnaryOpType::ToInt32:
|
||||||
|
|
@ -1128,7 +1167,7 @@ void N64Recomp::LiveGenerator::process_store_op(const StoreOp& op, const Instruc
|
||||||
sljit_sw srcw;
|
sljit_sw srcw;
|
||||||
sljit_sw imm = (sljit_sw)(int16_t)ctx.imm16;
|
sljit_sw imm = (sljit_sw)(int16_t)ctx.imm16;
|
||||||
|
|
||||||
get_operand_values(op.value_input, ctx, src, srcw);
|
get_operand_values(op.value_input, ctx, src, srcw, compiler, Registers::arithmetic_temp2);
|
||||||
|
|
||||||
// Only LO16 relocs are valid on stores.
|
// Only LO16 relocs are valid on stores.
|
||||||
if (ctx.reloc_type != RelocType::R_MIPS_NONE && ctx.reloc_type != RelocType::R_MIPS_LO16) {
|
if (ctx.reloc_type != RelocType::R_MIPS_NONE && ctx.reloc_type != RelocType::R_MIPS_LO16) {
|
||||||
|
|
@ -1456,6 +1495,13 @@ void N64Recomp::LiveGenerator::emit_branch_condition(const ConditionalBranchOp&
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Branch conditions do not allow float u32l operands.
|
||||||
|
if (is_fpr_u32l(op.operands.operands[0]) || is_fpr_u32l(op.operands.operands[1])) {
|
||||||
|
assert(false);
|
||||||
|
errored = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sljit_s32 condition_type;
|
sljit_s32 condition_type;
|
||||||
bool cmp_signed = op.operands.operand_operations[0] == UnaryOpType::ToS64;
|
bool cmp_signed = op.operands.operand_operations[0] == UnaryOpType::ToS64;
|
||||||
// Comparisons need to be inverted to account for the fact that the generator is expected to generate a code block that only runs if
|
// Comparisons need to be inverted to account for the fact that the generator is expected to generate a code block that only runs if
|
||||||
|
|
@ -1509,8 +1555,8 @@ void N64Recomp::LiveGenerator::emit_branch_condition(const ConditionalBranchOp&
|
||||||
sljit_sw src2;
|
sljit_sw src2;
|
||||||
sljit_sw src2w;
|
sljit_sw src2w;
|
||||||
|
|
||||||
get_operand_values(op.operands.operands[0], ctx, src1, src1w);
|
get_operand_values(op.operands.operands[0], ctx, src1, src1w, nullptr, 0);
|
||||||
get_operand_values(op.operands.operands[1], ctx, src2, src2w);
|
get_operand_values(op.operands.operands[1], ctx, src2, src2w, nullptr, 0);
|
||||||
|
|
||||||
// Relocations aren't valid on conditional branches.
|
// Relocations aren't valid on conditional branches.
|
||||||
if(ctx.reloc_type != RelocType::R_MIPS_NONE) {
|
if(ctx.reloc_type != RelocType::R_MIPS_NONE) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue