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) { void EmitIR<IR::Opcode::CallHostFunction>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(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.MOV(Xscratch0, args[0].GetImmediateU64());
code.BLR(Xscratch0); code.BLR(Xscratch0);
} }

View file

@ -555,7 +555,7 @@ void EmitIR<IR::Opcode::A32UpdateUpperLocationDescriptor>(oaknut::CodeGenerator&
template<> template<>
void EmitIR<IR::Opcode::A32CallSupervisor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A32CallSupervisor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr); ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) { if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run)); code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -576,7 +576,7 @@ void EmitIR<IR::Opcode::A32CallSupervisor>(oaknut::CodeGenerator& code, EmitCont
template<> template<>
void EmitIR<IR::Opcode::A32ExceptionRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A32ExceptionRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr); ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) { if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run)); code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -611,7 +611,7 @@ void EmitIR<IR::Opcode::A32InstructionSynchronizationBarrier>(oaknut::CodeGenera
return; return;
} }
ctx.reg_alloc.PrepareForCall(nullptr); ctx.reg_alloc.PrepareForCall();
EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised); 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 = {}) { 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) { if (callback.user_arg) {
code.MOV(X0, reinterpret_cast<u64>(*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.MOV(Xscratch0, reinterpret_cast<u64>(callback.function));
code.BLR(Xscratch0); code.BLR(Xscratch0);
code.MOV(Xresult, X0);
} }
template<> 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) { static void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[2].GetImmediateAccType());
EmitRelocation(code, ctx, fn); EmitRelocation(code, ctx, fn);
if (ordered) { if (ordered) {
code.DMB(oaknut::BarrierOp::ISH); code.DMB(oaknut::BarrierOp::ISH);
} }
code.MOV(Xresult, X0);
} }
static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) { static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[2].GetImmediateAccType());
code.MOV(Wscratch0, 1); code.MOV(Wscratch0, 1);
@ -45,11 +46,12 @@ static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ct
if (ordered) { if (ordered) {
code.DMB(oaknut::BarrierOp::ISH); code.DMB(oaknut::BarrierOp::ISH);
} }
code.MOV(Xresult, X0);
} }
static void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) { static void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[3].GetImmediateAccType());
if (ordered) { 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) { static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[3].GetImmediateAccType());
oaknut::Label end; oaknut::Label end;
@ -79,6 +81,7 @@ static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& c
code.DMB(oaknut::BarrierOp::ISH); code.DMB(oaknut::BarrierOp::ISH);
} }
code.l(end); code.l(end);
code.MOV(Xresult, X0);
} }
template<> template<>

View file

@ -342,7 +342,7 @@ void EmitIR<IR::Opcode::A64SetPC>(oaknut::CodeGenerator& code, EmitContext& ctx,
template<> template<>
void EmitIR<IR::Opcode::A64CallSupervisor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A64CallSupervisor>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr); ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) { if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run)); code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -363,7 +363,7 @@ void EmitIR<IR::Opcode::A64CallSupervisor>(oaknut::CodeGenerator& code, EmitCont
template<> template<>
void EmitIR<IR::Opcode::A64ExceptionRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A64ExceptionRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall(nullptr); ctx.reg_alloc.PrepareForCall();
if (ctx.conf.enable_cycle_counting) { if (ctx.conf.enable_cycle_counting) {
code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run)); code.LDR(Xscratch0, SP, offsetof(StackLayout, cycles_to_run));
@ -385,14 +385,14 @@ void EmitIR<IR::Opcode::A64ExceptionRaised>(oaknut::CodeGenerator& code, EmitCon
template<> template<>
void EmitIR<IR::Opcode::A64DataCacheOperationRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A64DataCacheOperationRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(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); EmitRelocation(code, ctx, LinkTarget::DataCacheOperationRaised);
} }
template<> template<>
void EmitIR<IR::Opcode::A64InstructionCacheOperationRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A64InstructionCacheOperationRaised>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(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); EmitRelocation(code, ctx, LinkTarget::InstructionCacheOperationRaised);
} }
@ -412,7 +412,7 @@ void EmitIR<IR::Opcode::A64InstructionSynchronizationBarrier>(oaknut::CodeGenera
return; return;
} }
ctx.reg_alloc.PrepareForCall(nullptr); ctx.reg_alloc.PrepareForCall();
EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised); EmitRelocation(code, ctx, LinkTarget::InstructionSynchronizationBarrierRaised);
} }
@ -426,8 +426,9 @@ void EmitIR<IR::Opcode::A64GetCNTFRQ>(oaknut::CodeGenerator& code, EmitContext&
template<> template<>
void EmitIR<IR::Opcode::A64GetCNTPCT>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A64GetCNTPCT>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
// FIXME: AddTicks / GetTicksRemaining // FIXME: AddTicks / GetTicksRemaining
ctx.reg_alloc.PrepareForCall(inst); auto Xresult = ctx.reg_alloc.PrepareForCallReg(inst);
EmitRelocation(code, ctx, LinkTarget::GetCNTPCT); EmitRelocation(code, ctx, LinkTarget::GetCNTPCT);
code.MOV(Xresult, X0);
} }
template<> 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) { static void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[2].GetImmediateAccType());
EmitRelocation(code, ctx, fn); EmitRelocation(code, ctx, fn);
if (ordered) { if (ordered) {
code.DMB(oaknut::BarrierOp::ISH); 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) { static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[2].GetImmediateAccType());
code.MOV(Wscratch0, 1); code.MOV(Wscratch0, 1);
@ -45,11 +58,26 @@ static void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ct
if (ordered) { if (ordered) {
code.DMB(oaknut::BarrierOp::ISH); 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) { static void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[3].GetImmediateAccType());
if (ordered) { 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) { static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); 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()); const bool ordered = IsOrdered(args[3].GetImmediateAccType());
oaknut::Label end; oaknut::Label end;
@ -79,6 +107,7 @@ static void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& c
code.DMB(oaknut::BarrierOp::ISH); code.DMB(oaknut::BarrierOp::ISH);
} }
code.l(end); code.l(end);
code.MOV(Xresult, X0);
} }
template<> template<>
@ -108,7 +137,7 @@ void EmitIR<IR::Opcode::A64ReadMemory64>(oaknut::CodeGenerator& code, EmitContex
template<> template<>
void EmitIR<IR::Opcode::A64ReadMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { 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<> template<>
@ -133,7 +162,7 @@ void EmitIR<IR::Opcode::A64ExclusiveReadMemory64>(oaknut::CodeGenerator& code, E
template<> template<>
void EmitIR<IR::Opcode::A64ExclusiveReadMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { 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<> template<>

View file

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

View file

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