Merge partially common register loads across basic blocks

This commit is contained in:
drmortalwombat 2024-07-13 20:44:49 +02:00
parent 5909db71d5
commit d3536a718e
2 changed files with 264 additions and 1 deletions

View File

@ -31818,6 +31818,246 @@ bool NativeCodeBasicBlock::ShortcutZeroPageCopyUp(NativeCodeProcedure* nproc)
return changed; return changed;
} }
bool NativeCodeBasicBlock::IsSameRegisterSource(const NativeCodeInstruction& rins) const
{
for (int i = mIns.Size() - 1; i >= 0; i--)
{
const NativeCodeInstruction& ins(mIns[i]);
if (rins.IsSame(ins))
return true;
if (rins.mType == ASMIT_LDY && ins.ChangesYReg())
return false;
if (rins.mType == ASMIT_LDX && ins.ChangesXReg())
return false;
if (rins.mType == ASMIT_LDA && ins.ChangesAccu())
return false;
if (rins.MayBeChangedOnAddress(ins))
return false;
}
if (mLoopHead || mEntryBlocks.Size() == 0)
return false;
for (int i = 0; i < mEntryBlocks.Size(); i++)
if (!mEntryBlocks[i]->IsSameRegisterSource(rins))
return false;
return true;
}
bool NativeCodeBasicBlock::FindInitialLoadA(NativeCodeInstruction *& ins)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
{
ins = &mIns[i];
return true;
}
}
if (mIns[i].ChangesAccu())
return false;
}
return false;
}
bool NativeCodeBasicBlock::FindInitialLoadX(NativeCodeInstruction *& ins)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDX && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
{
ins = &mIns[i];
return true;
}
}
if (mIns[i].ChangesXReg())
return false;
}
return false;
}
bool NativeCodeBasicBlock::FindInitialLoadY(NativeCodeInstruction *& ins)
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY && !(mIns[i].mLive & LIVE_CPU_REG_Z))
{
if (mIns[i].mMode == ASMIM_IMMEDIATE || mIns[i].mMode == ASMIM_IMMEDIATE_ADDRESS ||
mIns[i].mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(mIns[i].mAddress, 0, i))
{
ins = &mIns[i];
return true;
}
}
if (mIns[i].ChangesYReg())
return false;
}
return false;
}
bool NativeCodeBasicBlock::HoistCommonLoads(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mFalseJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1)
{
NativeCodeInstruction * tins = nullptr, * fins = nullptr;
if (!mExitRequiredRegs[CPU_REG_A] && mTrueJump->FindInitialLoadA(tins) && mFalseJump->FindInitialLoadA(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
{
int i = mIns.Size();
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
i--;
if (!ReferencesAccu(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
{
mIns.Insert(i, *tins);
tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (!mExitRequiredRegs[CPU_REG_X] && mTrueJump->FindInitialLoadX(tins) && mFalseJump->FindInitialLoadX(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
{
int i = mIns.Size();
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
i--;
if (!ReferencesXReg(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
{
mIns.Insert(i, *tins);
tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
changed = true;
}
}
if (!mExitRequiredRegs[CPU_REG_Y] && mTrueJump->FindInitialLoadY(tins) && mFalseJump->FindInitialLoadY(fins) && tins->IsSame(*fins) && !(tins->mFlags & NCIF_VOLATILE))
{
int i = mIns.Size();
while (i > 0 && (mIns[i - 1].mLive & LIVE_CPU_REG_Z))
i--;
if (!ReferencesYReg(i) && (i > 0 || !mEntryRequiredRegs[CPU_REG_Z]))
{
mIns.Insert(i, *tins);
tins->mType = ASMIT_NOP; tins->mMode = ASMIM_IMPLIED;
fins->mType = ASMIT_NOP; fins->mMode = ASMIM_IMPLIED;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->HoistCommonLoads())
changed = true;
if (mFalseJump && mFalseJump->HoistCommonLoads())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::PartialBackwardValuePropagation(void)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (!mLoopHead && mEntryBlocks.Size() > 1)
{
bool afail = mEntryRequiredRegs[CPU_REG_A];
bool xfail = mEntryRequiredRegs[CPU_REG_X];
bool yfail = mEntryRequiredRegs[CPU_REG_Y];
int i = 0;
while (i < mIns.Size() && !(afail && xfail && yfail))
{
NativeCodeInstruction& ins(mIns[i]);
if ((!yfail && ins.mType == ASMIT_LDY || !xfail && ins.mType == ASMIT_LDX || !afail && ins.mType == ASMIT_LDA)
&& (ins.mMode == ASMIM_IMMEDIATE || ins.mMode == ASMIM_IMMEDIATE_ADDRESS || ins.mMode == ASMIM_ZERO_PAGE)
&& !(ins.mLive & LIVE_CPU_REG_Z) && !(ins.mFlags & NCIF_VOLATILE))
{
if (ins.mMode != ASMIM_ZERO_PAGE || !ChangesZeroPage(ins.mAddress, 0, i))
{
int j = 0;
while (j < mEntryBlocks.Size() && !mEntryBlocks[j]->IsSameRegisterSource(ins))
j++;
if (j < mEntryBlocks.Size())
{
NativeCodeBasicBlock* pblock = mProc->AllocateBlock();
pblock->mEntryRequiredRegs = mEntryRequiredRegs;
pblock->mExitRequiredRegs = mEntryRequiredRegs;
pblock->mIns.Push(ins);
pblock->Close(ins.mIns, this, nullptr, ASMIT_JMP);
while (j > 0)
{
j--;
NativeCodeBasicBlock* eblock = mEntryBlocks[j];
mEntryBlocks.Remove(j);
mNumEntries--;
if (eblock->mTrueJump == this)
eblock->mTrueJump = pblock;
else if (eblock->mFalseJump == this)
eblock->mFalseJump = pblock;
pblock->mEntryBlocks.Push(eblock);
pblock->mNumEntries++;
}
j++;
while (j < mEntryBlocks.Size())
{
if (mEntryBlocks[j]->IsSameRegisterSource(ins))
j++;
else
{
NativeCodeBasicBlock* eblock = mEntryBlocks[j];
mEntryBlocks.Remove(j);
mNumEntries--;
if (eblock->mTrueJump == this)
eblock->mTrueJump = pblock;
else if (eblock->mFalseJump == this)
eblock->mFalseJump = pblock;
pblock->mEntryBlocks.Push(eblock);
pblock->mNumEntries++;
}
}
ins.mType = ASMIT_NOP;
ins.mMode = ASMIM_IMPLIED;
mEntryBlocks.Push(pblock);
mNumEntries++;
changed = true;
}
}
}
if (ins.ChangesYReg())
yfail = true;
if (ins.ChangesXReg())
xfail = true;
if (ins.ChangesAccu())
afail = true;
i++;
}
}
if (mTrueJump && mTrueJump->PartialBackwardValuePropagation())
changed = true;
if (mFalseJump && mFalseJump->PartialBackwardValuePropagation())
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::BackwardReplaceZeroPage(int at, int from, int to, bool diamond) bool NativeCodeBasicBlock::BackwardReplaceZeroPage(int at, int from, int to, bool diamond)
{ {
bool changed = false; bool changed = false;
@ -51217,6 +51457,21 @@ void NativeCodeProcedure::Optimize(void)
} }
} }
if (step == 18)
{
ResetVisited();
if (mEntryBlock->PartialBackwardValuePropagation())
changed = true;
if (!changed)
{
ResetVisited();
if (mEntryBlock->HoistCommonLoads())
changed = true;
}
}
#if _DEBUG #if _DEBUG
ResetVisited(); ResetVisited();
mEntryBlock->CheckAsmCode(); mEntryBlock->CheckAsmCode();
@ -51236,7 +51491,7 @@ void NativeCodeProcedure::Optimize(void)
} }
#if 1 #if 1
if (!changed && step < 17) if (!changed && step < 18)
{ {
ResetIndexFlipped(); ResetIndexFlipped();

View File

@ -630,6 +630,14 @@ public:
bool ShortcutZeroPageCopyUp(NativeCodeProcedure* nproc); bool ShortcutZeroPageCopyUp(NativeCodeProcedure* nproc);
bool BackwardReplaceZeroPage(int at, int from, int to, bool diamond); bool BackwardReplaceZeroPage(int at, int from, int to, bool diamond);
bool IsSameRegisterSource(const NativeCodeInstruction& rins) const;
bool PartialBackwardValuePropagation(void);
bool HoistCommonLoads(void);
bool FindInitialLoadA(NativeCodeInstruction *& ins);
bool FindInitialLoadX(NativeCodeInstruction *& ins);
bool FindInitialLoadY(NativeCodeInstruction *& ins);
NativeRegisterDataSet mEntryRegisterDataSet; NativeRegisterDataSet mEntryRegisterDataSet;
void BuildEntryDataSet(const NativeRegisterDataSet& set); void BuildEntryDataSet(const NativeRegisterDataSet& set);