More simple loop optimisations

This commit is contained in:
drmortalwombat 2021-09-28 16:24:44 +02:00
parent e72d28c243
commit c4a5dafb69
9 changed files with 547 additions and 178 deletions

48
autotest/asmtest.c Normal file
View File

@ -0,0 +1,48 @@
#include <stdio.h>
int asum(int a, int b)
{
__asm
{
ldy #a
clc
lda (fp), y
ldy #b
adc (fp), y
sta accu
ldy #a + 1
lda (fp), y
ldy #b + 1
adc (fp), y
sta accu + 1
}
}
int bsum(int a, int b)
{
printf("Hello\n");
__asm
{
ldy #a
clc
lda (fp), y
ldy #b
adc (fp), y
sta accu
ldy #a + 1
lda (fp), y
ldy #b + 1
adc (fp), y
sta accu + 1
}
}
int main(void)
{
int x = asum(7007, 8008);
int y = bsum(4004, 9009);
return (x == 7007 + 8008 && y == 4004 + 9009) ? 0 : -1;
}

View File

@ -102,6 +102,12 @@ if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -n byteindextest.c ..\release\oscar64 -e -n byteindextest.c
if %errorlevel% neq 0 goto :error if %errorlevel% neq 0 goto :error
..\release\oscar64 -e asmtest.c
if %errorlevel% neq 0 goto :error
..\release\oscar64 -e -n asmtest.c
if %errorlevel% neq 0 goto :error
exit /b 0 exit /b 0
:error :error
echo Failed with error #%errorlevel%. echo Failed with error #%errorlevel%.

View File

@ -983,6 +983,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
cins->mTTemp = proc->AddTemporary(cins->mTType); cins->mTTemp = proc->AddTemporary(cins->mTType);
block->Append(cins); block->Append(cins);
vr = CoerceType(proc, block, vr, TheSignedIntTypeDeclaration);
InterInstruction * mins = new InterInstruction(); InterInstruction * mins = new InterInstruction();
mins->mCode = IC_BINARY_OPERATOR; mins->mCode = IC_BINARY_OPERATOR;
mins->mOperator = IA_MUL; mins->mOperator = IA_MUL;

View File

