diff --git a/README.md b/README.md index c264e8d..0f134d7 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,18 @@ The compiler uses basic zero page space for temporaries, local variables and fun __zeropage int a; +### Prevent inlining + +With compiler option O2 and greater the compiler will try to inline small functions. This may not always be desirable, so the __noinline qualifier can be added to a function to prevent this. + + __noinline byte EzRead(char bank, const char * p) + { + eflash.bank = bank; + byte b = *p; + eflash.bank = CodeBank; + return b; + } + ### Pre-Processor control The pre processor has additional commands to control the scanner and allow for dynamic code generation including loops. diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 999b953..80b9225 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -72,6 +72,7 @@ static const uint64 DTF_EXPORT = (1ULL << 19); static const uint64 DTF_HWINTERRUPT = (1ULL << 20); static const uint64 DTF_STACKCALL = (1ULL << 21); static const uint64 DTF_ZEROPAGE = (1ULL << 22); +static const uint64 DTF_PREVENT_INLINE = (1ULL << 23); static const uint64 DTF_FUNC_VARIABLE = (1ULL << 32); static const uint64 DTF_FUNC_ASSEMBLER = (1ULL << 33); diff --git a/oscar64/GlobalAnalyzer.cpp b/oscar64/GlobalAnalyzer.cpp index 9a77dff..145f66a 100644 --- a/oscar64/GlobalAnalyzer.cpp +++ b/oscar64/GlobalAnalyzer.cpp @@ -62,7 +62,14 @@ void GlobalAnalyzer::AutoInline(void) for (int i = 0; i < mFunctions.Size(); i++) { Declaration* f = mFunctions[i]; - if (!(f->mFlags & DTF_INLINE) && !(f->mBase->mFlags & DTF_VARIADIC) && !(f->mFlags & DTF_FUNC_VARIABLE) && !((f->mFlags & DTF_FUNC_ASSEMBLER) && !(f->mFlags & DTF_REQUEST_INLINE)) && !(f->mFlags & DTF_INTRINSIC) && !(f->mFlags & DTF_FUNC_RECURSIVE) && f->mLocalSize < 100) + if (!(f->mFlags & DTF_INLINE) && + !(f->mFlags & DTF_EXPORT) && + !(f->mFlags & DTF_PREVENT_INLINE) && + !(f->mBase->mFlags & DTF_VARIADIC) && + !(f->mFlags & DTF_FUNC_VARIABLE) && + !((f->mFlags & DTF_FUNC_ASSEMBLER) && !(f->mFlags & DTF_REQUEST_INLINE)) && + !(f->mFlags & DTF_INTRINSIC) && + !(f->mFlags & DTF_FUNC_RECURSIVE) && f->mLocalSize < 100) { int nparams = 0; Declaration* dec = f->mBase->mParams; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index be5251b..e20f4f3 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -2419,9 +2419,15 @@ bool InterOperand::IsEqual(const InterOperand& op) const if (mMemory != op.mMemory) return false; - if (mIntConst != op.mIntConst || mFloatConst != op.mFloatConst || mVarIndex != op.mVarIndex || mLinkerObject != op.mLinkerObject) + if (mIntConst != op.mIntConst || mFloatConst != op.mFloatConst) return false; + if (mMemory != IM_NONE && mMemory != IM_INDIRECT) + { + if (mVarIndex != op.mVarIndex || mLinkerObject != op.mLinkerObject) + return false; + } + return true; } @@ -5740,10 +5746,13 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray switch (ins->mOperator) { case IA_EXT8TO16U: - case IA_EXT8TO16S: if (ins->mSrc[0].mTemp >= 0 && (vr.mMaxValue != 255 || vr.mMinValue != 0)) mReverseValueRange[ins->mSrc[0].mTemp].Limit(vr); break; + case IA_EXT8TO16S: + if (ins->mSrc[0].mTemp >= 0 && (vr.mMaxValue != 127 || vr.mMinValue != -128)) + mReverseValueRange[ins->mSrc[0].mTemp].Limit(vr); + break; } break; case IC_BINARY_OPERATOR: @@ -13005,35 +13014,60 @@ void InterCodeProcedure::MapCallerSavedTemps(void) assert(freeCallerSavedTemps <= mCallerSavedTemps); - mTempOffset.SetSize(0); - mTempSizes.SetSize(0); + mTempOffset.SetSize(mTemporaries.Size(), true); + mTempSizes.SetSize(mTemporaries.Size(), true); for (int i = 0; i < mTemporaries.Size(); i++) { - int size = InterTypeSize[mTemporaries[i]]; + if (!callerSaved[i]) + { + int size = InterTypeSize[mTemporaries[i]]; - if (freeTemps + size <= freeCallerSavedTemps && !callerSaved[i]) - { - mTempOffset.Push(freeTemps); - mTempSizes.Push(size); - freeTemps += size; - } - else if (callerSavedTemps + size <= maxCallerSavedTemps) - { - mTempOffset.Push(callerSavedTemps); - mTempSizes.Push(size); - callerSavedTemps += size; - } - else - { - mTempOffset.Push(calleeSavedTemps); - mTempSizes.Push(size); - calleeSavedTemps += size; + if (freeTemps + size <= freeCallerSavedTemps) + { + mTempOffset[i] = freeTemps; + mTempSizes[i] = size; + freeTemps += size; + } } } + +// if (freeTemps > callerSavedTemps) +// callerSavedTemps = freeTemps; + + for (int i = 0; i < mTemporaries.Size(); i++) + { + if (!mTempSizes[i]) + { + int size = InterTypeSize[mTemporaries[i]]; + + if (callerSavedTemps + size <= maxCallerSavedTemps) + { + mTempOffset[i] = callerSavedTemps; + mTempSizes[i] = size; + callerSavedTemps += size; + } + else + { + mTempOffset[i] = calleeSavedTemps; + mTempSizes[i] = size; + calleeSavedTemps += size; + } + } + } + mTempSize = calleeSavedTemps; mCallerSavedTemps = callerSavedTemps; +#if 0 + printf("Map %s, %d, %d, %d, %d\n", mIdent->mString, freeTemps, callerSavedTemps, calleeSavedTemps, freeCallerSavedTemps); + for (int i = 0; i < mTempOffset.Size(); i++) + printf("T%02d : %d, %d\n", i, mTempOffset[i], mTempSizes[i]); +#endif + + if (mSaveTempsLinkerObject && mTempSize > 16) + mSaveTempsLinkerObject->AddSpace(mTempSize - 16); + // printf("Map %s, %d, %d, %d, %d\n", mIdent->mString, freeTemps, callerSavedTemps, calleeSavedTemps, freeCallerSavedTemps); } diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index c5081fb..19755d8 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -62,9 +62,12 @@ void LinkerObject::AddData(const uint8* data, int size) uint8* LinkerObject::AddSpace(int size) { - mSize = size; - mData = new uint8[size]; - memset(mData, 0, size); + if (mSize != size) + { + mSize = size; + mData = new uint8[size]; + memset(mData, 0, size); + } return mData; } diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index d3edd54..1369624 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -16294,6 +16294,228 @@ bool NativeCodeBasicBlock::Check16BitSum(int at, NativeRegisterSum16Info& info) return false; } +bool NativeCodeBasicBlock::IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair) +{ + if (at == 0 && mVisited) + return false; + + if (!mPatched) + { + mPatched = true; + + if (at == 0) + { + mPatched = true; + + if (mNumEntries > 1) + { + for (int i = 0; i < mEntryBlocks.Size(); i++) + if (!mEntryBlocks[i]->IsDominatedBy(block)) + return false; + } + } + + while (at < mIns.Size()) + { + if (mIns[at].mMode == ASMIM_ZERO_PAGE) + { + if (mIns[at].mAddress == to) + return false; + if (pair && mIns[at].mAddress == to + 1) + return false; + } + else if (mIns[at].mMode == ASMIM_INDIRECT_Y) + { + if (mIns[at].mAddress == to) + return false; + if (mIns[at].mAddress + 1 == to) + return false; + if (pair && mIns[at].mAddress == to + 1) + return false; + if (!pair && mIns[at].mAddress == from) + return false; + if (mIns[at].mAddress + 1 == from) + return false; + if (pair && mIns[at].mAddress == from + 1) + return false; + } + else if (mIns[at].mType == ASMIT_JSR) + { + LinkerObject* lo = mIns[at].mLinkerObject; + if (lo) + { + for (int i = 0; i < lo->mNumTemporaries; i++) + { + if (from >= lo->mTemporaries[i] && from < lo->mTemporaries[i] + lo->mTempSizes[i] || + to >= lo->mTemporaries[i] && to < lo->mTemporaries[i] + lo->mTempSizes[i]) + return false; + } + } + + if (mIns[at].mFlags & NCIF_USE_ZP_32_X) + { + if (to >= mIns[at].mParam && to < mIns[at].mParam + 4 || + from >= mIns[at].mParam && from < mIns[at].mParam + 4) + return false; + } + } + + at++; + } + + if (mTrueJump && !mTrueJump->IsFinalZeroPageUse(block, 0, from, to, pair)) + return false; + if (mFalseJump && !mFalseJump->IsFinalZeroPageUse(block, 0, from, to, pair)) + return false; + } + + return true; +} + +bool NativeCodeBasicBlock::ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc) +{ +// return false; + + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mIns.Size(); i++) + { + if (i + 1 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END && + mIns[i + 1].mAddress >= BC_REG_TMP) + { + nproc->ResetPatched(); + if (IsFinalZeroPageUse(this, i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress, false)) + { + nproc->ResetPatched(); + if (ForwardReplaceZeroPage(i + 2, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) + changed = true; + + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + changed = true; + } + } + if (i + 3 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 1].mAddress + 1 && + mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END && + mIns[i + 1].mAddress >= BC_REG_TMP) + { + nproc->ResetPatched(); + if (IsFinalZeroPageUse(this, i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true)) + { + nproc->ResetPatched(); + if (ForwardReplaceZeroPage(i + 4, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) + changed = true; + nproc->ResetPatched(); + if (ForwardReplaceZeroPage(i + 4, mIns[i + 3].mAddress, mIns[i + 2].mAddress)) + changed = true; + + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; + + changed = true; + } + } + if (i + 5 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_ADC && + mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && + mIns[i + 3].mType == ASMIT_LDA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress == mIns[i + 0].mAddress + 1 && + mIns[i + 4].mType == ASMIT_ADC && !mIns[i + 4].MayBeSameAddress(mIns[i + 2]) && + mIns[i + 5].mType == ASMIT_STA && mIns[i + 5].mMode == ASMIM_ZERO_PAGE && mIns[i + 5].mAddress == mIns[i + 2].mAddress + 1 && + mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END && + mIns[i + 2].mAddress >= BC_REG_TMP) + { + nproc->ResetPatched(); + if (IsFinalZeroPageUse(this, i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress, true)) + { + nproc->ResetPatched(); + if (ForwardReplaceZeroPage(i + 6, mIns[i + 2].mAddress, mIns[i + 0].mAddress)) + changed = true; + nproc->ResetPatched(); + if (ForwardReplaceZeroPage(i + 6, mIns[i + 5].mAddress, mIns[i + 3].mAddress)) + changed = true; + + mIns[i + 2].mAddress = mIns[i + 0].mAddress; + mIns[i + 5].mAddress = mIns[i + 3].mAddress; + + changed = true; + } + } + if (i + 4 < mIns.Size() && + mIns[i + 0].mType == ASMIT_ADC && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress + 1 && + mIns[i + 3].mType == ASMIT_ADC && !mIns[i + 3].MayBeSameAddress(mIns[i + 1]) && + mIns[i + 4].mType == ASMIT_STA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 1].mAddress + 1 && + mIns[i + 0].mAddress >= BC_REG_FPARAMS && mIns[i + 0].mAddress < BC_REG_FPARAMS_END && + mIns[i + 1].mAddress >= BC_REG_TMP) + { + nproc->ResetPatched(); + if (IsFinalZeroPageUse(this, i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress, true)) + { + nproc->ResetPatched(); + if (ForwardReplaceZeroPage(i + 5, mIns[i + 1].mAddress, mIns[i + 0].mAddress)) + changed = true; + nproc->ResetPatched(); + if (ForwardReplaceZeroPage(i + 5, mIns[i + 4].mAddress, mIns[i + 2].mAddress)) + changed = true; + + mIns[i + 1].mAddress = mIns[i + 0].mAddress; + mIns[i + 4].mAddress = mIns[i + 2].mAddress; + + changed = true; + } + } + } + + if (mTrueJump && mTrueJump->ReplaceFinalZeroPageUse(nproc)) + changed = true; + if (mFalseJump && mFalseJump->ReplaceFinalZeroPageUse(nproc)) + changed = true; + } + + return changed; +} + +bool NativeCodeBasicBlock::ForwardReplaceZeroPage(int at, int from, int to) +{ + bool changed = false; + + if (!mPatched) + { + mPatched = true; + + for (int i = at; i < mIns.Size(); i++) + { + if (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_INDIRECT_Y) + { + if (mIns[i].mAddress == from) + { + mIns[i].mAddress = to; + changed = true; + } + } + } + + if (mTrueJump && mTrueJump->ForwardReplaceZeroPage(0, from, to)) + changed = true; + if (mFalseJump && mFalseJump->ForwardReplaceZeroPage(0, from, to)) + changed = true; + } + + return changed; +} + bool NativeCodeBasicBlock::Propagate16BitSum(void) { bool changed = false; @@ -19631,7 +19853,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) #endif else if (i + 3 < mIns.Size() && mIns[i + 0].mType == ASMIT_CLC && - mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) @@ -19644,7 +19866,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) } else if (i + 3 < mIns.Size() && mIns[i + 0].mType == ASMIT_SEC && - mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) @@ -19655,6 +19877,67 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) j += 3; i += 4; } + + else if (i + 3 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) && + mIns[i + 1].mType == ASMIT_CLC && + mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && + !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) + { + mIns[j + 0] = mIns[i + 0]; + mIns[j + 0].mType = ASMIT_LDX; + mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED; + mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress; + j += 3; + i += 4; + } + else if (i + 3 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) && + mIns[i + 1].mType == ASMIT_SEC && + mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 1 && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && + !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) + { + mIns[j + 0] = mIns[i + 0]; + mIns[j + 0].mType = ASMIT_LDX; + mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED; + mIns[j + 2].mType = ASMIT_STX; mIns[j + 2].mMode = ASMIM_ZERO_PAGE; mIns[j + 2].mAddress = mIns[i + 3].mAddress; + j += 3; + i += 4; + } + + else if (i + 3 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) && + mIns[i + 1].mType == ASMIT_CLC && + mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && + !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) + { + mIns[j + 0] = mIns[i + 0]; + mIns[j + 0].mType = ASMIT_LDX; + mIns[j + 1].mType = ASMIT_INX; mIns[j + 1].mMode = ASMIM_IMPLIED; + mIns[j + 2].mType = ASMIT_INX; mIns[j + 2].mMode = ASMIM_IMPLIED; + mIns[j + 3].mType = ASMIT_STX; mIns[j + 3].mMode = ASMIM_ZERO_PAGE; mIns[j + 3].mAddress = mIns[i + 3].mAddress; + j += 4; + i += 4; + } + else if (i + 3 < mIns.Size() && + mIns[i + 0].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 0].mMode) && + mIns[i + 1].mType == ASMIT_SEC && + mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 2 && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && + !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C | LIVE_CPU_REG_Z | LIVE_CPU_REG_X))) + { + mIns[j + 0] = mIns[i + 0]; + mIns[j + 0].mType = ASMIT_LDX; + mIns[j + 1].mType = ASMIT_DEX; mIns[j + 1].mMode = ASMIM_IMPLIED; + mIns[j + 2].mType = ASMIT_DEX; mIns[j + 2].mMode = ASMIM_IMPLIED; + mIns[j + 3].mType = ASMIT_STX; mIns[j + 3].mMode = ASMIM_ZERO_PAGE; mIns[j + 3].mAddress = mIns[i + 3].mAddress; + j += 4; + i += 4; + } + else if (i + 3 < mIns.Size() && mIns[i + 0].mType == ASMIT_CLC && mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && @@ -19679,6 +19962,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) j += 2; i += 4; } + else if (i + 1 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ABSOLUTE_X && mIns[i + 1].mType == ASMIT_TAY && !(mIns[i + 1].mLive & LIVE_CPU_REG_A)) @@ -23321,7 +23605,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } else if ( mIns[i + 0].mType == ASMIT_CLC && - mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) { @@ -23337,7 +23621,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } else if ( mIns[i + 0].mType == ASMIT_SEC && - mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDY, mIns[i + 1].mMode) && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && mIns[i + 3].mType == ASMIT_TAY && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) { @@ -23353,7 +23637,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } else if ( mIns[i + 0].mType == ASMIT_CLC && - mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) && mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) { @@ -23369,7 +23653,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass } else if ( mIns[i + 0].mType == ASMIT_SEC && - mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && HasAsmInstructionMode(ASMIT_LDX, mIns[i + 1].mMode) && mIns[i + 2].mType == ASMIT_SBC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress <= 2 && mIns[i + 3].mType == ASMIT_TAX && !(mIns[i + 3].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z | LIVE_CPU_REG_C))) { @@ -23659,6 +23943,17 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 3].mType = ASMIT_NOP; mIns[i + 3].mMode = ASMIM_IMPLIED; progress = true; } + else if ( + mIns[i + 0].mType == ASMIT_SEC && + mIns[i + 1].mType == ASMIT_SBC && + mIns[i + 2].mType == ASMIT_SEC && + mIns[i + 3].mType == ASMIT_SBC && mIns[i + 3].mMode == ASMIM_IMMEDIATE && mIns[i + 3].mAddress == 1 && !(mIns[i + 3].mLive & LIVE_CPU_REG_C)) + { + mIns[i + 0].mType = ASMIT_CLC; + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + 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_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && @@ -24824,6 +25119,25 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass CheckLive(); } } + else if (sz >= 2 && + mIns[sz - 2].ChangesAccuAndFlag() && + mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C]) + { + if (mBranch == ASMIT_BCC) + { + mBranch = ASMIT_BPL; + mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED; + + CheckLive(); + } + else if (mBranch == ASMIT_BCS) + { + mBranch = ASMIT_BMI; + mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED; + + CheckLive(); + } + } else if (sz >= 4 && mIns[sz - 4].mType == ASMIT_EOR && mIns[sz - 4].mMode == ASMIM_IMMEDIATE && mIns[sz - 4].mAddress == 0x80 && @@ -25392,56 +25706,65 @@ void NativeCodeProcedure::CompressTemporaries(void) remap[i] = i; int tpos = BC_REG_TMP + mInterProc->mFreeCallerSavedTemps; -// BC_REG_TMP_SAVED; -// if (mInterProc->mLeafProcedure) -// tpos = BC_REG_TMP; + int spos = BC_REG_TMP_SAVED; - for (int i = 0; i < mInterProc->mTempOffset.Size(); i++) +// for (int tsize = 4; tsize > 0; tsize >>= 1) { - bool tused = false; - - int reg = BC_REG_TMP + mInterProc->mTempOffset[i]; -// if (mInterProc->mLeafProcedure || reg >= BC_REG_TMP_SAVED) - if (reg >= BC_REG_TMP + mInterProc->mFreeCallerSavedTemps) + for (int i = 0; i < mInterProc->mTempOffset.Size(); i++) { - int size = mInterProc->mTempSizes[i]; - int usize = 0; + bool tused = false; - for (int j = 0; j < size; j++) - if (used[reg + j]) - usize = j + 1; - - if (usize) + int reg = BC_REG_TMP + mInterProc->mTempOffset[i]; + // if (mInterProc->mLeafProcedure || reg >= BC_REG_TMP_SAVED) + if (reg >= BC_REG_TMP + mInterProc->mFreeCallerSavedTemps) { - if (tpos < BC_REG_TMP_SAVED && tpos + usize > BC_REG_TMP + mInterProc->mCallerSavedTemps) - tpos = BC_REG_TMP_SAVED; + int size = mInterProc->mTempSizes[i]; +// if (size == tsize) + { + int usize = 0; - for (int j = 0; j < usize; j++) - remap[reg + j] = tpos + j; + for (int j = 0; j < size; j++) + if (used[reg + j]) + usize = j + 1; - mInterProc->mTempOffset[i] = tpos - BC_REG_TMP; - mInterProc->mTempSizes[i] = usize; - tpos += usize; + if (usize) + { + int pos = spos; + if (tpos + usize <= BC_REG_TMP + mInterProc->mCallerSavedTemps) + { + pos = tpos; + tpos += usize; + } + else + spos += usize; - } - else - { - mInterProc->mTempOffset[i] = 0; - mInterProc->mTempSizes[i] = 0; + for (int j = 0; j < usize; j++) + remap[reg + j] = pos + j; + + mInterProc->mTempOffset[i] = pos - BC_REG_TMP; + mInterProc->mTempSizes[i] = usize; + } + else + { + mInterProc->mTempOffset[i] = 0; + mInterProc->mTempSizes[i] = 0; + } + } } } } - if (tpos < BC_REG_TMP_SAVED) - { -// printf("%s, %d -> %d\n", mInterProc->mIdent->mString, mInterProc->mCallerSavedTemps, tpos - BC_REG_TMP); - mInterProc->mCallerSavedTemps = tpos - BC_REG_TMP; - } + mInterProc->mCallerSavedTemps = tpos - BC_REG_TMP; ResetVisited(); mEntryBlock->RemapZeroPage(remap); - mInterProc->mTempSize = tpos - BC_REG_TMP; + assert(mInterProc->mTempSize >= tpos - BC_REG_TMP); + + if (spos > BC_REG_TMP_SAVED) + mInterProc->mTempSize = spos - BC_REG_TMP; + else + mInterProc->mTempSize = tpos - BC_REG_TMP; if (mNoFrame && !used[BC_REG_STACK] && mInterProc->mTempSize <= 16) mStackExpand = 0; @@ -26021,6 +26344,13 @@ void NativeCodeProcedure::Optimize(void) } #endif +#if 1 + if (step == 2) + { + ResetVisited(); + mEntryBlock->ReplaceFinalZeroPageUse(this); + } +#endif #if 1 do { diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 2ce2c56..002e89b 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -345,6 +345,10 @@ public: bool Check16BitSum(int at, NativeRegisterSum16Info& info); bool Propagate16BitSum(void); + bool IsFinalZeroPageUse(const NativeCodeBasicBlock* block, int at, int from, int to, bool pair); + bool ReplaceFinalZeroPageUse(NativeCodeProcedure* nproc); + bool ForwardReplaceZeroPage(int at, int from, int to); + NativeRegisterDataSet mEntryRegisterDataSet; void BuildEntryDataSet(const NativeRegisterDataSet& set); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 7f11619..5b39e73 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -986,6 +986,11 @@ Declaration* Parser::ParseDeclaration(bool variable) storageFlags |= DTF_ZEROPAGE; mScanner->NextToken(); } + else if (mScanner->mToken == TK_NOINLINE) + { + storageFlags |= DTF_PREVENT_INLINE; + mScanner->NextToken(); + } else if (mScanner->mToken == TK_INLINE) { storageFlags |= DTF_REQUEST_INLINE; diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index 65092a3..9de3172 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -56,6 +56,7 @@ const char* TokenNames[] = "__fastcall", "__export", "__zeropage", + "__noinline", "number", "char", @@ -1341,6 +1342,8 @@ void Scanner::NextRawToken(void) mToken = TK_EXPORT; else if (!strcmp(tkident, "__zeropage")) mToken = TK_ZEROPAGE; + else if (!strcmp(tkident, "__noinline")) + mToken = TK_NOINLINE; else { mToken = TK_IDENT; diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index 1c2cf31..3c9c588 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -54,6 +54,7 @@ enum Token TK_FASTCALL, TK_EXPORT, TK_ZEROPAGE, + TK_NOINLINE, TK_NUMBER, TK_CHARACTER, diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 49c209d..c182380 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.7.141"); + strcpy(strProductVersion, "1.7.142"); #ifdef __APPLE__ uint32_t length = sizeof(basePath); diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index 5b749e2..639849e 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,7,141,0 - PRODUCTVERSION 1,7,141,0 + FILEVERSION 1,7,142,0 + PRODUCTVERSION 1,7,142,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,12 +43,12 @@ BEGIN BEGIN VALUE "CompanyName", "oscar64" VALUE "FileDescription", "oscar64 compiler" - VALUE "FileVersion", "1.7.141.0" + VALUE "FileVersion", "1.7.142.0" VALUE "InternalName", "oscar64.exe" VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "OriginalFilename", "oscar64.exe" VALUE "ProductName", "oscar64" - VALUE "ProductVersion", "1.7.141.0" + VALUE "ProductVersion", "1.7.142.0" END END BLOCK "VarFileInfo" diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index a908e01..c9a98c6 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -4153,15 +4153,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" - "ProductCode" = "8:{AAAF5F55-0261-47DA-B051-EF84642395A5}" - "PackageCode" = "8:{A7501921-EE58-422B-AEE2-4491A2249AC0}" + "ProductCode" = "8:{54C9EB87-4154-49FD-B146-2408492EDE3B}" + "PackageCode" = "8:{A90AA9BF-452A-4C37-B592-CAF52893124A}" "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.7.141" + "ProductVersion" = "8:1.7.142" "Manufacturer" = "8:oscar64" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:"