Skip to content

Commit

Permalink
Merge pull request #1947 from Sonicadvance1/AArch64_tu_tl_merge
Browse files Browse the repository at this point in the history
[AArch64] Implement TU/TL merging.
  • Loading branch information
Sonicadvance1 committed Jan 26, 2015
2 parents 315f6dd + d291148 commit c340a32
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 29 deletions.
8 changes: 4 additions & 4 deletions Source/Core/Common/Arm64Emitter.cpp
Expand Up @@ -1010,9 +1010,9 @@ void ARM64XEmitter::SMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra)
{
EncodeData3SrcInst(3, Rd, Rn, Rm, Ra);
}
void ARM64XEmitter::SMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra)
void ARM64XEmitter::SMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
EncodeData3SrcInst(4, Rd, Rn, Rm, Ra);
EncodeData3SrcInst(4, Rd, Rn, Rm, SP);
}
void ARM64XEmitter::UMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra)
{
Expand All @@ -1022,9 +1022,9 @@ void ARM64XEmitter::UMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra)
{
EncodeData3SrcInst(6, Rd, Rn, Rm, Ra);
}
void ARM64XEmitter::UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra)
void ARM64XEmitter::UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
EncodeData3SrcInst(7, Rd, Rn, Rm, Ra);
EncodeData3SrcInst(7, Rd, Rn, Rm, SP);
}
void ARM64XEmitter::MUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Common/Arm64Emitter.h
Expand Up @@ -478,10 +478,10 @@ class ARM64XEmitter
void MSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void SMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void SMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void SMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void SMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void UMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void UMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra);
void UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void MUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
void MNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);

Expand Down
1 change: 0 additions & 1 deletion Source/Core/Core/PowerPC/Jit64/Jit.h
Expand Up @@ -115,7 +115,6 @@ class Jit64 : public Jitx86Base
void GenerateConstantOverflow(bool overflow);
void GenerateConstantOverflow(s64 val);
void GenerateOverflow();
bool MergeAllowedNextInstructions(int count);
void FinalizeCarryOverflow(bool oe, bool inv = false);
void FinalizeCarry(Gen::CCFlags cond);
void FinalizeCarry(bool ca);
Expand Down
16 changes: 0 additions & 16 deletions Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp
Expand Up @@ -50,22 +50,6 @@ void Jit64::GenerateOverflow()
SetJumpTarget(exit);
}

bool Jit64::MergeAllowedNextInstructions(int count)
{
if (PowerPC::GetState() == PowerPC::CPU_STEPPING || js.instructionsLeft < count)
return false;
// Be careful: a breakpoint kills flags in between instructions
for (int i = 1; i <= count; i++)
{
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging &&
PowerPC::breakpoints.IsAddressBreakPoint(js.op[i].address))
return false;
if (js.op[i].isBranchTarget)
return false;
}
return true;
}

void Jit64::FinalizeCarry(CCFlags cond)
{
js.carryFlagSet = false;
Expand Down
3 changes: 3 additions & 0 deletions Source/Core/Core/PowerPC/JitArm64/Jit.cpp
Expand Up @@ -320,6 +320,9 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB
BRK(0x666);
}
}

i += js.skipInstructions;
js.skipInstructions = 0;
}

if (code_block.m_memory_exception)
Expand Down
78 changes: 72 additions & 6 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
Expand Up @@ -203,12 +203,80 @@ void JitArm64::mfspr(UGeckoInstruction inst)
JITDISABLE(bJITSystemRegistersOff);

