backend/A64: refactor to fpscr from mxcsr
This commit is contained in:
parent
47c0632e16
commit
bb39f419e2
@ -306,7 +306,6 @@ void A32EmitA64::GenTerminalHandlers() {
|
|||||||
code.ANDI2R(fast_dispatch_entry_reg, fast_dispatch_entry_reg, fast_dispatch_table_mask);
|
code.ANDI2R(fast_dispatch_entry_reg, fast_dispatch_entry_reg, fast_dispatch_table_mask);
|
||||||
code.ADD(fast_dispatch_entry_reg, fast_dispatch_entry_reg, code.ABI_SCRATCH1);
|
code.ADD(fast_dispatch_entry_reg, fast_dispatch_entry_reg, code.ABI_SCRATCH1);
|
||||||
|
|
||||||
// code.cmp(location_descriptor_reg, qword[fast_dispatch_entry_reg + offsetof(FastDispatchEntry, location_descriptor)]);
|
|
||||||
code.LDR(INDEX_UNSIGNED, code.ABI_SCRATCH1, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, location_descriptor));
|
code.LDR(INDEX_UNSIGNED, code.ABI_SCRATCH1, fast_dispatch_entry_reg, offsetof(FastDispatchEntry, location_descriptor));
|
||||||
code.CMP(location_descriptor_reg, code.ABI_SCRATCH1);
|
code.CMP(location_descriptor_reg, code.ABI_SCRATCH1);
|
||||||
fast_dispatch_cache_miss = code.B(CC_NEQ);
|
fast_dispatch_cache_miss = code.B(CC_NEQ);
|
||||||
@ -397,7 +396,6 @@ void A32EmitA64::EmitA32GetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
ctx.reg_alloc.HostCall(inst);
|
ctx.reg_alloc.HostCall(inst);
|
||||||
code.MOV(code.ABI_PARAM1, X28);
|
code.MOV(code.ABI_PARAM1, X28);
|
||||||
code.QuickCallFunction(&GetCpsrImpl);
|
code.QuickCallFunction(&GetCpsrImpl);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetCpsrImpl(u32 value, A32JitState* jit_state) {
|
static void SetCpsrImpl(u32 value, A32JitState* jit_state) {
|
||||||
@ -416,7 +414,6 @@ void A32EmitA64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
|
|
||||||
code.MOV(code.ABI_PARAM2, X28);
|
code.MOV(code.ABI_PARAM2, X28);
|
||||||
code.QuickCallFunction(&SetCpsrImpl);
|
code.QuickCallFunction(&SetCpsrImpl);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitA64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitA64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
@ -425,7 +422,6 @@ void A32EmitA64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
|
|
||||||
code.ANDI2R(a, a, 0xF0000000);
|
code.ANDI2R(a, a, 0xF0000000);
|
||||||
code.STR(INDEX_UNSIGNED, a, X28, offsetof(A32JitState, CPSR_nzcv));
|
code.STR(INDEX_UNSIGNED, a, X28, offsetof(A32JitState, CPSR_nzcv));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitA64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitA64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
@ -686,7 +682,7 @@ void A32EmitA64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
ctx.reg_alloc.HostCall(nullptr);
|
ctx.reg_alloc.HostCall(nullptr);
|
||||||
ARM64Reg cycles_remaining = ctx.reg_alloc.ScratchGpr();
|
ARM64Reg cycles_remaining = ctx.reg_alloc.ScratchGpr();
|
||||||
|
|
||||||
code.SwitchMxcsrOnExit();
|
code.SwitchFpscrOnExit();
|
||||||
code.LDR(INDEX_UNSIGNED, code.ABI_PARAM2, X28, offsetof(A32JitState, cycles_to_run));
|
code.LDR(INDEX_UNSIGNED, code.ABI_PARAM2, X28, offsetof(A32JitState, cycles_to_run));
|
||||||
code.LDR(INDEX_UNSIGNED, cycles_remaining, X28, offsetof(A32JitState, cycles_remaining));
|
code.LDR(INDEX_UNSIGNED, cycles_remaining, X28, offsetof(A32JitState, cycles_remaining));
|
||||||
code.SUB(code.ABI_PARAM2, code.ABI_PARAM2, cycles_remaining);
|
code.SUB(code.ABI_PARAM2, code.ABI_PARAM2, cycles_remaining);
|
||||||
@ -699,7 +695,7 @@ void A32EmitA64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
|
|||||||
Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(config.callbacks).EmitCall(code);
|
Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(config.callbacks).EmitCall(code);
|
||||||
code.STR(INDEX_UNSIGNED, code.ABI_RETURN, X28, offsetof(A32JitState, cycles_to_run));
|
code.STR(INDEX_UNSIGNED, code.ABI_RETURN, X28, offsetof(A32JitState, cycles_to_run));
|
||||||
code.STR(INDEX_UNSIGNED, code.ABI_RETURN, X28, offsetof(A32JitState, cycles_remaining));
|
code.STR(INDEX_UNSIGNED, code.ABI_RETURN, X28, offsetof(A32JitState, cycles_remaining));
|
||||||
code.SwitchMxcsrOnEntry();
|
code.SwitchFpscrOnEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitA64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitA64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
@ -1243,7 +1239,7 @@ void A32EmitA64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
|
|||||||
code.MOVI2R(DecodeReg(code.ABI_PARAM2), A32::LocationDescriptor{terminal.next}.PC());
|
code.MOVI2R(DecodeReg(code.ABI_PARAM2), A32::LocationDescriptor{terminal.next}.PC());
|
||||||
code.MOVI2R(DecodeReg(code.ABI_PARAM3), terminal.num_instructions);
|
code.MOVI2R(DecodeReg(code.ABI_PARAM3), terminal.num_instructions);
|
||||||
code.STR(INDEX_UNSIGNED,DecodeReg(code.ABI_PARAM2), X28, MJitStateReg(A32::Reg::PC));
|
code.STR(INDEX_UNSIGNED,DecodeReg(code.ABI_PARAM2), X28, MJitStateReg(A32::Reg::PC));
|
||||||
code.SwitchMxcsrOnExit();
|
code.SwitchFpscrOnExit();
|
||||||
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(config.callbacks).EmitCall(code);
|
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(config.callbacks).EmitCall(code);
|
||||||
code.ReturnFromRunCode(true); // TODO: Check cycles
|
code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||||
}
|
}
|
||||||
|
@ -134,22 +134,22 @@ void BlockOfCode::RunCodeFrom(void* jit_state, CodePtr code_ptr) const {
|
|||||||
run_code_from(jit_state, code_ptr);
|
run_code_from(jit_state, code_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::ReturnFromRunCode(bool mxcsr_already_exited) {
|
void BlockOfCode::ReturnFromRunCode(bool fpscr_already_exited) {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
if (mxcsr_already_exited)
|
if (fpscr_already_exited)
|
||||||
index |= MXCSR_ALREADY_EXITED;
|
index |= FPSCR_ALREADY_EXITED;
|
||||||
B(return_from_run_code[index]);
|
B(return_from_run_code[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::ForceReturnFromRunCode(bool mxcsr_already_exited) {
|
void BlockOfCode::ForceReturnFromRunCode(bool fpscr_already_exited) {
|
||||||
size_t index = FORCE_RETURN;
|
size_t index = FORCE_RETURN;
|
||||||
if (mxcsr_already_exited)
|
if (fpscr_already_exited)
|
||||||
index |= MXCSR_ALREADY_EXITED; //TODO: refactor to fpcr
|
index |= FPSCR_ALREADY_EXITED;
|
||||||
B(return_from_run_code[index]);
|
B(return_from_run_code[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::GenRunCode() {
|
void BlockOfCode::GenRunCode() {
|
||||||
const u8* loop, *enter_mxcsr_then_loop;
|
const u8* loop, *enter_fpscr_then_loop;
|
||||||
|
|
||||||
run_code_from = (RunCodeFromFuncType) const_cast<u8*>(AlignCode16());
|
run_code_from = (RunCodeFromFuncType) const_cast<u8*>(AlignCode16());
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ void BlockOfCode::GenRunCode() {
|
|||||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_to_run);
|
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_to_run);
|
||||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_remaining);
|
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_remaining);
|
||||||
|
|
||||||
SwitchMxcsrOnEntry();
|
SwitchFpscrOnEntry();
|
||||||
BR(Arm64Gen::X27);
|
BR(Arm64Gen::X27);
|
||||||
|
|
||||||
run_code = (RunCodeFuncType) const_cast<u8*>(AlignCode16());
|
run_code = (RunCodeFuncType) const_cast<u8*>(AlignCode16());
|
||||||
@ -180,23 +180,23 @@ void BlockOfCode::GenRunCode() {
|
|||||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_to_run);
|
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_to_run);
|
||||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_remaining);
|
STR(Arm64Gen::INDEX_UNSIGNED, ABI_RETURN, Arm64Gen::X28, jsi.offsetof_cycles_remaining);
|
||||||
|
|
||||||
enter_mxcsr_then_loop = GetCodePtr();
|
enter_fpscr_then_loop = GetCodePtr();
|
||||||
SwitchMxcsrOnEntry();
|
SwitchFpscrOnEntry();
|
||||||
loop = GetCodePtr();
|
loop = GetCodePtr();
|
||||||
|
|
||||||
cb.LookupBlock->EmitCall(*this);
|
cb.LookupBlock->EmitCall(*this);
|
||||||
BR(ABI_RETURN);
|
BR(ABI_RETURN);
|
||||||
|
|
||||||
// Return from run code variants
|
// Return from run code variants
|
||||||
const auto emit_return_from_run_code = [this, &loop, &enter_mxcsr_then_loop](bool mxcsr_already_exited, bool force_return){
|
const auto emit_return_from_run_code = [this, &loop, &enter_fpscr_then_loop](bool fpscr_already_exited, bool force_return){
|
||||||
if (!force_return) {
|
if (!force_return) {
|
||||||
LDR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_cycles_remaining);
|
LDR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_cycles_remaining);
|
||||||
CMP(ABI_SCRATCH1, Arm64Gen::ZR);
|
CMP(ABI_SCRATCH1, Arm64Gen::ZR);
|
||||||
B(CC_GT, mxcsr_already_exited ? enter_mxcsr_then_loop : loop);
|
B(CC_GT, fpscr_already_exited ? enter_fpscr_then_loop : loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mxcsr_already_exited) {
|
if (!fpscr_already_exited) {
|
||||||
SwitchMxcsrOnExit();
|
SwitchFpscrOnExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
cb.AddTicks->EmitCall(*this, [this](RegList param) {
|
cb.AddTicks->EmitCall(*this, [this](RegList param) {
|
||||||
@ -212,19 +212,19 @@ void BlockOfCode::GenRunCode() {
|
|||||||
return_from_run_code[0] = AlignCode16();
|
return_from_run_code[0] = AlignCode16();
|
||||||
emit_return_from_run_code(false, false);
|
emit_return_from_run_code(false, false);
|
||||||
|
|
||||||
return_from_run_code[MXCSR_ALREADY_EXITED] = AlignCode16();
|
return_from_run_code[FPSCR_ALREADY_EXITED] = AlignCode16();
|
||||||
emit_return_from_run_code(true, false);
|
emit_return_from_run_code(true, false);
|
||||||
|
|
||||||
return_from_run_code[FORCE_RETURN] = AlignCode16();
|
return_from_run_code[FORCE_RETURN] = AlignCode16();
|
||||||
emit_return_from_run_code(false, true);
|
emit_return_from_run_code(false, true);
|
||||||
|
|
||||||
return_from_run_code[MXCSR_ALREADY_EXITED | FORCE_RETURN] = AlignCode16();
|
return_from_run_code[FPSCR_ALREADY_EXITED | FORCE_RETURN] = AlignCode16();
|
||||||
emit_return_from_run_code(true, true);
|
emit_return_from_run_code(true, true);
|
||||||
|
|
||||||
PerfMapRegister(run_code_from, GetCodePtr(), "dynarmic_dispatcher");
|
PerfMapRegister(run_code_from, GetCodePtr(), "dynarmic_dispatcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::SwitchMxcsrOnEntry() {
|
void BlockOfCode::SwitchFpscrOnEntry() {
|
||||||
MRS(ABI_SCRATCH1, Arm64Gen::FIELD_FPCR);
|
MRS(ABI_SCRATCH1, Arm64Gen::FIELD_FPCR);
|
||||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_save_host_FPCR);
|
STR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_save_host_FPCR);
|
||||||
|
|
||||||
@ -234,7 +234,7 @@ void BlockOfCode::SwitchMxcsrOnEntry() {
|
|||||||
_MSR(Arm64Gen::FIELD_FPSR, ABI_SCRATCH1);
|
_MSR(Arm64Gen::FIELD_FPSR, ABI_SCRATCH1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::SwitchMxcsrOnExit() {
|
void BlockOfCode::SwitchFpscrOnExit() {
|
||||||
MRS(ABI_SCRATCH1, Arm64Gen::FIELD_FPCR);
|
MRS(ABI_SCRATCH1, Arm64Gen::FIELD_FPCR);
|
||||||
STR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_guest_FPCR);
|
STR(Arm64Gen::INDEX_UNSIGNED, ABI_SCRATCH1, Arm64Gen::X28, jsi.offsetof_guest_FPCR);
|
||||||
MRS(ABI_SCRATCH1, Arm64Gen::FIELD_FPSR);
|
MRS(ABI_SCRATCH1, Arm64Gen::FIELD_FPSR);
|
||||||
|
@ -48,13 +48,13 @@ public:
|
|||||||
/// Runs emulated code from code_ptr.
|
/// Runs emulated code from code_ptr.
|
||||||
void RunCodeFrom(void* jit_state, CodePtr code_ptr) const;
|
void RunCodeFrom(void* jit_state, CodePtr code_ptr) const;
|
||||||
/// Code emitter: Returns to dispatcher
|
/// Code emitter: Returns to dispatcher
|
||||||
void ReturnFromRunCode(bool mxcsr_already_exited = false);
|
void ReturnFromRunCode(bool fpscr_already_exited = false);
|
||||||
/// Code emitter: Returns to dispatcher, forces return to host
|
/// Code emitter: Returns to dispatcher, forces return to host
|
||||||
void ForceReturnFromRunCode(bool mxcsr_already_exited = false);
|
void ForceReturnFromRunCode(bool fpscr_already_exited = false);
|
||||||
/// Code emitter: Makes guest MXCSR the current MXCSR
|
/// Code emitter: Makes guest FPSR and FPCR the current FPSR and FPCR
|
||||||
void SwitchMxcsrOnEntry();
|
void SwitchFpscrOnEntry();
|
||||||
/// Code emitter: Makes saved host MXCSR the current MXCSR
|
/// Code emitter: Makes saved host FPCR the current FPCR
|
||||||
void SwitchMxcsrOnExit();
|
void SwitchFpscrOnExit();
|
||||||
/// Code emitter: Updates cycles remaining my calling cb.AddTicks and cb.GetTicksRemaining
|
/// Code emitter: Updates cycles remaining my calling cb.AddTicks and cb.GetTicksRemaining
|
||||||
/// @note this clobbers ABI caller-save registers
|
/// @note this clobbers ABI caller-save registers
|
||||||
void UpdateTicks();
|
void UpdateTicks();
|
||||||
@ -132,7 +132,7 @@ private:
|
|||||||
using RunCodeFromFuncType = void(*)(void*, CodePtr);
|
using RunCodeFromFuncType = void(*)(void*, CodePtr);
|
||||||
RunCodeFuncType run_code = nullptr;
|
RunCodeFuncType run_code = nullptr;
|
||||||
RunCodeFromFuncType run_code_from = nullptr;
|
RunCodeFromFuncType run_code_from = nullptr;
|
||||||
static constexpr size_t MXCSR_ALREADY_EXITED = 1 << 0;
|
static constexpr size_t FPSCR_ALREADY_EXITED = 1 << 0;
|
||||||
static constexpr size_t FORCE_RETURN = 1 << 1;
|
static constexpr size_t FORCE_RETURN = 1 << 1;
|
||||||
std::array<const void*, 4> return_from_run_code;
|
std::array<const void*, 4> return_from_run_code;
|
||||||
void GenRunCode();
|
void GenRunCode();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user