Optimize alternate XY cross block register use

This commit is contained in:
drmortalwombat 2023-02-05 12:30:18 +01:00
parent 932a65be8c
commit ff26dffada
2 changed files with 367 additions and 5 deletions

View File

@ -16094,6 +16094,23 @@ static bool ChangedOnPath(const NativeCodeBasicBlock* block, int start, int end,
return false; return false;
} }
static bool ChangesAccuOnPath(const NativeCodeBasicBlock* block, int start, int end)
{
for (int i = start; i < end; i++)
if (block->mIns[i].ChangesAccu())
return true;
return false;
}
static bool ReferencedsRegOnPath(const NativeCodeBasicBlock* block, int start, int end)
{
for (int i = start; i < end; i++)
if (block->mIns[i].ReferencesYReg())
return true;
return false;
}
void NativeCodeBasicBlock::PrependInstruction(const NativeCodeInstruction& ins) void NativeCodeBasicBlock::PrependInstruction(const NativeCodeInstruction& ins)
{ {
mIns.Insert(0, ins); mIns.Insert(0, ins);
@ -16160,6 +16177,42 @@ bool NativeCodeBasicBlock::PropagateSinglePath(void)
#if 1 #if 1
if (mTrueJump && mFalseJump && mTrueJump->mEntryProvidedRegs.Size() && mFalseJump->mEntryRequiredRegs.Size()) if (mTrueJump && mFalseJump && mTrueJump->mEntryProvidedRegs.Size() && mFalseJump->mEntryRequiredRegs.Size())
{ {
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A] && !mFalseJump->mEntryRequiredRegs[CPU_REG_A] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] ||
mFalseJump->mEntryRequiredRegs[CPU_REG_A] && !mTrueJump->mEntryRequiredRegs[CPU_REG_A] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
{
int i = mIns.Size();
while (i > 0 && !mIns[i - 1].ReferencesAccu())
i--;
if (i > 0 && (mIns[i - 1].mType == ASMIT_LDA || mIns[i - 1].mType == ASMIT_ORA || mIns[i - 1].mType == ASMIT_AND || mIns[i - 1].mType == ASMIT_EOR) && !(mIns[i - 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i - 1].mMode == ASMIM_IMMEDIATE || (mIns[i - 1].mMode == ASMIM_ZERO_PAGE && !ChangedOnPath(this, i, mIns.Size(), mIns[i - 1].mAddress)))
{
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
mTrueJump->PrependInstruction(mIns[i - 1]);
else
mFalseJump->PrependInstruction(mIns[i - 1]);
mIns.Remove(i - 1);
changed = true;
}
}
int sz = mIns.Size();
if (sz > 1 && mIns[sz - 1].mType == ASMIT_ASL && mIns[sz - 1].mMode == ASMIM_IMPLIED && (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_C] && mIns[sz - 2].ChangesAccuAndFlag())
{
if (mBranch == ASMIT_BCC)
mBranch = ASMIT_BPL;
else
mBranch = ASMIT_BMI;
if (mTrueJump->mEntryRequiredRegs[CPU_REG_A])
mTrueJump->PrependInstruction(mIns[sz - 1]);
else
mFalseJump->PrependInstruction(mIns[sz - 1]);
mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
mIns.Remove(sz - 1);
changed = true;
}
}
if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z]|| if (mTrueJump->mEntryRequiredRegs[CPU_REG_X] && !mFalseJump->mEntryRequiredRegs[CPU_REG_X] && mTrueJump->mNumEntries == 1 && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z]||
mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z]) mFalseJump->mEntryRequiredRegs[CPU_REG_X] && !mTrueJump->mEntryRequiredRegs[CPU_REG_X] && mFalseJump->mNumEntries == 1 && !mFalseJump->mEntryRequiredRegs[CPU_REG_Z])
{ {
@ -16197,6 +16250,15 @@ bool NativeCodeBasicBlock::PropagateSinglePath(void)
changed = true; changed = true;
} }
} }
else if (i > 0 && mIns[i - 1].mType == ASMIT_TAY && !(mIns[i - 1].mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_A)) && !ChangesAccuOnPath(this, i, mIns.Size()))
{
if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y])
mTrueJump->PrependInstruction(mIns[i - 1]);
else
mFalseJump->PrependInstruction(mIns[i - 1]);
mIns.Remove(i - 1);
changed = true;
}
} }
} }
#endif #endif
@ -17975,7 +18037,7 @@ bool NativeCodeBasicBlock::BypassRegisterConditionBlock(void)
mIns.Push(NativeCodeInstruction(ASMIT_STA, eblock->mIns[0])); mIns.Push(NativeCodeInstruction(ASMIT_STA, eblock->mIns[0]));
cblock->mIns.Remove(csz); cblock->mIns.Remove(csz);
cblock->mExitRequiredRegs -= CPU_REG_A; cblock->mExitRequiredRegs -= CPU_REG_A;
changed = true; changed = true;
} }
} }
#endif #endif
@ -18066,6 +18128,55 @@ bool NativeCodeBasicBlock::BypassRegisterConditionBlock(void)
} }
} }
} }
#if 1
CheckLive();
if (eblock->mIns.Size() > 0 && eblock->mIns[0].mType == ASMIT_LDY && eblock->mIns[0].mMode == ASMIM_ZERO_PAGE &&
!(eblock->mIns[0].mLive & LIVE_MEM) && !cblock->ReferencesYReg() && cblock->mIns.Size() > 0 && !mExitRequiredRegs[CPU_REG_Y])
{
NativeCodeInstruction& ins = cblock->mIns[cblock->mIns.Size() - 1];
if ((ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) && ins.SameEffectiveAddress(eblock->mIns[0]) && !ChangedOnPath(cblock, 0, cblock->mIns.Size() - 1, ins.mAddress))
{
int i = mIns.Size();
bool fail = false;
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i - 1].ReferencesYReg() || mIns[i - 1].ChangesZeroPage(ins.mAddress))
{
fail = true;
break;
}
i--;
}
if (!fail)
{
mIns.Insert(i, eblock->mIns[0]);
mIns[i].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_C;
eblock->mIns.Remove(0);
if (ins.mType == ASMIT_INC)
ins.mType = ASMIT_INY;
else if (ins.mType == ASMIT_DEC)
ins.mType = ASMIT_DEY;
ins.mMode = ASMIM_IMPLIED;
while (i < mIns.Size())
{
mIns[i].mLive |= LIVE_CPU_REG_Y;
i++;
}
for (i = 0; i < cblock->mIns.Size(); i++)
cblock->mIns[i].mLive |= LIVE_CPU_REG_Y;
changed = true;
CheckLive();
}
}
}
#endif
} }
} }
@ -18657,7 +18768,7 @@ bool NativeCodeBasicBlock::CheckCrossBlockXFloodExit(const NativeCodeBasicBlock*
} }
else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX) else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX)
{ {
return !(ins.mLive & LIVE_CPU_REG_Z); return !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_X));
} }
else else
return false; return false;
@ -18797,6 +18908,7 @@ bool NativeCodeBasicBlock::PatchCrossBlockXFlood(const NativeCodeBasicBlock* blo
else if (ins.mType == ASMIT_LDX) else if (ins.mType == ASMIT_LDX)
{ {
ins.mType = ASMIT_NOP; ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
return true; return true;
} }
} }
@ -18914,7 +19026,7 @@ bool NativeCodeBasicBlock::CheckCrossBlockYFloodExit(const NativeCodeBasicBlock*
} }
else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STY) else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STY)
{ {
return !(ins.mLive & LIVE_CPU_REG_Z); return !(ins.mLive & (LIVE_CPU_REG_Z | LIVE_CPU_REG_Y));
} }
else else
return false; return false;
@ -19054,6 +19166,7 @@ bool NativeCodeBasicBlock::PatchCrossBlockYFlood(const NativeCodeBasicBlock* blo
else if (ins.mType == ASMIT_LDY) else if (ins.mType == ASMIT_LDY)
{ {
ins.mType = ASMIT_NOP; ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
return true; return true;
} }
} }
@ -19076,6 +19189,206 @@ bool NativeCodeBasicBlock::PatchCrossBlockYFlood(const NativeCodeBasicBlock* blo
return changed; return changed;
} }
bool NativeCodeBasicBlock::CrossBlockY2XFlood(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY && HasAsmInstructionMode(ASMIT_LDX, mIns[i].mMode) && !(mIns[i].mLive & LIVE_CPU_REG_X))
{
proc->ResetPatched();
if (CheckCrossBlockY2XFlood(this, i + 1))
{
mIns[i].mType = ASMIT_LDX;
mIns[i].mLive |= LIVE_CPU_REG_X;
proc->ResetPatched();
if (PatchCrossBlockY2XFlood(this, i + 1))
{
changed = true;
}
}
}
}
if (mTrueJump && mTrueJump->CrossBlockY2XFlood(proc))
changed = true;
if (mFalseJump && mFalseJump->CrossBlockY2XFlood(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::CheckCrossBlockY2XFlood(const NativeCodeBasicBlock* block, int at)
{
if (at == 0 && this == block)
return false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[CPU_REG_Y])
return true;
if (mNumEntries > 1)
{
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockY2XFloodExit(block))
return false;
}
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y || ins.ReferencesXReg())
return false;
else if (!(ins.mLive & LIVE_CPU_REG_Y))
return true;
at++;
}
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockY2XFlood(block, 0))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockY2XFlood(block, 0))
return false;
}
return true;
}
bool NativeCodeBasicBlock::CheckCrossBlockY2XFloodExit(const NativeCodeBasicBlock* block)
{
if (!mPatchExit)
{
mPatchExit = true;
if (mTrueJump && !mTrueJump->CheckCrossBlockY2XFlood(block, 0))
return false;
if (mFalseJump && !mFalseJump->CheckCrossBlockY2XFlood(block, 0))
return false;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y || ins.ReferencesXReg())
return false;
else if (ins.mType == ASMIT_LDY || ins.mType == ASMIT_TAY)
return true;
at--;
}
mPatched = true;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->CheckCrossBlockY2XFloodExit(block))
return false;
}
return true;
}
bool NativeCodeBasicBlock::PatchCrossBlockY2XFlood(const NativeCodeBasicBlock* block, int at)
{
bool changed = false;
if (!mPatched)
{
mPatched = true;
if (at == 0)
{
if (!mEntryRequiredRegs[CPU_REG_Y])
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockY2XFloodExit(block))
changed = true;
mEntryRequiredRegs += CPU_REG_X;
}
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.ReplaceYRegWithXReg())
changed = true;
if (!(ins.mLive & LIVE_CPU_REG_Y))
return changed;
at++;
}
mPatchExit = true;
mExitRequiredRegs |= CPU_REG_X;
if (mTrueJump && mTrueJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::PatchCrossBlockY2XFloodExit(const NativeCodeBasicBlock* block)
{
bool changed = false;
if (!mPatchExit)
{
mPatchExit = true;
mExitRequiredRegs += CPU_REG_X;
if (mTrueJump && mTrueJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
if (mFalseJump && mFalseJump->PatchCrossBlockY2XFlood(block, 0))
changed = true;
int at = mIns.Size() - 1;
while (at >= 0)
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.ReplaceYRegWithXReg())
changed = true;
if (ins.mType == ASMIT_LDX || ins.mType == ASMIT_TAX)
return changed;
at--;
}
mPatched = true;
mEntryRequiredRegs += CPU_REG_X;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (mEntryBlocks[i]->PatchCrossBlockY2XFloodExit(block))
changed = true;
return changed;
}
return false;
}
bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) const bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) const
{ {
@ -29156,6 +29469,18 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 1] = ins; mIns[i + 1] = ins;
progress = true; progress = true;
} }
else if (mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_CPX && !(mIns[i + 1].mLive & LIVE_CPU_REG_X))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_CMP;
progress = true;
}
else if (mIns[i + 0].mType == ASMIT_TAY && mIns[i + 1].mType == ASMIT_CPY && !(mIns[i + 1].mLive & LIVE_CPU_REG_Y))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_CMP;
progress = true;
}
#endif #endif
else if ( else if (
mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED && mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
@ -33199,6 +33524,28 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
sz -= 2; sz -= 2;
CheckLive(); CheckLive();
} }
else if (pass >= 7 && sz >= 2 &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 2].mLive & LIVE_MEM) &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 1 && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C)) && !mExitRequiredRegs[CPU_REG_Z])
{
if (mBranch == ASMIT_BNE)
{
mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
mBranch = ASMIT_BCS;
mIns.SetSize(sz - 1);
changed = true;
}
else if (mBranch == ASMIT_BEQ)
{
mIns[sz - 2].mType = ASMIT_LSR; mIns[sz - 2].mLive |= LIVE_CPU_REG_C;
mBranch = ASMIT_BCC;
mIns.SetSize(sz - 1);
changed = true;
}
sz -= 1;
CheckLive();
}
if (sz >= 1 && if (sz >= 1 &&
mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) &&
@ -34471,7 +34818,7 @@ void NativeCodeProcedure::RebuildEntry(void)
void NativeCodeProcedure::Optimize(void) void NativeCodeProcedure::Optimize(void)
{ {
CheckFunc = !strcmp(mInterProc->mIdent->mString, "heapcheck"); CheckFunc = !strcmp(mInterProc->mIdent->mString, "builddop_src");
#if 1 #if 1
int step = 0; int step = 0;
@ -34972,6 +35319,15 @@ void NativeCodeProcedure::Optimize(void)
} }
#endif #endif
#if 1
if (step == 7)
{
ResetVisited();
if (mEntryBlock->CrossBlockY2XFlood(this))
changed = true;
}
#endif
#if 1 #if 1
if (step >= 6) if (step >= 6)
{ {
@ -35004,6 +35360,7 @@ void NativeCodeProcedure::Optimize(void)
mGenerator->mErrors->Error(mInterProc->mLocation, EWARN_OPTIMIZER_LOCKED, "Optimizer locked in infinite loop", mInterProc->mIdent); mGenerator->mErrors->Error(mInterProc->mLocation, EWARN_OPTIMIZER_LOCKED, "Optimizer locked in infinite loop", mInterProc->mIdent);
} }
#if 1 #if 1
if (!changed && step < 9) if (!changed && step < 9)
{ {
@ -35016,7 +35373,6 @@ void NativeCodeProcedure::Optimize(void)
else else
cnt++; cnt++;
} while (changed); } while (changed);
#if 1 #if 1

View File

@ -514,6 +514,12 @@ public:
bool PatchCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at); bool PatchCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at);
bool PatchCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg); bool PatchCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg);
bool CrossBlockY2XFlood(NativeCodeProcedure* proc);
bool CheckCrossBlockY2XFlood(const NativeCodeBasicBlock* block, int at);
bool CheckCrossBlockY2XFloodExit(const NativeCodeBasicBlock* block);
bool PatchCrossBlockY2XFlood(const NativeCodeBasicBlock* block, int at);
bool PatchCrossBlockY2XFloodExit(const NativeCodeBasicBlock* block);
bool IsDominatedBy(const NativeCodeBasicBlock* block) const; bool IsDominatedBy(const NativeCodeBasicBlock* block) const;
void CheckLive(void); void CheckLive(void);