|
|
|
@ -23,7 +23,10 @@ constexpr u64 FUNCTION_CALLER_SAVED_SPACE_RESERVE = 144; // 18 registers -> 224
|
|
|
|
constexpr u64 FUNCTION_STACK_SIZE =
|
|
|
|
constexpr u64 FUNCTION_STACK_SIZE =
|
|
|
|
FUNCTION_CALLEE_SAVED_SPACE_RESERVE + FUNCTION_CALLER_SAVED_SPACE_RESERVE + FUNCTION_CALL_SHADOW_SPACE;
|
|
|
|
FUNCTION_CALLEE_SAVED_SPACE_RESERVE + FUNCTION_CALLER_SAVED_SPACE_RESERVE + FUNCTION_CALL_SHADOW_SPACE;
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::WRegister GetHostReg8(HostReg reg) { return a64::WRegister(reg); }
|
|
|
|
static const a64::WRegister GetHostReg8(HostReg reg)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return a64::WRegister(reg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::WRegister GetHostReg8(const Value& value)
|
|
|
|
static const a64::WRegister GetHostReg8(const Value& value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -31,7 +34,10 @@ static const a64::WRegister GetHostReg8(const Value& value)
|
|
|
|
return a64::WRegister(value.host_reg);
|
|
|
|
return a64::WRegister(value.host_reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::WRegister GetHostReg16(HostReg reg) { return a64::WRegister(reg); }
|
|
|
|
static const a64::WRegister GetHostReg16(HostReg reg)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return a64::WRegister(reg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::WRegister GetHostReg16(const Value& value)
|
|
|
|
static const a64::WRegister GetHostReg16(const Value& value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -39,7 +45,10 @@ static const a64::WRegister GetHostReg16(const Value& value)
|
|
|
|
return a64::WRegister(value.host_reg);
|
|
|
|
return a64::WRegister(value.host_reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::WRegister GetHostReg32(HostReg reg) { return a64::WRegister(reg); }
|
|
|
|
static const a64::WRegister GetHostReg32(HostReg reg)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return a64::WRegister(reg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::WRegister GetHostReg32(const Value& value)
|
|
|
|
static const a64::WRegister GetHostReg32(const Value& value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -47,7 +56,10 @@ static const a64::WRegister GetHostReg32(const Value& value)
|
|
|
|
return a64::WRegister(value.host_reg);
|
|
|
|
return a64::WRegister(value.host_reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::XRegister GetHostReg64(HostReg reg) { return a64::XRegister(reg); }
|
|
|
|
static const a64::XRegister GetHostReg64(HostReg reg)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return a64::XRegister(reg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::XRegister GetHostReg64(const Value& value)
|
|
|
|
static const a64::XRegister GetHostReg64(const Value& value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -55,7 +67,10 @@ static const a64::XRegister GetHostReg64(const Value& value)
|
|
|
|
return a64::XRegister(value.host_reg);
|
|
|
|
return a64::XRegister(value.host_reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const a64::XRegister GetCPUPtrReg() { return GetHostReg64(RCPUPTR); }
|
|
|
|
static const a64::XRegister GetCPUPtrReg()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return GetHostReg64(RCPUPTR);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CodeGenerator::CodeGenerator(JitCodeBuffer* code_buffer)
|
|
|
|
CodeGenerator::CodeGenerator(JitCodeBuffer* code_buffer)
|
|
|
|
: m_code_buffer(code_buffer), m_register_cache(*this),
|
|
|
|
: m_code_buffer(code_buffer), m_register_cache(*this),
|
|
|
|
@ -98,7 +113,10 @@ const char* CodeGenerator::GetHostRegName(HostReg reg, RegSize size /*= HostPoin
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::AlignCodeBuffer(JitCodeBuffer* code_buffer) { code_buffer->Align(16, 0x90); }
|
|
|
|
void CodeGenerator::AlignCodeBuffer(JitCodeBuffer* code_buffer)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
code_buffer->Align(16, 0x90);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::InitHostRegs()
|
|
|
|
void CodeGenerator::InitHostRegs()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -111,9 +129,15 @@ void CodeGenerator::InitHostRegs()
|
|
|
|
m_register_cache.SetCPUPtrHostReg(RCPUPTR);
|
|
|
|
m_register_cache.SetCPUPtrHostReg(RCPUPTR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::SwitchToFarCode() { m_emit = &m_far_emitter; }
|
|
|
|
void CodeGenerator::SwitchToFarCode()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit = &m_far_emitter;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::SwitchToNearCode() { m_emit = &m_near_emitter; }
|
|
|
|
void CodeGenerator::SwitchToNearCode()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit = &m_near_emitter;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void* CodeGenerator::GetCurrentNearCodePointer() const
|
|
|
|
void* CodeGenerator::GetCurrentNearCodePointer() const
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -125,12 +149,12 @@ void* CodeGenerator::GetCurrentFarCodePointer() const
|
|
|
|
return static_cast<u8*>(m_code_buffer->GetFreeFarCodePointer()) + m_far_emitter.GetCursorOffset();
|
|
|
|
return static_cast<u8*>(m_code_buffer->GetFreeFarCodePointer()) + m_far_emitter.GetCursorOffset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Value CodeGenerator::GetValueInHostRegister(const Value& value)
|
|
|
|
Value CodeGenerator::GetValueInHostRegister(const Value& value, bool allow_zero_register /* = true */)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (value.IsInHostRegister())
|
|
|
|
if (value.IsInHostRegister())
|
|
|
|
return Value::FromHostReg(&m_register_cache, value.host_reg, value.size);
|
|
|
|
return Value::FromHostReg(&m_register_cache, value.host_reg, value.size);
|
|
|
|
|
|
|
|
|
|
|
|
if (value.HasConstantValue(0))
|
|
|
|
if (value.HasConstantValue(0) && allow_zero_register)
|
|
|
|
return Value::FromHostReg(&m_register_cache, static_cast<HostReg>(31), value.size);
|
|
|
|
return Value::FromHostReg(&m_register_cache, static_cast<HostReg>(31), value.size);
|
|
|
|
|
|
|
|
|
|
|
|
Value new_value = m_register_cache.AllocateScratch(value.size);
|
|
|
|
Value new_value = m_register_cache.AllocateScratch(value.size);
|
|
|
|
@ -487,6 +511,38 @@ void CodeGenerator::EmitMul(HostReg to_reg_hi, HostReg to_reg_lo, const Value& l
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::EmitDiv(HostReg to_reg_quotient, HostReg to_reg_remainder, HostReg num, HostReg denom, RegSize size,
|
|
|
|
|
|
|
|
bool signed_divide)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// only 32-bit supported for now..
|
|
|
|
|
|
|
|
Assert(size == RegSize_32);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Value quotient_value;
|
|
|
|
|
|
|
|
if (to_reg_quotient == HostReg_Count)
|
|
|
|
|
|
|
|
quotient_value = m_register_cache.AllocateScratch(size);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
quotient_value.SetHostReg(&m_register_cache, to_reg_quotient, size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (signed_divide)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit->sdiv(GetHostReg32(quotient_value), GetHostReg32(num), GetHostReg32(denom));
|
|
|
|
|
|
|
|
if (to_reg_remainder != HostReg_Count)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit->msub(GetHostReg32(to_reg_remainder), GetHostReg32(quotient_value), GetHostReg32(denom),
|
|
|
|
|
|
|
|
GetHostReg32(num));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit->udiv(GetHostReg32(quotient_value), GetHostReg32(num), GetHostReg32(denom));
|
|
|
|
|
|
|
|
if (to_reg_remainder != HostReg_Count)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit->msub(GetHostReg32(to_reg_remainder), GetHostReg32(quotient_value), GetHostReg32(denom),
|
|
|
|
|
|
|
|
GetHostReg32(num));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::EmitInc(HostReg to_reg, RegSize size)
|
|
|
|
void CodeGenerator::EmitInc(HostReg to_reg, RegSize size)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Panic("Not implemented");
|
|
|
|
Panic("Not implemented");
|
|
|
|
@ -882,7 +938,10 @@ u32 CodeGenerator::PrepareStackForCall()
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::RestoreStackAfterCall(u32 adjust_size) { m_register_cache.PopCallerSavedRegisters(); }
|
|
|
|
void CodeGenerator::RestoreStackAfterCall(u32 adjust_size)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_register_cache.PopCallerSavedRegisters();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static s64 GetBranchDisplacement(const void* current, const void* target)
|
|
|
|
static s64 GetBranchDisplacement(const void* current, const void* target)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -1038,7 +1097,6 @@ void CodeGenerator::EmitFunctionCallPtr(Value* return_value, const void* ptr, co
|
|
|
|
if (return_value)
|
|
|
|
if (return_value)
|
|
|
|
return_value->Discard();
|
|
|
|
return_value->Discard();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// shadow space allocate
|
|
|
|
// shadow space allocate
|
|
|
|
const u32 adjust_size = PrepareStackForCall();
|
|
|
|
const u32 adjust_size = PrepareStackForCall();
|
|
|
|
|
|
|
|
|
|
|
|
@ -1314,9 +1372,15 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const
|
|
|
|
m_register_cache.PopState();
|
|
|
|
m_register_cache.PopState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::EmitLoadGlobal(HostReg host_reg, RegSize size, const void* ptr) { Panic("Not implemented"); }
|
|
|
|
void CodeGenerator::EmitLoadGlobal(HostReg host_reg, RegSize size, const void* ptr)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Panic("Not implemented");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::EmitStoreGlobal(void* ptr, const Value& value) { Panic("Not implemented"); }
|
|
|
|
void CodeGenerator::EmitStoreGlobal(void* ptr, const Value& value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Panic("Not implemented");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::EmitFlushInterpreterLoadDelay()
|
|
|
|
void CodeGenerator::EmitFlushInterpreterLoadDelay()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -1411,6 +1475,11 @@ void CodeGenerator::EmitBranch(const void* address, bool allow_scratch)
|
|
|
|
m_emit->br(GetHostReg64(temp));
|
|
|
|
m_emit->br(GetHostReg64(temp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::EmitBranch(LabelType* label)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit->B(label);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static a64::Condition TranslateCondition(Condition condition, bool invert)
|
|
|
|
static a64::Condition TranslateCondition(Condition condition, bool invert)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
switch (condition)
|
|
|
|
switch (condition)
|
|
|
|
@ -1634,6 +1703,9 @@ void CodeGenerator::EmitBranchIfBitClear(HostReg reg, RegSize size, u8 bit, Labe
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CodeGenerator::EmitBindLabel(LabelType* label) { m_emit->Bind(label); }
|
|
|
|
void CodeGenerator::EmitBindLabel(LabelType* label)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_emit->Bind(label);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace CPU::Recompiler
|
|
|
|
} // namespace CPU::Recompiler
|
|
|
|
|