diff --git a/autotest/asmtest.c b/autotest/asmtest.c new file mode 100644 index 0000000..fb3c0d6 --- /dev/null +++ b/autotest/asmtest.c @@ -0,0 +1,48 @@ +#include + +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; +} + diff --git a/autotest/autotest.bat b/autotest/autotest.bat index af63c66..7c98a8c 100644 --- a/autotest/autotest.bat +++ b/autotest/autotest.bat @@ -102,6 +102,12 @@ if %errorlevel% neq 0 goto :error ..\release\oscar64 -e -n byteindextest.c 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 :error echo Failed with error #%errorlevel%. diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index 86b9cab..21c03f0 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -983,6 +983,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* cins->mTTemp = proc->AddTemporary(cins->mTType); block->Append(cins); + vr = CoerceType(proc, block, vr, TheSignedIntTypeDeclaration); + InterInstruction * mins = new InterInstruction(); mins->mCode = IC_BINARY_OPERATOR; mins->mOperator = IA_MUL; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index a6a4404..716f70a 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -444,6 +444,21 @@ bool NativeCodeInstruction::ChangesAccuAndFlag(void) const 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 { if (mMode == ASMIM_IMPLIED) @@ -5138,185 +5153,286 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc) mVisited = true; bool changed = false; - 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 && - 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 simple = true; - bool yother = false, yindex = false; - int zreg = mIns[sz - 3].mAddress; - int limit = mIns[sz - 1].mAddress; - - 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; - } + for(int i=0; iAllocateBlock(); + 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)) @@ -5351,6 +5467,22 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) } } #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; do { @@ -5428,16 +5560,49 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) { mIns[i].mAddress &= mIns[i + 1].mAddress; 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) { mIns[i].mAddress |= mIns[i + 1].mAddress; 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) { mIns[i].mAddress ^= mIns[i + 1].mAddress; 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 ( 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 + 0].mLive |= LIVE_CPU_REG_Z; + progress = true; } else if ( 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].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A; + progress = true; } if ( 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; 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].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].mAddress = ireg; 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; 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 ( mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index b6458b4..5353f7e 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -57,6 +57,8 @@ public: bool ChangesAddress(void) const; bool ChangesAccu(void) const; bool RequiresAccu(void) const; + bool RequiresYReg(void) const; + bool ChangesYReg(void) const; bool SameEffectiveAddress(const NativeCodeInstruction& ins) const; bool IsSame(const NativeCodeInstruction& ins) const; bool IsCommutative(void) const; diff --git a/oscar64/Preprocessor.cpp b/oscar64/Preprocessor.cpp index 1e8fad8..917f60b 100644 --- a/oscar64/Preprocessor.cpp +++ b/oscar64/Preprocessor.cpp @@ -34,7 +34,7 @@ bool SourceFile::ReadLine(char* line) } 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) { int s = 0; @@ -171,6 +205,21 @@ bool Preprocessor::CloseSource(void) 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) : mSource(nullptr), mSourceList(nullptr), mPaths(nullptr), mErrors(errors) { diff --git a/oscar64/Preprocessor.h b/oscar64/Preprocessor.h index 8c8e2df..522d3af 100644 --- a/oscar64/Preprocessor.h +++ b/oscar64/Preprocessor.h @@ -4,6 +4,15 @@ #include #include "MachineTypes.h" +class SourceStack +{ +public: + SourceStack* mUp; + + int mFilePos; + Location mLocation; +}; + class SourceFile { public: @@ -11,6 +20,7 @@ public: SourceFile * mUp, * mNext; Location mLocation; + SourceStack * mStack; bool ReadLine(char* line); @@ -19,6 +29,11 @@ public: bool Open(const char* name, const char * path); void Close(void); + + bool PushSource(void); + bool PopSource(void); + bool DropSource(void); + protected: FILE* mFile; }; @@ -51,6 +66,10 @@ public: bool OpenSource(const char* reason, const char* name, bool local); bool CloseSource(void); + bool PushSource(void); + bool PopSource(void); + bool DropSource(void); + Preprocessor(Errors * errors); ~Preprocessor(void); }; diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index dfab64d..6f8deb5 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -121,7 +121,11 @@ const char* TokenNames[] = { "'#endif'", "'#ifdef'", "'#ifndef'", - "'#pragma'" + "'#pragma'", + + "'#assign'", + "'#repeat'", + "'#until'" }; @@ -529,6 +533,54 @@ void Scanner::NextToken(void) if (mToken != TK_EOL) 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) { Macro* def = nullptr; @@ -917,7 +969,7 @@ void Scanner::NextRawToken(void) case '#': { - if (!mAssemblerMode) + if (!mAssemblerMode || mOffset == 1) { int n = 0; char tkprep[128]; @@ -946,6 +998,12 @@ void Scanner::NextRawToken(void) mToken = TK_PREP_ENDIF; else if (!strcmp(tkprep, "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 mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "Invalid preprocessor command", tkprep); } diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index 82c233b..548be3b 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -122,6 +122,10 @@ enum Token TK_PREP_IFNDEF, TK_PREP_PRAGMA, + TK_PREP_ASSIGN, + TK_PREP_REPEAT, + TK_PREP_UNTIL, + NUM_TOKENS };