@ -444,6 +444,21 @@ bool NativeCodeInstruction::ChangesAccuAndFlag(void) const
mType == ASMIT_SBC || mType == ASMIT_ADC; mType == ASMIT_SBC || mType == ASMIT_ADC;
} }
bool NativeCodeInstruction::RequiresYReg(void) const
{
if (mMode == ASMIM_ABSOLUTE_Y || mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ZERO_PAGE_Y)
return true;
if (mType == ASMIT_TYA || mType == ASMIT_STY || mType == ASMIT_CPY || mType == ASMIT_INY || mType == ASMIT_DEY)
return true;
return false;
}
bool NativeCodeInstruction::ChangesYReg(void) const
{
return mType == ASMIT_TAY || mType == ASMIT_LDY || mType == ASMIT_INY || mType == ASMIT_DEY;
}
bool NativeCodeInstruction::RequiresAccu(void) const bool NativeCodeInstruction::RequiresAccu(void) const
{ {
if (mMode == ASMIM_IMPLIED) if (mMode == ASMIM_IMPLIED)
@ -5138,185 +5153,286 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc)
mVisited = true; mVisited = true;
bool changed = false; bool changed = false;
int sz = mIns.Size(); int sz = mIns.Size();
if (sz > 3 && sz < 16 && mNumEntries == 2 && mTrueJump == this) if (sz > 3 && sz < 32 && mNumEntries == 2 && mTrueJump == this)
{ {
if (mIns[sz - 3].mType == ASMIT_INC && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE && bool simple = true;
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) &&
mBranch == ASMIT_BCC)
{
// check for usage of Y register
bool yother = false, yindex = false; for(int i=0; i<mIns.Size(); i++)
int zreg = mIns[sz - 3].mAddress; {
int limit = mIns[sz - 1].mAddress; if (mIns[i].mType == ASMIT_JSR)
simple = false;
for (int i = 0; i < sz - 4; i++)
{
if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (mIns[i].mType == ASMIT_LDX && mIns[i].mAddress == zreg)
yother = true;
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
}
if (!yother)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
if (mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(mIns[i]);
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA, ASMIM_IMPLIED));
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPY, ASMIM_IMMEDIATE, limit));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
}
else if (mIns[sz - 1].mType == ASMIT_DEC && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mBranch == ASMIT_BNE)
{
// check for usage of Y register
bool yother = false, yindex = false;
int zreg = mIns[sz - 1].mAddress;
for (int i = 0; i < sz - 1; i++)
{
if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (mIns[i].mType == ASMIT_LDX && mIns[i].mAddress == zreg)
yother = true;
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
}
if (!yother)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 1 < sz; i++)
{
if (mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(mIns[i]);
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA, ASMIM_IMPLIED));
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
}
else if (mIns[sz - 3].mType == ASMIT_INC && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) &&
mBranch == ASMIT_BCC)
{
// check for usage of Y register
bool yother = false, yindex = false, lchanged = false;
int lreg = mIns[sz - 1].mAddress;
int zreg = mIns[sz - 3].mAddress;
for (int i = 0; i < sz - 4; i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].ChangesAddress())
lchanged = true;
if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (mIns[i].mType == ASMIT_LDX && mIns[i].mAddress == zreg)
yother = true;
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
}
if (!yother && !lchanged)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
if (mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(mIns[i]);
else if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA, ASMIM_IMPLIED));
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPY, ASMIM_ZERO_PAGE, lreg));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
} }
if (simple)
{
if (mIns[sz - 3].mType == ASMIT_INC && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) &&
mBranch == ASMIT_BCC)
{
// check for usage of Y register
bool yother = false, yindex = false, xother = false, xindex = false;
int zreg = mIns[sz - 3].mAddress;
int limit = mIns[sz - 1].mAddress;
for (int i = 0; i < sz - 3; i++)
{
if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yother = true;
if (mIns[i].mType == ASMIT_INX || mIns[i].mType == ASMIT_DEX || mIns[i].mType == ASMIT_TAX)
xother = true;
else if (mIns[i].mType == ASMIT_LDX)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xindex = true;
else
xother = true;
}
else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_INDIRECT_X))
xother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xother = true;
}
if (!yother)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA, ASMIM_IMPLIED));
else if (mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(mIns[i]);
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPY, ASMIM_IMMEDIATE, limit));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
else if (!xother)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED));
else if (mIns[i].mType != ASMIT_LDX)
lblock->mIns.Push(mIns[i]);
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_INX, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_IMMEDIATE, limit));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
}
else if (mIns[sz - 1].mType == ASMIT_DEC && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && mBranch == ASMIT_BNE)
{
// check for usage of Y register
bool yother = false, yindex = false;
int zreg = mIns[sz - 1].mAddress;
for (int i = 0; i < sz - 1; i++)
{
if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yother = true;
}
if (!yother)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 1 < sz; i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA, ASMIM_IMPLIED));
else if (mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(mIns[i]);
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEY, ASMIM_IMPLIED));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
}
else if (mIns[sz - 3].mType == ASMIT_INC && mIns[sz - 3].mMode == ASMIM_ZERO_PAGE &&
mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_ZERO_PAGE && mIns[sz - 3].mAddress == mIns[sz - 2].mAddress &&
mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_ZERO_PAGE && !(mIns[sz - 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_X | LIVE_CPU_REG_Y)) &&
mBranch == ASMIT_BCC)
{
// check for usage of Y register
bool yother = false, yindex = false, lchanged = false, xother = false, xindex = false;
int lreg = mIns[sz - 1].mAddress;
int zreg = mIns[sz - 3].mAddress;
for (int i = 0; i < sz - 3; i++)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == lreg && mIns[i].ChangesAddress())
lchanged = true;
if (mIns[i].mType == ASMIT_INY || mIns[i].mType == ASMIT_DEY || mIns[i].mType == ASMIT_TAY)
yother = true;
else if (mIns[i].mType == ASMIT_LDY)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yindex = true;
else
yother = true;
}
else if (!yindex && (mIns[i].mType == ASMIT_STY || mIns[i].mType == ASMIT_TYA || mIns[i].mMode == ASMIM_ABSOLUTE_Y || mIns[i].mMode == ASMIM_INDIRECT_Y))
yother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
yother = true;
if (mIns[i].mType == ASMIT_INX || mIns[i].mType == ASMIT_DEX || mIns[i].mType == ASMIT_TAX)
xother = true;
else if (mIns[i].mType == ASMIT_LDX)
{
if (mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xindex = true;
else
xother = true;
}
else if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xother = true;
else if (!xindex && (mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_TXA || mIns[i].mMode == ASMIM_ABSOLUTE_X || mIns[i].mMode == ASMIM_INDIRECT_X))
xother = true;
else if (mIns[i].mType != ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
xother = true;
}
if (!yother && !lchanged)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TYA, ASMIM_IMPLIED));
else if (mIns[i].mType != ASMIT_LDY)
lblock->mIns.Push(mIns[i]);
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPY, ASMIM_ZERO_PAGE, lreg));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
else if (!xother && !lchanged)
{
NativeCodeBasicBlock* lblock = proc->AllocateBlock();
NativeCodeBasicBlock* eblock = proc->AllocateBlock();
for (int i = 0; i + 3 < sz; i++)
{
if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == zreg)
lblock->mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED));
else if (mIns[i].mType != ASMIT_LDX)
lblock->mIns.Push(mIns[i]);
}
lblock->mIns.Push(NativeCodeInstruction(ASMIT_INX, ASMIM_IMPLIED));
lblock->mIns.Push(NativeCodeInstruction(ASMIT_CPX, ASMIM_ZERO_PAGE, lreg));
lblock->mBranch = mBranch;
lblock->mTrueJump = lblock;
lblock->mFalseJump = eblock;
eblock->mIns.Push(NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, zreg));
eblock->mBranch = ASMIT_JMP;
eblock->mTrueJump = mFalseJump;
eblock->mFalseJump = nullptr;
mIns.Clear();
mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, zreg));
mBranch = ASMIT_JMP;
mTrueJump = lblock;
mFalseJump = nullptr;
changed = true;
}
}
}
} }
if (mTrueJump && mTrueJump->OptimizeSimpleLoop(proc)) if (mTrueJump && mTrueJump->OptimizeSimpleLoop(proc))
@ -5351,6 +5467,22 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void)
} }
} }
#endif #endif
// shorten x/y register livetime
#if 1
for (int i = 0; i + 1 < mIns.Size(); i++)
{
if (mIns[i].mType == ASMIT_LDY && mIns[i].mMode == ASMIM_IMMEDIATE)
{
if (!mIns[i + 1].RequiresYReg() && !mIns[i + 1].ChangesYReg() && !(mIns[i + 1].mLive & LIVE_CPU_REG_Z))
{
NativeCodeInstruction ins = mIns[i];
mIns[i] = mIns[i + 1];
mIns[i + 1] = ins;
}
}
}
#endif
bool progress = false; bool progress = false;
do { do {
@ -5428,16 +5560,49 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void)
{ {
mIns[i].mAddress &= mIns[i + 1].mAddress; mIns[i].mAddress &= mIns[i + 1].mAddress;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mType = ASMIT_NOP;
progress = true;
} }
else if (mIns[i].mType == ASMIT_ORA && mIns[i + 1].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE) else if (mIns[i].mType == ASMIT_ORA && mIns[i + 1].mType == ASMIT_ORA && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
{ {
mIns[i].mAddress |= mIns[i + 1].mAddress; mIns[i].mAddress |= mIns[i + 1].mAddress;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mType = ASMIT_NOP;
progress = true;
} }
else if (mIns[i].mType == ASMIT_EOR && mIns[i + 1].mType == ASMIT_EOR && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE) else if (mIns[i].mType == ASMIT_EOR && mIns[i + 1].mType == ASMIT_EOR && mIns[i].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mMode == ASMIM_IMMEDIATE)
{ {
mIns[i].mAddress ^= mIns[i + 1].mAddress; mIns[i].mAddress ^= mIns[i + 1].mAddress;
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mType = ASMIT_NOP;
progress = true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
{
mIns[i + 1].mType = ASMIT_NOP;
progress = true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_EOR && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0)
{
mIns[i + 1].mType = ASMIT_NOP;
progress = true;
}
else if (mIns[i].mType == ASMIT_LDA && mIns[i + 1].mType == ASMIT_AND && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff)
{
mIns[i + 1].mType = ASMIT_NOP;
progress = true;
}
else if (mIns[i].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ROR)
{
mIns[i + 0].mType = ASMIT_NOP;
mIns[i + 1].mType = ASMIT_LSR;
progress = true;
}
else if (
mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress &&
(mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ASL || mIns[i + 1].mType == ASMIT_ROL || mIns[i + 1].mType == ASMIT_ROR))
{
mIns[i + 0].mType = mIns[i + 1].mType;
mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_STA;
progress = true;
} }
else if ( else if (
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & LIVE_CPU_REG_A) && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & LIVE_CPU_REG_A) &&
@ -5446,6 +5611,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void)
{ {
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mType = ASMIT_NOP;
mIns[i + 0].mLive |= LIVE_CPU_REG_Z; mIns[i + 0].mLive |= LIVE_CPU_REG_Z;
progress = true;
} }
else if ( else if (
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_ZERO_PAGE &&
@ -5455,11 +5621,12 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void)
mIns[i + 0].mType = ASMIT_ASL; mIns[i + 0].mType = ASMIT_ASL;
mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 0].mLive |= LIVE_CPU_REG_A; mIns[i + 0].mLive |= LIVE_CPU_REG_A;
progress = true;
} }
if ( if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_Y))) mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mLive & LIVE_MEM ))
{ {
int apos, breg, ireg; int apos, breg, ireg;
if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg)) if (FindAddressSumY(i, mIns[i + 1].mAddress, apos, breg, ireg))
@ -5471,6 +5638,11 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void)
mIns[apos + 6].mType = ASMIT_NOP; mIns[apos + 6].mType = ASMIT_NOP;
mIns[apos + 6].mMode = ASMIM_IMPLIED; mIns[apos + 6].mMode = ASMIM_IMPLIED;
} }
if (mIns[i + 1].mLive & LIVE_CPU_REG_Y)
{
mIns.Insert(i + 2, NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0));
mIns[i + 2].mLive |= LIVE_CPU_REG_Y;
}
mIns[i + 0].mMode = ASMIM_ZERO_PAGE; mIns[i + 0].mMode = ASMIM_ZERO_PAGE;
mIns[i + 0].mAddress = ireg; mIns[i + 0].mAddress = ireg;
mIns[i + 1].mAddress = breg; mIns[i + 1].mAddress = breg;
@ -5546,6 +5718,15 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void)
mIns[i + 2].mType = ASMIT_SBC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1; mIns[i + 2].mType = ASMIT_SBC; mIns[i + 2].mMode = ASMIM_IMMEDIATE; mIns[i + 2].mAddress = 1;
progress = true; progress = true;
} }
else if (
mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&
mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE &&
mIns[i + 2].mType == ASMIT_ROR && mIns[i + 2].mMode == ASMIM_IMPLIED)
{
mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED;
mIns[i + 2].mType = ASMIT_CLC; mIns[i + 2].mMode = ASMIM_IMPLIED;
progress = true;
}
#if 1 #if 1
if ( if (
mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 &&

View File

@ -57,6 +57,8 @@ public:
bool ChangesAddress(void) const; bool ChangesAddress(void) const;
bool ChangesAccu(void) const; bool ChangesAccu(void) const;
bool RequiresAccu(void) const; bool RequiresAccu(void) const;
bool RequiresYReg(void) const;
bool ChangesYReg(void) const;
bool SameEffectiveAddress(const NativeCodeInstruction& ins) const; bool SameEffectiveAddress(const NativeCodeInstruction& ins) const;
bool IsSame(const NativeCodeInstruction& ins) const; bool IsSame(const NativeCodeInstruction& ins) const;
bool IsCommutative(void) const; bool IsCommutative(void) const;

View File

@ -34,7 +34,7 @@ bool SourceFile::ReadLine(char* line)
} }
SourceFile::SourceFile(void) SourceFile::SourceFile(void)
: mFile(nullptr), mFileName{ 0 } : mFile(nullptr), mFileName{ 0 }, mStack(nullptr)
{ {
} }
@ -88,6 +88,40 @@ void SourceFile::Close(void)
} }
} }
bool SourceFile::PushSource(void)
{
SourceStack* stack = new SourceStack();
stack->mUp = mStack;
mStack = stack;
stack->mFilePos = ftell(mFile);
return true;
}
bool SourceFile::PopSource(void)
{
SourceStack* stack = mStack;
if (stack)
{
fseek(mFile, stack->mFilePos, SEEK_SET);
mStack = mStack->mUp;
return true;
}
else
return false;
}
bool SourceFile::DropSource(void)
{
SourceStack* stack = mStack;
if (stack)
{
mStack = mStack->mUp;
return true;
}
else
return false;
}
bool Preprocessor::NextLine(void) bool Preprocessor::NextLine(void)
{ {
int s = 0; int s = 0;
@ -171,6 +205,21 @@ bool Preprocessor::CloseSource(void)
return false; return false;
} }
bool Preprocessor::PushSource(void)
{
return mSource->PushSource();
}
bool Preprocessor::PopSource(void)
{
return mSource->PopSource();
}
bool Preprocessor::DropSource(void)
{
return mSource->DropSource();
}
Preprocessor::Preprocessor(Errors* errors) Preprocessor::Preprocessor(Errors* errors)
: mSource(nullptr), mSourceList(nullptr), mPaths(nullptr), mErrors(errors) : mSource(nullptr), mSourceList(nullptr), mPaths(nullptr), mErrors(errors)
{ {

View File

@ -4,6 +4,15 @@
#include <stdio.h> #include <stdio.h>
#include "MachineTypes.h" #include "MachineTypes.h"
class SourceStack
{
public:
SourceStack* mUp;
int mFilePos;
Location mLocation;
};
class SourceFile class SourceFile
{ {
public: public:
@ -11,6 +20,7 @@ public:
SourceFile * mUp, * mNext; SourceFile * mUp, * mNext;
Location mLocation; Location mLocation;
SourceStack * mStack;
bool ReadLine(char* line); bool ReadLine(char* line);
@ -19,6 +29,11 @@ public:
bool Open(const char* name, const char * path); bool Open(const char* name, const char * path);
void Close(void); void Close(void);
bool PushSource(void);
bool PopSource(void);
bool DropSource(void);
protected: protected:
FILE* mFile; FILE* mFile;
}; };
@ -51,6 +66,10 @@ public:
bool OpenSource(const char* reason, const char* name, bool local); bool OpenSource(const char* reason, const char* name, bool local);
bool CloseSource(void); bool CloseSource(void);
bool PushSource(void);
bool PopSource(void);
bool DropSource(void);
Preprocessor(Errors * errors); Preprocessor(Errors * errors);
~Preprocessor(void); ~Preprocessor(void);
}; };

