From 932a65be8c6db3a0897a0a4b5f49d19bf02f611c Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Thu, 2 Feb 2023 20:10:35 +0100 Subject: [PATCH] Optimize cross block XY register usage --- oscar64/InterCode.cpp | 2 +- oscar64/NativeCodeGenerator.cpp | 702 ++++++++++++++++++++++++++++++- oscar64/NativeCodeGenerator.h | 18 +- oscar64/oscar64.cpp | 2 +- oscar64/oscar64.rc | 8 +- oscar64setup/oscar64setup.vdproj | 6 +- 6 files changed, 718 insertions(+), 20 deletions(-) diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index d2ede14..a39f2f1 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -8523,7 +8523,7 @@ void InterCodeBasicBlock::PerformValueForwarding(const GrowingInstructionPtrArra else if (li0->mCode == IC_CONSTANT && li1->mCode == IC_LEA) { InterInstruction* ai0 = ltvalue[li1->mSrc[0].mTemp], * ai1 = ltvalue[li1->mSrc[1].mTemp]; - if (ai0 && ai1 && ai0->mCode == IC_CONSTANT && ai0->mConst.mIntConst >= 0) + if (ai0 && ai1 && ai0->mCode == IC_CONSTANT)// && ai0->mConst.mIntConst >= 0) { InterInstruction* cai = new InterInstruction(ins->mLocation, IC_CONSTANT); cai->mDst.mTemp = spareTemps++; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index de4b090..637e887 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -126,6 +126,17 @@ void NativeRegisterDataSet::ResetZeroPage(int addr) } } +int NativeRegisterDataSet::FindAbsolute(LinkerObject* linkerObject, int addr) +{ + for (int i = 0; i < 256; i++) + { + if (mRegs[i].mMode == NRDM_ABSOLUTE && mRegs[i].mLinkerObject == linkerObject && mRegs[i].mValue == addr) + return i; + } + + return -1; +} + void NativeRegisterDataSet::ResetAbsolute(LinkerObject* linkerObject, int addr) { for (int i = 0; i < NUM_REGS; i++) @@ -1198,6 +1209,28 @@ bool NativeCodeInstruction::UsesZeroPage(int address) const return false; } + else if (mType == ASMIT_RTS) + { + if (mFlags & NCIF_LOWER) + { + if (address == BC_REG_ACCU + 0) + return true; + + if (mFlags & NCIF_UPPER) + { + if (address == BC_REG_ACCU + 1) + return true; + + if (mFlags & NCIF_LONG) + { + if (address == BC_REG_ACCU + 2 || address == BC_REG_ACCU + 3) + return true; + } + } + } + + return false; + } else return false; } @@ -3203,6 +3236,21 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT changed = true; } #endif + +#if 1 + if (mMode == ASMIM_ABSOLUTE && final && !(mFlags & NCIF_VOLATILE) && !ChangesAddress() && HasAsmInstructionMode(mType, ASMIM_ZERO_PAGE)) + { + int i = data.FindAbsolute(mLinkerObject, mAddress); + if (i >= 0) + { + mMode = ASMIM_ZERO_PAGE; + mAddress = i; + mLinkerObject = nullptr; + changed = true; + } + } +#endif + if (mMode == ASMIM_ZERO_PAGE) { switch (mType) @@ -3434,7 +3482,7 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT mAddress = data.mRegs[mAddress].mValue; changed = true; } - else if (data.mRegs[mAddress].mMode == NRDM_ABSOLUTE) + else if (data.mRegs[mAddress].mMode == NRDM_ABSOLUTE && !final) { mMode = ASMIM_ABSOLUTE; mLinkerObject = data.mRegs[mAddress].mLinkerObject; @@ -13930,6 +13978,8 @@ bool NativeCodeBasicBlock::SimplifyDiamond(NativeCodeProcedure* proc) { if (!mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 1 && mTrueJump->mTrueJump->mNumEntries == 2) { + NativeCodeBasicBlock* mblock = mTrueJump->mTrueJump; + if (mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 && mTrueJump->mIns[0].mMode == ASMIM_IMMEDIATE && mFalseJump->mIns[0].mMode == ASMIM_IMMEDIATE) { @@ -13976,6 +14026,15 @@ bool NativeCodeBasicBlock::SimplifyDiamond(NativeCodeProcedure* proc) } } } + + if (mblock->mIns.Size() > 0 && mblock->mIns[0].mType == ASMIT_STX && !(mblock->mIns[0].mLive & LIVE_CPU_REG_X) && + !mTrueJump->ChangesXReg() && !mFalseJump->ChangesXReg()) + { + mIns.Push(mblock->mIns[0]); + mblock->mIns.Remove(0); + mIns[mIns.Size() - 1].mLive |= LIVE_CPU_REG_X; + changed = true; + } } #if 1 if (mTrueJump->mEntryRequiredRegs[CPU_REG_Y] && !mFalseJump->mEntryRequiredRegs[CPU_REG_Y] && !mTrueJump->mEntryRequiredRegs[CPU_REG_Z] && mTrueJump->mNumEntries == 1) @@ -14777,6 +14836,34 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) mBranch = ASMIT_BCC; break; } + else if (mIns[i + 0].mType == ASMIT_LDA && + mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0xff && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 0].SameEffectiveAddress(mIns[i + 2]) && + HasAsmInstructionMode(ASMIT_DEC, mIns[i + 2].mMode) && + !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z))) + { + changed = true; + + NativeCodeBasicBlock* iblock = proc->AllocateBlock(); + NativeCodeBasicBlock* fblock = proc->AllocateBlock(); + + fblock->mTrueJump = mTrueJump; + fblock->mFalseJump = mFalseJump; + fblock->mBranch = mBranch; + + for (int j = i + 3; j < mIns.Size(); j++) + fblock->mIns.Push(mIns[j]); + iblock->mIns.Push(mIns[i + 2]); + mIns.SetSize(i); + iblock->mIns[0].mType = ASMIT_DEC; + iblock->mTrueJump = fblock; + iblock->mBranch = ASMIT_JMP; + + mTrueJump = fblock; + mFalseJump = iblock; + mBranch = ASMIT_BCS; + break; + } else if (mIns[i + 0].mType == ASMIT_TXA && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i + 2].mType == ASMIT_TAX && @@ -18417,6 +18504,578 @@ bool NativeCodeBasicBlock::PatchForwardSumYPointer(const NativeCodeBasicBlock* b } +bool NativeCodeBasicBlock::CrossBlockXYFlood(NativeCodeProcedure* proc) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mIns.Size(); i++) + { + if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_STX || mIns[i].mType == ASMIT_STY) && mIns[i].mMode == ASMIM_ZERO_PAGE && !(mIns[i].mLive & LIVE_CPU_REG_Z)) + { + proc->ResetPatched(); + if (mIns[i].mType != ASMIT_STY && !(mIns[i].mLive & LIVE_CPU_REG_X) &&CheckCrossBlockXFlood(this, mIns[i].mAddress, i + 1)) + { + if (mIns[i].mType == ASMIT_STX) + mIns[i].mType = ASMIT_NOP; + else + mIns[i].mType = ASMIT_TAX; + mIns[i].mMode = ASMIM_IMPLIED; + mIns[i].mLive |= LIVE_CPU_REG_X; + + proc->ResetPatched(); + if (PatchCrossBlockXFlood(this, mIns[i].mAddress, i + 1)) + { + changed = true; + } + } + else + { + proc->ResetPatched(); + if (mIns[i].mType != ASMIT_STX && !(mIns[i].mLive & LIVE_CPU_REG_Y) && CheckCrossBlockYFlood(this, mIns[i].mAddress, i + 1)) + { + if (mIns[i].mType == ASMIT_STY) + mIns[i].mType = ASMIT_NOP; + else + mIns[i].mType = ASMIT_TAY; + mIns[i].mMode = ASMIM_IMPLIED; + mIns[i].mLive |= LIVE_CPU_REG_Y; + + proc->ResetPatched(); + if (PatchCrossBlockYFlood(this, mIns[i].mAddress, i + 1)) + { + changed = true; + } + } + } + } + } + + if (mTrueJump && mTrueJump->CrossBlockXYFlood(proc)) + changed = true; + if (mFalseJump && mFalseJump->CrossBlockXYFlood(proc)) + changed = true; + } + + return changed; +} + +bool NativeCodeBasicBlock::CheckCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at) +{ + if (at == 0 && this == block) + return false; + + if (!mPatched) + { + mPatched = true; + + if (at == 0) + { + if (!mEntryRequiredRegs[reg]) + return true; + + if (mNumEntries > 1) + { + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (!mEntryBlocks[i]->CheckCrossBlockXFloodExit(block, reg)) + return false; + } + } + + while (at < mIns.Size()) + { + NativeCodeInstruction& ins(mIns[at]); + + if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1)) + return false; + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + if (!(ins.mLive & LIVE_MEM)) + return true; + } + else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) + { + } + else if (ins.mType == ASMIT_LDX) + { + return !(ins.mLive & (LIVE_MEM | LIVE_CPU_REG_Z)); + } + else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) + { + } + else + return false; + } + else if (ins.ChangesXReg() || ins.RequiresXReg() || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg)) + return false; + + at++; + } + + mPatchExit = true; + + if (mTrueJump && !mTrueJump->CheckCrossBlockXFlood(block, reg, 0)) + return false; + if (mFalseJump && !mFalseJump->CheckCrossBlockXFlood(block, reg, 0)) + return false; + + } + + return true; +} + +bool NativeCodeBasicBlock::CheckCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg) +{ + if (!mPatchExit) + { + mPatchExit = true; + + if (mTrueJump && !mTrueJump->CheckCrossBlockXFlood(block, reg, 0)) + return false; + if (mFalseJump && !mFalseJump->CheckCrossBlockXFlood(block, reg, 0)) + return false; + + int at = mIns.Size() - 1; + while (at >= 0) + { + NativeCodeInstruction& ins(mIns[at]); + + if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1)) + return false; + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + } + else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) + { + } + else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STX) + { + return !(ins.mLive & LIVE_CPU_REG_Z); + } + else + return false; + } + else if (ins.ChangesXReg() || ins.RequiresXReg() || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg)) + return false; + + at--; + } + + mPatched = true; + + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (!mEntryBlocks[i]->CheckCrossBlockXFloodExit(block, reg)) + return false; + } + + return true; +} + +bool NativeCodeBasicBlock::PatchCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg) +{ + bool changed = false; + + if (!mPatchExit) + { + mPatchExit = true; + + mExitRequiredRegs += CPU_REG_X; + + if (mTrueJump && mTrueJump->PatchCrossBlockXFlood(block, reg, 0)) + changed = true; + if (mFalseJump && mFalseJump->PatchCrossBlockXFlood(block, reg, 0)) + changed = true; + + int at = mIns.Size() - 1; + while (at >= 0) + { + NativeCodeInstruction& ins(mIns[at]); + + ins.mLive |= LIVE_CPU_REG_X; + + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + ins.mType = ASMIT_TXA; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_INC) + { + ins.mType = ASMIT_INX; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_DEC) + { + ins.mType = ASMIT_DEX; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_STA) + { + ins.mType = ASMIT_TAX; + ins.mMode = ASMIM_IMPLIED; + return true; + } + else if (ins.mType == ASMIT_STX) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + return true; + } + } + + at--; + } + + mPatched = true; + mEntryRequiredRegs += CPU_REG_X; + + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (mEntryBlocks[i]->PatchCrossBlockXFloodExit(block, reg)) + changed = true; + + return changed; + } + + return false; +} + +bool NativeCodeBasicBlock::PatchCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at) +{ + bool changed = false; + + if (!mPatched) + { + mPatched = true; + + if (at == 0) + { + if (!mEntryRequiredRegs[reg]) + return false; + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (mEntryBlocks[i]->PatchCrossBlockXFloodExit(block, reg)) + changed = true; + mEntryRequiredRegs += CPU_REG_X; + } + + while (at < mIns.Size()) + { + NativeCodeInstruction& ins(mIns[at]); + + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + ins.mType = ASMIT_TXA; + ins.mMode = ASMIM_IMPLIED; + if (!(ins.mLive & LIVE_MEM)) + return true; + changed = true; + } + else if (ins.mType == ASMIT_INC) + { + ins.mType = ASMIT_INX; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_DEC) + { + ins.mType = ASMIT_DEX; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_LDX) + { + ins.mType = ASMIT_NOP; + return true; + } + } + + ins.mLive |= LIVE_CPU_REG_X; + + at++; + } + + mPatchExit = true; + + mExitRequiredRegs |= CPU_REG_X; + + if (mTrueJump && mTrueJump->PatchCrossBlockXFlood(block, reg, 0)) + changed = true; + if (mFalseJump && mFalseJump->PatchCrossBlockXFlood(block, reg, 0)) + changed = true; + } + + return changed; +} + + +bool NativeCodeBasicBlock::CheckCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at) +{ + if (at == 0 && this == block) + return false; + + if (!mPatched) + { + mPatched = true; + + if (at == 0) + { + if (!mEntryRequiredRegs[reg]) + return true; + + if (mNumEntries > 1) + { + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (!mEntryBlocks[i]->CheckCrossBlockYFloodExit(block, reg)) + return false; +} + } + + while (at < mIns.Size()) + { + NativeCodeInstruction& ins(mIns[at]); + + if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1)) + return false; + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + if (!(ins.mLive & LIVE_MEM)) + return true; + } + else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) + { + } + else if (ins.mType == ASMIT_LDY) + { + return !(ins.mLive & (LIVE_MEM | LIVE_CPU_REG_Z)); + } + else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) + { + } + else + return false; + } + else if (ins.ChangesYReg() || ins.RequiresYReg() || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg)) + return false; + + at++; + } + + mPatchExit = true; + + if (mTrueJump && !mTrueJump->CheckCrossBlockYFlood(block, reg, 0)) + return false; + if (mFalseJump && !mFalseJump->CheckCrossBlockYFlood(block, reg, 0)) + return false; + + } + + return true; +} + +bool NativeCodeBasicBlock::CheckCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg) +{ + if (!mPatchExit) + { + mPatchExit = true; + + if (mTrueJump && !mTrueJump->CheckCrossBlockYFlood(block, reg, 0)) + return false; + if (mFalseJump && !mFalseJump->CheckCrossBlockYFlood(block, reg, 0)) + return false; + + int at = mIns.Size() - 1; + while (at >= 0) + { + NativeCodeInstruction& ins(mIns[at]); + + if (ins.mMode == ASMIM_INDIRECT_Y && (ins.mAddress == reg || ins.mAddress == reg + 1)) + return false; + else if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + } + else if (ins.mType == ASMIT_INC || ins.mType == ASMIT_DEC) + { + } + else if (ins.mType == ASMIT_STA || ins.mType == ASMIT_STY) + { + return !(ins.mLive & LIVE_CPU_REG_Z); + } + else + return false; + } + else if (ins.ChangesYReg() || ins.RequiresYReg() || ins.ChangesZeroPage(reg) || ins.ReferencesZeroPage(reg)) + return false; + + at--; + } + + mPatched = true; + + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (!mEntryBlocks[i]->CheckCrossBlockYFloodExit(block, reg)) + return false; + } + + return true; +} + +bool NativeCodeBasicBlock::PatchCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg) +{ + bool changed = false; + + if (!mPatchExit) + { + mPatchExit = true; + + mExitRequiredRegs += CPU_REG_Y; + + if (mTrueJump && mTrueJump->PatchCrossBlockYFlood(block, reg, 0)) + changed = true; + if (mFalseJump && mFalseJump->PatchCrossBlockYFlood(block, reg, 0)) + changed = true; + + int at = mIns.Size() - 1; + while (at >= 0) + { + NativeCodeInstruction& ins(mIns[at]); + + ins.mLive |= LIVE_CPU_REG_Y; + + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + ins.mType = ASMIT_TYA; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_INC) + { + ins.mType = ASMIT_INY; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_DEC) + { + ins.mType = ASMIT_DEY; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_STA) + { + ins.mType = ASMIT_TAY; + ins.mMode = ASMIM_IMPLIED; + return true; + } + else if (ins.mType == ASMIT_STY) + { + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + return true; + } + } + + at--; + } + + mPatched = true; + mEntryRequiredRegs += CPU_REG_Y; + + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (mEntryBlocks[i]->PatchCrossBlockYFloodExit(block, reg)) + changed = true; + + return changed; + } + + return false; +} + +bool NativeCodeBasicBlock::PatchCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at) +{ + bool changed = false; + + if (!mPatched) + { + mPatched = true; + + if (at == 0) + { + if (!mEntryRequiredRegs[reg]) + return false; + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (mEntryBlocks[i]->PatchCrossBlockYFloodExit(block, reg)) + changed = true; + mEntryRequiredRegs += CPU_REG_Y; + } + + while (at < mIns.Size()) + { + NativeCodeInstruction& ins(mIns[at]); + + if (ins.mMode == ASMIM_ZERO_PAGE && ins.mAddress == reg) + { + if (ins.mType == ASMIT_LDA) + { + ins.mType = ASMIT_TYA; + ins.mMode = ASMIM_IMPLIED; + if (!(ins.mLive & LIVE_MEM)) + return true; + changed = true; + } + else if (ins.mType == ASMIT_INC) + { + ins.mType = ASMIT_INY; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_DEC) + { + ins.mType = ASMIT_DEY; + ins.mMode = ASMIM_IMPLIED; + changed = true; + } + else if (ins.mType == ASMIT_LDY) + { + ins.mType = ASMIT_NOP; + return true; + } + } + + ins.mLive |= LIVE_CPU_REG_Y; + + at++; + } + + mPatchExit = true; + + mExitRequiredRegs |= CPU_REG_Y; + + if (mTrueJump && mTrueJump->PatchCrossBlockYFlood(block, reg, 0)) + changed = true; + if (mFalseJump && mFalseJump->PatchCrossBlockYFlood(block, reg, 0)) + changed = true; + } + + return changed; +} + bool NativeCodeBasicBlock::IsDominatedBy(const NativeCodeBasicBlock* block) const { @@ -22580,7 +23239,7 @@ bool NativeCodeBasicBlock::BitFieldForwarding(const NativeRegisterDataSet& data) return changed; } -bool NativeCodeBasicBlock::GlobalValueForwarding(void) +bool NativeCodeBasicBlock::GlobalValueForwarding(bool final) { bool changed = false; @@ -22610,16 +23269,16 @@ bool NativeCodeBasicBlock::GlobalValueForwarding(void) { AsmInsType carryop; - if (mIns[i].ValueForwarding(mDataSet, carryop, true, false)) + if (mIns[i].ValueForwarding(mDataSet, carryop, true, final)) changed = true; if (carryop != ASMIT_NOP) mIns.Insert(i + 1, NativeCodeInstruction(carryop)); } - if (this->mTrueJump && this->mTrueJump->GlobalValueForwarding()) + if (this->mTrueJump && this->mTrueJump->GlobalValueForwarding(final)) changed = true; - if (this->mFalseJump && this->mFalseJump->GlobalValueForwarding()) + if (this->mFalseJump && this->mFalseJump->GlobalValueForwarding(final)) changed = true; } @@ -30720,6 +31379,21 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 2].mLive |= LIVE_CPU_REG_A; progress = true; } + else if ( + mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_SEC && + mIns[i + 2].mType == ASMIT_LDA && !mIns[i + 2].SameEffectiveAddress(mIns[i + 0]) && + mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].SameEffectiveAddress(mIns[i + 0]) && !(mIns[i + 3].mLive & LIVE_MEM)) + { + mIns[i + 0].mType = ASMIT_EOR; + mIns[i + 0].mMode = ASMIM_IMMEDIATE; + mIns[i + 0].mAddress = 0xff; + mIns[i + 0].mLive |= LIVE_CPU_REG_A; + mIns[i + 1].mLive |= LIVE_CPU_REG_A; + mIns[i + 2].mType = ASMIT_ADC; + mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; + progress = true; + } else if ( mIns[i + 0].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress < 4 && @@ -31487,7 +32161,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass if (mFalseJump) mFalseJump->CheckLive(); #if 1 - if (i + 1 < mIns.Size()) + if (pass < 7 && i + 1 < mIns.Size()) { if ( mIns[i + 0].mType == ASMIT_LDA && (mIns[i + 0].mMode == ASMIM_ABSOLUTE || mIns[i + 0].mMode == ASMIM_ABSOLUTE_X || mIns[i + 0].mMode == ASMIM_ABSOLUTE_Y || mIns[i + 0].mMode == ASMIM_INDIRECT_Y) && @@ -33797,7 +34471,7 @@ void NativeCodeProcedure::RebuildEntry(void) void NativeCodeProcedure::Optimize(void) { - CheckFunc = !strcmp(mInterProc->mIdent->mString, "missile_animate"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "heapcheck"); #if 1 int step = 0; @@ -33903,7 +34577,7 @@ void NativeCodeProcedure::Optimize(void) if (step > 1) { ResetVisited(); - if (mEntryBlock->GlobalValueForwarding()) + if (mEntryBlock->GlobalValueForwarding(step == 7)) changed = true; } #endif @@ -34289,6 +34963,15 @@ void NativeCodeProcedure::Optimize(void) changed = true; } +#if 1 + if (step == 7) + { + ResetVisited(); + if (mEntryBlock->CrossBlockXYFlood(this)) + changed = true; + } +#endif + #if 1 if (step >= 6) { @@ -34369,7 +35052,7 @@ void NativeCodeProcedure::Optimize(void) mEntryBlock->CheckVisited(); ResetVisited(); - if (mEntryBlock->GlobalValueForwarding()) + if (mEntryBlock->GlobalValueForwarding(true)) changed = true; #endif } @@ -34468,6 +35151,7 @@ void NativeCodeProcedure::ResetPatched(void) mBlocks[i]->mPatchStart = false; mBlocks[i]->mPatchLoop = false; mBlocks[i]->mPatchLoopChanged = false; + mBlocks[i]->mPatchExit = false; } } diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 5c37715..ada72ae 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -46,6 +46,7 @@ struct NativeRegisterDataSet void ResetZeroPage(int addr); void ResetAbsolute(LinkerObject * linkerObject, int addr); + int FindAbsolute(LinkerObject* linkerObject, int addr); void ResetIndirect(int reg); void ResetX(void); void ResetY(void); @@ -177,7 +178,7 @@ public: GrowingArray mEntryBlocks; int mOffset, mSize, mPlace, mNumEntries, mNumEntered, mFrameOffset, mTemp; - bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame, mVisited, mLoopHead, mVisiting, mLocked, mPatched, mPatchFail, mPatchChecked, mPatchStart, mPatchLoop, mPatchLoopChanged; + bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame, mVisited, mLoopHead, mVisiting, mLocked, mPatched, mPatchFail, mPatchChecked, mPatchStart, mPatchLoop, mPatchLoopChanged, mPatchExit; bool mEntryRegA, mEntryRegX, mEntryRegY, mExitRegA, mExitRegX; NativeCodeBasicBlock * mDominator, * mSameBlock; @@ -386,7 +387,7 @@ public: bool ReverseReplaceTAX(int at); bool ValueForwarding(const NativeRegisterDataSet& data, bool global, bool final); - bool GlobalValueForwarding(void); + bool GlobalValueForwarding(bool final); bool BitFieldForwarding(const NativeRegisterDataSet& data); bool ReverseBitfieldForwarding(void); @@ -501,11 +502,24 @@ public: bool CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval); bool PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval); + bool CrossBlockXYFlood(NativeCodeProcedure * proc); + + bool CheckCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at); + bool CheckCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg); + bool PatchCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at); + bool PatchCrossBlockXFloodExit(const NativeCodeBasicBlock* block, int reg); + + bool CheckCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at); + bool CheckCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg); + bool PatchCrossBlockYFlood(const NativeCodeBasicBlock* block, int reg, int at); + bool PatchCrossBlockYFloodExit(const NativeCodeBasicBlock* block, int reg); + bool IsDominatedBy(const NativeCodeBasicBlock* block) const; void CheckLive(void); void CheckBlocks(bool sequence = false); void CheckVisited(void); + }; class NativeCodeProcedure diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 81e1e9c..daa52f9 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -74,7 +74,7 @@ int main2(int argc, const char** argv) #else strcpy(strProductName, "oscar64"); - strcpy(strProductVersion, "1.15.182"); + strcpy(strProductVersion, "1.15.183"); #ifdef __APPLE__ uint32_t length = sizeof(basePath); diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index 5c563a2..5e77c19 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,15,182,0 - PRODUCTVERSION 1,15,182,0 + FILEVERSION 1,15,183,0 + PRODUCTVERSION 1,15,183,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,12 +43,12 @@ BEGIN BEGIN VALUE "CompanyName", "oscar64" VALUE "FileDescription", "oscar64 compiler" - VALUE "FileVersion", "1.15.182.0" + VALUE "FileVersion", "1.15.183.0" VALUE "InternalName", "oscar64.exe" VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "OriginalFilename", "oscar64.exe" VALUE "ProductName", "oscar64" - VALUE "ProductVersion", "1.15.182.0" + VALUE "ProductVersion", "1.15.183.0" END END BLOCK "VarFileInfo" diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index f19991a..9b5f2f3 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -4554,15 +4554,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" - "ProductCode" = "8:{D9D7E97A-B793-4546-B204-9518010E2DB9}" - "PackageCode" = "8:{40E0B5C5-53B2-4285-802B-FBA08B4E661D}" + "ProductCode" = "8:{0316346F-2B7D-478A-BD0C-8AAF6E0371EA}" + "PackageCode" = "8:{BAD074A9-2FC1-4FF7-B987-B330F1B645A2}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:1.15.182" + "ProductVersion" = "8:1.15.183" "Manufacturer" = "8:oscar64" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:"