Loop direction inversion for simple counts

This commit is contained in:
drmortalwombat 2023-02-11 10:36:46 +01:00
parent acbd70a84f
commit 71a071fea4
3 changed files with 307 additions and 0 deletions

View File

@ -115,6 +115,15 @@ void IntegerValueRange::Limit(const IntegerValueRange& range)
LimitMax(range.mMaxValue); LimitMax(range.mMaxValue);
} }
void IntegerValueRange::SetLimit(int64 minValue, int64 maxValue)
{
mMinState = S_BOUND;
mMinValue = minValue;
mMaxState = S_BOUND;
mMaxValue = maxValue;
}
bool IntegerValueRange::Merge(const IntegerValueRange& range, bool head, bool initial) bool IntegerValueRange::Merge(const IntegerValueRange& range, bool head, bool initial)
{ {
bool changed = false; bool changed = false;
@ -10568,6 +10577,242 @@ void InterCodeBasicBlock::CollectLoopPath(const GrowingArray<InterCodeBasicBlock
} }
} }
static bool IsMatchingStore(const InterInstruction* lins, const InterInstruction* sins)
{
if (sins->mCode == IC_STORE &&
sins->mSrc[1].mTemp < 0 && lins->mSrc[0].mMemory == sins->mSrc[1].mMemory && lins->mSrc[0].mIntConst == sins->mSrc[1].mIntConst &&
lins->mDst.mType == sins->mSrc[0].mType)
{
switch (lins->mSrc[0].mMemory)
{
case IM_FPARAM:
return lins->mSrc[0].mVarIndex == sins->mSrc[1].mVarIndex;
}
}
return false;
}
static bool CollidingMem(InterCodeBasicBlock* block, InterInstruction * lins, int from, int to, const GrowingVariableArray& staticVars)
{
for (int i = from; i < to; i++)
{
InterInstruction* ins = block->mInstructions[i];
if (CollidingMem(lins, ins, staticVars))
return true;
}
return false;
}
bool InterCodeBasicBlock::CollectSingleHeadLoopBody(InterCodeBasicBlock* head, InterCodeBasicBlock* tail, GrowingArray<InterCodeBasicBlock*>& body)
{
int i = 0;
body.Push(head);
while (i < body.Size())
{
InterCodeBasicBlock* block = body[i++];
if (block->mTrueJump)
{
if (block->mTrueJump == head)
return false;
if (block->mTrueJump != tail && !body.Contains(block->mTrueJump))
body.Push(block->mTrueJump);
if (block->mFalseJump)
{
if (block->mFalseJump == head)
return false;
if (block->mFalseJump != tail && !body.Contains(block->mFalseJump))
body.Push(block->mFalseJump);
}
}
else
return false;
}
body.Push(tail);
return true;
}
static InterInstruction * FindSourceInstruction(InterCodeBasicBlock* block, int temp)
{
for (;;)
{
int i = block->mInstructions.Size() - 1;
while (i >= 0)
{
if (block->mInstructions[i]->mDst.mTemp == temp)
return block->mInstructions[i];
i--;
}
if (block->mEntryBlocks.Size() != 1)
return nullptr;
block = block->mEntryBlocks[0];
}
}
bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedParams, const GrowingVariableArray& staticVars)
{
bool modified = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mEntryBlocks.Size() == 2)
{
InterCodeBasicBlock* tail, *post;
if (mEntryBlocks[0] == mLoopPrefix)
tail = mEntryBlocks[1];
else
tail = mEntryBlocks[0];
if (tail->mTrueJump == this)
post = tail->mFalseJump;
else
post = tail->mTrueJump;
if (post && post->mNumEntries == 1)
{
GrowingArray<InterCodeBasicBlock*> body(nullptr);
if (tail->CollectSingleHeadLoopBody(this, tail, body))
{
int tz = tail->mInstructions.Size();
if (tz > 2)
{
InterInstruction* ai = tail->mInstructions[tz - 3];
InterInstruction* ci = tail->mInstructions[tz - 2];
InterInstruction* bi = tail->mInstructions[tz - 1];
if (ai->mCode == IC_BINARY_OPERATOR && ai->mOperator == IA_ADD && ai->mSrc[0].mTemp < 0 && ai->mDst.mTemp == ai->mSrc[1].mTemp && ai->mSrc[0].mIntConst > 0 && IsIntegerType(ai->mDst.mType) &&
ci->mCode == IC_RELATIONAL_OPERATOR && ci->mOperator == IA_CMPLU && ci->mSrc[0].mTemp < 0 && ci->mSrc[1].mTemp == ai->mDst.mTemp &&
bi->mCode == IC_BRANCH && bi->mSrc[0].mTemp == ci->mDst.mTemp && !post->mEntryRequiredTemps[ai->mDst.mTemp] &&
!tail->IsTempReferencedInRange(0, tz - 3, ai->mDst.mTemp))
{
int i = 0;
while (i + 1 < body.Size() && !body[i]->IsTempReferencedInRange(0, body[i]->mInstructions.Size(), ai->mDst.mTemp))
i++;
if (i + 1 == body.Size())
{
InterInstruction* si = FindSourceInstruction(mLoopPrefix, ai->mDst.mTemp);
if (si && si->mCode == IC_CONSTANT)
{
int num = (ci->mSrc[0].mIntConst - si->mSrc[0].mIntConst) / ai->mSrc[0].mIntConst;
if (num > 0)
{
ai->mOperator = IA_SUB;
ai->mSrc[0].mIntConst = 1;
ci->mOperator = IA_CMPGU;
ci->mSrc[0].mIntConst = 0;
InterInstruction* mins = new InterInstruction(si->mLocation, IC_CONSTANT);
mins->mConst.mType = ai->mDst.mType;
mins->mConst.mIntConst = num;
mins->mDst = ai->mDst;
mLoopPrefix->mInstructions.Insert(mLoopPrefix->mInstructions.Size() - 1, mins);
ai->mSrc[1].mRange.SetLimit(1, num);
ai->mDst.mRange.SetLimit(0, num - 1);
ci->mSrc[1].mRange.SetLimit(0, num - 1);
}
modified = true;
}
}
}
}
int i = 0;
while (i < mInstructions.Size())
{
InterInstruction* lins = mInstructions[i];
if (lins->mCode == IC_LOAD && lins->mSrc[0].mTemp < 0)
{
if (CanMoveInstructionBeforeBlock(i))
{
int j = tail->mInstructions.Size() - 1;
while (j >= 0 && !IsMatchingStore(lins, tail->mInstructions[j]))
j--;
if (j >= 0)
{
InterInstruction* sins = tail->mInstructions[j];
if (tail->CanMoveInstructionBehindBlock(j))
{
if (!CollidingMem(this, lins, i + 1, mInstructions.Size(), staticVars) &&
!CollidingMem(tail, lins, 0, j, staticVars))
{
int k = 1;
while (k + 1 < body.Size() && !CollidingMem(body[k], lins, 0, body[k]->mInstructions.Size(), staticVars))
k++;
if (k + 1 == body.Size())
{
if (sins->mSrc[0].mTemp >= 0)
tail->mExitRequiredTemps += sins->mSrc[0].mTemp;
post->mInstructions.Insert(0, sins);
tail->mInstructions.Remove(j);
if (sins->mSrc[0].mTemp != lins->mDst.mTemp)
{
InterInstruction* mins;
if (sins->mSrc[0].mTemp >= 0)
{
mins = new InterInstruction(sins->mLocation, IC_LOAD_TEMPORARY);
mins->mSrc[0] = sins->mSrc[0];
}
else
{
mins = new InterInstruction(sins->mLocation, IC_CONSTANT);
mins->mConst = sins->mSrc[0];
}
mins->mDst = lins->mDst;
tail->mExitRequiredTemps += mins->mDst.mTemp;
tail->mInstructions.Insert(tail->mInstructions.Size() - 1, mins);
}
mLoopPrefix->mInstructions.Insert(mLoopPrefix->mInstructions.Size() - 1, lins);
mLoopPrefix->mExitRequiredTemps += lins->mDst.mTemp;
mEntryRequiredTemps += lins->mDst.mTemp;
mInstructions.Remove(i);
i--;
modified = true;
}
}
}
}
}
}
i++;
}
}
}
}
if (mTrueJump && mTrueJump->SingleTailLoopOptimization(aliasedParams, staticVars))
modified = true;
if (mFalseJump && mFalseJump->SingleTailLoopOptimization(aliasedParams, staticVars))
modified = true;
}
return modified;
}
void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams) void InterCodeBasicBlock::InnerLoopOptimization(const NumberSet& aliasedParams)
{ {
if (!mVisited) if (!mVisited)
@ -14712,6 +14957,43 @@ void InterCodeProcedure::Close(void)
PropagateConstOperationsUp(); PropagateConstOperationsUp();
#if 1
do {
changed = false;
BuildLoopPrefix();
DisassembleDebug("added dominators");
ResetEntryBlocks();
ResetVisited();
mEntryBlock->CollectEntryBlocks(nullptr);
BuildDataFlowSets();
ResetVisited();
changed = mEntryBlock->SingleTailLoopOptimization(mParamAliasedSet, mModule->mGlobalVars);
DisassembleDebug("SingleTailLoopOptimization");
if (changed)
{
TempForwarding();
RemoveUnusedInstructions();
RemoveUnusedStoreInstructions(paramMemory);
}
BuildTraces(false);
DisassembleDebug("Rebuilt traces");
} while (changed);
#endif
#if 1 #if 1
BuildDataFlowSets(); BuildDataFlowSets();

View File

@ -158,6 +158,7 @@ public:
bool Merge(const IntegerValueRange& range, bool head, bool initial); bool Merge(const IntegerValueRange& range, bool head, bool initial);
void Limit(const IntegerValueRange& range); void Limit(const IntegerValueRange& range);
void SetLimit(int64 minValue, int64 maxValue);
bool IsConstant(void) const; bool IsConstant(void) const;
@ -505,6 +506,10 @@ public:
void CollectLoopPath(const GrowingArray<InterCodeBasicBlock*>& body, GrowingArray<InterCodeBasicBlock*>& path); void CollectLoopPath(const GrowingArray<InterCodeBasicBlock*>& body, GrowingArray<InterCodeBasicBlock*>& path);
void InnerLoopOptimization(const NumberSet& aliasedParams); void InnerLoopOptimization(const NumberSet& aliasedParams);
void PushMoveOutOfLoop(void); void PushMoveOutOfLoop(void);
bool CollectSingleHeadLoopBody(InterCodeBasicBlock* head, InterCodeBasicBlock* tail, GrowingArray<InterCodeBasicBlock*>& body);
bool SingleTailLoopOptimization(const NumberSet& aliasedParams, const GrowingVariableArray& staticVars);
InterCodeBasicBlock* BuildLoopPrefix(InterCodeProcedure * proc); InterCodeBasicBlock* BuildLoopPrefix(InterCodeProcedure * proc);
void BuildLoopSuffix(InterCodeProcedure* proc); void BuildLoopSuffix(InterCodeProcedure* proc);

View File

@ -31054,6 +31054,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 2].mType = ASMIT_CMP; mIns[i + 2].mType = ASMIT_CMP;
progress = true; progress = true;
} }
else if (
mIns[i + 0].mType == ASMIT_CLC &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & (LIVE_CPU_REG_C | LIVE_CPU_REG_A)))
{
mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mLive |= LIVE_CPU_REG_X;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_DEX;
progress = true;
}
else if ( else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mType == ASMIT_LDA &&
mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
@ -31066,6 +31076,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
progress = true; progress = true;
} }
else if (
mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_IMMEDIATE &&
mIns[i + 1].mType == ASMIT_SEC &&
mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
mIns[i + 0].mAddress = (mIns[i + 0].mAddress - mIns[i + 2].mAddress) & 0xff;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
progress = true;
}
else if ( else if (
mIns[i + 0].ChangesAccuAndFlag() && mIns[i + 0].ChangesAccuAndFlag() &&
(mIns[i + 1].mType == ASMIT_INC || mIns[i + 1].mType == ASMIT_DEC) && (mIns[i + 1].mType == ASMIT_INC || mIns[i + 1].mType == ASMIT_DEC) &&