View File

@ -121,7 +121,11 @@ const char* TokenNames[] = {
"'#endif'", "'#endif'",
"'#ifdef'", "'#ifdef'",
"'#ifndef'", "'#ifndef'",
"'#pragma'" "'#pragma'",
"'#assign'",
"'#repeat'",
"'#until'"
}; };
@ -529,6 +533,54 @@ void Scanner::NextToken(void)
if (mToken != TK_EOL) if (mToken != TK_EOL)
mErrors->Error(mLocation, ERRR_PREPROCESSOR, "End of line expected"); mErrors->Error(mLocation, ERRR_PREPROCESSOR, "End of line expected");
} }
else if (mToken == TK_PREP_ASSIGN)
{
mPreprocessorMode = true;
NextRawToken();
if (mToken == TK_IDENT)
{
const Ident* ident = mTokenIdent;
NextToken();
int v = PrepParseConditional();
Macro* macro = mDefines->Lookup(ident);
if (!macro)
{
macro = new Macro(ident);
mDefines->Insert(macro);
}
char buffer[20];
sprintf_s(buffer, "%d", v);
macro->SetString(buffer);
mPreprocessorMode = false;
if (mToken != TK_EOL)
mErrors->Error(mLocation, ERRR_PREPROCESSOR, "End of line expected");
}
}
else if (mToken == TK_PREP_REPEAT)
{
mPreprocessor->PushSource();
}
else if (mToken == TK_PREP_UNTIL)
{
mPreprocessorMode = true;
NextToken();
int v = PrepParseConditional();
if (mToken != TK_EOL)
mErrors->Error(mLocation, ERRR_PREPROCESSOR, "End of line expected");
if (v)
mPreprocessor->DropSource();
else
{
mPreprocessor->PopSource();
mPreprocessor->PushSource();
mPreprocessor->NextLine();
mOffset = 0;
}
mPreprocessorMode = false;
}
else if (mToken == TK_IDENT) else if (mToken == TK_IDENT)
{ {
Macro* def = nullptr; Macro* def = nullptr;
@ -917,7 +969,7 @@ void Scanner::NextRawToken(void)
case '#': case '#':
{ {
if (!mAssemblerMode) if (!mAssemblerMode || mOffset == 1)
{ {
int n = 0; int n = 0;
char tkprep[128]; char tkprep[128];
@ -946,6 +998,12 @@ void Scanner::NextRawToken(void)
mToken = TK_PREP_ENDIF; mToken = TK_PREP_ENDIF;
else if (!strcmp(tkprep, "pragma")) else if (!strcmp(tkprep, "pragma"))
mToken = TK_PREP_PRAGMA; mToken = TK_PREP_PRAGMA;
else if (!strcmp(tkprep, "assign"))
mToken = TK_PREP_ASSIGN;
else if (!strcmp(tkprep, "repeat"))
mToken = TK_PREP_REPEAT;
else if (!strcmp(tkprep, "until"))
mToken = TK_PREP_UNTIL;
else else
mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "Invalid preprocessor command", tkprep); mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "Invalid preprocessor command", tkprep);
} }

View File

@ -122,6 +122,10 @@ enum Token
TK_PREP_IFNDEF, TK_PREP_IFNDEF,
TK_PREP_PRAGMA, TK_PREP_PRAGMA,
TK_PREP_ASSIGN,
TK_PREP_REPEAT,
TK_PREP_UNTIL,
NUM_TOKENS NUM_TOKENS
}; };