From 55a7f576aadda53c835e2b29f82f4619078a4d45 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Mon, 12 Sep 2016 09:08:56 +0000 Subject: [PATCH] JitArm64: Fix CoreTiming contract Call Advance at the start of each timing slice instead of the end. Possibly fixed a bug where a slice would randomly branch straight back to Advance() because the flags were not set to the right values before branching to the dispatcher entrypoint. --- Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp | 40 ++++++++++++-------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp index bf6f395586..7c47e7a2b6 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp @@ -28,18 +28,28 @@ void JitArm64::GenerateAsm() MOVP2R(PPC_REG, &PowerPC::ppcState); - // Load the current PC into DISPATCHER_PC - LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - - FixupBranch to_dispatcher = B(); + // The PC will be loaded into DISPATCHER_PC after the call to CoreTiming::Advance(). + // Advance() does an exception check so we don't know what PC to use until afterwards. + FixupBranch to_start_of_timing_slice = B(); // If we align the dispatcher to a page then we can load its location with one ADRP instruction + // do + // { + // CoreTiming::Advance(); // <-- Checks for exceptions (changes PC) + // DISPATCHER_PC = PC; + // do + // { + // dispatcherNoCheck: + // ExecuteBlock(JitBase::Dispatch()); + // dispatcher: + // } while (PowerPC::ppcState.downcount > 0); + // doTiming: + // NPC = PC = DISPATCHER_PC; + // } while (CPU::GetState() == CPU::CPU_RUNNING); AlignCodePage(); dispatcher = GetCodePtr(); WARN_LOG(DYNA_REC, "Dispatcher is %p\n", dispatcher); - SetJumpTarget(to_dispatcher); - // Downcount Check // The result of slice decrementation should be in flags if somebody jumped here // IMPORTANT - We jump on negative, not carry!!! @@ -119,12 +129,6 @@ void JitArm64::GenerateAsm() STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); - MOVP2R(X30, &CoreTiming::Advance); - BLR(X30); - - // Load the PC back into DISPATCHER_PC (the exception handler might have changed it) - LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - // Check the state pointer to see if we are exiting // Gets checked on at the end of every slice MOVP2R(X0, CPU::GetStatePtr()); @@ -133,11 +137,17 @@ void JitArm64::GenerateAsm() CMP(W0, 0); FixupBranch Exit = B(CC_NEQ); - B(dispatcher); + SetJumpTarget(to_start_of_timing_slice); + MOVP2R(X30, &CoreTiming::Advance); + BLR(X30); + + // Load the PC back into DISPATCHER_PC (the exception handler might have changed it) + LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + + // We can safely assume that downcount >= 1 + B(dispatcherNoCheck); SetJumpTarget(Exit); - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - ABI_PopRegisters(regs_to_save); RET(X30);