More native code common subexpression elimination

This commit is contained in:
drmortalwombat 2023-03-18 19:02:05 +01:00
parent 9c5e018c5a
commit a584f74788
2 changed files with 328 additions and 66 deletions

View File

@ -9321,7 +9321,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED));
for(int i=shift; i<8; i++)
mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_IMPLIED));
mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, 0xff << shift));
mIns.Push(NativeCodeInstruction(ASMIT_AND, ASMIM_IMMEDIATE, (0xff << shift) & 0xff));
mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg ));
}
else
@ -13838,41 +13838,136 @@ bool NativeCodeBasicBlock::CanGlobalSwapXY(void)
}
bool NativeCodeBasicBlock::IsSimpleSubExpression(int at) const
bool NativeCodeBasicBlock::IsSimpleSubExpression(int at, NativeSimpleSubExpression& ex)
{
if (at >= 2 && mIns[at - 2].mType == ASMIT_LDA && mIns[at - 2].mMode == ASMIM_ZERO_PAGE && mIns[at - 1].mMode == ASMIM_IMMEDIATE)
if (at + 2 < mIns.Size())
{
if (mIns[at - 1].mType == ASMIT_AND || mIns[at - 1].mType == ASMIT_ORA || mIns[at - 1].mType == ASMIT_EOR)
return true;
if (at >= 3)
if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 2].mType == ASMIT_STA && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 1].mMode == ASMIM_IMMEDIATE && (mIns[at + 1].mType == ASMIT_AND || mIns[at + 1].mType == ASMIT_ORA || mIns[at + 1].mType == ASMIT_EOR))
{
if (mIns[at - 1].mType == ASMIT_ADC && mIns[at - 3].mType == ASMIT_CLC)
return true;
if (mIns[at - 1].mType == ASMIT_SBC && mIns[at - 3].mType == ASMIT_SEC)
return true;
ex.mType = mIns[at + 1].mType;
ex.mValue = mIns[at + 1].mAddress;
ex.mOp = &(mIns[at + 1]);
ex.mSrc = &(mIns[at + 0]);
ex.mDst = &(mIns[at + 2]);
return true;
}
}
if (at + 3 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDA && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
{
ex.mType = mIns[at + 2].mType;
ex.mValue = mIns[at + 2].mAddress;
ex.mSrc = &(mIns[at + 0]);
ex.mOp = &(mIns[at + 2]);
ex.mDst = &(mIns[at + 3]);
return true;
}
}
if (at + 3 < mIns.Size())
{
if (mIns[at + 1].mType == ASMIT_LDA && (mIns[at + 1].mMode == ASMIM_ZERO_PAGE || mIns[at + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
(mIns[at + 0].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 0].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
{
ex.mType = mIns[at + 2].mType;
ex.mValue = mIns[at + 2].mAddress;
ex.mSrc = &(mIns[at + 1]);
ex.mOp = &(mIns[at + 2]);
ex.mDst = &(mIns[at + 3]);
return true;
}
}
if (at + 3 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_STA && mIns[at + 0].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 2].mMode == ASMIM_IMMEDIATE &&
(mIns[at + 1].mType == ASMIT_CLC && mIns[at + 2].mType == ASMIT_ADC || mIns[at + 1].mType == ASMIT_SEC && mIns[at + 2].mType == ASMIT_SBC) &&
!(mIns[at + 2].mLive & LIVE_CPU_REG_C))
{
ex.mType = mIns[at + 2].mType;
ex.mValue = mIns[at + 2].mAddress;
ex.mSrc = &(mIns[at + 0]);
ex.mOp = &(mIns[at + 2]);
ex.mDst = &(mIns[at + 3]);
return true;
}
}
if (at + 2 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDX && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 2].mType == ASMIT_STX && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 1].mType == ASMIT_INX)
{
ex.mType = ASMIT_ADC;
ex.mValue = 1;
ex.mOp = &(mIns[at + 1]);
ex.mSrc = &(mIns[at + 0]);
ex.mDst = &(mIns[at + 2]);
return true;
}
}
if (at + 2 < mIns.Size())
{
if (mIns[at + 0].mType == ASMIT_LDY && (mIns[at + 0].mMode == ASMIM_ZERO_PAGE || mIns[at + 0].mMode == ASMIM_ABSOLUTE) &&
mIns[at + 2].mType == ASMIT_STY && mIns[at + 2].mMode == ASMIM_ZERO_PAGE &&
mIns[at + 1].mType == ASMIT_INY)
{
ex.mType = ASMIT_ADC;
ex.mValue = 1;
ex.mOp = &(mIns[at + 1]);
ex.mSrc = &(mIns[at + 0]);
ex.mDst = &(mIns[at + 2]);
return true;
}
}
if (at >= 3 &&
mIns[at - 3].mType == ASMIT_STA && mIns[at - 3].mMode == ASMIM_ZERO_PAGE && mIns[at - 2].mType == ASMIT_CLC &&
mIns[at - 1].mType == ASMIT_ADC && mIns[at - 1].mMode == ASMIM_IMMEDIATE)
return true;
return false;
}
bool NativeCodeBasicBlock::IsSameSimpleSubExpression(int pat, int at) const
int NativeSimpleSubExpressions::FindCommon(const NativeSimpleSubExpression& ex) const
{
if (pat >= 2 && mIns[pat - 2].mType == ASMIT_LDA)
if (ex.mSrc->mType == ASMIT_LDA || ex.mSrc->mType == ASMIT_LDX || ex.mSrc->mType == ASMIT_LDY)
{
return mIns[pat - 2].IsSame(mIns[at - 2]) && mIns[pat - 1].IsSame(mIns[at - 1]);
for (int i = 0; i < mExps.Size(); i++)
{
if (mExps[i].mType == ex.mType && mExps[i].mValue == ex.mValue && ex.mSrc->SameEffectiveAddress(*(mExps[i].mSrc)))
return i;
}
}
else
return -1;
}
void NativeSimpleSubExpressions::Filter(const NativeCodeInstruction& ins)
{
if (ins.mType == ASMIT_JSR)
mExps.SetSize(0);
else if (ins.ChangesAddress())
{
return mIns[pat - 3].SameEffectiveAddress(mIns[at - 2]) && mIns[pat - 1].IsSame(mIns[at - 1]);
int i = 0;
while (i < mExps.Size())
{
if (mExps[i].mSrc->MayBeChangedOnAddress(ins) ||
&ins != mExps[i].mDst && mExps[i].mDst->MayBeChangedOnAddress(ins))
mExps.Remove(i);
else
i++;
}
}
}
bool NativeCodeBasicBlock::PropagateCommonSubExpression(void)
{
bool changed = false;
@ -13881,56 +13976,26 @@ bool NativeCodeBasicBlock::PropagateCommonSubExpression(void)
{
mVisited = true;
int cex[256];
for (int i = 0; i < 256; i++)
cex[i] = -1;
NativeSimpleSubExpressions exps;
for (int i = 0; i < mIns.Size(); i++)
{
bool reset = false;
NativeCodeInstruction& ins(mIns[i]);
if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE)
NativeSimpleSubExpression ex;
if (IsSimpleSubExpression(i, ex))
{
if (IsSimpleSubExpression(i))
int j = exps.FindCommon(ex);
if (j >= 0)
{
int si = cex[ins.mAddress];
if (si >= 0 && IsSameSimpleSubExpression(si, i) && !(ins.mLive & LIVE_CPU_REG_C))
{
mIns[i].mType = ASMIT_LDA;
mIns[si].mLive |= LIVE_MEM;
mIns[i - 1].mType = ASMIT_NOP; mIns[i - 1].mMode = ASMIM_IMPLIED;
mIns[i - 2].mType = ASMIT_NOP; mIns[i - 2].mMode = ASMIM_IMPLIED;
changed = true;
}
else
cex[ins.mAddress] = i;
*ex.mSrc = NativeCodeInstruction(ex.mSrc->mType, *(exps.mExps[j].mDst));
ex.mSrc = exps.mExps[j].mSrc;
ex.mOp->mType = ASMIT_NOP;
ex.mOp->mMode = ASMIM_IMPLIED;
changed = true;
}
else
reset = true;
exps.mExps.Push(ex);
}
else if (ins.mMode == ASMIM_ZERO_PAGE && ins.ChangesAddress())
reset = true;
else if (ins.mType == ASMIT_JSR)
{
for (int i = 0; i < 256; i++)
cex[i] = -1;
}
if (reset)
{
cex[ins.mAddress] = -1;
for (int j = 0; j < 256; j++)
{
int k = cex[j];
if (k >= 0 && (
mIns[k - 2].mType == ASMIT_LDA && mIns[k - 2].mAddress == ins.mAddress || mIns[k - 3].mAddress == ins.mAddress))
{
cex[j] = -1;
}
}
}
else
exps.Filter(mIns[i]);
}
if (mTrueJump && mTrueJump->PropagateCommonSubExpression())
@ -15009,6 +15074,87 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc)
mFalseJump = eblock;
mBranch = ASMIT_BCC;
eblock->Close(rblock, nullptr, ASMIT_JMP);
break;
}
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TXA &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAX && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
rblock->mIns.Push(NativeCodeInstruction(ASMIT_TXA));
eblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX));
for (int j = i + 3; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mTrueJump = rblock;
mFalseJump = eblock;
mBranch = ASMIT_BCS;
eblock->Close(rblock, nullptr, ASMIT_JMP);
break;
}
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
rblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA));
eblock->mIns.Push(NativeCodeInstruction(ASMIT_INY));
for (int j = i + 3; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mTrueJump = rblock;
mFalseJump = eblock;
mBranch = ASMIT_BCC;
eblock->Close(rblock, nullptr, ASMIT_JMP);
break;
}
if (i + 2 < mIns.Size() &&
mIns[i + 0].mType == ASMIT_TYA &&
mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 &&
mIns[i + 2].mType == ASMIT_TAY && !(mIns[i + 2].mLive & LIVE_CPU_REG_C))
{
changed = true;
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
NativeCodeBasicBlock* rblock = proc->AllocateBlock();
rblock->mTrueJump = mTrueJump;
rblock->mFalseJump = mFalseJump;
rblock->mBranch = mBranch;
rblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA));
eblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY));
for (int j = i + 3; j < mIns.Size(); j++)
rblock->mIns.Push(mIns[j]);
mIns.SetSize(i);
mTrueJump = rblock;
mFalseJump = eblock;
mBranch = ASMIT_BCS;
eblock->Close(rblock, nullptr, ASMIT_JMP);
break;
}
@ -24061,6 +24207,80 @@ bool NativeCodeBasicBlock::ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc)
return changed;
}
bool NativeCodeBasicBlock::Check16BitSum(const NativeCodeBasicBlock* block, int origin, int at, int reg)
{
if (!mEntryRequiredRegs.Size())
return false;
if (mPatched)
return true;
if (at == 0)
{
if (!mEntryRequiredRegs[reg])
return true;
mPatched = true;
}
for (int i = at; i < mIns.Size(); i++)
{
if (mIns[i].ReferencesZeroPage(reg))
{
if (block == this && i == origin)
return true;
if (mIns[i].mType == ASMIT_JSR)
return false;
if (mIns[i].UsesZeroPage(reg))
return false;
if (mIns[i].ChangesZeroPage(reg))
return true;
}
}
if (mTrueJump && !mTrueJump->Check16BitSum(block, origin, 0, reg))
return false;
if (mFalseJump && !mFalseJump->Check16BitSum(block, origin, 0, reg))
return false;
return true;
}
bool NativeCodeBasicBlock::EliminateUpper16BitSum(NativeCodeProcedure* nproc)
{
bool changed = false;
if (!mVisited)
{
mVisited = true;
for (int i = 0; i + 2 < mIns.Size(); i++)
{
if (mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
(mIns[i + 1].mType == ASMIT_ADC || mIns[i + 1].mType == ASMIT_SBC) &&
mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) &&
mIns[i + 2].mAddress != BC_REG_LOCALS + 1 && mIns[i + 2].mAddress != BC_REG_STACK + 1)
{
nproc->ResetPatched();
if (Check16BitSum(this, i, i + 3, mIns[i + 2].mAddress))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode == ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode == ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode == ASMIM_IMPLIED;
changed = true;
}
}
}
if (mTrueJump && mTrueJump->EliminateUpper16BitSum(nproc))
changed = true;
if (mFalseJump && mFalseJump->EliminateUpper16BitSum(nproc))
changed = true;
}
return changed;
}
bool NativeCodeBasicBlock::Propagate16BitHighSum(void)
{
bool changed = false;
@ -35467,6 +35687,21 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
mIns[i + 4].mType = ASMIT_DEC;
progress = true;
}
else if (
mIns[i + 0].mType == ASMIT_TAX &&
mIns[i + 1].mType == ASMIT_LDA && (mIns[i + 1].mMode == ASMIM_ZERO_PAGE || mIns[i + 1].mMode == ASMIM_ABSOLUTE) &&
mIns[i + 2].mType == ASMIT_CLC &&
mIns[i + 3].mType == ASMIT_ADC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 &&
mIns[i + 4].mType == ASMIT_STA && (mIns[i + 4].mMode == ASMIM_ZERO_PAGE || mIns[i + 4].mMode == ASMIM_ABSOLUTE) && !(mIns[i + 4].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C)))
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_LDX; mIns[i + 1].mLive |= LIVE_CPU_REG_X;
mIns[i + 2].mType = ASMIT_INX; mIns[i + 2].mLive |= LIVE_CPU_REG_X;
mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_STX; mIns[i + 4].mLive |= LIVE_CPU_REG_A;
mIns.Insert(i + 5, NativeCodeInstruction(ASMIT_TAX));
progress = true;
}
#if 1
else if (
mIns[i + 0].mType == ASMIT_ASL && mIns[i + 0].mMode == ASMIM_ZERO_PAGE &&
@ -38143,11 +38378,14 @@ void NativeCodeProcedure::Optimize(void)
ResetVisited();
bchanged = mEntryBlock->BitFieldForwarding(data);
if (!bchanged)
if (bchanged)
RebuildEntry();
else
{
ResetPatched();
mEntryBlock->CheckVisited();
}
} while (bchanged);
}
@ -38410,6 +38648,13 @@ void NativeCodeProcedure::Optimize(void)
changed = true;
}
if (step == 3)
{
ResetVisited();
if (mEntryBlock->EliminateUpper16BitSum(this))
changed = true;
}
#if 1
if (step == 5 || step == 6)
{

View File

@ -68,6 +68,21 @@ struct NativeRegisterSum16Info
bool operator!=(const NativeRegisterSum16Info& ri) const;
};
struct NativeSimpleSubExpression
{
AsmInsType mType;
int mValue;
NativeCodeInstruction * mSrc, * mDst, * mOp;
};
struct NativeSimpleSubExpressions
{
ExpandingArray<NativeSimpleSubExpression> mExps;
int FindCommon(const NativeSimpleSubExpression& ex) const;
void Filter(const NativeCodeInstruction& ins);
};
static const uint32 NCIF_LOWER = 0x00000001;
static const uint32 NCIF_UPPER = 0x00000002;
@ -454,6 +469,9 @@ public:
bool Propagate16BitHighSum(void);
bool Check16BitSum(const NativeCodeBasicBlock* block, int origin, int at, int reg);
bool EliminateUpper16BitSum(NativeCodeProcedure* nproc);
bool IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair);
bool ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc);
bool ForwardReplaceZeroPage(int at, int from, int to);
@ -506,8 +524,7 @@ public:
bool CanGlobalSwapXY(void);
bool GlobalSwapXY(void);
bool IsSimpleSubExpression(int at) const;
bool IsSameSimpleSubExpression(int pat, int at) const;
bool IsSimpleSubExpression(int at, NativeSimpleSubExpression & ex);
bool PropagateCommonSubExpression(void);
bool ForwardAbsoluteLoadStores(void);