u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
int d = inst.RD;
switch (iIndex)
{
case SPR_TL:
case SPR_TU:
{
ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = EncodeRegTo64(WB);

// An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the
// cost of calling out to C for this is actually significant.
MOVI2R(XA, (u64)&CoreTiming::globalTimer);
LDR(INDEX_UNSIGNED, XA, XA, 0);
MOVI2R(XB, (u64)&CoreTiming::fakeTBStartTicks);
LDR(INDEX_UNSIGNED, XB, XB, 0);
SUB(XA, XA, XB);

// It might seem convenient to correct the timer for the block position here for even more accurate
// timing, but as of currently, this can break games. If we end up reading a time *after* the time
// at which an interrupt was supposed to occur, e.g. because we're 100 cycles into a block with only
// 50 downcount remaining, some games don't function correctly, such as Karaoke Party Revolution,
// which won't get past the loading screen.
// a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67
ORR(XB, SP, 1, 60);
ADD(XB, XB, 1);
UMULH(XA, XA, XB);

MOVI2R(XB, (u64)&CoreTiming::fakeTBStartValue);
LDR(INDEX_UNSIGNED, XB, XB, 0);
ADD(XA, XB, XA, ArithOption(XA, ST_LSR, 3));
STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(spr[SPR_TL]));

if (MergeAllowedNextInstructions(1))
{
const UGeckoInstruction& next = js.op[1].inst;
// Two calls of TU/TL next to each other are extremely common in typical usage, so merge them
// if we can.
u32 nextIndex = (next.SPRU << 5) | (next.SPRL & 0x1F);
// Be careful; the actual opcode is for mftb (371), not mfspr (339)
int n = next.RD;
if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && n != d)
{
js.downcountAmount++;
js.skipInstructions = 1;
gpr.BindToRegister(d, false);
gpr.BindToRegister(n, false);
if (iIndex == SPR_TL)
MOV(gpr.R(d), WA);
else
ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32));

if (nextIndex == SPR_TL)
MOV(gpr.R(n), WA);
else
ORR(EncodeRegTo64(gpr.R(n)), SP, XA, ArithOption(XA, ST_LSR, 32));

gpr.Unlock(WA, WB);
break;
}
}
gpr.BindToRegister(d, false);
if (iIndex == SPR_TU)
ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32));
else
MOV(gpr.R(d), WA);
gpr.Unlock(WA, WB);
}
break;
case SPR_XER:
{
gpr.BindToRegister(inst.RD, false);
ARM64Reg RD = gpr.R(inst.RD);
gpr.BindToRegister(d, false);
ARM64Reg RD = gpr.R(d);
ARM64Reg WA = gpr.GetReg();
LDRH(INDEX_UNSIGNED, RD, X29, PPCSTATE_OFF(xer_stringctrl));
LDRB(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(xer_ca));
Expand All @@ -220,12 +288,10 @@ void JitArm64::mfspr(UGeckoInstruction inst)
break;
case SPR_WPAR:
case SPR_DEC:
case SPR_TL:
case SPR_TU:
FALLBACK_IF(true);
default:
gpr.BindToRegister(inst.RD, false);
ARM64Reg RD = gpr.R(inst.RD);
gpr.BindToRegister(d, false);
ARM64Reg RD = gpr.R(d);
LDR(INDEX_UNSIGNED, RD, X29, PPCSTATE_OFF(spr) + iIndex * 4);
break;
}
Expand Down
16 changes: 16 additions & 0 deletions Source/Core/Core/PowerPC/JitCommon/JitBase.cpp
Expand Up @@ -66,3 +66,19 @@ void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer *code_buffer, const u8 *no
DEBUG_LOG(DYNA_REC,"IR_X86 bin: %s\n\n\n", ss.str().c_str());
}
}

bool JitBase::MergeAllowedNextInstructions(int count)
{
if (PowerPC::GetState() == PowerPC::CPU_STEPPING || js.instructionsLeft < count)
return false;
// Be careful: a breakpoint kills flags in between instructions
for (int i = 1; i <= count; i++)
{
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging &&
PowerPC::breakpoints.IsAddressBreakPoint(js.op[i].address))
return false;
if (js.op[i].isBranchTarget)
return false;
}
return true;
}
2 changes: 2 additions & 0 deletions Source/Core/Core/PowerPC/JitCommon/JitBase.h
Expand Up @@ -107,6 +107,8 @@ class JitBase : public CPUCoreBase
PPCAnalyst::CodeBlock code_block;
PPCAnalyst::PPCAnalyzer analyzer;

bool MergeAllowedNextInstructions(int count);

public:
// This should probably be removed from public:
JitOptions jo;
Expand Down

1 comment on commit c340a32

@Mullin
Copy link
Contributor

@Mullin Mullin commented on c340a32 Jan 28, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be easy port to Armv7, right ?

Please sign in to comment.