Package up emit context

This commit is contained in:
MerryMage 2018-01-01 23:40:34 +00:00
parent 7bf421dd38
commit 2d164d9345
4 changed files with 846 additions and 802 deletions

View file

@ -49,6 +49,25 @@ static Xbyak::Address MJitStateExtReg(A32::ExtReg reg) {
ASSERT_MSG(false, "Should never happen.");
}
A32EmitContext::A32EmitContext(RegAlloc& reg_alloc, IR::Block& block)
: EmitContext(reg_alloc, block) {}
A32::LocationDescriptor A32EmitContext::Location() const {
return A32::LocationDescriptor{block.Location()};
}
bool A32EmitContext::FPSCR_RoundTowardsZero() const {
return Location().FPSCR().RMode() != A32::FPSCR::RoundingMode::TowardsZero;
}
bool A32EmitContext::FPSCR_FTZ() const {
return Location().FPSCR().FTZ();
}
bool A32EmitContext::FPSCR_DN() const {
return Location().FPSCR().DN();
}
A32EmitX64::A32EmitX64(BlockOfCode* code, UserCallbacks cb, Jit* jit_interface)
: EmitX64(code, cb, jit_interface) {}
@ -62,6 +81,7 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
EmitCondPrelude(block);
RegAlloc reg_alloc{code};
A32EmitContext ctx{reg_alloc, block};
for (auto iter = block.begin(); iter != block.end(); ++iter) {
IR::Inst* inst = &*iter;
@ -71,11 +91,11 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
#define OPCODE(name, type, ...) \
case IR::Opcode::name: \
A32EmitX64::Emit##name(reg_alloc, block, inst); \
A32EmitX64::Emit##name(ctx, inst); \
break;
#define A32OPC(name, type, ...) \
case IR::Opcode::A32##name: \
A32EmitX64::EmitA32##name(reg_alloc, block, inst); \
A32EmitX64::EmitA32##name(ctx, inst); \
break;
#include "frontend/ir/opcodes.inc"
#undef OPCODE
@ -108,68 +128,68 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
return block_desc;
}
void A32EmitX64::EmitA32GetRegister(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32GetRegister(A32EmitContext& ctx, IR::Inst* inst) {
A32::Reg reg = inst->GetArg(0).GetA32RegRef();
Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(result, MJitStateReg(reg));
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32GetExtendedRegister32(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32GetExtendedRegister32(A32EmitContext& ctx, IR::Inst* inst) {
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
ASSERT(A32::IsSingleExtReg(reg));
Xbyak::Xmm result = reg_alloc.ScratchXmm();
Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
code->movss(result, MJitStateExtReg(reg));
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32GetExtendedRegister64(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32GetExtendedRegister64(A32EmitContext& ctx, IR::Inst* inst) {
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
ASSERT(A32::IsDoubleExtReg(reg));
Xbyak::Xmm result = reg_alloc.ScratchXmm();
Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
code->movsd(result, MJitStateExtReg(reg));
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetRegister(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetRegister(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
A32::Reg reg = inst->GetArg(0).GetA32RegRef();
if (args[1].IsImmediate()) {
code->mov(MJitStateReg(reg), args[1].GetImmediateU32());
} else if (args[1].IsInXmm()) {
Xbyak::Xmm to_store = reg_alloc.UseXmm(args[1]);
Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]);
code->movd(MJitStateReg(reg), to_store);
} else {
Xbyak::Reg32 to_store = reg_alloc.UseGpr(args[1]).cvt32();
Xbyak::Reg32 to_store = ctx.reg_alloc.UseGpr(args[1]).cvt32();
code->mov(MJitStateReg(reg), to_store);
}
}
void A32EmitX64::EmitA32SetExtendedRegister32(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetExtendedRegister32(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
ASSERT(A32::IsSingleExtReg(reg));
if (args[1].IsInXmm()) {
Xbyak::Xmm to_store = reg_alloc.UseXmm(args[1]);
Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]);
code->movss(MJitStateExtReg(reg), to_store);
} else {
Xbyak::Reg32 to_store = reg_alloc.UseGpr(args[1]).cvt32();
Xbyak::Reg32 to_store = ctx.reg_alloc.UseGpr(args[1]).cvt32();
code->mov(MJitStateExtReg(reg), to_store);
}
}
void A32EmitX64::EmitA32SetExtendedRegister64(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetExtendedRegister64(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
ASSERT(A32::IsDoubleExtReg(reg));
if (args[1].IsInXmm()) {
Xbyak::Xmm to_store = reg_alloc.UseXmm(args[1]);
Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]);
code->movsd(MJitStateExtReg(reg), to_store);
} else {
Xbyak::Reg64 to_store = reg_alloc.UseGpr(args[1]);
Xbyak::Reg64 to_store = ctx.reg_alloc.UseGpr(args[1]);
code->mov(MJitStateExtReg(reg), to_store);
}
}
@ -178,11 +198,11 @@ static u32 GetCpsrImpl(A32JitState* jit_state) {
return jit_state->Cpsr();
}
void A32EmitX64::EmitA32GetCpsr(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32GetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
if (code->DoesCpuSupport(Xbyak::util::Cpu::tBMI2)) {
Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 b = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 c = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 b = ctx.reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 c = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(c, dword[r15 + offsetof(A32JitState, CPSR_ge)]);
// Here we observe that CPSR_q and CPSR_nzcv are right next to each other in memory,
@ -202,9 +222,9 @@ void A32EmitX64::EmitA32GetCpsr(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst)
code->or_(result, dword[r15 + offsetof(A32JitState, CPSR_jaifm)]);
code->or_(result, c);
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
} else {
reg_alloc.HostCall(inst);
ctx.reg_alloc.HostCall(inst);
code->mov(code->ABI_PARAM1, code->r15);
code->CallFunction(&GetCpsrImpl);
}
@ -214,36 +234,36 @@ static void SetCpsrImpl(u32 value, A32JitState* jit_state) {
jit_state->SetCpsr(value);
}
void A32EmitX64::EmitA32SetCpsr(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
reg_alloc.HostCall(nullptr, args[0]);
void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, args[0]);
code->mov(code->ABI_PARAM2, code->r15);
code->CallFunction(&SetCpsrImpl);
}
void A32EmitX64::EmitA32SetCpsrNZCV(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
u32 imm = args[0].GetImmediateU32();
code->mov(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], u32(imm & 0xF0000000));
} else {
Xbyak::Reg32 a = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
code->and_(a, 0xF0000000);
code->mov(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], a);
}
}
void A32EmitX64::EmitA32SetCpsrNZCVQ(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
u32 imm = args[0].GetImmediateU32();
code->mov(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], u32(imm & 0xF0000000));
code->mov(code->byte[r15 + offsetof(A32JitState, CPSR_q)], u8((imm & 0x08000000) != 0 ? 1 : 0));
} else {
Xbyak::Reg32 a = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
code->bt(a, 27);
code->setc(code->byte[r15 + offsetof(A32JitState, CPSR_q)]);
@ -252,17 +272,17 @@ void A32EmitX64::EmitA32SetCpsrNZCVQ(RegAlloc& reg_alloc, IR::Block&, IR::Inst*
}
}
void A32EmitX64::EmitA32GetNFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32();
void A32EmitX64::EmitA32GetNFlag(A32EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(result, dword[r15 + offsetof(A32JitState, CPSR_nzcv)]);
code->shr(result, 31);
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetNFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32SetNFlag(A32EmitContext& ctx, IR::Inst* inst) {
constexpr size_t flag_bit = 31;
constexpr u32 flag_mask = 1u << flag_bit;
auto args = reg_alloc.GetArgumentInfo(inst);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
if (args[0].GetImmediateU1()) {
code->or_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], flag_mask);
@ -270,7 +290,7 @@ void A32EmitX64::EmitA32SetNFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
}
} else {
Xbyak::Reg32 to_store = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
code->shl(to_store, flag_bit);
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
@ -278,18 +298,18 @@ void A32EmitX64::EmitA32SetNFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
}
}
void A32EmitX64::EmitA32GetZFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32();
void A32EmitX64::EmitA32GetZFlag(A32EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(result, dword[r15 + offsetof(A32JitState, CPSR_nzcv)]);
code->shr(result, 30);
code->and_(result, 1);
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetZFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32SetZFlag(A32EmitContext& ctx, IR::Inst* inst) {
constexpr size_t flag_bit = 30;
constexpr u32 flag_mask = 1u << flag_bit;
auto args = reg_alloc.GetArgumentInfo(inst);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
if (args[0].GetImmediateU1()) {
code->or_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], flag_mask);
@ -297,7 +317,7 @@ void A32EmitX64::EmitA32SetZFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
}
} else {
Xbyak::Reg32 to_store = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
code->shl(to_store, flag_bit);
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
@ -305,18 +325,18 @@ void A32EmitX64::EmitA32SetZFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
}
}
void A32EmitX64::EmitA32GetCFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32();
void A32EmitX64::EmitA32GetCFlag(A32EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(result, dword[r15 + offsetof(A32JitState, CPSR_nzcv)]);
code->shr(result, 29);
code->and_(result, 1);
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetCFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32SetCFlag(A32EmitContext& ctx, IR::Inst* inst) {
constexpr size_t flag_bit = 29;
constexpr u32 flag_mask = 1u << flag_bit;
auto args = reg_alloc.GetArgumentInfo(inst);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
if (args[0].GetImmediateU1()) {
code->or_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], flag_mask);
@ -324,7 +344,7 @@ void A32EmitX64::EmitA32SetCFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
}
} else {
Xbyak::Reg32 to_store = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
code->shl(to_store, flag_bit);
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
@ -332,18 +352,18 @@ void A32EmitX64::EmitA32SetCFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
}
}
void A32EmitX64::EmitA32GetVFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32();
void A32EmitX64::EmitA32GetVFlag(A32EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(result, dword[r15 + offsetof(A32JitState, CPSR_nzcv)]);
code->shr(result, 28);
code->and_(result, 1);
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetVFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32SetVFlag(A32EmitContext& ctx, IR::Inst* inst) {
constexpr size_t flag_bit = 28;
constexpr u32 flag_mask = 1u << flag_bit;
auto args = reg_alloc.GetArgumentInfo(inst);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
if (args[0].GetImmediateU1()) {
code->or_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], flag_mask);
@ -351,7 +371,7 @@ void A32EmitX64::EmitA32SetVFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
}
} else {
Xbyak::Reg32 to_store = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
code->shl(to_store, flag_bit);
code->and_(dword[r15 + offsetof(A32JitState, CPSR_nzcv)], ~flag_mask);
@ -359,39 +379,39 @@ void A32EmitX64::EmitA32SetVFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst
}
}
void A32EmitX64::EmitA32OrQFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32OrQFlag(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
if (args[0].GetImmediateU1())
code->mov(dword[r15 + offsetof(A32JitState, CPSR_q)], 1);
} else {
Xbyak::Reg8 to_store = reg_alloc.UseGpr(args[0]).cvt8();
Xbyak::Reg8 to_store = ctx.reg_alloc.UseGpr(args[0]).cvt8();
code->or_(code->byte[r15 + offsetof(A32JitState, CPSR_q)], to_store);
}
}
void A32EmitX64::EmitA32GetGEFlags(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
Xbyak::Xmm result = reg_alloc.ScratchXmm();
void A32EmitX64::EmitA32GetGEFlags(A32EmitContext& ctx, IR::Inst* inst) {
Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
code->movd(result, dword[r15 + offsetof(A32JitState, CPSR_ge)]);
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetGEFlags(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetGEFlags(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ASSERT(!args[0].IsImmediate());
if (args[0].IsInXmm()) {
Xbyak::Xmm to_store = reg_alloc.UseXmm(args[0]);
Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[0]);
code->movd(dword[r15 + offsetof(A32JitState, CPSR_ge)], to_store);
} else {
Xbyak::Reg32 to_store = reg_alloc.UseGpr(args[0]).cvt32();
Xbyak::Reg32 to_store = ctx.reg_alloc.UseGpr(args[0]).cvt32();
code->mov(dword[r15 + offsetof(A32JitState, CPSR_ge)], to_store);
}
}
void A32EmitX64::EmitA32SetGEFlagsCompressed(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetGEFlagsCompressed(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (args[0].IsImmediate()) {
u32 imm = args[0].GetImmediateU32();
u32 ge = 0;
@ -402,8 +422,8 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(RegAlloc& reg_alloc, IR::Block&, IR
code->mov(dword[r15 + offsetof(A32JitState, CPSR_ge)], ge);
} else if (code->DoesCpuSupport(Xbyak::util::Cpu::tBMI2)) {
Xbyak::Reg32 a = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 b = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 b = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(b, 0x01010101);
code->shr(a, 16);
@ -411,7 +431,7 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(RegAlloc& reg_alloc, IR::Block&, IR
code->imul(a, a, 0xFF);
code->mov(dword[r15 + offsetof(A32JitState, CPSR_ge)], a);
} else {
Xbyak::Reg32 a = reg_alloc.UseScratchGpr(args[0]).cvt32();
Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
code->shr(a, 16);
code->and_(a, 0xF);
@ -422,8 +442,8 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(RegAlloc& reg_alloc, IR::Block&, IR
}
}
void A32EmitX64::EmitA32BXWritePC(RegAlloc& reg_alloc, IR::Block& block, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto& arg = args[0];
// Pseudocode:
@ -440,16 +460,16 @@ void A32EmitX64::EmitA32BXWritePC(RegAlloc& reg_alloc, IR::Block& block, IR::Ins
u32 new_pc = arg.GetImmediateU32();
u32 mask = Common::Bit<0>(new_pc) ? 0xFFFFFFFE : 0xFFFFFFFC;
u32 et = 0;
et |= A32::LocationDescriptor{block.Location()}.EFlag() ? 2 : 0;
et |= ctx.Location().EFlag() ? 2 : 0;
et |= Common::Bit<0>(new_pc) ? 1 : 0;
code->mov(MJitStateReg(A32::Reg::PC), new_pc & mask);
code->mov(dword[r15 + offsetof(A32JitState, CPSR_et)], et);
} else {
if (A32::LocationDescriptor{block.Location()}.EFlag()) {
Xbyak::Reg32 new_pc = reg_alloc.UseScratchGpr(arg).cvt32();
Xbyak::Reg32 mask = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 et = reg_alloc.ScratchGpr().cvt32();
if (ctx.Location().EFlag()) {
Xbyak::Reg32 new_pc = ctx.reg_alloc.UseScratchGpr(arg).cvt32();
Xbyak::Reg32 mask = ctx.reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 et = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(mask, new_pc);
code->and_(mask, 1);
@ -459,8 +479,8 @@ void A32EmitX64::EmitA32BXWritePC(RegAlloc& reg_alloc, IR::Block& block, IR::Ins
code->and_(new_pc, mask);
code->mov(MJitStateReg(A32::Reg::PC), new_pc);
} else {
Xbyak::Reg32 new_pc = reg_alloc.UseScratchGpr(arg).cvt32();
Xbyak::Reg32 mask = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg32 new_pc = ctx.reg_alloc.UseScratchGpr(arg).cvt32();
Xbyak::Reg32 mask = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(mask, new_pc);
code->and_(mask, 1);
@ -472,16 +492,16 @@ void A32EmitX64::EmitA32BXWritePC(RegAlloc& reg_alloc, IR::Block& block, IR::Ins
}
}
void A32EmitX64::EmitA32CallSupervisor(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
reg_alloc.HostCall(nullptr);
void A32EmitX64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(nullptr);
code->SwitchMxcsrOnExit();
code->mov(code->ABI_PARAM1, qword[r15 + offsetof(A32JitState, cycles_to_run)]);
code->sub(code->ABI_PARAM1, qword[r15 + offsetof(A32JitState, cycles_remaining)]);
code->CallFunction(cb.AddTicks);
reg_alloc.EndOfAllocScope();
auto args = reg_alloc.GetArgumentInfo(inst);
reg_alloc.HostCall(nullptr, args[0]);
ctx.reg_alloc.EndOfAllocScope();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, args[0]);
code->CallFunction(cb.CallSVC);
code->CallFunction(cb.GetTicksRemaining);
code->mov(qword[r15 + offsetof(A32JitState, cycles_to_run)], code->ABI_RETURN);
@ -493,8 +513,8 @@ static u32 GetFpscrImpl(A32JitState* jit_state) {
return jit_state->Fpscr();
}
void A32EmitX64::EmitA32GetFpscr(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
reg_alloc.HostCall(inst);
void A32EmitX64::EmitA32GetFpscr(A32EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(inst);
code->mov(code->ABI_PARAM1, code->r15);
code->stmxcsr(code->dword[code->r15 + offsetof(A32JitState, guest_MXCSR)]);
@ -505,36 +525,36 @@ static void SetFpscrImpl(u32 value, A32JitState* jit_state) {
jit_state->SetFpscr(value);
}
void A32EmitX64::EmitA32SetFpscr(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
reg_alloc.HostCall(nullptr, args[0]);
void A32EmitX64::EmitA32SetFpscr(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, args[0]);
code->mov(code->ABI_PARAM2, code->r15);
code->CallFunction(&SetFpscrImpl);
code->ldmxcsr(code->dword[code->r15 + offsetof(A32JitState, guest_MXCSR)]);
}
void A32EmitX64::EmitA32GetFpscrNZCV(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32();
void A32EmitX64::EmitA32GetFpscrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code->mov(result, dword[r15 + offsetof(A32JitState, FPSCR_nzcv)]);
reg_alloc.DefineValue(inst, result);
ctx.reg_alloc.DefineValue(inst, result);
}
void A32EmitX64::EmitA32SetFpscrNZCV(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg32 value = reg_alloc.UseGpr(args[0]).cvt32();
void A32EmitX64::EmitA32SetFpscrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg32 value = ctx.reg_alloc.UseGpr(args[0]).cvt32();
code->mov(dword[r15 + offsetof(A32JitState, FPSCR_nzcv)], value);
}
void A32EmitX64::EmitA32ClearExclusive(RegAlloc&, IR::Block&, IR::Inst*) {
void A32EmitX64::EmitA32ClearExclusive(A32EmitContext&, IR::Inst*) {
code->mov(code->byte[r15 + offsetof(A32JitState, exclusive_state)], u8(0));
}
void A32EmitX64::EmitA32SetExclusive(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32SetExclusive(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ASSERT(args[1].IsImmediate());
Xbyak::Reg32 address = reg_alloc.UseGpr(args[0]).cvt32();
Xbyak::Reg32 address = ctx.reg_alloc.UseGpr(args[0]).cvt32();
code->mov(code->byte[r15 + offsetof(A32JitState, exclusive_state)], u8(1));
code->mov(dword[r15 + offsetof(A32JitState, exclusive_address)], address);
@ -644,36 +664,36 @@ static void WriteMemory(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* inst,
code->L(end);
}
void A32EmitX64::EmitA32ReadMemory8(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ReadMemory(code, reg_alloc, inst, cb, 8, cb.memory.Read8);
void A32EmitX64::EmitA32ReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 8, cb.memory.Read8);
}
void A32EmitX64::EmitA32ReadMemory16(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ReadMemory(code, reg_alloc, inst, cb, 16, cb.memory.Read16);
void A32EmitX64::EmitA32ReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 16, cb.memory.Read16);
}
void A32EmitX64::EmitA32ReadMemory32(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ReadMemory(code, reg_alloc, inst, cb, 32, cb.memory.Read32);
void A32EmitX64::EmitA32ReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 32, cb.memory.Read32);
}
void A32EmitX64::EmitA32ReadMemory64(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ReadMemory(code, reg_alloc, inst, cb, 64, cb.memory.Read64);
void A32EmitX64::EmitA32ReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
ReadMemory(code, ctx.reg_alloc, inst, cb, 64, cb.memory.Read64);
}
void A32EmitX64::EmitA32WriteMemory8(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
WriteMemory(code, reg_alloc, inst, cb, 8, cb.memory.Write8);
void A32EmitX64::EmitA32WriteMemory8(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 8, cb.memory.Write8);
}
void A32EmitX64::EmitA32WriteMemory16(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
WriteMemory(code, reg_alloc, inst, cb, 16, cb.memory.Write16);
void A32EmitX64::EmitA32WriteMemory16(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 16, cb.memory.Write16);
}
void A32EmitX64::EmitA32WriteMemory32(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
WriteMemory(code, reg_alloc, inst, cb, 32, cb.memory.Write32);
void A32EmitX64::EmitA32WriteMemory32(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 32, cb.memory.Write32);
}
void A32EmitX64::EmitA32WriteMemory64(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
WriteMemory(code, reg_alloc, inst, cb, 64, cb.memory.Write64);
void A32EmitX64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
WriteMemory(code, ctx.reg_alloc, inst, cb, 64, cb.memory.Write64);
}
template <typename FunctionPointer>
@ -709,20 +729,20 @@ static void ExclusiveWrite(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst* ins
reg_alloc.DefineValue(inst, passed);
}
void A32EmitX64::EmitA32ExclusiveWriteMemory8(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ExclusiveWrite(code, reg_alloc, inst, cb.memory.Write8, false);
void A32EmitX64::EmitA32ExclusiveWriteMemory8(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write8, false);
}
void A32EmitX64::EmitA32ExclusiveWriteMemory16(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ExclusiveWrite(code, reg_alloc, inst, cb.memory.Write16, false);
void A32EmitX64::EmitA32ExclusiveWriteMemory16(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write16, false);
}
void A32EmitX64::EmitA32ExclusiveWriteMemory32(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ExclusiveWrite(code, reg_alloc, inst, cb.memory.Write32, false);
void A32EmitX64::EmitA32ExclusiveWriteMemory32(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write32, false);
}
void A32EmitX64::EmitA32ExclusiveWriteMemory64(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
ExclusiveWrite(code, reg_alloc, inst, cb.memory.Write64, true);
void A32EmitX64::EmitA32ExclusiveWriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
ExclusiveWrite(code, ctx.reg_alloc, inst, cb.memory.Write64, true);
}
static void EmitCoprocessorException() {
@ -740,7 +760,7 @@ static void CallCoprocCallback(BlockOfCode* code, RegAlloc& reg_alloc, Jit* jit_
code->CallFunction(callback.function);
}
void A32EmitX64::EmitA32CoprocInternalOperation(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32CoprocInternalOperation(A32EmitContext& ctx, IR::Inst* inst) {
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
size_t coproc_num = coproc_info[0];
@ -763,11 +783,11 @@ void A32EmitX64::EmitA32CoprocInternalOperation(RegAlloc& reg_alloc, IR::Block&,
return;
}
CallCoprocCallback(code, reg_alloc, jit_interface, *action);
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, *action);
}
void A32EmitX64::EmitA32CoprocSendOneWord(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32CoprocSendOneWord(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
size_t coproc_num = coproc_info[0];
@ -789,13 +809,13 @@ void A32EmitX64::EmitA32CoprocSendOneWord(RegAlloc& reg_alloc, IR::Block&, IR::I
EmitCoprocessorException();
return;
case 1:
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, args[1]);
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, args[1]);
return;
case 2: {
u32* destination_ptr = boost::get<u32*>(action);
Xbyak::Reg32 reg_word = reg_alloc.UseGpr(args[1]).cvt32();
Xbyak::Reg64 reg_destination_addr = reg_alloc.ScratchGpr();
Xbyak::Reg32 reg_word = ctx.reg_alloc.UseGpr(args[1]).cvt32();
Xbyak::Reg64 reg_destination_addr = ctx.reg_alloc.ScratchGpr();
code->mov(reg_destination_addr, reinterpret_cast<u64>(destination_ptr));
code->mov(code->dword[reg_destination_addr], reg_word);
@ -807,8 +827,8 @@ void A32EmitX64::EmitA32CoprocSendOneWord(RegAlloc& reg_alloc, IR::Block&, IR::I
}
}
void A32EmitX64::EmitA32CoprocSendTwoWords(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32CoprocSendTwoWords(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
size_t coproc_num = coproc_info[0];
@ -828,14 +848,14 @@ void A32EmitX64::EmitA32CoprocSendTwoWords(RegAlloc& reg_alloc, IR::Block&, IR::
EmitCoprocessorException();
return;
case 1:
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, args[1], args[2]);
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), nullptr, args[1], args[2]);
return;
case 2: {
auto destination_ptrs = boost::get<std::array<u32*, 2>>(action);
Xbyak::Reg32 reg_word1 = reg_alloc.UseGpr(args[1]).cvt32();
Xbyak::Reg32 reg_word2 = reg_alloc.UseGpr(args[2]).cvt32();
Xbyak::Reg64 reg_destination_addr = reg_alloc.ScratchGpr();
Xbyak::Reg32 reg_word1 = ctx.reg_alloc.UseGpr(args[1]).cvt32();
Xbyak::Reg32 reg_word2 = ctx.reg_alloc.UseGpr(args[2]).cvt32();
Xbyak::Reg64 reg_destination_addr = ctx.reg_alloc.ScratchGpr();
code->mov(reg_destination_addr, reinterpret_cast<u64>(destination_ptrs[0]));
code->mov(code->dword[reg_destination_addr], reg_word1);
@ -849,7 +869,7 @@ void A32EmitX64::EmitA32CoprocSendTwoWords(RegAlloc& reg_alloc, IR::Block&, IR::
}
}
void A32EmitX64::EmitA32CoprocGetOneWord(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32CoprocGetOneWord(A32EmitContext& ctx, IR::Inst* inst) {
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
size_t coproc_num = coproc_info[0];
@ -871,18 +891,18 @@ void A32EmitX64::EmitA32CoprocGetOneWord(RegAlloc& reg_alloc, IR::Block&, IR::In
EmitCoprocessorException();
return;
case 1:
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
return;
case 2: {
u32* source_ptr = boost::get<u32*>(action);
Xbyak::Reg32 reg_word = reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg64 reg_source_addr = reg_alloc.ScratchGpr();
Xbyak::Reg32 reg_word = ctx.reg_alloc.ScratchGpr().cvt32();
Xbyak::Reg64 reg_source_addr = ctx.reg_alloc.ScratchGpr();
code->mov(reg_source_addr, reinterpret_cast<u64>(source_ptr));
code->mov(reg_word, code->dword[reg_source_addr]);
reg_alloc.DefineValue(inst, reg_word);
ctx.reg_alloc.DefineValue(inst, reg_word);
return;
}
@ -891,7 +911,7 @@ void A32EmitX64::EmitA32CoprocGetOneWord(RegAlloc& reg_alloc, IR::Block&, IR::In
}
}
void A32EmitX64::EmitA32CoprocGetTwoWords(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
void A32EmitX64::EmitA32CoprocGetTwoWords(A32EmitContext& ctx, IR::Inst* inst) {
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
size_t coproc_num = coproc_info[0];
@ -911,14 +931,14 @@ void A32EmitX64::EmitA32CoprocGetTwoWords(RegAlloc& reg_alloc, IR::Block&, IR::I
EmitCoprocessorException();
return;
case 1:
CallCoprocCallback(code, reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, boost::get<Coprocessor::Callback>(action), inst);
return;
case 2: {
auto source_ptrs = boost::get<std::array<u32*, 2>>(action);
Xbyak::Reg64 reg_result = reg_alloc.ScratchGpr();
Xbyak::Reg64 reg_destination_addr = reg_alloc.ScratchGpr();
Xbyak::Reg64 reg_tmp = reg_alloc.ScratchGpr();
Xbyak::Reg64 reg_result = ctx.reg_alloc.ScratchGpr();
Xbyak::Reg64 reg_destination_addr = ctx.reg_alloc.ScratchGpr();
Xbyak::Reg64 reg_tmp = ctx.reg_alloc.ScratchGpr();
code->mov(reg_destination_addr, reinterpret_cast<u64>(source_ptrs[1]));
code->mov(reg_result.cvt32(), code->dword[reg_destination_addr]);
@ -927,7 +947,7 @@ void A32EmitX64::EmitA32CoprocGetTwoWords(RegAlloc& reg_alloc, IR::Block&, IR::I
code->mov(reg_tmp.cvt32(), code->dword[reg_destination_addr]);
code->or_(reg_result, reg_tmp);
reg_alloc.DefineValue(inst, reg_result);
ctx.reg_alloc.DefineValue(inst, reg_result);
return;
}
@ -936,8 +956,8 @@ void A32EmitX64::EmitA32CoprocGetTwoWords(RegAlloc& reg_alloc, IR::Block&, IR::I
}
}
void A32EmitX64::EmitA32CoprocLoadWords(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32CoprocLoadWords(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
size_t coproc_num = coproc_info[0];
@ -959,11 +979,11 @@ void A32EmitX64::EmitA32CoprocLoadWords(RegAlloc& reg_alloc, IR::Block&, IR::Ins
return;
}
CallCoprocCallback(code, reg_alloc, jit_interface, *action, nullptr, args[1]);
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, *action, nullptr, args[1]);
}
void A32EmitX64::EmitA32CoprocStoreWords(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) {
auto args = reg_alloc.GetArgumentInfo(inst);
void A32EmitX64::EmitA32CoprocStoreWords(A32EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto coproc_info = inst->GetArg(0).GetCoprocInfo();
size_t coproc_num = coproc_info[0];
@ -985,7 +1005,7 @@ void A32EmitX64::EmitA32CoprocStoreWords(RegAlloc& reg_alloc, IR::Block&, IR::In
return;
}
CallCoprocCallback(code, reg_alloc, jit_interface, *action, nullptr, args[1]);
CallCoprocCallback(code, ctx.reg_alloc, jit_interface, *action, nullptr, args[1]);
}
void A32EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) {

View file

@ -15,7 +15,6 @@
#include <xbyak_util.h>
#include "backend_x64/reg_alloc.h"
#include "backend_x64/emit_x64.h"
#include "common/address_range.h"
#include "dynarmic/callbacks.h"
@ -25,6 +24,16 @@
namespace Dynarmic {
namespace BackendX64 {
class RegAlloc;
struct A32EmitContext final : public EmitContext {
A32EmitContext(RegAlloc& reg_alloc, IR::Block& block);
A32::LocationDescriptor Location() const;
bool FPSCR_RoundTowardsZero() const override;
bool FPSCR_FTZ() const override;
bool FPSCR_DN() const override;
};
class A32EmitX64 final : public EmitX64<u32> {
public:
A32EmitX64(BlockOfCode* code, UserCallbacks cb, Jit* jit_interface);
@ -39,7 +48,7 @@ public:
protected:
// Microinstruction emitters
#define OPCODE(...)
#define A32OPC(name, type, ...) void EmitA32##name(RegAlloc& reg_alloc, IR::Block& block, IR::Inst* inst);
#define A32OPC(name, type, ...) void EmitA32##name(A32EmitContext& ctx, IR::Inst* inst);
#include "frontend/ir/opcodes.inc"
#undef OPCODE
#undef A32OPC

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,19 @@ namespace BackendX64 {
class BlockOfCode;
struct EmitContext {
EmitContext(RegAlloc& reg_alloc, IR::Block& block);
void EraseInstruction(IR::Inst* inst);
virtual bool FPSCR_RoundTowardsZero() const = 0;
virtual bool FPSCR_FTZ() const = 0;
virtual bool FPSCR_DN() const = 0;
RegAlloc& reg_alloc;
IR::Block& block;
};
template <typename ProgramCounterType>
class EmitX64 {
public:
@ -58,7 +71,7 @@ public:
protected:
// Microinstruction emitters
#define OPCODE(name, type, ...) void Emit##name(RegAlloc& reg_alloc, IR::Block& block, IR::Inst* inst);
#define OPCODE(name, type, ...) void Emit##name(EmitContext& ctx, IR::Inst* inst);
#define A32OPC(...)
#include "frontend/ir/opcodes.inc"
#undef OPCODE