From 5435e1c9306cd33ff011d4e66232f35aca113b21 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Sat, 27 Aug 2022 15:23:50 +0200 Subject: [PATCH] Improve register allocation in complex loops --- oscar64/Array.h | 8 + oscar64/Declaration.cpp | 49 +++ oscar64/NativeCodeGenerator.cpp | 724 ++++++++++++++++++++++++++++++-- oscar64/NativeCodeGenerator.h | 14 +- oscar64/Parser.cpp | 2 +- 5 files changed, 757 insertions(+), 40 deletions(-) diff --git a/oscar64/Array.h b/oscar64/Array.h index 4520ead..5fe9ed4 100644 --- a/oscar64/Array.h +++ b/oscar64/Array.h @@ -326,4 +326,12 @@ public: return i; return -1; } + + bool Contains(const T& t) const + { + for (int i = 0; i < size; i++) + if (array[i] == t) + return true; + return false; + } }; diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index d3eecfa..b9d35fd 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -455,6 +455,55 @@ Expression* Expression::ConstantFold(Errors * errors) } #endif } + else if (mType == EX_RELATIONAL && mLeft->mType == EX_CONSTANT && mRight->mType == EX_CONSTANT) + { + if (mLeft->mDecValue->mType == DT_CONST_INTEGER && mRight->mDecValue->mType == DT_CONST_INTEGER) + { + int64 ival = 0, ileft = mLeft->mDecValue->mInteger, iright = mRight->mDecValue->mInteger; + + bool check = false; + switch (mToken) + { + case TK_EQUAL: + check = ileft == iright; + break; + case TK_NOT_EQUAL: + check = ileft != iright; + break; + case TK_GREATER_THAN: + check = ileft > iright; + break; + case TK_GREATER_EQUAL: + check = ileft >= iright; + break; + case TK_LESS_THAN: + check = ileft < iright; + break; + case TK_LESS_EQUAL: + check = ileft <= iright; + break; + } + + Declaration * dec = new Declaration(mLocation, DT_CONST_INTEGER); + dec->mBase = TheBoolTypeDeclaration; + dec->mInteger = check ? 1 : 0; + Expression * exp = new Expression(mLocation, EX_CONSTANT); + exp->mDecValue = dec; + exp->mDecType = dec->mBase; + return exp; + + } + } + else if (mType == EX_CONDITIONAL && mLeft->mType == EX_CONSTANT) + { + if (mLeft->mDecValue->mType == DT_CONST_INTEGER) + { + if (mLeft->mDecValue->mInteger != 0) + return mRight->mLeft->ConstantFold(errors); + else + return mRight->mRight->ConstantFold(errors); + } + } else if (mType == EX_BINARY && mToken == TK_ADD && mLeft->mType == EX_VARIABLE && mLeft->mDecValue->mType == DT_VARIABLE && (mLeft->mDecValue->mFlags & DTF_GLOBAL) && mLeft->mDecType->mType == DT_TYPE_ARRAY && mRight->mType == EX_CONSTANT && mRight->mDecValue->mType == DT_CONST_INTEGER) { Expression* ex = new Expression(mLocation, EX_VARIABLE); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 4315376..8548ce0 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -3082,7 +3082,7 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT { data.mRegs[data.mRegs[CPU_REG_A].mValue].mMode = NRDM_ZERO_PAGE; data.mRegs[data.mRegs[CPU_REG_A].mValue].mValue = mAddress; - data.mRegs[mAddress].mMode = NRDM_UNKNOWN; + data.mRegs[mAddress].Reset(); } else #endif @@ -12390,7 +12390,7 @@ bool NativeCodeBasicBlock::SimplifyDiamond(NativeCodeProcedure* proc) { mVisited = true; - if (mTrueJump && mFalseJump) + if (mTrueJump && mFalseJump && mTrueJump->mEntryRequiredRegs.Size() && mFalseJump->mEntryRequiredRegs.Size()) { if (!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1 && mTrueJump->mTrueJump->mNumEntries == 2) { @@ -14146,14 +14146,14 @@ bool NativeCodeBasicBlock::CanForwardZPMove(int saddr, int daddr, int & index) c return false; } -bool NativeCodeBasicBlock::CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock* nblock) const +bool NativeCodeBasicBlock::CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock* nblock, const NativeCodeBasicBlock* fblock) const { if (mExitRequiredRegs[CPU_REG_X]) return false; - if (mTrueJump && mTrueJump != nblock && mTrueJump->mEntryRequiredRegs[addr]) + if (mTrueJump && mTrueJump != nblock && mTrueJump != fblock && mTrueJump->mEntryRequiredRegs[addr]) return false; - if (mFalseJump && mFalseJump != nblock && mFalseJump->mEntryRequiredRegs[addr]) + if (mFalseJump && mFalseJump != nblock && mFalseJump != fblock && mFalseJump->mEntryRequiredRegs[addr]) return false; int i = mIns.Size(); @@ -14179,6 +14179,8 @@ bool NativeCodeBasicBlock::CanChangeTailZPStoreToX(int addr, const NativeCodeBas void NativeCodeBasicBlock::ChangeTailZPStoreToX(int addr) { + mExitRequiredRegs += CPU_REG_X; + int i = mIns.Size(); while (i > 0) { @@ -14406,12 +14408,18 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool NativeCodeBasicBlock* eblock = mEntryBlocks[0]; if (mIns.Size() > 0 && eblock->mIns.Size() > 0) { - if (mIns[0].mType == ASMIT_ORA && mIns[0].mMode == ASMIM_IMMEDIATE && mIns[0].mAddress == 0 && eblock->mIns.Last().ChangesAccuAndFlag()) + int sz = eblock->mIns.Size(); + + if (mIns[0].mType == ASMIT_ORA && mIns[0].mMode == ASMIM_IMMEDIATE && mIns[0].mAddress == 0) { - eblock->mExitRequiredRegs += CPU_REG_Z; - mEntryRequiredRegs += CPU_REG_Z; - mIns.Remove(0); - changed = true; + if (eblock->mIns.Last().ChangesAccuAndFlag() || + sz >= 2 && !eblock->mIns.Last().ChangesZFlag() && eblock->mIns[sz - 2].ChangesAccuAndFlag()) + { + eblock->mExitRequiredRegs += CPU_REG_Z; + mEntryRequiredRegs += CPU_REG_Z; + mIns.Remove(0); + changed = true; + } } } } @@ -14537,6 +14545,40 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool #endif +#if 1 + if (mFalseJump && mTrueJump->mIns.Size() > 0 && mFalseJump->mIns.Size() > 0 && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1 && + mTrueJump->mIns[0].mType == ASMIT_LDA && mTrueJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mTrueJump->mIns[0].mLive & LIVE_MEM) && + mFalseJump->mIns[0].mType == ASMIT_LDA && mFalseJump->mIns[0].mMode == ASMIM_ZERO_PAGE && !(mFalseJump->mIns[0].mLive & LIVE_MEM) && + mTrueJump->mIns[0].mAddress == mFalseJump->mIns[0].mAddress) + { + if (mExitRequiredRegs.Size() > 0 && !mExitRequiredRegs[CPU_REG_X]) + { + if (CanChangeTailZPStoreToX(mTrueJump->mIns[0].mAddress, mTrueJump, mFalseJump)) + { + ChangeTailZPStoreToX(mTrueJump->mIns[0].mAddress); + + mExitRequiredRegs += CPU_REG_X; + + mTrueJump->mEntryProvidedRegs += CPU_REG_X; + mFalseJump->mEntryProvidedRegs += CPU_REG_X; + + mTrueJump->mEntryRequiredRegs += CPU_REG_X; + mFalseJump->mEntryRequiredRegs += CPU_REG_X; + + mTrueJump->mIns[0].mType = ASMIT_TXA; + mTrueJump->mIns[0].mMode = ASMIM_IMPLIED; + + mFalseJump->mIns[0].mType = ASMIT_TXA; + mFalseJump->mIns[0].mMode = ASMIM_IMPLIED; + + changed = true; + + CheckLive(); + } + } + } +#endif + #if 1 if (mIns.Size() >= 1 && mIns[0].mType == ASMIT_TAX && !(mIns[0].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) { @@ -17827,7 +17869,8 @@ bool NativeCodeBasicBlock::MoveStoreXUp(int at) mIns[at - 1 + i] = mIns[at + i]; } mIns[at + n] = ins; - done = true; + if (ins.mType != ASMIT_STY) + done = true; } at--; } @@ -17913,7 +17956,9 @@ bool NativeCodeBasicBlock::MoveStoreYUp(int at) mIns[at - 1] = mIns[at]; mIns[at] = ins; at--; - done = true; + + if (ins.mType != ASMIT_STX) + done = true; } return done; @@ -18564,6 +18609,54 @@ bool NativeCodeBasicBlock::BitFieldForwarding(const NativeRegisterDataSet& data) return changed; } +bool NativeCodeBasicBlock::GlobalValueForwarding(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (mEntryBlocks.Size() == 0) + mDataSet.Reset(); + else + { + if (this == mEntryBlocks[0]->mTrueJump) + mDataSet = mEntryBlocks[0]->mNDataSet; + else + mDataSet = mEntryBlocks[0]->mFDataSet; + + for (int i = 1; i < mEntryBlocks.Size(); i++) + { + if (this == mEntryBlocks[i]->mTrueJump) + mDataSet.Intersect(mEntryBlocks[i]->mNDataSet); + else + mDataSet.Intersect(mEntryBlocks[i]->mFDataSet); + } + } + + for (int i = 0; i < mIns.Size(); i++) + { + AsmInsType carryop; + + if (mIns[i].ValueForwarding(mDataSet, carryop, true, false)) + changed = true; + if (carryop != ASMIT_NOP) + mIns.Insert(i + 1, NativeCodeInstruction(carryop)); + } + + CheckLive(); + + if (this->mTrueJump && this->mTrueJump->GlobalValueForwarding()) + changed = true; + if (this->mFalseJump && this->mFalseJump->GlobalValueForwarding()) + changed = true; + } + + return changed; +} + + bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data, bool global, bool final) { bool changed = false; @@ -18902,6 +18995,9 @@ bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data, bo changed = true; if (this->mFalseJump && this->mFalseJump->ValueForwarding(mFDataSet, global, final)) changed = true; + + + } return changed; @@ -20609,6 +20705,474 @@ bool NativeCodeBasicBlock::OptimizeInnerLoops(NativeCodeProcedure* proc) return changed; } +NativeCodeBasicBlock* NativeCodeBasicBlock::BuildSingleEntry(NativeCodeProcedure* proc, NativeCodeBasicBlock* block) +{ + if (block->mNumEntries > 1) + { + NativeCodeBasicBlock* nblock = proc->AllocateBlock(); + nblock->mTrueJump = block; + nblock->mEntryRequiredRegs = block->mEntryRequiredRegs; + nblock->mExitRequiredRegs = block->mExitRequiredRegs; + int k = block->mEntryBlocks.IndexOf(this); + block->mEntryBlocks[k] = nblock; + nblock->mEntryBlocks.Push(this); + nblock->mNumEntries = 1; + return nblock; + } + else + return block; +} + +NativeCodeBasicBlock* NativeCodeBasicBlock::BuildSingleExit(NativeCodeProcedure* proc, NativeCodeBasicBlock* block) +{ + if (block->mFalseJump) + { + NativeCodeBasicBlock* nblock = proc->AllocateBlock(); + if (block->mFalseJump == this) + block->mFalseJump = nblock; + if (block->mTrueJump == this) + block->mTrueJump = nblock; + nblock->mTrueJump = this; + + nblock->mEntryRequiredRegs = this->mEntryRequiredRegs; + nblock->mExitRequiredRegs = this->mExitRequiredRegs; + + int k = mEntryBlocks.IndexOf(block); + mEntryBlocks[k] = nblock; + nblock->mEntryBlocks.Push(block); + nblock->mNumEntries = 1; + return nblock; + } + else + return block; +} + + +bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) +{ + bool changed = false; + + if (!mVisited) + { + if (mLoopHead) + { + GrowingArray lblocks(nullptr); + + proc->ResetPatched(); + if (CollectGenericLoop(proc, lblocks)) + { + int yreg = -1, xreg = -1; + int zyreg[256], zxreg[256]; + for (int i = 0; i < 256; i++) + { + zyreg[i] = 0; + zxreg[i] = 0; + } + + if (mEntryRequiredRegs[CPU_REG_Y]) + yreg = -2; + if (mEntryRequiredRegs[CPU_REG_X]) + xreg = -2; + + for (int i = 0; i < lblocks.Size(); i++) + { + NativeCodeBasicBlock* block = lblocks[i]; + + int yoffset = 0, xoffset = 0; + + for (int j = 0; j < block->mIns.Size(); j++) + { + const NativeCodeInstruction& ins(block->mIns[j]); + + switch (ins.mType) + { + case ASMIT_LDY: + if (ins.mMode == ASMIM_ZERO_PAGE && (yreg == -1 || yreg == ins.mAddress)) + yreg = ins.mAddress; + else + yreg = -2; + if (ins.mMode == ASMIM_ZERO_PAGE) + zxreg[ins.mAddress] = -1; + yoffset = 0; + break; + case ASMIT_LDX: + if (ins.mMode == ASMIM_ZERO_PAGE && (xreg == -1 || xreg == ins.mAddress)) + xreg = ins.mAddress; + else + xreg = -2; + if (ins.mMode == ASMIM_ZERO_PAGE) + zyreg[ins.mAddress] = -1; + xoffset = 0; + break; + case ASMIT_STY: + if (ins.mMode == ASMIM_ZERO_PAGE) + zxreg[ins.mAddress] = -1; + break; + case ASMIT_STX: + if (ins.mMode == ASMIM_ZERO_PAGE) + zyreg[ins.mAddress] = -1; + break; + case ASMIT_INY: + yoffset++; + break; + case ASMIT_DEY: + yoffset--; + break; + case ASMIT_INX: + xoffset++; + break; + case ASMIT_DEX: + xoffset--; + break; + case ASMIT_INC: + case ASMIT_DEC: + if (ins.mMode == ASMIM_ZERO_PAGE) + { + if (zxreg[ins.mAddress] >= 0) + zxreg[ins.mAddress] += 3; + if (zyreg[ins.mAddress] >= 0) + zyreg[ins.mAddress] += 3; + } + break; + case ASMIT_LDA: + case ASMIT_STA: + if (ins.mMode == ASMIM_ZERO_PAGE) + { + if (ins.mAddress == yreg && yoffset != 0) + yreg = -2; + if (ins.mAddress == xreg && xoffset != 0) + xreg = -2; + + if (zxreg[ins.mAddress] >= 0) + zxreg[ins.mAddress]++; + if (zyreg[ins.mAddress] >= 0) + zyreg[ins.mAddress]++; + } + break; + case ASMIT_TYA: + if (yoffset) + yreg = -2; + break; + case ASMIT_TXA: + if (xoffset) + xreg = -2; + break; + case ASMIT_TAY: + yreg = -2; + break; + case ASMIT_TAX: + xreg = -2; + break; + case ASMIT_JSR: + yreg = -2; + xreg = -2; + break; + default: + if (ins.mMode == ASMIM_ZERO_PAGE) + { + zxreg[ins.mAddress] = -1; + zyreg[ins.mAddress] = -1; + } + } + + if (!(ins.mLive & LIVE_CPU_REG_Y)) + yoffset = 0; + if (!(ins.mLive & LIVE_CPU_REG_X)) + xoffset = 0; + + if (ins.mMode == ASMIM_INDIRECT_Y) + { + zxreg[ins.mAddress] = -1; + zyreg[ins.mAddress] = -1; + zxreg[ins.mAddress + 1] = -1; + zyreg[ins.mAddress + 1] = -1; + } + } +#if 1 + if (yoffset && block->mExitRequiredRegs[CPU_REG_Y]) + yreg = -2; + if (xoffset && block->mExitRequiredRegs[CPU_REG_X]) + xreg = -2; +#endif + } + + if (xreg != -2) + { + if (xreg == -1) + { + int nx = 0; + for (int i = 0; i < 256; i++) + { + if (i != yreg && zxreg[i] > nx) + { + nx = zxreg[i]; + xreg = i; + } + } + } + else if (zxreg[xreg] < 0) + xreg = -1; + } + + if (yreg != -2) + { + if (yreg == -1) + { + int nx = 0; + for (int i = 0; i < 256; i++) + { + if (i != xreg && zyreg[i] > nx) + { + nx = zyreg[i]; + yreg = i; + } + } + } + else if (zyreg[yreg] < 0) + yreg = -1; + } + + if (yreg >= 0 || xreg >= 0) + { + GrowingArray entries(nullptr); + GrowingArray exits(nullptr); + + for (int i = 0; i < lblocks.Size(); i++) + { + NativeCodeBasicBlock* block = lblocks[i]; + + if (yreg >= 0) + { + block->mEntryRequiredRegs += CPU_REG_Y; + block->mExitRequiredRegs += CPU_REG_Y; + } + if (xreg >= 0) + { + block->mEntryRequiredRegs += CPU_REG_X; + block->mExitRequiredRegs += CPU_REG_X; + } + + if (block->mTrueJump && !lblocks.Contains(block->mTrueJump)) + { + block->mTrueJump = block->BuildSingleEntry(proc, block->mTrueJump); + if (yreg >= 0) + block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); + if (xreg >= 0) + block->mTrueJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); + } + if (block->mFalseJump && !lblocks.Contains(block->mFalseJump)) + { + block->mFalseJump = block->BuildSingleEntry(proc, block->mFalseJump); + if (yreg >= 0) + block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STY, ASMIM_ZERO_PAGE, yreg)); + if (xreg >= 0) + block->mFalseJump->mIns.Insert(0, NativeCodeInstruction(ASMIT_STX, ASMIM_ZERO_PAGE, xreg)); + } + + for (int j = 0; j < block->mEntryBlocks.Size(); j++) + { + if (!lblocks.Contains(block->mEntryBlocks[j])) + { + block->mEntryBlocks[j] = block->BuildSingleExit(proc, block->mEntryBlocks[j]); + if (yreg >= 0) + block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, yreg)); + if (xreg >= 0) + block->mEntryBlocks[j]->mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_ZERO_PAGE, xreg)); + } + } + + int yoffset = 0, xoffset = 0; + + for (int j = 0; j < block->mIns.Size(); j++) + { + NativeCodeInstruction& ins(block->mIns[j]); + + switch (ins.mType) + { + case ASMIT_LDY: + case ASMIT_STY: + if (ins.mAddress == yreg) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + yoffset = 0; + } + break; + case ASMIT_LDX: + case ASMIT_STX: + if (ins.mAddress == xreg) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + xoffset = 0; + } + break; + case ASMIT_INC: + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg) + { + ins.mType = ASMIT_INY; + ins.mMode = ASMIM_IMPLIED; + } + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) + { + ins.mType = ASMIT_INX; + ins.mMode = ASMIM_IMPLIED; + } + break; + case ASMIT_DEC: + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg) + { + ins.mType = ASMIT_DEY; + ins.mMode = ASMIM_IMPLIED; + } + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) + { + ins.mType = ASMIT_DEX; + ins.mMode = ASMIM_IMPLIED; + } + break; + + case ASMIT_LDA: + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg) + { + ins.mType = ASMIT_TYA; + ins.mMode = ASMIM_IMPLIED; + } + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) + { + ins.mType = ASMIT_TXA; + ins.mMode = ASMIM_IMPLIED; + } + break; + case ASMIT_STA: + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == yreg) + { + ins.mType = ASMIT_TAY; + ins.mMode = ASMIM_IMPLIED; + } + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == xreg) + { + ins.mType = ASMIT_TAX; + ins.mMode = ASMIM_IMPLIED; + } + break; + + case ASMIT_INY: + yoffset++; + break; + case ASMIT_DEY: + yoffset--; + break; + case ASMIT_INX: + xoffset++; + break; + case ASMIT_DEX: + xoffset--; + break; + } + + if (yoffset && yreg >= 0 && !(ins.mLive & LIVE_CPU_REG_Y)) + { + while (yoffset > 0) + { + j++; + block->mIns.Insert(j, NativeCodeInstruction(ASMIT_DEY)); + yoffset--; + } + while (yoffset < 0) + { + j++; + block->mIns.Insert(j, NativeCodeInstruction(ASMIT_INY)); + yoffset++; + } + } + + if (xoffset && xreg >= 0 && !(ins.mLive & LIVE_CPU_REG_X)) + { + while (xoffset > 0) + { + j++; + block->mIns.Insert(j, NativeCodeInstruction(ASMIT_DEX)); + xoffset--; + } + while (xoffset < 0) + { + j++; + block->mIns.Insert(j, NativeCodeInstruction(ASMIT_INX)); + xoffset++; + } + } + + if (yreg >= 0) + ins.mLive |= LIVE_CPU_REG_Y; + if (xreg >= 0) + ins.mLive |= LIVE_CPU_REG_X; + + } + + block->CheckLive(); + } + + changed = true; + } + } + } + + mVisited = true; + + if (mTrueJump && mTrueJump->OptimizeGenericLoop(proc)) + changed = true; + if (mFalseJump && mFalseJump->OptimizeGenericLoop(proc)) + changed = true; + } + + return changed; +} + +void NativeCodeBasicBlock::CollectReachable(GrowingArray& lblock) +{ + if (!mVisited && !mPatched) + { + lblock.Push(this); + mPatched = true; + + if (mTrueJump) mTrueJump->CollectReachable(lblock); + if (mFalseJump) mFalseJump->CollectReachable(lblock); + } +} + +bool NativeCodeBasicBlock::CollectGenericLoop(NativeCodeProcedure* proc, GrowingArray& lblocks) +{ + GrowingArray rblocks(nullptr); + + proc->ResetPatched(); + CollectReachable(rblocks); + + proc->ResetPatched(); + + bool changed; + do + { + changed = false; + + for (int i = 0; i < rblocks.Size(); i++) + { + NativeCodeBasicBlock* block(rblocks[i]); + + if (!block->mPatched && + (block->mTrueJump && (block->mTrueJump->mPatched || block->mTrueJump == this) || + block->mFalseJump && (block->mFalseJump->mPatched || block->mFalseJump == this))) + { + lblocks.Push(block); + block->mPatched = true; + changed = true; + } + } + + } while (changed); + + return lblocks.Size() > 0; +} bool NativeCodeBasicBlock::OptimizeFindLoop(NativeCodeProcedure* proc) { @@ -24205,6 +24769,19 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 2].mType = ASMIT_STA; progress = true; } + + else if ( + mIns[i + 0].mType == ASMIT_TAX && + !mIns[i + 1].ChangesXReg() && !mIns[i + 1].ChangesAccu() && mIns[i + 1].ChangesZFlag() && + mIns[i + 2].mType == ASMIT_TXA && (mIns[i + 2].mLive & LIVE_CPU_REG_Z)) + { + mIns[i + 2] = mIns[i + 0]; mIns[i + 2].mLive |= LIVE_CPU_REG_Z; + mIns[i + 1].mLive |= LIVE_CPU_REG_A; + mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED; + progress = true; + } + + else if ( mIns[i + 0].mType == ASMIT_TAX && mIns[i + 1].mType == ASMIT_TAY && @@ -25544,7 +26121,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass !(mIns[i + 4].mLive & LIVE_CPU_REG_A)) { mIns[i + 0].mType = ASMIT_ROR; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_A; - mIns[i + 1].mType = ASMIT_EOR; mIns[i + 1].mAddress = 0x80; mIns[i + 1].mLive |= LIVE_CPU_REG_A; + mIns[i + 1].mType = ASMIT_EOR; mIns[i + 1].mAddress = 0x80; mIns[i + 1].mLive |= LIVE_CPU_REG_A | LIVE_CPU_REG_Z; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; mIns[i + 4].mType = ASMIT_STA; @@ -26496,6 +27073,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass else if (sz >= 2 && mIns[sz - 2].ChangesAccuAndFlag() && mIns[sz - 1].mType == ASMIT_ASL && mIns[sz - 1].mMode == ASMIM_IMPLIED && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C]) + { if (mBranch == ASMIT_BCC) { @@ -26793,8 +27371,26 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass return false; } +void NativeCodeBasicBlock::CheckVisited(void) +{ +#if _DEBUG + if (!mPatched) + { + mPatched = true; + assert(mVisited); -void NativeCodeBasicBlock::CheckBlocks(void) + if (mTrueJump) + mTrueJump->CheckVisited(); + if (mFalseJump) + mFalseJump->CheckVisited(); + } + +#endif +} + + + +void NativeCodeBasicBlock::CheckBlocks(bool sequence) { #if _DEBUG if (!mVisited) @@ -26802,6 +27398,14 @@ void NativeCodeBasicBlock::CheckBlocks(void) mVisited = true; CheckLive(); + if (sequence) + { + if (mTrueJump) + assert(mTrueJump->mEntryBlocks.Contains(this)); + if (mFalseJump) + assert(mFalseJump->mEntryBlocks.Contains(this)); + } + if (mTrueJump) mTrueJump->CheckBlocks(); if (mFalseJump) mFalseJump->CheckBlocks(); } @@ -27767,6 +28371,30 @@ bool NativeCodeProcedure::MapFastParamsToTemps(void) return mEntryBlock->RemapZeroPage(alias); } +void NativeCodeProcedure::RebuildEntry(void) +{ + ResetVisited(); + for (int i = 0; i < mBlocks.Size(); i++) + { + mBlocks[i]->mNumEntries = 0; + mBlocks[i]->mVisiting = false; + mBlocks[i]->mLoopHead = false; + mBlocks[i]->mFromJump = nullptr; + mBlocks[i]->mDominator = nullptr; + mBlocks[i]->mSameBlock = nullptr; + } + + ResetVisited(); + ResetEntryBlocks(); + mEntryBlock->CountEntries(nullptr); + + ResetVisited(); + mEntryBlock->CollectEntryBlocks(nullptr); + + + mEntryBlock->BuildDominatorTree(nullptr); +} + void NativeCodeProcedure::Optimize(void) { #if 1 @@ -27783,16 +28411,7 @@ void NativeCodeProcedure::Optimize(void) { changed = false; - ResetVisited(); - for (int i = 0; i < mBlocks.Size(); i++) - { - mBlocks[i]->mNumEntries = 0; - mBlocks[i]->mVisiting = false; - mBlocks[i]->mLoopHead = false; - mBlocks[i]->mFromJump = nullptr; - mBlocks[i]->mDominator = nullptr; - mBlocks[i]->mSameBlock = nullptr; - } + RebuildEntry(); #if 1 if (step > 3) @@ -27812,15 +28431,7 @@ void NativeCodeProcedure::Optimize(void) mEntryBlock->Split16BitLoopCount(this); } - ResetVisited(); - ResetEntryBlocks(); - mEntryBlock->CountEntries(nullptr); - - ResetVisited(); - mEntryBlock->CollectEntryBlocks(nullptr); - - - mEntryBlock->BuildDominatorTree(nullptr); + RebuildEntry(); #if 1 if (step > 3) @@ -27852,6 +28463,8 @@ void NativeCodeProcedure::Optimize(void) #if 1 do { + RebuildEntry(); + BuildDataFlowSets(); ResetVisited(); changed = mEntryBlock->RemoveUnusedResultInstructions(); @@ -27862,9 +28475,23 @@ void NativeCodeProcedure::Optimize(void) changed = true; else { - ResetVisited(); - if (mEntryBlock->Propagate16BitSum()) - changed = true; +#if 1 + ResetPatched(); + mEntryBlock->CheckVisited(); + + if (step > 1) + { + ResetVisited(); + if (mEntryBlock->GlobalValueForwarding()) + changed = true; + } +#endif + if (!changed) + { + ResetVisited(); + if (mEntryBlock->Propagate16BitSum()) + changed = true; + } } } while (changed); @@ -27921,6 +28548,11 @@ void NativeCodeProcedure::Optimize(void) ResetVisited(); mEntryBlock->CollectEntryBlocks(nullptr); +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckBlocks(true); +#endif + #if 1 if (step == 2) { @@ -27940,7 +28572,7 @@ void NativeCodeProcedure::Optimize(void) #if _DEBUG ResetVisited(); - mEntryBlock->CheckBlocks(); + mEntryBlock->CheckBlocks(true); #endif @@ -27956,6 +28588,12 @@ void NativeCodeProcedure::Optimize(void) changed = true; } #endif + +#if _DEBUG + ResetVisited(); + mEntryBlock->CheckBlocks(true); +#endif + #if 1 if (step == 3) { @@ -27976,6 +28614,12 @@ void NativeCodeProcedure::Optimize(void) if (mEntryBlock->ReduceLocalYPressure()) changed = true; #endif + +#if 1 + ResetVisited(); + if (!changed && mEntryBlock->OptimizeGenericLoop(this)) + changed = true; +#endif } #endif @@ -28150,6 +28794,12 @@ void NativeCodeProcedure::Optimize(void) } #endif +#endif +#if 0 + if (cnt > 190) + { + printf("Opps\n"); + } #endif if (cnt > 200) { diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 6e5ba96..aba01f2 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -208,8 +208,15 @@ public: bool OptimizeInnerLoops(NativeCodeProcedure* proc); NativeCodeBasicBlock* CollectInnerLoop(NativeCodeBasicBlock* head, GrowingArray& lblocks); + bool OptimizeGenericLoop(NativeCodeProcedure* proc); + bool CollectGenericLoop(NativeCodeProcedure* proc, GrowingArray& lblocks); + void CollectReachable(GrowingArray& lblock); + bool OptimizeFindLoop(NativeCodeProcedure* proc); + NativeCodeBasicBlock* BuildSingleEntry(NativeCodeProcedure* proc, NativeCodeBasicBlock* block); + NativeCodeBasicBlock* BuildSingleExit(NativeCodeProcedure* proc, NativeCodeBasicBlock* block); + void PutByte(uint8 code); void PutWord(uint16 code); @@ -338,6 +345,7 @@ public: bool ReverseReplaceTAX(int at); bool ValueForwarding(const NativeRegisterDataSet& data, bool global, bool final); + bool GlobalValueForwarding(void); bool BitFieldForwarding(const NativeRegisterDataSet& data); void CollectEntryBlocks(NativeCodeBasicBlock* block); @@ -354,7 +362,7 @@ public: bool HasTailSTX(int& addr, int& index) const; bool PropagateSinglePath(void); - bool CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock * nblock) const; + bool CanChangeTailZPStoreToX(int addr, const NativeCodeBasicBlock * nblock, const NativeCodeBasicBlock* fblock = nullptr) const; void ChangeTailZPStoreToX(int addr); bool Check16BitSum(int at, NativeRegisterSum16Info& info); @@ -410,7 +418,8 @@ public: bool IsDominatedBy(const NativeCodeBasicBlock* block) const; void CheckLive(void); - void CheckBlocks(void); + void CheckBlocks(bool sequence = false); + void CheckVisited(void); }; class NativeCodeProcedure @@ -448,6 +457,7 @@ class NativeCodeProcedure void ResetEntryBlocks(void); void ResetVisited(void); void ResetPatched(void); + void RebuildEntry(void); void SaveTempsToStack(int tempSave); void LoadTempsFromStack(int tempSave); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 34d44fd..d6390a8 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -1932,7 +1932,7 @@ Expression* Parser::ParseConditionalExpression(void) texp->mRight = ParseConditionalExpression(); nexp->mDecType = texp->mLeft->mDecType; - exp = nexp; + exp = nexp->ConstantFold(mErrors); } return exp;