Improve loop register allocation
This commit is contained in:
parent
d070e32b4d
commit
bf89d7af33
|
@ -17667,7 +17667,7 @@ static bool IsSimilarLea(InterInstruction* ins0, InterInstruction* ins1)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InterCodeBasicBlock::ShortLeaMerge(void)
|
bool InterCodeBasicBlock::ShortLeaMerge(int& spareTemps)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
|
@ -17735,6 +17735,26 @@ bool InterCodeBasicBlock::ShortLeaMerge(void)
|
||||||
mInstructions.Insert(0, iins[0]->Clone());
|
mInstructions.Insert(0, iins[0]->Clone());
|
||||||
iins[0]->mSrc[1].mIntConst = minint;
|
iins[0]->mSrc[1].mIntConst = minint;
|
||||||
|
|
||||||
|
if (iins[0]->mSrc[0].mTemp < 0)
|
||||||
|
{
|
||||||
|
if (spareTemps + 2 >= mEntryRequiredTemps.Size() + 16)
|
||||||
|
return true;
|
||||||
|
int ttemp = spareTemps++;
|
||||||
|
mInstructions[0]->mSrc[0].mTemp = ttemp;
|
||||||
|
mInstructions[0]->mSrc[0].mType = IT_INT16;
|
||||||
|
|
||||||
|
for (int k = 0; k < mEntryBlocks.Size(); k++)
|
||||||
|
{
|
||||||
|
InterInstruction* sins = iins[k];
|
||||||
|
sins->mCode = IC_CONSTANT;
|
||||||
|
sins->mDst = mInstructions[0]->mSrc[0];
|
||||||
|
sins->mConst = sins->mSrc[0];
|
||||||
|
sins->mConst.mIntConst -= minint;
|
||||||
|
sins->mNumOperands = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
for (int k = 0; k < mEntryBlocks.Size(); k++)
|
for (int k = 0; k < mEntryBlocks.Size(); k++)
|
||||||
{
|
{
|
||||||
InterInstruction* sins = iins[k];
|
InterInstruction* sins = iins[k];
|
||||||
|
@ -17747,6 +17767,7 @@ bool InterCodeBasicBlock::ShortLeaMerge(void)
|
||||||
sins->mDst.mRange.mMaxValue += sins->mSrc[1].mIntConst;
|
sins->mDst.mRange.mMaxValue += sins->mSrc[1].mIntConst;
|
||||||
mEntryBlocks[k]->mExitRequiredTemps += sins->mDst.mTemp;
|
mEntryBlocks[k]->mExitRequiredTemps += sins->mDst.mTemp;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -17756,8 +17777,8 @@ bool InterCodeBasicBlock::ShortLeaMerge(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTrueJump && mTrueJump->ShortLeaMerge()) changed = true;
|
if (mTrueJump && mTrueJump->ShortLeaMerge(spareTemps)) changed = true;
|
||||||
if (mFalseJump && mFalseJump->ShortLeaMerge()) changed = true;
|
if (mFalseJump && mFalseJump->ShortLeaMerge(spareTemps)) changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -22076,7 +22097,7 @@ void InterCodeProcedure::Close(void)
|
||||||
|
|
||||||
CheckBlocks();
|
CheckBlocks();
|
||||||
|
|
||||||
MergeBasicBlocks();
|
MergeBasicBlocks(activeSet);
|
||||||
|
|
||||||
CheckBlocks();
|
CheckBlocks();
|
||||||
|
|
||||||
|
@ -22168,7 +22189,7 @@ void InterCodeProcedure::Close(void)
|
||||||
|
|
||||||
// Optimize for size
|
// Optimize for size
|
||||||
|
|
||||||
MergeBasicBlocks();
|
MergeBasicBlocks(activeSet);
|
||||||
BuildTraces(false, false, true);
|
BuildTraces(false, false, true);
|
||||||
DisassembleDebug("Final Merged basic blocks");
|
DisassembleDebug("Final Merged basic blocks");
|
||||||
|
|
||||||
|
@ -22541,15 +22562,44 @@ bool PartitionSameExitCode(GrowingArray<InterCodeBasicBlock* > & eblocks, Growin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterCodeProcedure::ShortLeaMerge(void)
|
bool InterCodeProcedure::ShortLeaMerge(FastNumberSet& activeSet)
|
||||||
{
|
{
|
||||||
ResetVisited();
|
int silvused = mTemporaries.Size();
|
||||||
mEntryBlock->ShortLeaMerge();
|
|
||||||
|
|
||||||
DisassembleDebug("ShortLeaMerge");
|
int n = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ResetEntryBlocks();
|
||||||
|
ResetVisited();
|
||||||
|
mEntryBlock->CollectEntryBlocks(nullptr);
|
||||||
|
|
||||||
|
n++;
|
||||||
|
if (silvused != mTemporaries.Size())
|
||||||
|
{
|
||||||
|
mTemporaries.SetSize(activeSet.Num(), true);
|
||||||
|
|
||||||
|
ResetVisited();
|
||||||
|
mEntryBlock->ShrinkActiveTemporaries(activeSet, mTemporaries);
|
||||||
|
|
||||||
|
mLocalValueRange.SetSize(activeSet.Num(), true);
|
||||||
|
|
||||||
|
ResetVisited();
|
||||||
|
mEntryBlock->RemapActiveTemporaries(activeSet);
|
||||||
|
|
||||||
|
silvused = mTemporaries.Size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterCodeProcedure::MergeBasicBlocks(void)
|
ResetVisited();
|
||||||
|
} while (mEntryBlock->ShortLeaMerge(silvused));
|
||||||
|
|
||||||
|
assert(silvused == mTemporaries.Size());
|
||||||
|
|
||||||
|
DisassembleDebug("ShortLeaMerge");
|
||||||
|
|
||||||
|
return n > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterCodeProcedure::MergeBasicBlocks(FastNumberSet& activeSet)
|
||||||
{
|
{
|
||||||
ResetVisited();
|
ResetVisited();
|
||||||
mEntryBlock->FollowJumps();
|
mEntryBlock->FollowJumps();
|
||||||
|
@ -22708,13 +22758,13 @@ void InterCodeProcedure::MergeBasicBlocks(void)
|
||||||
if (!changed)
|
if (!changed)
|
||||||
{
|
{
|
||||||
ResetVisited();
|
ResetVisited();
|
||||||
changed = mEntryBlock->ShortLeaMerge();
|
mEntryBlock->FollowJumps();
|
||||||
|
|
||||||
|
changed = ShortLeaMerge(activeSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (changed);
|
} while (changed);
|
||||||
|
|
||||||
ResetVisited();
|
|
||||||
mEntryBlock->FollowJumps();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -567,6 +567,7 @@ public:
|
||||||
bool IsInsModifiedInRange(int from, int to, const InterInstruction* ins);
|
bool IsInsModifiedInRange(int from, int to, const InterInstruction* ins);
|
||||||
|
|
||||||
InterInstruction* FindTempOrigin(int temp) const;
|
InterInstruction* FindTempOrigin(int temp) const;
|
||||||
|
InterInstruction* FindTempOriginSinglePath(int temp) const;
|
||||||
|
|
||||||
bool CheapInlining(int & numTemps);
|
bool CheapInlining(int & numTemps);
|
||||||
bool CollapseDispatch();
|
bool CollapseDispatch();
|
||||||
|
@ -617,7 +618,7 @@ public:
|
||||||
void SplitBranches(void);
|
void SplitBranches(void);
|
||||||
void FollowJumps(void);
|
void FollowJumps(void);
|
||||||
|
|
||||||
bool ShortLeaMerge(void);
|
bool ShortLeaMerge(int& spareTemps);
|
||||||
|
|
||||||
bool IsEqual(const InterCodeBasicBlock* block) const;
|
bool IsEqual(const InterCodeBasicBlock* block) const;
|
||||||
|
|
||||||
|
@ -745,9 +746,9 @@ protected:
|
||||||
void RecheckLocalAliased(void);
|
void RecheckLocalAliased(void);
|
||||||
void ConstLoopOptimization(void);
|
void ConstLoopOptimization(void);
|
||||||
|
|
||||||
void ShortLeaMerge(void);
|
bool ShortLeaMerge(FastNumberSet& activeSet);
|
||||||
|
|
||||||
void MergeBasicBlocks(void);
|
void MergeBasicBlocks(FastNumberSet& activeSet);
|
||||||
void CheckUsedDefinedTemps(void);
|
void CheckUsedDefinedTemps(void);
|
||||||
void WarnUsedUndefinedVariables(void);
|
void WarnUsedUndefinedVariables(void);
|
||||||
void WarnInvalidValueRanges(void);
|
void WarnInvalidValueRanges(void);
|
||||||
|
|
|
@ -4344,9 +4344,9 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT
|
||||||
{
|
{
|
||||||
mType = ASMIT_NOP;
|
mType = ASMIT_NOP;
|
||||||
mMode = ASMIM_IMPLIED;
|
mMode = ASMIM_IMPLIED;
|
||||||
}
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
|
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
|
||||||
{
|
{
|
||||||
mType = ASMIT_TAY;
|
mType = ASMIT_TAY;
|
||||||
|
@ -4400,9 +4400,9 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT
|
||||||
{
|
{
|
||||||
mType = ASMIT_NOP;
|
mType = ASMIT_NOP;
|
||||||
mMode = ASMIM_IMPLIED;
|
mMode = ASMIM_IMPLIED;
|
||||||
}
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
|
else if (final && data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE && data.mRegs[CPU_REG_A].mLinkerObject == mLinkerObject && data.mRegs[CPU_REG_A].mValue == mAddress)
|
||||||
{
|
{
|
||||||
mType = ASMIT_TAX;
|
mType = ASMIT_TAX;
|
||||||
|
@ -18841,7 +18841,7 @@ bool NativeCodeBasicBlock::Expand16BitLoopBranch(void)
|
||||||
if (mTrueJump && mFalseJump && mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
|
if (mTrueJump && mFalseJump && mBranch == ASMIT_BNE && mTrueJump->mIns.Size() == 0 && mTrueJump->mBranch == ASMIT_BCC)
|
||||||
{
|
{
|
||||||
int sz = mIns.Size();
|
int sz = mIns.Size();
|
||||||
if (sz >= 1 && mIns[sz - 1].mType == ASMIT_CMP)
|
if (sz >= 1 && (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY))
|
||||||
{
|
{
|
||||||
if (mTrueJump->mTrueJump->mLoopHead && IsDominatedBy(mTrueJump->mTrueJump) ||
|
if (mTrueJump->mTrueJump->mLoopHead && IsDominatedBy(mTrueJump->mTrueJump) ||
|
||||||
mLoopHead && !mTrueJump->mTrueJump->mFalseJump && mTrueJump->mTrueJump->mTrueJump == this)
|
mLoopHead && !mTrueJump->mTrueJump->mFalseJump && mTrueJump->mTrueJump->mTrueJump == this)
|
||||||
|
@ -21318,6 +21318,303 @@ bool NativeCodeBasicBlock::LocalRegisterXYMap(void)
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NativeCodeBasicBlock::LoopRegisterXYMap(void)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (!mVisited)
|
||||||
|
{
|
||||||
|
mVisited = true;
|
||||||
|
|
||||||
|
if (mLoopHead && mEntryBlocks.Size() > 1)
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* pblock = nullptr;
|
||||||
|
ExpandingArray<NativeCodeBasicBlock*> lblocks, pblocks, eblocks;
|
||||||
|
|
||||||
|
bool addprefix = false;
|
||||||
|
for (int i = 0; i < mEntryBlocks.Size(); i++)
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* b = mEntryBlocks[i];
|
||||||
|
|
||||||
|
if (b == this || b->IsDominatedBy(this))
|
||||||
|
lblocks.Push(b);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (b->mFalseJump)
|
||||||
|
addprefix = true;
|
||||||
|
pblocks.Push(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lblocks.Size() > 0)
|
||||||
|
{
|
||||||
|
if (pblocks.Size() > 1 || addprefix)
|
||||||
|
{
|
||||||
|
pblock = mProc->AllocateBlock();
|
||||||
|
pblock->mEntryRequiredRegs = mEntryRequiredRegs;
|
||||||
|
pblock->mExitRequiredRegs = mExitRequiredRegs;
|
||||||
|
pblock->Close(pblocks[0]->mBranchIns, this, nullptr, ASMIT_JMP);
|
||||||
|
AddEntryBlock(pblock);
|
||||||
|
for (int i = 0; i < pblocks.Size(); i++)
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* b = pblocks[i];
|
||||||
|
if (this == b->mTrueJump)
|
||||||
|
{
|
||||||
|
b->mTrueJump = pblock;
|
||||||
|
RemEntryBlock(b);
|
||||||
|
pblock->AddEntryBlock(b);
|
||||||
|
}
|
||||||
|
if (this == b->mFalseJump)
|
||||||
|
{
|
||||||
|
b->mFalseJump = pblock;
|
||||||
|
RemEntryBlock(b);
|
||||||
|
pblock->AddEntryBlock(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pblocks.Size() == 1)
|
||||||
|
pblock = pblocks[0];
|
||||||
|
|
||||||
|
if (pblock && lblocks.Size() + 1 == mEntryBlocks.Size())
|
||||||
|
{
|
||||||
|
mProc->ResetPatched();
|
||||||
|
mPatched = true;
|
||||||
|
|
||||||
|
if (!lblocks.Contains(this))
|
||||||
|
lblocks.Push(this);
|
||||||
|
|
||||||
|
for (int i = 0; i < lblocks.Size(); i++)
|
||||||
|
lblocks[i]->mPatched = true;
|
||||||
|
pblock->mPatched = true;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i < lblocks.Size())
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* block = lblocks[i];
|
||||||
|
for (int j = 0; j < block->mEntryBlocks.Size(); j++)
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* cblock = block->mEntryBlocks[j];
|
||||||
|
if (!cblock->mPatched)
|
||||||
|
{
|
||||||
|
cblock->mPatched = true;
|
||||||
|
lblocks.Push(cblock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inner = true;
|
||||||
|
|
||||||
|
NativeCodeBasicBlock* eblock = nullptr;
|
||||||
|
i = 0;
|
||||||
|
while (i < lblocks.Size())
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* b = lblocks[i];
|
||||||
|
if (b->mLoopHead && b != this)
|
||||||
|
{
|
||||||
|
inner = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b->mFalseJump && !(lblocks.Contains(b->mFalseJump) && lblocks.Contains(b->mTrueJump)))
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* eblock = lblocks.Contains(b->mFalseJump) ? b->mTrueJump : b->mFalseJump;
|
||||||
|
if (eblock->mEntryBlocks.Size() > 1)
|
||||||
|
{
|
||||||
|
int k = 0;
|
||||||
|
while (k < eblock->mEntryBlocks.Size() && lblocks.Contains(eblock->mEntryBlocks[k]))
|
||||||
|
k++;
|
||||||
|
|
||||||
|
if (k != eblock->mEntryBlocks.Size())
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* eb = mProc->AllocateBlock();
|
||||||
|
eb->mEntryRequiredRegs = eblock->mEntryRequiredRegs;
|
||||||
|
eb->mExitRequiredRegs = eblock->mEntryRequiredRegs;
|
||||||
|
eb->Close(eblock->mBranchIns, eblock, nullptr, ASMIT_JMP);
|
||||||
|
eb->AddEntryBlock(b);
|
||||||
|
eblock->AddEntryBlock(eb);
|
||||||
|
eblock->RemEntryBlock(b);
|
||||||
|
if (b->mFalseJump == eblock)
|
||||||
|
b->mFalseJump = eb;
|
||||||
|
else
|
||||||
|
b->mTrueJump = eb;
|
||||||
|
eblocks.Push(eb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
eblocks.Push(eblock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
eblocks.Push(eblock);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inner && eblocks.Size() > 0)
|
||||||
|
{
|
||||||
|
bool xfree = !mEntryRequiredRegs[CPU_REG_X], yfree = !mEntryRequiredRegs[CPU_REG_Y];
|
||||||
|
|
||||||
|
if (xfree || yfree)
|
||||||
|
{
|
||||||
|
int iregs[256];
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
iregs[i] = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < lblocks.Size(); i++)
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* b(lblocks[i]);
|
||||||
|
|
||||||
|
for (int j = 0; j < b->mIns.Size(); j++)
|
||||||
|
{
|
||||||
|
const NativeCodeInstruction& ins(b->mIns[j]);
|
||||||
|
|
||||||
|
if (ins.ReferencesXReg() || ins.ChangesXReg())
|
||||||
|
xfree = false;
|
||||||
|
if (ins.ReferencesYReg() || ins.ChangesYReg())
|
||||||
|
yfree = false;
|
||||||
|
if (ins.mMode == ASMIM_INDIRECT_Y)
|
||||||
|
{
|
||||||
|
iregs[ins.mAddress + 0] = -1;
|
||||||
|
iregs[ins.mAddress + 1] = -1;
|
||||||
|
}
|
||||||
|
else if (ins.mMode == ASMIM_ZERO_PAGE && iregs[ins.mAddress] >= 0)
|
||||||
|
{
|
||||||
|
if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC)
|
||||||
|
iregs[ins.mAddress] += 5;
|
||||||
|
else if (ins.mType == ASMIT_LDA || ins.mType == ASMIT_STA)
|
||||||
|
iregs[ins.mAddress] += 3;
|
||||||
|
else if (ins.IsCommutative() && j > 0 && b->mIns[j - 1].mType == ASMIT_LDA && (b->mIns[j - 1].mMode == ASMIM_IMMEDIATE || b->mIns[j - 1].mMode == ASMIM_IMMEDIATE_ADDRESS))
|
||||||
|
iregs[ins.mAddress] += 3;
|
||||||
|
else
|
||||||
|
iregs[ins.mAddress] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xfree || yfree)
|
||||||
|
{
|
||||||
|
int mini = 0;
|
||||||
|
int mina = 3;
|
||||||
|
for (int i = 1; i < 256; i++)
|
||||||
|
{
|
||||||
|
if (iregs[i] > mina)
|
||||||
|
{
|
||||||
|
mina = iregs[i];
|
||||||
|
mini = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mini > 0)
|
||||||
|
{
|
||||||
|
if (xfree)
|
||||||
|
{
|
||||||
|
pblock->mIns.Push(NativeCodeInstruction(pblock->mBranchIns, ASMIT_LDX, ASMIM_ZERO_PAGE, mini));
|
||||||
|
pblock->mExitRequiredRegs += CPU_REG_X;
|
||||||
|
for (int i = 0; i < eblocks.Size(); i++)
|
||||||
|
{
|
||||||
|
eblocks[i]->mIns.Insert(0, NativeCodeInstruction(pblock->mBranchIns, ASMIT_STX, ASMIM_ZERO_PAGE, mini));
|
||||||
|
eblocks[i]->mEntryRequiredRegs += CPU_REG_X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pblock->mIns.Push(NativeCodeInstruction(pblock->mBranchIns, ASMIT_LDY, ASMIM_ZERO_PAGE, mini));
|
||||||
|
pblock->mExitRequiredRegs += CPU_REG_Y;
|
||||||
|
for (int i = 0; i < eblocks.Size(); i++)
|
||||||
|
{
|
||||||
|
eblocks[i]->mIns.Insert(0, NativeCodeInstruction(pblock->mBranchIns, ASMIT_STY, ASMIM_ZERO_PAGE, mini));
|
||||||
|
eblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < lblocks.Size(); i++)
|
||||||
|
{
|
||||||
|
NativeCodeBasicBlock* b(lblocks[i]);
|
||||||
|
|
||||||
|
if (xfree)
|
||||||
|
{
|
||||||
|
b->mEntryRequiredRegs += CPU_REG_X;
|
||||||
|
b->mExitRequiredRegs += CPU_REG_X;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b->mEntryRequiredRegs += CPU_REG_Y;
|
||||||
|
b->mExitRequiredRegs += CPU_REG_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < b->mIns.Size(); j++)
|
||||||
|
{
|
||||||
|
NativeCodeInstruction& ins(b->mIns[j]);
|
||||||
|
|
||||||
|
if (xfree)
|
||||||
|
ins.mLive |= LIVE_CPU_REG_X;
|
||||||
|
else
|
||||||
|
ins.mLive |= LIVE_CPU_REG_Y;
|
||||||
|
|
||||||
|
if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == mini)
|
||||||
|
{
|
||||||
|
if (ins.IsCommutative())
|
||||||
|
{
|
||||||
|
ins.CopyMode(b->mIns[j - 1]);
|
||||||
|
if (xfree)
|
||||||
|
b->mIns[j - 1].mType = ASMIT_TXA;
|
||||||
|
else
|
||||||
|
b->mIns[j - 1].mType = ASMIT_TYA;
|
||||||
|
b->mIns[j - 1].mMode = ASMIM_IMPLIED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (ins.mType)
|
||||||
|
{
|
||||||
|
case ASMIT_INC:
|
||||||
|
if (xfree)
|
||||||
|
ins.mType = ASMIT_INX;
|
||||||
|
else
|
||||||
|
ins.mType = ASMIT_INY;
|
||||||
|
ins.mMode = ASMIM_IMPLIED;
|
||||||
|
break;
|
||||||
|
case ASMIT_DEC:
|
||||||
|
if (xfree)
|
||||||
|
ins.mType = ASMIT_DEX;
|
||||||
|
else
|
||||||
|
ins.mType = ASMIT_DEY;
|
||||||
|
ins.mMode = ASMIM_IMPLIED;
|
||||||
|
break;
|
||||||
|
case ASMIT_LDA:
|
||||||
|
if (xfree)
|
||||||
|
ins.mType = ASMIT_TXA;
|
||||||
|
else
|
||||||
|
ins.mType = ASMIT_TYA;
|
||||||
|
ins.mMode = ASMIM_IMPLIED;
|
||||||
|
break;
|
||||||
|
case ASMIT_STA:
|
||||||
|
if (xfree)
|
||||||
|
ins.mType = ASMIT_TAX;
|
||||||
|
else
|
||||||
|
ins.mType = ASMIT_TAY;
|
||||||
|
ins.mMode = ASMIM_IMPLIED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTrueJump && mTrueJump->LoopRegisterXYMap()) changed = true;
|
||||||
|
if (mFalseJump && mFalseJump->LoopRegisterXYMap()) changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
void NativeCodeBasicBlock::GlobalRegisterXYCheck(int* xregs, int* yregs)
|
void NativeCodeBasicBlock::GlobalRegisterXYCheck(int* xregs, int* yregs)
|
||||||
{
|
{
|
||||||
if (!mVisited)
|
if (!mVisited)
|
||||||
|
@ -23206,6 +23503,9 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
CheckLive();
|
||||||
|
|
||||||
while (eb->mIns.Size() > 0)
|
while (eb->mIns.Size() > 0)
|
||||||
{
|
{
|
||||||
int addr, index, taddr, tindex;
|
int addr, index, taddr, tindex;
|
||||||
|
@ -23365,6 +23665,9 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
CheckLive();
|
||||||
|
|
||||||
if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]))
|
if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X]))
|
||||||
{
|
{
|
||||||
for (int i = eb->mIns.Size() - 1; i > 0; i--)
|
for (int i = eb->mIns.Size() - 1; i > 0; i--)
|
||||||
|
@ -23396,6 +23699,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (changed)
|
||||||
|
CheckLive();
|
||||||
}
|
}
|
||||||
#if 1
|
#if 1
|
||||||
if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X] || !mEntryRequiredRegs[CPU_REG_Y]))
|
if (!changed && !mEntryRequiredRegs[CPU_REG_Z] && (!mEntryRequiredRegs[CPU_REG_A] || !mEntryRequiredRegs[CPU_REG_X] || !mEntryRequiredRegs[CPU_REG_Y]))
|
||||||
|
@ -23440,6 +23745,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (changed)
|
||||||
|
CheckLive();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -23481,6 +23788,8 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckLive();
|
||||||
|
|
||||||
if (mEntryBlocks.Size() > 2)
|
if (mEntryBlocks.Size() > 2)
|
||||||
{
|
{
|
||||||
NativeCodeBasicBlock* nblock = SplitMatchingTails(proc);
|
NativeCodeBasicBlock* nblock = SplitMatchingTails(proc);
|
||||||
|
@ -27650,6 +27959,44 @@ bool NativeCodeBasicBlock::PatchCrossBlockY2XFloodExit(const NativeCodeBasicBloc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeCodeBasicBlock::PropagateAddGlobalCarry(void)
|
||||||
|
{
|
||||||
|
if (!mVisited)
|
||||||
|
{
|
||||||
|
mVisited = true;
|
||||||
|
|
||||||
|
// Accessing memory outside of a global array is undefined behaviour, so
|
||||||
|
// if we find an indirect memory access and the pointer arithmetic for the
|
||||||
|
// upper byte included an immediate address without an offset, the carry
|
||||||
|
// must be clear
|
||||||
|
|
||||||
|
for (int i = 0; i < mIns.Size(); i++)
|
||||||
|
{
|
||||||
|
if (mIns[i].mMode == ASMIM_INDIRECT_Y)
|
||||||
|
{
|
||||||
|
int j = i - 1;
|
||||||
|
while (j > 0 && !(mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[i].mAddress + 1 && mIns[j].ChangesAddress()))
|
||||||
|
j--;
|
||||||
|
if (j > 0 &&
|
||||||
|
mIns[j].mType == ASMIT_STA &&
|
||||||
|
mIns[j - 1].mType == ASMIT_ADC &&
|
||||||
|
mIns[j - 1].mMode == ASMIM_IMMEDIATE_ADDRESS &&
|
||||||
|
(mIns[j - 1].mFlags & NCIF_UPPER) &&
|
||||||
|
mIns[j - 1].mAddress == 0)
|
||||||
|
{
|
||||||
|
while (j < mIns.Size() && !mIns[j].ChangesCarry())
|
||||||
|
j++;
|
||||||
|
if (j < mIns.Size() && mIns[j].mType == ASMIT_CLC)
|
||||||
|
mIns[j].mType = ASMIT_NOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTrueJump) mTrueJump->PropagateAddGlobalCarry();
|
||||||
|
if (mFalseJump) mFalseJump->PropagateAddGlobalCarry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NativeCodeBasicBlock::PropagateZPAbsolute(const NativeRegisterDataSet& data)
|
void NativeCodeBasicBlock::PropagateZPAbsolute(const NativeRegisterDataSet& data)
|
||||||
{
|
{
|
||||||
if (!mVisited)
|
if (!mVisited)
|
||||||
|
@ -34408,6 +34755,8 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pblocks.Size() < mEntryBlocks.Size())
|
||||||
|
{
|
||||||
if (pblocks.Size() > 1 || addprefix)
|
if (pblocks.Size() > 1 || addprefix)
|
||||||
{
|
{
|
||||||
pblock = mProc->AllocateBlock();
|
pblock = mProc->AllocateBlock();
|
||||||
|
@ -34434,12 +34783,16 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
|
||||||
}
|
}
|
||||||
else if (pblocks.Size() == 1)
|
else if (pblocks.Size() == 1)
|
||||||
pblock = pblocks[0];
|
pblock = pblocks[0];
|
||||||
|
}
|
||||||
|
|
||||||
if (pblock && lblocks.Size() + 1 == mEntryBlocks.Size())
|
if (pblock && lblocks.Size() + 1 == mEntryBlocks.Size())
|
||||||
{
|
{
|
||||||
proc->ResetPatched();
|
proc->ResetPatched();
|
||||||
mPatched = true;
|
mPatched = true;
|
||||||
|
|
||||||
|
if (!lblocks.Contains(this))
|
||||||
|
lblocks.Push(this);
|
||||||
|
|
||||||
for (int i = 0; i < lblocks.Size(); i++)
|
for (int i = 0; i < lblocks.Size(); i++)
|
||||||
lblocks[i]->mPatched = true;
|
lblocks[i]->mPatched = true;
|
||||||
pblock->mPatched = true;
|
pblock->mPatched = true;
|
||||||
|
@ -34465,7 +34818,8 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
|
||||||
while (i < lblocks.Size())
|
while (i < lblocks.Size())
|
||||||
{
|
{
|
||||||
NativeCodeBasicBlock* b = lblocks[i];
|
NativeCodeBasicBlock* b = lblocks[i];
|
||||||
if (b->mFalseJump && !(lblocks.Contains(b->mFalseJump) || lblocks.Contains(b->mTrueJump)))
|
// !FIXME should be &&
|
||||||
|
if (b->mFalseJump && !(lblocks.Contains(b->mFalseJump) && lblocks.Contains(b->mTrueJump)))
|
||||||
{
|
{
|
||||||
if (eblock)
|
if (eblock)
|
||||||
{
|
{
|
||||||
|
@ -37662,7 +38016,7 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoopInvariant(NativeCodeProcedure*
|
||||||
i++;
|
i++;
|
||||||
if (i == lblocks.Size())
|
if (i == lblocks.Size())
|
||||||
{
|
{
|
||||||
if (this == tail->mTrueJump)
|
if (lblocks.Contains(tail->mTrueJump))
|
||||||
{
|
{
|
||||||
tail->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
|
tail->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
|
||||||
tail->mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
|
tail->mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
|
||||||
|
@ -37693,6 +38047,71 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoopInvariant(NativeCodeProcedure*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
{
|
||||||
|
if (mIns.Size() > 0 && mIns[0].mType == ASMIT_LDY && mIns[0].mMode == ASMIM_ZERO_PAGE)
|
||||||
|
{
|
||||||
|
int k = 1;
|
||||||
|
while (k < mIns.Size() && !(mIns[k].mMode == ASMIM_ZERO_PAGE && mIns[k].mAddress == mIns[0].mAddress))
|
||||||
|
k++;
|
||||||
|
|
||||||
|
if (k < mIns.Size() && !ChangesYReg(1) &&
|
||||||
|
!ReferencesZeroPage(mIns[0].mAddress, 1, k) &&
|
||||||
|
!ReferencesZeroPage(mIns[0].mAddress, k + 1) &&
|
||||||
|
(mIns[k].mType == ASMIT_INC || mIns[k].mType == ASMIT_DEC))
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (i < lblocks.Size() && (lblocks[i] == this || (!lblocks[i]->ChangesYReg() && !lblocks[i]->ReferencesZeroPage(mIns[0].mAddress))))
|
||||||
|
i++;
|
||||||
|
if (i == lblocks.Size())
|
||||||
|
{
|
||||||
|
AsmInsType it, nit;
|
||||||
|
|
||||||
|
if (mIns[k].mType == ASMIT_INC)
|
||||||
|
{
|
||||||
|
it = ASMIT_INY;
|
||||||
|
nit = ASMIT_DEY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it = ASMIT_DEY;
|
||||||
|
nit = ASMIT_INY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lblocks.Contains(tail->mTrueJump))
|
||||||
|
{
|
||||||
|
tail->mFalseJump->mEntryRequiredRegs += CPU_REG_Y;
|
||||||
|
tail->mFalseJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, it));
|
||||||
|
tail->mFalseJump->mIns.Insert(1, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tail->mTrueJump->mEntryRequiredRegs += CPU_REG_Y;
|
||||||
|
tail->mTrueJump->mIns.Insert(0, NativeCodeInstruction(mIns[0].mIns, it));
|
||||||
|
tail->mTrueJump->mIns.Insert(1, NativeCodeInstruction(mIns[0].mIns, ASMIT_STY, mIns[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
prev->mIns.Push(mIns[0]);
|
||||||
|
prev->mIns.Push(NativeCodeInstruction(mIns[0].mIns, nit));
|
||||||
|
|
||||||
|
mIns[0].mType = it;
|
||||||
|
mIns[0].mMode = ASMIM_IMPLIED;
|
||||||
|
mIns.Remove(k);
|
||||||
|
|
||||||
|
mEntryRequiredRegs += CPU_REG_Y;
|
||||||
|
mExitRequiredRegs += CPU_REG_Y;
|
||||||
|
prev->mExitRequiredRegs += CPU_REG_Y;
|
||||||
|
for (int i = 0; i < lblocks.Size(); i++)
|
||||||
|
{
|
||||||
|
lblocks[i]->mEntryRequiredRegs += CPU_REG_Y;
|
||||||
|
lblocks[i]->mExitRequiredRegs += CPU_REG_Y;
|
||||||
|
}
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mEntryBlocks.Size() == 2)
|
if (mEntryBlocks.Size() == 2)
|
||||||
|
@ -48045,11 +48464,21 @@ void NativeCodeBasicBlock::CheckLive(void)
|
||||||
assert(mEntryRequiredRegs[CPU_REG_Y]);
|
assert(mEntryRequiredRegs[CPU_REG_Y]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExitRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_Z] && (mFalseJump || mTrueJump->mEntryRequiredRegs[CPU_REG_Z]))
|
if (mExitRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_Z])
|
||||||
|
{
|
||||||
|
if (mFalseJump)
|
||||||
live |= LIVE_CPU_REG_Z;
|
live |= LIVE_CPU_REG_Z;
|
||||||
|
else if (mTrueJump->mEntryRequiredRegs[CPU_REG_Z])
|
||||||
|
{
|
||||||
|
if (mTrueJump->mIns.Size() == 0 || !mTrueJump->mIns[0].ChangesZFlag())
|
||||||
|
live |= LIVE_CPU_REG_Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mExitRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_C] && (mFalseJump || mTrueJump->mEntryRequiredRegs[CPU_REG_C]))
|
if (mExitRequiredRegs.Size() > 0 && mExitRequiredRegs[CPU_REG_C] && (mFalseJump || mTrueJump->mEntryRequiredRegs[CPU_REG_C]))
|
||||||
live |= LIVE_CPU_REG_C;
|
live |= LIVE_CPU_REG_C;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int j = mIns.Size() - 1; j >= 0; j--)
|
for (int j = mIns.Size() - 1; j >= 0; j--)
|
||||||
{
|
{
|
||||||
assert(mIns[j].mType != ASMIT_INV);
|
assert(mIns[j].mType != ASMIT_INV);
|
||||||
|
@ -48796,7 +49225,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
|
||||||
mInterProc = proc;
|
mInterProc = proc;
|
||||||
mInterProc->mLinkerObject->mNativeProc = this;
|
mInterProc->mLinkerObject->mNativeProc = this;
|
||||||
|
|
||||||
CheckFunc = !strcmp(mInterProc->mIdent->mString, "main");
|
CheckFunc = !strcmp(mInterProc->mIdent->mString, "vspr_sort");
|
||||||
|
|
||||||
int nblocks = proc->mBlocks.Size();
|
int nblocks = proc->mBlocks.Size();
|
||||||
tblocks = new NativeCodeBasicBlock * [nblocks];
|
tblocks = new NativeCodeBasicBlock * [nblocks];
|
||||||
|
@ -49909,6 +50338,12 @@ void NativeCodeProcedure::Optimize(void)
|
||||||
#if 1
|
#if 1
|
||||||
if (step == 4)
|
if (step == 4)
|
||||||
{
|
{
|
||||||
|
#if 1
|
||||||
|
ResetVisited();
|
||||||
|
if (!changed && mEntryBlock->LoopRegisterXYMap())
|
||||||
|
changed = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
ResetVisited();
|
ResetVisited();
|
||||||
if (!changed && mEntryBlock->OptimizeGenericLoop(this))
|
if (!changed && mEntryBlock->OptimizeGenericLoop(this))
|
||||||
changed = true;
|
changed = true;
|
||||||
|
@ -49916,6 +50351,7 @@ void NativeCodeProcedure::Optimize(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CheckBlocks(true);
|
CheckBlocks(true);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
ResetVisited();
|
ResetVisited();
|
||||||
if (!changed && mEntryBlock->ShortcutZeroPageCopyUp(this))
|
if (!changed && mEntryBlock->ShortcutZeroPageCopyUp(this))
|
||||||
|
@ -49967,8 +50403,9 @@ void NativeCodeProcedure::Optimize(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
if (step == 5 || step == 6)
|
if (!changed && (step == 5 || step == 6))
|
||||||
{
|
{
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
int xregs[256], yregs[256];
|
int xregs[256], yregs[256];
|
||||||
|
|
||||||
|
@ -50486,7 +50923,6 @@ void NativeCodeProcedure::Optimize(void)
|
||||||
else
|
else
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
|
|
||||||
} while (changed);
|
} while (changed);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
@ -50582,6 +51018,9 @@ void NativeCodeProcedure::Optimize(void)
|
||||||
data.Reset();
|
data.Reset();
|
||||||
mEntryBlock->PropagateZPAbsolute(data);
|
mEntryBlock->PropagateZPAbsolute(data);
|
||||||
|
|
||||||
|
ResetVisited();
|
||||||
|
mEntryBlock->PropagateAddGlobalCarry();
|
||||||
|
|
||||||
BuildDataFlowSets();
|
BuildDataFlowSets();
|
||||||
ResetVisited();
|
ResetVisited();
|
||||||
mEntryBlock->RemoveUnusedResultInstructions();
|
mEntryBlock->RemoveUnusedResultInstructions();
|
||||||
|
|
|
@ -639,6 +639,7 @@ public:
|
||||||
void FindZeroPageAlias(const NumberSet& statics, NumberSet& invalid, uint8* alias, int accu);
|
void FindZeroPageAlias(const NumberSet& statics, NumberSet& invalid, uint8* alias, int accu);
|
||||||
bool RemapZeroPage(const uint8* remap);
|
bool RemapZeroPage(const uint8* remap);
|
||||||
|
|
||||||
|
bool LoopRegisterXYMap(void);
|
||||||
void GlobalRegisterXYCheck(int* xregs, int * yregs);
|
void GlobalRegisterXYCheck(int* xregs, int * yregs);
|
||||||
void GlobalRegisterXMap(int reg);
|
void GlobalRegisterXMap(int reg);
|
||||||
void GlobalRegisterYMap(int reg);
|
void GlobalRegisterYMap(int reg);
|
||||||
|
@ -772,6 +773,8 @@ public:
|
||||||
|
|
||||||
void PropagateZPAbsolute(const NativeRegisterDataSet& data);
|
void PropagateZPAbsolute(const NativeRegisterDataSet& data);
|
||||||
|
|
||||||
|
void PropagateAddGlobalCarry(void);
|
||||||
|
|
||||||
void RegisterFunctionCalls(void);
|
void RegisterFunctionCalls(void);
|
||||||
bool MergeFunctionCalls(void);
|
bool MergeFunctionCalls(void);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue