Optimize loop invariants in single entry/exit loops

This commit is contained in:
drmortalwombat 2023-05-19 21:25:29 +02:00
parent f8d69f7945
commit 2ac276458a
5 changed files with 272 additions and 7 deletions

View File

@ -231,7 +231,7 @@ Imports the character data and compresses it using lzo compression.
#embed ctm_tiles8 "cards.ctm" #embed ctm_tiles8 "cards.ctm"
}; };
Imports the tiles in 8 bit form and builds word constants Imports the tiles in 8 bit form and builds byte constants
const unsigned CardsTiles[] = { const unsigned CardsTiles[] = {
#embed ctm_tiles16 word "cards.ctm" #embed ctm_tiles16 word "cards.ctm"
@ -239,6 +239,18 @@ Imports the tiles in 8 bit form and builds word constants
Imports the tiles in 16 bit form and builds word constants Imports the tiles in 16 bit form and builds word constants
const char CardsMap[] = {
#embed ctm_map8 "cards.ctm"
};
Imports the map (screen) in 8 bit form and builds byte constants
const unsigned CardsMap[] = {
#embed ctm_map16 word "cards.ctm"
};
Imports the map (screen) in 16 bit form and builds word constants
const char CardsAttrib1[] = { const char CardsAttrib1[] = {
#embed ctm_attr1 "cards.ctm" #embed ctm_attr1 "cards.ctm"
}; };

View File

@ -240,6 +240,18 @@ public:
else return array[n]; else return array[n];
} }
const T getAt(int n) const
{
if (n >= size) return empty;
else return array[n];
}
void destroyAt(int n)
{
if (n < size)
array[n] = empty;
}
void Push(T t) void Push(T t)
{ {
(*this)[size] = t; (*this)[size] = t;

View File

@ -3616,11 +3616,11 @@ static void DestroySourceValues(int temp, GrowingInstructionPtrArray& tvalue, Fa
{ {
j = tvalid.Element(i); j = tvalid.Element(i);
ins = tvalue[j]; ins = tvalue.getAt(j);
if (ins->UsesTemp(temp)) if (ins->UsesTemp(temp))
{ {
tvalue[j] = NULL; tvalue.destroyAt(j);
tvalid -= j; tvalid -= j;
} }
else else
@ -15661,7 +15661,7 @@ void InterCodeProcedure::Close(void)
{ {
GrowingTypeArray tstack(IT_NONE); GrowingTypeArray tstack(IT_NONE);
CheckFunc = !strcmp(mIdent->mString, "rirq_build1"); CheckFunc = !strcmp(mIdent->mString, "main");
mEntryBlock = mBlocks[0]; mEntryBlock = mBlocks[0];
@ -15994,6 +15994,10 @@ void InterCodeProcedure::Close(void)
ResetVisited(); ResetVisited();
mEntryBlock->FollowJumps(); mEntryBlock->FollowJumps();
ResetEntryBlocks();
ResetVisited();
mEntryBlock->CollectEntryBlocks(nullptr);
DisassembleDebug("Followed Jumps 2"); DisassembleDebug("Followed Jumps 2");
RebuildIntegerRangeSet(); RebuildIntegerRangeSet();
@ -16990,8 +16994,8 @@ void InterCodeProcedure::Disassemble(const char* name, bool dumpSets)
FILE* file; FILE* file;
static bool initial = true; static bool initial = true;
// if (!CheckFunc) if (!CheckFunc)
// return; return;
if (!initial) if (!initial)
{ {

View File

@ -11342,6 +11342,9 @@ void NativeCodeBasicBlock::RelationalOperator(InterCodeProcedure* proc, const In
NativeCodeBasicBlock* nblock = nproc->AllocateBlock(); NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
NativeCodeBasicBlock* cblock = this; NativeCodeBasicBlock* cblock = this;
if (op == IA_CMPLU && ins->mSrc[0].mTemp == -1 && ins->mSrc[1].IsUnsigned() && ins->mSrc[1].mRange.mMaxValue == ins->mSrc[0].mIntConst)
op = IA_CMPNE;
int li = 1, ri = 0; int li = 1, ri = 0;
if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS) if (op == IA_CMPLEU || op == IA_CMPGU || op == IA_CMPLES || op == IA_CMPGS)
{ {
@ -20815,6 +20818,76 @@ bool NativeCodeBasicBlock::PatchSingleUseGlobalLoad(const NativeCodeBasicBlock*
return changed; return changed;
} }
bool NativeCodeBasicBlock::CheckForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval)
{
// Checking only current block as first optimization step
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_ZERO_PAGE && (ins.mAddress == reg || ins.mAddress == yreg))
return false;
else if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
if (yval != 0)
return false;
else if (!(ins.mLive & LIVE_MEM))
return true;
}
if (ins.mType == ASMIT_LDY && ins.mMode == ASMIM_IMMEDIATE)
yval = ins.mAddress;
else if (ins.mType == ASMIT_INY && yval >= 0)
yval = (yval + 1) & 255;
else if (ins.mType == ASMIT_DEY && yval >= 0)
yval = (yval - 1) & 255;
else if (ins.mType == ASMIT_JSR)
{
if (ins.UsesZeroPage(reg) || ins.ChangesZeroPage(yreg))
return false;
yval = -1;
}
else if (ins.ChangesZeroPage(reg) || ins.ChangesZeroPage(yreg))
return false;
else if (ins.ChangesYReg())
yval = -1;
at++;
}
return false;
}
bool NativeCodeBasicBlock::PatchForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval)
{
bool changed = false;
while (at < mIns.Size())
{
NativeCodeInstruction& ins(mIns[at]);
if (ins.mMode == ASMIM_INDIRECT_Y && ins.mAddress == reg)
{
bool done = !(ins.mLive & LIVE_MEM);
if (ins.mLive & LIVE_CPU_REG_Y)
mIns.Insert(at + 1, NativeCodeInstruction(ins.mIns, ASMIT_LDY, ASMIM_IMMEDIATE, 0));
mIns.Insert(at, NativeCodeInstruction(ins.mIns, ASMIT_LDY, ASMIM_ZERO_PAGE, yreg));
at++;
changed = true;
if (done)
return changed;
}
at++;
}
return changed;
}
bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval) bool NativeCodeBasicBlock::CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction& iins, int at, int yval)
{ {
if (!mPatched) if (!mPatched)
@ -27398,6 +27471,116 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc
return lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full); return lblock->OptimizeSimpleLoopInvariant(proc, this, eblock, full);
} }
bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mEntryBlocks.Size() == 2)
{
NativeCodeBasicBlock* pblock, * eblock;
if (mEntryBlocks[0]->mFalseJump)
{
pblock = mEntryBlocks[1];
eblock = mEntryBlocks[0];
}
else
{
eblock = mEntryBlocks[1];
pblock = mEntryBlocks[0];
}
if (!pblock->mFalseJump && eblock->IsDominatedBy(this))
{
ExpandingArray<NativeCodeBasicBlock*> lblocks;
proc->ResetPatched();
mPatched = true;
lblocks.Push(eblock);
eblock->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++;
}
int aimm = -1;
if (!pblock->mExitRequiredRegs[CPU_REG_A] || !pblock->mExitRequiredRegs[CPU_REG_X])
{
for (int i = 0; i < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_IMMEDIATE)
aimm = mIns[i].mAddress;
else if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && aimm >= 0)
{
int reg = mIns[i].mAddress;
if (!ReferencedOnPath(this, 0, i, reg) && !ChangedOnPath(this, i + 1, mIns.Size(), reg))
{
int k = 0;
while (k < lblocks.Size() && !(lblocks[k] != this && lblocks[k]->ChangesZeroPage(reg)))
k++;
if (k == lblocks.Size())
{
if (!pblock->mExitRequiredRegs[CPU_REG_A])
{
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDA, ASMIM_IMMEDIATE, aimm));
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STA, ASMIM_ZERO_PAGE, reg));
}
else if (!pblock->mExitRequiredRegs[CPU_REG_X])
{
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_LDX, ASMIM_IMMEDIATE, aimm));
pblock->mIns.Push(NativeCodeInstruction(mIns[i].mIns, ASMIT_STX, ASMIM_ZERO_PAGE, reg));
}
mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED;
changed = true;
mEntryRequiredRegs += reg;
mExitRequiredRegs += reg;
pblock->mExitRequiredRegs += reg;
for (int i = 0; i < lblocks.Size(); i++)
{
lblocks[i]->mEntryRequiredRegs += reg;
lblocks[i]->mExitRequiredRegs += reg;
}
}
}
}
else if (mIns[i].ChangesAccu())
aimm = -1;
}
}
}
}
if (mTrueJump && mTrueJump->OptimizeSingleEntryLoop(proc))
changed = true;
if (mFalseJump && mFalseJump->OptimizeSingleEntryLoop(proc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void)
{ {
bool changed = false; bool changed = false;
@ -33445,6 +33628,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
progress = true; progress = true;
} }
#endif #endif
else if (
mIns[i + 0].mType == ASMIT_LSR && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mType = ASMIT_AND;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0xfe;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
progress = true;
}
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 &&
mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) mIns[i + 1].mType == ASMIT_LSR && mIns[i + 1].mMode == ASMIM_IMPLIED && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)))
@ -37406,6 +37599,34 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
} }
} }
#endif #endif
#if 1
if (
mLoopHead &&
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_LDA &&
mIns[i + 4].mType == ASMIT_ADC &&
mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 1].mAddress + 1)
{
int yval = RetrieveYValue(i);
proc->ResetPatched();
if (CheckForwardLowYPointer(this, mIns[i + 1].mAddress, mIns[i + 0].mAddress, i + 6, yval))
{
proc->ResetPatched();
if (PatchForwardLowYPointer(this, mIns[i + 1].mAddress, mIns[i + 0].mAddress, i + 6, yval))
progress = true;
mIns[i + 0].mMode = ASMIM_IMMEDIATE;
mIns[i + 0].mAddress = 0;
if (mTrueJump)
mTrueJump->CheckLive();
if (mFalseJump)
mFalseJump->CheckLive();
}
}
#endif
#if 1 #if 1
if ( if (
@ -39859,6 +40080,15 @@ void NativeCodeProcedure::Optimize(void)
changed = true; changed = true;
} }
#endif #endif
#if 1
if (step == 9)
{
RebuildEntry();
ResetVisited();
if (mEntryBlock->OptimizeSingleEntryLoop(this))
changed = true;
}
#endif
#if 1 #if 1
if (step == 2 && !changed) if (step == 2 && !changed)
{ {
@ -39920,7 +40150,6 @@ void NativeCodeProcedure::Optimize(void)
else else
cnt++; cnt++;
} while (changed); } while (changed);

View File

@ -263,6 +263,7 @@ public:
bool OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock * prevBlock, NativeCodeBasicBlock* exitBlock, bool full); bool OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock * prevBlock, NativeCodeBasicBlock* exitBlock, bool full);
bool RemoveSimpleLoopUnusedIndex(void); bool RemoveSimpleLoopUnusedIndex(void);
bool OptimizeLoopCarryOver(void); bool OptimizeLoopCarryOver(void);
bool OptimizeSingleEntryLoop(NativeCodeProcedure* proc);
bool OptimizeSimpleLoop(NativeCodeProcedure* proc, bool full); bool OptimizeSimpleLoop(NativeCodeProcedure* proc, bool full);
bool SimpleLoopReversal(NativeCodeProcedure* proc); bool SimpleLoopReversal(NativeCodeProcedure* proc);
@ -571,6 +572,13 @@ public:
bool CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval); bool CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval);
bool PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval); bool PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval);
// reg : base register pair to replace LSB with zero
// ireg : index register
// at : start position in block
// yval: known y immediate value of -1 if not known
bool CheckForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval);
bool PatchForwardLowYPointer(const NativeCodeBasicBlock* block, int reg, int yreg, int at, int yval);
bool CrossBlock16BitFlood(NativeCodeProcedure* proc); bool CrossBlock16BitFlood(NativeCodeProcedure* proc);
bool CheckCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at, bool rvalid); bool CheckCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at, bool rvalid);
bool CheckCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg, bool rvalid); bool CheckCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg, bool rvalid);