reg_alloc: Q0 is scratch and needs to be moved

This commit is contained in:
Merry 2022-11-27 14:05:26 +00:00 committed by Liam
parent f7a092c06b
commit 26cef90d81
8 changed files with 72 additions and 34 deletions

View file

@ -40,7 +40,7 @@ template<>
void EmitIR<IR::Opcode::CallHostFunction>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr, args[1], args[2], args[3]);
ctx.reg_alloc.PrepareForCall(args[1], args[2], args[3]);
code.MOV(Xscratch0, args[0].GetImmediateU64());
code.BLR(Xscratch0);
}

View file

@ -555,7 +555,7 @@ void EmitIR<IR::Opcode::A32UpdateUpperLocationDescriptor>(oaknut::CodeGenerator&
template<>
void EmitIR<IR::Opcode::A32CallSupervisor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr);
ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -576,7 +576,7 @@ void EmitIR<IR::Opcode::A32CallSupervisor>(oaknut::CodeGenerator& code, EmitCont
template<>
void EmitIR<IR::Opcode::A32ExceptionRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr);
ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -611,7 +611,7 @@ void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(oaknut::CodeGenera
return;
}
ctx.reg_alloc.PrepareForCall(nullptr);
ctx.reg_alloc.PrepareForCall();
EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised);
}

View file

@ -24,7 +24,7 @@ static void EmitCoprocessorException() {
}
static void CallCoprocCallback(oaknut::CodeGenerator& code, EmitContext& ctx, A32::Coprocessor::Callback callback, IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
ctx.reg_alloc.PrepareForCall(inst, {}, arg0, arg1);
const auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst, {}, arg0, arg1);
if (callback.user_arg) {
code.MOV(X0, reinterpret_cast<u64>(*callback.user_arg));
@ -32,6 +32,7 @@ static void CallCoprocCallback(oaknut::CodeGenerator& code, EmitContext& ctx, A3
code.MOV(Xscratch0, reinterpret_cast<u64>(callback.function));
code.BLR(Xscratch0);
code.MOV(Xresult, X0);
}
template<>

View file

@ -25,18 +25,19 @@ static bool IsOrdered(IR::AccType acctype) {
static void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1]);
auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst, {}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
EmitRelocation(code, ctx, fn);
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
code.MOV(Xresult, X0);
}
static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1]);
auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst, {}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
code.MOV(Wscratch0, 1);
@ -45,11 +46,12 @@ static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ct
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
code.MOV(Xresult, X0);
}
static void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1], args[2]);
ctx.reg_alloc.PrepareForCall({}, args[1], args[2]);
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
if (ordered) {
@ -63,7 +65,7 @@ static void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::I
static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1], args[2]);
auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst, {}, args[1], args[2]);
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
oaknut::Label end;
@ -79,6 +81,7 @@ static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& c
code.DMB(oaknut::BarrierOp::ISH);
}
code.l(end);
code.MOV(Xresult, X0);
}
template<>

View file

@ -342,7 +342,7 @@ void EmitIR<IR::Opcode::A64SetPC>(oaknut::CodeGenerator& code, EmitContext& ctx,
template<>
void EmitIR<IR::Opcode::A64CallSupervisor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr);
ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -363,7 +363,7 @@ void EmitIR<IR::Opcode::A64CallSupervisor>(oaknut::CodeGenerator& code, EmitCont
template<>
void EmitIR<IR::Opcode::A64ExceptionRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr);
ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -385,14 +385,14 @@ void EmitIR<IR::Opcode::A64ExceptionRaised>(oaknut::CodeGenerator& code, EmitCon
template<>
void EmitIR<IR::Opcode::A64DataCacheOperationRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr, {}, args[1], args[2]);
ctx.reg_alloc.PrepareForCall({}, args[1], args[2]);
EmitRelocation(code, ctx, LinkTarget::DataCacheOperationRaised);
}
template<>
void EmitIR<IR::Opcode::A64InstructionCacheOperationRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr, {}, args[0], args[1]);
ctx.reg_alloc.PrepareForCall({}, args[0], args[1]);
EmitRelocation(code, ctx, LinkTarget::InstructionCacheOperationRaised);
}
@ -412,7 +412,7 @@ void EmitIR<IR::Opcode::A64InstructionSynchronizationBarrier>(oaknut::CodeGenera
return;
}
ctx.reg_alloc.PrepareForCall(nullptr);
ctx.reg_alloc.PrepareForCall();
EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised);
}
@ -426,8 +426,9 @@ void EmitIR<IR::Opcode::A64GetCNTFRQ>(oaknut::CodeGenerator& code, EmitContext&
template<>
void EmitIR<IR::Opcode::A64GetCNTPCT>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
// FIXME: AddTicks / GetTicksRemaining
ctx.reg_alloc.PrepareForCall(inst);
auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst);
EmitRelocation(code, ctx, LinkTarget::GetCNTPCT);
code.MOV(Xresult, X0);
}
template<>

View file

@ -25,18 +25,31 @@ static bool IsOrdered(IR::AccType acctype) {
static void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1]);
auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst, {}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
EmitRelocation(code, ctx, fn);
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
code.MOV(Xresult, X0);
}
static void EmitReadMemory128(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Qresult = ctx.reg_alloc.PrepareForCallVec(inst, {}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
EmitRelocation(code, ctx, fn);
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
code.MOV(Qresult.B16(), Q0.B16());
}
static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1]);
auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst, {}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
code.MOV(Wscratch0, 1);
@ -45,11 +58,26 @@ static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ct
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
code.MOV(Xresult, X0);
}
static void EmitExclusiveReadMemory128(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Qresult = ctx.reg_alloc.PrepareForCallVec(inst, {}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
code.MOV(Wscratch0, 1);
code.STRB(Wscratch0, Xstate, offsetof(A64JitState, exclusive_state));
EmitRelocation(code, ctx, fn);
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
code.MOV(Qresult.B16(), Q0.B16());
}
static void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1], args[2]);
ctx.reg_alloc.PrepareForCall({}, args[1], args[2]);
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
if (ordered) {
@ -63,7 +91,7 @@ static void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::I
static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(inst, {}, args[1], args[2]);
auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst, {}, args[1], args[2]);
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
oaknut::Label end;
@ -79,6 +107,7 @@ static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& c
code.DMB(oaknut::BarrierOp::ISH);
}
code.l(end);
code.MOV(Xresult, X0);
}
template<>
@ -108,7 +137,7 @@ void EmitIR<IR::Opcode::A64ReadMemory64>(oaknut::CodeGenerator& code, EmitContex
template<>
void EmitIR<IR::Opcode::A64ReadMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory128);
EmitReadMemory128(code, ctx, inst, LinkTarget::ReadMemory128);
}
template<>
@ -133,7 +162,7 @@ void EmitIR<IR::Opcode::A64ExclusiveReadMemory64>(oaknut::CodeGenerator& code, E
template<>
void EmitIR<IR::Opcode::A64ExclusiveReadMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory128);
EmitExclusiveReadMemory128(code, ctx, inst, LinkTarget::ExclusiveReadMemory128);
}
template<>

View file

@ -138,7 +138,7 @@ bool RegAlloc::IsValueLive(IR::Inst* inst) const {
return !!ValueLocation(inst);
}
void RegAlloc::PrepareForCall(IR::Inst* result, std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3) {
void RegAlloc::PrepareForCall(std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3) {
fpsr_manager.Spill();
SpillFlags();
@ -180,14 +180,20 @@ void RegAlloc::PrepareForCall(IR::Inst* result, std::optional<Argument::copyable
ngrn++;
}
}
}
if (result) {
if (result->GetType() == IR::Type::U128) {
DefineAsRegister(result, Q0);
} else {
DefineAsRegister(result, X0);
}
}
oaknut::XReg RegAlloc::PrepareForCallReg(IR::Inst* result, std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3) {
PrepareForCall(arg0, arg1, arg2, arg3);
ASSERT(result && result->GetType() != IR::Type::U128);
DefineAsRegister(result, X0);
return X0;
}
oaknut::QReg RegAlloc::PrepareForCallVec(IR::Inst* result, std::optional<Argument::copyable_reference> arg0, std::optional<Argument::copyable_reference> arg1, std::optional<Argument::copyable_reference> arg2, std::optional<Argument::copyable_reference> arg3) {
PrepareForCall(arg0, arg1, arg2, arg3);
ASSERT(result && result->GetType() == IR::Type::U128);
DefineAsRegister(result, Q8);
return Q8;
}
void RegAlloc::DefineAsExisting(IR::Inst* inst, Argument& arg) {

View file

@ -271,11 +271,9 @@ public:
}
}
void PrepareForCall(IR::Inst* result = nullptr,
std::optional<Argument::copyable_reference> arg0 = {},
std::optional<Argument::copyable_reference> arg1 = {},
std::optional<Argument::copyable_reference> arg2 = {},
std::optional<Argument::copyable_reference> arg3 = {});
void PrepareForCall(std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}, std::optional<Argument::copyable_reference> arg2 = {}, std::optional<Argument::copyable_reference> arg3 = {});
oaknut::XReg PrepareForCallReg(IR::Inst* result, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}, std::optional<Argument::copyable_reference> arg2 = {}, std::optional<Argument::copyable_reference> arg3 = {});
oaknut::QReg PrepareForCallVec(IR::Inst* result, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}, std::optional<Argument::copyable_reference> arg2 = {}, std::optional<Argument::copyable_reference> arg3 = {});
void DefineAsExisting(IR::Inst* inst, Argument& arg);
void DefineAsRegister(IR::Inst* inst, oaknut::Reg reg);