C -> O for ppc64; impl NZCV?

Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-11-04 10:00:59 +00:00
parent c1b028dca4
commit 2e3020c274
5 changed files with 141 additions and 75 deletions

View file

@ -62,8 +62,53 @@ void EmitIR<IR::Opcode::GetGEFromOp>(powah::Context&, EmitContext&, IR::Inst*) {
}
template<>
void EmitIR<IR::Opcode::GetNZCVFromOp>(powah::Context&, EmitContext& ctx, IR::Inst* inst) {
ASSERT(false && "unimp");
void EmitIR<IR::Opcode::GetNZCVFromOp>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
if (ctx.reg_alloc.IsValueLive(inst)) {
ASSERT(false && "unimp value live");
return;
}
// CR0:
// 0 - N/LT, result is negative
// 1 - P/GT, result is positive
// 2 - Z/EQ, result is zero
// 3 - S/SO, summary overflow (carry?)
// XER:
// 32 - SO
// 33 - Overflow
// 34 - Carry
// NZCV -> (CR0.0, CR0.2, XER.34, XER.33)
if (false) {
//code.MFSPR(powah::GPR{1}, tmp4, powah::R0); // From XER
/*uint64_t nzcv(uint64_t cr0, uint64_t xer) {
return ((xer >> 33) & 1)
| (((xer >> 34) & 1) << 1)
| (((cr0 >> (32 + 2)) & 1) << 2)
| (((cr0 >> (32 + 0)) & 1) << 3);
}*/
// auto const tmp9 = ctx.reg_alloc.ScratchGpr();
// auto const tmp10 = ctx.reg_alloc.ScratchGpr();
// code.SRDI(tmp9, tmp3, 34);
// code.RLDICL(tmp10, tmp4, 31, 63);
// code.SRDI(tmp3, tmp3, 32);
// code.RLDIC(tmp9, tmp9, 2, 61);
// code.OR(tmp9, tmp9, tmp10);
// code.RLDIC(tmp3, tmp3, 3, 60);
// code.SRDI(tmp4, tmp4, 34);
// code.OR(tmp3, tmp9, tmp3);
// code.RLDIC(tmp4, tmp4, 1, 62);
// code.OR(tmp3, tmp3, tmp4);
} else {
// MFCR Fills RT 32:63, RT 0:31 left blank
auto const source = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const tmp3 = ctx.reg_alloc.ScratchGpr();
auto const tmp = ctx.reg_alloc.ScratchGpr();
code.LI(tmp, -1);
code.RLDICR(tmp, tmp, 0, 0);
code.MFCR(powah::R0, tmp3, powah::R0);
code.CMPW(tmp, source);
code.MFCR(powah::R0, tmp3, powah::R0);
ctx.reg_alloc.DefineValue(inst, tmp3);
}
}
template<>
@ -185,6 +230,7 @@ EmittedBlockInfo EmitPPC64(powah::Context& code, IR::Block block, const EmitConf
for (size_t i = 0; i < gpr_order.size(); ++i)
code.LD(powah::GPR{gpr_order[i]}, powah::R1, -(i * 8));
code.BLR();
code.ApplyRelocs();
/*
llvm-objcopy -I binary -O elf64-powerpc --rename-section=.data=.text,code test.bin test.elf && llvm-objdump -d test.elf

View file

@ -38,7 +38,8 @@ void EmitIR<IR::Opcode::A64SetNZCVRaw>(powah::Context& code, EmitContext& ctx, I
template<>
void EmitIR<IR::Opcode::A64SetNZCV>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
ASSERT(false && "unimp");
auto const value = ctx.reg_alloc.UseGpr(inst->GetArg(0));
code.STW(value, PPC64::RJIT, offsetof(A64JitState, pstate));
}
template<>
@ -111,8 +112,7 @@ void EmitIR<IR::Opcode::A64SetW>(powah::Context& code, EmitContext& ctx, IR::Ins
auto const tmp = ctx.reg_alloc.ScratchGpr();
auto const offs = offsetof(A64JitState, regs)
+ A64::RegNumber(inst->GetArg(0).GetA64RegRef()) * sizeof(u64);
code.MR(tmp, value);
code.RLDICL(tmp, tmp, 0, 32);
code.RLDICL(tmp, value, 0, 32);
code.STD(tmp, PPC64::RJIT, offs);
} else {
ASSERT(false && "unimp");

View file

@ -4,6 +4,7 @@
#include <powah_emit.hpp>
#include <fmt/ostream.h>
#include "abi.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/backend/ppc64/a32_core.h"
#include "dynarmic/backend/ppc64/abi.h"
@ -436,17 +437,28 @@ void EmitIR<IR::Opcode::Add32>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.ADD(result, src_a, src_b);
code.ADDC_(result, src_a, src_b);
code.RLDICL(result, result, 0, 32);
ctx.reg_alloc.DefineValue(inst, result);
}
/*
struct jit {
uint32_t nzcv;
};
uint64_t addc(jit *p, uint64_t a, uint64_t b) {
long long unsigned int e;
uint64_t r = __builtin_addcll(a, b, p->nzcv & 0b0010, &e);
p->nzcv = (p->nzcv & 0b1101) | e;
return r;
}
*/
template<>
void EmitIR<IR::Opcode::Add64>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.ADD(result, src_a, src_b);
code.ADDC_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -455,7 +467,7 @@ void EmitIR<IR::Opcode::Sub32>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.SUBF(result, src_b, src_a);
code.SUBFC_(result, src_b, src_a);
code.RLDICL(result, result, 0, 32);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -465,7 +477,7 @@ void EmitIR<IR::Opcode::Sub64>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.SUBF(result, src_b, src_a);
code.SUBFC_(result, src_b, src_a);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -474,7 +486,7 @@ void EmitIR<IR::Opcode::Mul32>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.MULLW(result, src_a, src_b);
code.MULLWO_(result, src_a, src_b);
code.RLDICL(result, result, 0, 32);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -484,7 +496,7 @@ void EmitIR<IR::Opcode::Mul64>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.MULLD(result, src_a, src_b);
code.MULLDO_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -493,7 +505,7 @@ void EmitIR<IR::Opcode::SignedMultiplyHigh64>(powah::Context& code, EmitContext&
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.MULLD(result, src_a, src_b);
code.MULLDO_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -502,7 +514,7 @@ void EmitIR<IR::Opcode::UnsignedMultiplyHigh64>(powah::Context& code, EmitContex
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.MULLD(result, src_a, src_b);
code.MULLDO_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -511,7 +523,7 @@ void EmitIR<IR::Opcode::UnsignedDiv32>(powah::Context& code, EmitContext& ctx, I
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.DIVDU(result, src_a, src_b);
code.DIVWU_(result, src_a, src_b);
code.RLDICL(result, result, 0, 32);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -521,7 +533,7 @@ void EmitIR<IR::Opcode::UnsignedDiv64>(powah::Context& code, EmitContext& ctx, I
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.DIVDU(result, src_a, src_b);
code.DIVDU_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -530,7 +542,7 @@ void EmitIR<IR::Opcode::SignedDiv32>(powah::Context& code, EmitContext& ctx, IR:
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.DIVW(result, src_a, src_b);
code.DIVW_(result, src_a, src_b);
code.EXTSW(result, result);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -540,7 +552,7 @@ void EmitIR<IR::Opcode::SignedDiv64>(powah::Context& code, EmitContext& ctx, IR:
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.DIVD(result, src_a, src_b);
code.DIVD_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -549,7 +561,8 @@ void EmitIR<IR::Opcode::And32>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.AND(result, src_a, src_b);
code.RLDICL(result, src_a, 0, 32); // Truncate
code.AND_(result, result, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -558,7 +571,8 @@ void EmitIR<IR::Opcode::And64>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.AND(result, src_a, src_b);
code.AND_(result, src_a, src_b);
code.ADDI(result, result, 0); //update cr0
ctx.reg_alloc.DefineValue(inst, result);
}
@ -567,7 +581,7 @@ void EmitIR<IR::Opcode::AndNot32>(powah::Context& code, EmitContext& ctx, IR::In
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.NAND(result, src_a, src_b);
code.NAND_(result, src_a, src_b);
code.RLDICL(result, result, 0, 32);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -577,7 +591,7 @@ void EmitIR<IR::Opcode::AndNot64>(powah::Context& code, EmitContext& ctx, IR::In
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.NAND(result, src_a, src_b);
code.NAND_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -586,7 +600,7 @@ void EmitIR<IR::Opcode::Eor32>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.XOR(result, src_a, src_b);
code.XOR_(result, src_a, src_b);
code.RLDICL(result, result, 0, 32);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -596,7 +610,7 @@ void EmitIR<IR::Opcode::Eor64>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.XOR(result, src_a, src_b);
code.XOR_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -605,7 +619,7 @@ void EmitIR<IR::Opcode::Or32>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.OR(result, src_a, src_b);
code.OR_(result, src_a, src_b);
code.RLDICL(result, result, 0, 32);
ctx.reg_alloc.DefineValue(inst, result);
}
@ -615,10 +629,11 @@ void EmitIR<IR::Opcode::Or64>(powah::Context& code, EmitContext& ctx, IR::Inst*
auto const result = ctx.reg_alloc.ScratchGpr();
auto const src_a = ctx.reg_alloc.UseGpr(inst->GetArg(0));
auto const src_b = ctx.reg_alloc.UseGpr(inst->GetArg(1));
code.OR(result, src_a, src_b);
code.OR_(result, src_a, src_b);
ctx.reg_alloc.DefineValue(inst, result);
}
// TODO(lizzie): NZVC support for NOT
template<>
void EmitIR<IR::Opcode::Not32>(powah::Context& code, EmitContext& ctx, IR::Inst* inst) {
auto const result = ctx.reg_alloc.ScratchGpr();