diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 341be81..82ee9ff 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -1353,6 +1353,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1380,6 +1381,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mSrc[0].mTemp; ins->mSrc[0].mType = mInstructions[i]->mSrc[0].mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } } @@ -1473,6 +1475,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1498,6 +1501,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1532,6 +1536,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1557,6 +1562,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1595,6 +1601,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mSrc[0].mTemp = ins->mSrc[1].mTemp; ins->mSrc[0].mType = ins->mSrc[1].mType; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); UpdateValue(ins, tvalue, aliasedLocals, aliasedParams, staticVars); @@ -1633,6 +1640,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr { ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); UpdateValue(ins, tvalue, aliasedLocals, aliasedParams, staticVars); @@ -1690,6 +1698,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr { ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); UpdateValue(ins, tvalue, aliasedLocals, aliasedParams, staticVars); @@ -1714,6 +1723,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1744,6 +1754,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1773,6 +1784,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1806,6 +1818,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1830,6 +1843,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1861,6 +1875,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -1884,6 +1899,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = mInstructions[i]->mDst.mTemp; ins->mSrc[0].mType = mInstructions[i]->mDst.mType; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -3102,6 +3118,7 @@ void InterInstruction::SimpleLocalToTemp(int vindex, int temp) mCode = IC_LOAD_TEMPORARY; mSrc[0].mTemp = temp; mSrc[0].mType = mDst.mType; + mNumOperands = 1; assert(mSrc[0].mTemp >= 0); @@ -3119,6 +3136,7 @@ void InterInstruction::SimpleLocalToTemp(int vindex, int temp) else { mCode = IC_LOAD_TEMPORARY; + mNumOperands = 1; assert(mSrc[0].mTemp >= 0); } @@ -3517,11 +3535,16 @@ void InterCodeBasicBlock::BuildDominatorTree(InterCodeBasicBlock* from) if (from == this) return; else if (!mDominator) + { + assert(!from || mIndex != 0); mDominator = from; + } else if (from == mDominator) return; else { + assert(mIndex != 0); + GrowingInterCodeBasicBlockPtrArray d1(nullptr), d2(nullptr); InterCodeBasicBlock* b = mDominator; @@ -3832,6 +3855,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI ins->mSrc[0].mType = ins->mSrc[1].mType; ins->mSrc[0].mTemp = ins->mSrc[1].mTemp; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else @@ -3886,6 +3910,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI if (ins->mSrc[0].mType == ins->mDst.mType) { ins->mCode = IC_LOAD_TEMPORARY; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (TypeInteger(ins->mSrc[0].mType) && ins->mDst.mType == IT_POINTER) @@ -3960,6 +3985,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI if (ins->mOperator == IA_ADD && ins->mSrc[1].mFloatConst == 0) { ins->mCode = IC_LOAD_TEMPORARY; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mOperator == IA_MUL) @@ -3967,6 +3993,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI if (ins->mSrc[1].mFloatConst == 1.0) { ins->mCode = IC_LOAD_TEMPORARY; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mSrc[1].mFloatConst == 0.0) @@ -3995,6 +4022,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = ins->mSrc[1].mTemp; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mOperator == IA_MUL) @@ -4004,6 +4032,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = ins->mSrc[1].mTemp; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mSrc[0].mFloatConst == 0.0) @@ -4042,6 +4071,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI if (ins->mOperator == IA_ADD && ins->mSrc[1].mIntConst == 0) { ins->mCode = IC_LOAD_TEMPORARY; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mOperator == IA_MUL) @@ -4049,6 +4079,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI if (ins->mSrc[1].mIntConst == 1) { ins->mCode = IC_LOAD_TEMPORARY; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mSrc[1].mIntConst == 2) @@ -4090,6 +4121,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = ins->mSrc[1].mTemp; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mOperator == IA_MUL) @@ -4099,6 +4131,7 @@ void InterCodeBasicBlock::CheckValueUsage(InterInstruction * ins, const GrowingI ins->mCode = IC_LOAD_TEMPORARY; ins->mSrc[0].mTemp = ins->mSrc[1].mTemp; ins->mSrc[1].mTemp = -1; + ins->mNumOperands = 1; assert(ins->mSrc[0].mTemp >= 0); } else if (ins->mSrc[0].mIntConst == 2) @@ -9586,7 +9619,7 @@ void InterCodeProcedure::DisassembleDebug(const char* name) Disassemble(name); } -void InterCodeProcedure::BuildTraces(bool expand) +void InterCodeProcedure::BuildTraces(bool expand, bool dominators) { // Count number of entries // @@ -9612,7 +9645,8 @@ void InterCodeProcedure::BuildTraces(bool expand) ResetVisited(); for (int i = 0; i < mBlocks.Size(); i++) mBlocks[i]->mDominator = nullptr; - mEntryBlock->BuildDominatorTree(nullptr); + if (dominators) + mEntryBlock->BuildDominatorTree(nullptr); } void InterCodeProcedure::BuildDataFlowSets(void) @@ -10395,7 +10429,7 @@ void InterCodeProcedure::Close(void) // Optimize for size MergeBasicBlocks(); - BuildTraces(false); + BuildTraces(false, false); DisassembleDebug("Final Merged basic blocks"); } diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 22e8345..942c9f3 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -526,7 +526,7 @@ public: void Disassemble(FILE* file); void Disassemble(const char* name, bool dumpSets = false); protected: - void BuildTraces(bool expand); + void BuildTraces(bool expand, bool dominators = true); void BuildDataFlowSets(void); void RenameTemporaries(void); void TempForwarding(void); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index a9dc34b..229a194 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -852,6 +852,7 @@ bool NativeCodeInstruction::ChangesZFlag(void) const mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_INY || mType == ASMIT_DEY || mType == ASMIT_INX || mType == ASMIT_DEX || + mType == ASMIT_TAX || mType == ASMIT_TAY || mType == ASMIT_TXA || mType == ASMIT_TYA || mType == ASMIT_CMP || mType == ASMIT_CPX || mType == ASMIT_CPY || mType == ASMIT_LDA || mType == ASMIT_LDX || mType == ASMIT_LDY || mType == ASMIT_JSR; @@ -1807,6 +1808,8 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT { for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) data.ResetZeroPage(i); + for(int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) + data.ResetZeroPage(i); } return false; @@ -2450,8 +2453,20 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT } else if (data.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE) { - data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE; - data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue; +#if 1 + if (data.mRegs[data.mRegs[CPU_REG_A].mValue].mMode == NRDM_UNKNOWN && mAddress >= BC_REG_FPARAMS && mAddress < BC_REG_FPARAMS_END) + { + 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; + } + else +#endif + { + data.mRegs[mAddress].mMode = NRDM_ZERO_PAGE; + data.mRegs[mAddress].mValue = data.mRegs[CPU_REG_A].mValue; + } + } else if (data.mRegs[CPU_REG_A].mMode == NRDM_ABSOLUTE) { @@ -4205,6 +4220,33 @@ void NativeCodeBasicBlock::StoreValue(InterCodeProcedure* proc, const InterInstr } +void NativeCodeBasicBlock::LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins) +{ + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp])); + + for (int i = 0; i < InterTypeSize[rins->mDst.mType]; i++) + { + if (i != 0) + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[rins->mDst.mTemp] + i)); + } +} + +void NativeCodeBasicBlock::StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* wins) +{ + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[iins->mSrc[0].mTemp])); + + for (int i = 0; i < InterTypeSize[wins->mSrc[0].mType]; i++) + { + if (i != 0) + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[wins->mSrc[0].mTemp] + i)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[iins->mSrc[1].mTemp])); + } +} + + void NativeCodeBasicBlock::LoadStoreIndirectValue(InterCodeProcedure* proc, const InterInstruction* rins, const InterInstruction* wins) { int size = InterTypeSize[wins->mSrc[0].mType]; @@ -5515,6 +5557,15 @@ void NativeCodeBasicBlock::ShiftRegisterLeft(InterCodeProcedure* proc, int reg, mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, reg + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, reg + 1)); } + else if (shift >= 8) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg)); + for (int i = 8; i < shift; i++) + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, reg)); + } else if (shift >= 5) { mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, reg + 1)); @@ -9229,6 +9280,111 @@ void NativeCodeBasicBlock::CountEntries(NativeCodeBasicBlock * fromJump) } } +bool NativeCodeBasicBlock::IsSame(const NativeCodeBasicBlock* block) const +{ + if (block->mIns.Size() != mIns.Size()) + return false; + + if (block->mBranch != mBranch) + return false; + + if (mTrueJump) + { + if (!block->mTrueJump) + return false; + + if (mTrueJump == this) + { + if (block->mTrueJump != block) + return false; + } + else if (mTrueJump != block->mTrueJump) + return false; + } + else if (block->mTrueJump) + return false; + + if (mFalseJump) + { + if (!block->mFalseJump) + return false; + + if (mFalseJump == this) + { + if (block->mFalseJump != block) + return false; + } + else if (mFalseJump != block->mFalseJump) + return false; + } + else if (block->mFalseJump) + return false; + + for (int i = 0; i < mIns.Size(); i++) + if (!mIns[i].IsSame(block->mIns[i])) + return false; + + return true; +} + +bool NativeCodeBasicBlock::FindSameBlocks(NativeCodeProcedure* nproc) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (!mSameBlock) + { + for (int i = 0; i < nproc->mBlocks.Size(); i++) + { + if (nproc->mBlocks[i]->IsSame(this)) + { + nproc->mBlocks[i]->mSameBlock = this; + changed = true; + } + } + } + + if (mTrueJump && mTrueJump->FindSameBlocks(nproc)) + changed = true; + if (mFalseJump && mFalseJump->FindSameBlocks(nproc)) + changed = true; + } + + return changed; +} + +bool NativeCodeBasicBlock::MergeSameBlocks(NativeCodeProcedure* nproc) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (mTrueJump && mTrueJump->mSameBlock) + { + mTrueJump = mTrueJump->mSameBlock; + changed = true; + } + + if (mFalseJump && mFalseJump->mSameBlock) + { + mFalseJump = mFalseJump->mSameBlock; + changed = true; + } + + if (mTrueJump && mTrueJump->MergeSameBlocks(nproc)) + changed = true; + if (mFalseJump && mFalseJump->MergeSameBlocks(nproc)) + changed = true; + } + + return true; +} + bool NativeCodeBasicBlock::MergeBasicBlocks(void) { bool changed = false; @@ -9289,7 +9445,7 @@ bool NativeCodeBasicBlock::MergeBasicBlocks(void) changed = true; } - while (mFalseJump && mFalseJump->mIns.Size() == 0 && !mFalseJump->mFalseJump && !mFalseJump->mLocked && mFalseJump != this && mFalseJump->mTrueJump != mFalseJump) + while (mFalseJump && mFalseJump->mTrueJump && mFalseJump->mIns.Size() == 0 && !mFalseJump->mFalseJump && !mFalseJump->mLocked && mFalseJump != this && mFalseJump->mTrueJump != mFalseJump) { mFalseJump->mNumEntries--; mFalseJump = mFalseJump->mTrueJump; @@ -10411,6 +10567,49 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) for (int i = 0; i < mIns.Size(); i++) { + if (i + 6 < mIns.Size()) + { + if (mIns[i + 0].mType == ASMIT_CLC && + mIns[i + 1].mType == ASMIT_LDA && + 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 + 1].SameEffectiveAddress(mIns[i + 3]) && + mIns[i + 4].mType == ASMIT_LDA && + mIns[i + 5].mType == ASMIT_ADC && mIns[i + 5].mMode == ASMIM_IMMEDIATE && mIns[i + 5].mAddress == 0 && + mIns[i + 6].mType == ASMIT_STA && mIns[i + 4].SameEffectiveAddress(mIns[i + 6]) && + HasAsmInstructionMode(ASMIT_INC, mIns[i + 3].mMode) && + HasAsmInstructionMode(ASMIT_INC, mIns[i + 6].mMode) && + !(mIns[i + 6].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; + + mIns[i + 0].mType = ASMIT_NOP; + mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + mIns[i + 3].mType = ASMIT_INC; mIns[i + 3].mLive |= LIVE_CPU_REG_Z; + + for (int j = i + 7; j < mIns.Size(); j++) + fblock->mIns.Push(mIns[j]); + iblock->mIns.Push(mIns[i + 6]); + mIns.SetSize(i + 4); + iblock->mIns[0].mType = ASMIT_INC; + iblock->mTrueJump = fblock; + iblock->mBranch = ASMIT_JMP; + + mTrueJump = fblock; + mFalseJump = iblock; + mBranch = ASMIT_BNE; + break; + } + + } + if (i + 2 < mIns.Size()) { if (mIns[i + 0].mType == ASMIT_LDA && @@ -10441,6 +10640,34 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) mBranch = ASMIT_BCC; break; } + else if (mIns[i + 0].mType == ASMIT_LDA && + mIns[i + 1].mType == ASMIT_SBC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && + 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; + } } } @@ -12180,6 +12407,29 @@ bool NativeCodeBasicBlock::JoinTAXARange(int from, int to) } mIns.Remove(start); + return true; + } + else if (mIns[start + 0].mType == ASMIT_LDY && mIns[start + 0].mMode == ASMIM_IMMEDIATE && + mIns[start + 1].mType == ASMIT_LDA && mIns[start + 1].mMode == ASMIM_INDIRECT_Y && + !(mIns[start + 1].mLive & LIVE_CPU_REG_Y) && !(mIns[to].mLive & LIVE_CPU_REG_Y)) + { + + for (int i = from + 1; i < to; i++) + { + if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mAddress == mIns[start + 1].mAddress || mIns[i].mAddress == mIns[start + 1].mAddress + 1) && mIns[i].ChangesAddress()) + return false; + if (mIns[i].ChangesGlobalMemory()) + return false; + } + + mIns.Remove(to); + for (int i = start; i < from; i++) + { + mIns.Insert(to, mIns[start]); + mIns.Remove(start); + } + mIns.Remove(start); + return true; } } @@ -12226,6 +12476,34 @@ bool NativeCodeBasicBlock::JoinTAXARange(int from, int to) bool NativeCodeBasicBlock::JoinTAYARange(int from, int to) { + int start = from; + if (from >= 2) + { + start = from - 2; + if (mIns[start + 0].mType == ASMIT_LDY && mIns[start + 0].mMode == ASMIM_IMMEDIATE && + mIns[start + 1].mType == ASMIT_LDA && mIns[start + 1].mMode == ASMIM_INDIRECT_Y) + { + + for (int i = from + 1; i < to; i++) + { + if (mIns[i].mMode == ASMIM_ZERO_PAGE && (mIns[i].mAddress == mIns[start + 1].mAddress || mIns[i].mAddress == mIns[start + 1].mAddress + 1) && mIns[i].ChangesAddress()) + return false; + if (mIns[i].ChangesGlobalMemory()) + return false; + } + + mIns.Remove(to); + for (int i = start; i < from; i++) + { + mIns.Insert(to, mIns[start]); + mIns.Remove(start); + } + mIns.Remove(start); + + return true; + } + } + return false; } @@ -13874,6 +14152,9 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc { bool changed = false; + if (mBranch == ASMIT_JMP) + return false; + int sz = mIns.Size(); if (sz == 2 && (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE) && mIns[0].mType == ASMIT_LDA && mIns[1].mType == ASMIT_CMP && !(mIns[1].mFlags & NCIF_VOLATILE) && !(mIns[1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) @@ -14481,6 +14762,8 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc) bool changed = false; int sz = mIns.Size(); + assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); + #if 1 if (sz > 3 && mIns[sz - 2].mType == ASMIT_LDA && mIns[sz - 2].mMode == ASMIM_IMMEDIATE && @@ -14952,11 +15235,15 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoop(NativeCodeProcedure * proc) } #if 1 + assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); if (!changed) changed = OptimizeSimpleLoopInvariant(proc, nullptr, nullptr); + assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); #endif } + assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); + if (mTrueJump && mTrueJump->OptimizeSimpleLoop(proc)) changed = true; if (mFalseJump && mFalseJump->OptimizeSimpleLoop(proc)) @@ -15264,6 +15551,8 @@ bool NativeCodeBasicBlock::OptimizeSelect(NativeCodeProcedure* proc) { mVisited = true; + assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); + if (mFalseJump && mIns.Size() > 0 && mIns.Last().ChangesAccuAndFlag() && mTrueJump->mIns.Size() == 1 && mFalseJump->mIns.Size() == 1 && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && @@ -15290,6 +15579,8 @@ bool NativeCodeBasicBlock::OptimizeSelect(NativeCodeProcedure* proc) } } + assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); + if (mTrueJump && mTrueJump->OptimizeSelect(proc)) changed = true; if (mFalseJump && mFalseJump->OptimizeSelect(proc)) @@ -15589,6 +15880,19 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) j += 4; i += 7; } + else if (i + 4 < mIns.Size() && + mIns[i + 0].mType == ASMIT_CLC && + mIns[i + 1].mType == ASMIT_LDA && + mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0x01 && + mIns[i + 3].mType == ASMIT_CLC && + mIns[i + 4].mType == ASMIT_ADC && !(mIns[i + 4].mLive & LIVE_CPU_REG_C | LIVE_CPU_REG_Z)) + { + mIns[j + 0] = mIns[i + 0]; mIns[j + 0].mType = ASMIT_SEC; + mIns[j + 1] = mIns[i + 1]; + mIns[j + 2] = mIns[i + 4]; + j += 3; + i += 5; + } else if (i + 2 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_ADC && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && @@ -16018,6 +16322,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) i = 0; j = 0; int accuVal = 0, accuMask = 0; + bool accuFlags = false; while (i < mIns.Size()) { bool skip = false; @@ -16050,9 +16355,11 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) case ASMIT_ADC: case ASMIT_SBC: accuMask = 0; + accuFlags = true; case ASMIT_CMP: carryClear = false; carrySet = false; + accuFlags = false; break; case ASMIT_AND: if (mIns[i].mMode == ASMIM_IMMEDIATE) @@ -16065,15 +16372,19 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) } else accuMask = 0; + accuFlags = true; break; case ASMIT_ORA: if (mIns[i].mMode == ASMIM_IMMEDIATE) { + if (mIns[i].mAddress == 0 && accuFlags) + skip = true; accuVal = 0xff; accuMask = mIns[i].mAddress; } else accuMask = 0; + accuFlags = true; break; case ASMIT_LDA: if (mIns[i].mMode == ASMIM_IMMEDIATE) @@ -16083,6 +16394,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) } else accuMask = 0x00; + accuFlags = true; break; case ASMIT_ASL: if (mIns[i].mMode == ASMIM_IMPLIED && (accuMask & 0x80)) @@ -16107,6 +16419,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) carryClear = false; carrySet = false; } + accuFlags = mIns[i].mMode == ASMIM_IMPLIED; break; case ASMIT_LSR: if (mIns[i].mMode == ASMIM_IMPLIED && (accuMask & 0x01)) @@ -16131,6 +16444,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) carryClear = false; carrySet = false; } + accuFlags = mIns[i].mMode == ASMIM_IMPLIED; break; case ASMIT_ROL: if (mIns[i].mMode == ASMIM_IMPLIED && (accuMask & 0x80)) @@ -16155,6 +16469,7 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) carryClear = false; carrySet = false; } + accuFlags = mIns[i].mMode == ASMIM_IMPLIED; break; case ASMIT_ROR: if (mIns[i].mMode == ASMIM_IMPLIED && (accuMask & 0x01)) @@ -16179,6 +16494,11 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) carryClear = false; carrySet = false; } + accuFlags = mIns[i].mMode == ASMIM_IMPLIED; + break; + case ASMIT_TAX: + case ASMIT_TAY: + accuFlags = true; break; default: if (mIns[i].ChangesCarry()) @@ -16188,7 +16508,14 @@ void NativeCodeBasicBlock::BlockSizeReduction(NativeCodeProcedure* proc) } if (mIns[i].ChangesAccu()) + { accuMask = 0; + accuFlags = false; + } + else if (mIns[i].ChangesZFlag()) + { + accuFlags = false; + } } if (!skip) @@ -16242,6 +16569,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass { if (!mVisited) { + assert(mBranch != ASMIT_JMP || mFalseJump == nullptr); assert(mIns.Size() == 0 || mIns[0].mType != ASMIT_INV); bool changed = RemoveNops(); @@ -18298,9 +18626,9 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass progress = true; } else if ( - mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_CPU_REG_Y) && + mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_Y) && !mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && - mIns[i + 2].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z))) + mIns[i + 2].mType == ASMIT_LDY && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z))) { mIns[i + 0].mType = ASMIT_TAY; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_Y; mIns[i + 1].mLive |= LIVE_CPU_REG_Y; @@ -18308,9 +18636,9 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass progress = true; } else if ( - mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 2].mLive & LIVE_CPU_REG_X) && + mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 0].mLive & LIVE_CPU_REG_X) && !mIns[i + 1].UsesZeroPage(mIns[i + 0].mAddress) && - mIns[i + 2].mType == ASMIT_LDX && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z))) + mIns[i + 2].mType == ASMIT_LDX && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 2].mAddress == mIns[i + 0].mAddress && !(mIns[i + 2].mLive & (LIVE_MEM | LIVE_CPU_REG_Z))) { mIns[i + 0].mType = ASMIT_TAX; mIns[i + 0].mMode = ASMIM_IMPLIED; mIns[i + 0].mLive |= LIVE_CPU_REG_X; mIns[i + 1].mLive |= LIVE_CPU_REG_X; @@ -19684,6 +20012,21 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass changed = true; } } + + if (sz >= 1 && + mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A) && + (mBranch == ASMIT_BEQ || mBranch == ASMIT_BNE)) + { + mIns[sz - 1].mType = ASMIT_ORA; + mIns[sz - 1].mAddress = 0x00; + + if (mBranch == ASMIT_BEQ) + mBranch = ASMIT_BPL; + else + mBranch = ASMIT_BMI; + + changed = true; + } #endif #if 1 if (mTrueJump && mFalseJump && !mTrueJump->mFalseJump && !mFalseJump->mFalseJump && mTrueJump->mTrueJump == mFalseJump->mTrueJump && @@ -19798,7 +20141,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BypassEmptyBlocks(void) { if (mBypassed) return this; - else if (!mFalseJump && mCode.Size() == 0 && this != mTrueJump) + else if (mTrueJump && !mFalseJump && mCode.Size() == 0 && this != mTrueJump) return mTrueJump->BypassEmptyBlocks(); else { @@ -19875,7 +20218,7 @@ void NativeCodeBasicBlock::BuildPlacement(GrowingArray& p mFalseJump->BuildPlacement(placement); } #if 1 - else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mFalseJump->mFalseJump && !mTrueJump->mTrueJump->mPlaced && mTrueJump->mTrueJump->mNumEntries > 1) + else if (!mTrueJump->mFalseJump && mTrueJump->mTrueJump && mFalseJump->mFalseJump && !mTrueJump->mTrueJump->mPlaced && mTrueJump->mTrueJump->mNumEntries > 1 && mTrueJump->mTrueJump->mTrueJump != mTrueJump->mTrueJump) { mTrueJump->mPlaced = true; mTrueJump->mPlace = placement.Size(); @@ -20557,9 +20900,21 @@ void NativeCodeProcedure::Optimize(void) mBlocks[i]->mLoopHead = false; mBlocks[i]->mFromJump = nullptr; mBlocks[i]->mDominator = nullptr; + mBlocks[i]->mSameBlock = nullptr; } - ResetEntryBlocks(); + if (step > 3) + { + ResetVisited(); + if (mEntryBlock->FindSameBlocks(this)) + { + ResetVisited(); + changed = mEntryBlock->MergeSameBlocks(this); + } + } + + ResetVisited(); + ResetEntryBlocks(); mEntryBlock->CountEntries(nullptr); ResetVisited(); @@ -21059,7 +21414,27 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode else if (iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp) avalid = true; } - block->LoadEffectiveAddress(iproc, ins, nullptr, nullptr, avalid); + + if (i + 1 < iblock->mInstructions.Size() && + iblock->mInstructions[i + 1]->mCode == IC_LOAD && iblock->mInstructions[i + 1]->mSrc[0].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[0].mFinal && + iblock->mInstructions[i + 0]->mSrc[1].mTemp >= 0 && iblock->mInstructions[i + 0]->mSrc[0].IsUByte() && + iblock->mInstructions[i + 1]->mSrc[0].mIntConst == 0) + { + block->LoadByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]); + i++; + } + else if (i + 1 < iblock->mInstructions.Size() && + iblock->mInstructions[i + 1]->mCode == IC_STORE && iblock->mInstructions[i + 1]->mSrc[1].mTemp == ins->mDst.mTemp && iblock->mInstructions[i + 1]->mSrc[1].mFinal && + iblock->mInstructions[i + 0]->mSrc[1].mTemp >= 0 && iblock->mInstructions[i + 0]->mSrc[0].IsUByte() && + iblock->mInstructions[i + 1]->mSrc[1].mIntConst == 0 && iblock->mInstructions[i + 1]->mSrc[0].mTemp >= 0) + { + block->StoreByteIndexedValue(iproc, ins, iblock->mInstructions[i + 1]); + i++; + } + else + { + block->LoadEffectiveAddress(iproc, ins, nullptr, nullptr, avalid); + } } break; case IC_CONSTANT: diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 270b630..058bc19 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -137,7 +137,7 @@ public: int mOffset, mSize, mPlace, mNumEntries, mNumEntered, mFrameOffset; bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame, mVisited, mLoopHead, mVisiting, mLocked, mPatched, mPatchFail; - NativeCodeBasicBlock * mDominator; + NativeCodeBasicBlock * mDominator, * mSameBlock; NativeCodeBasicBlock* mLoopHeadBlock; @@ -201,6 +201,9 @@ public: NativeCodeBasicBlock * CopyValue(InterCodeProcedure* proc, const InterInstruction * ins, NativeCodeProcedure* nproc); NativeCodeBasicBlock * StrcpyValue(InterCodeProcedure* proc, const InterInstruction* ins, NativeCodeProcedure* nproc); + void LoadByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); + void StoreByteIndexedValue(InterCodeProcedure* proc, const InterInstruction* iins, const InterInstruction* rins); + void CallAssembler(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins); void CallFunction(InterCodeProcedure* proc, NativeCodeProcedure* nproc, const InterInstruction * ins); @@ -219,6 +222,10 @@ public: bool BuildGlobalRequiredRegSet(NumberSet& fromRequiredTemps); bool RemoveUnusedResultInstructions(void); + bool IsSame(const NativeCodeBasicBlock* block) const; + bool FindSameBlocks(NativeCodeProcedure* nproc); + bool MergeSameBlocks(NativeCodeProcedure* nproc); + void CountEntries(NativeCodeBasicBlock* fromJump); bool MergeBasicBlocks(void); void MarkLoopHead(void); diff --git a/oscar64/Preprocessor.cpp b/oscar64/Preprocessor.cpp index 06bdd52..65c905a 100644 --- a/oscar64/Preprocessor.cpp +++ b/oscar64/Preprocessor.cpp @@ -1,6 +1,7 @@ #include "Preprocessor.h" #include #include +#include SourcePath::SourcePath(const char* path) { @@ -19,12 +20,141 @@ SourcePath::~SourcePath(void) } +bool SourceFile::ReadLineRLE(char* line) +{ + assert(mFill >= 0 && mFill < 256); + + int c; + while (mLimit && mFill < 256 && (c = fgetc(mFile)) >= 0) + { + mLimit--; + mBuffer[mFill++] = c; + } + + assert(mFill >= 0 && mFill <= 256); + + if (mFill) + { + if (mFill >= 3 && mBuffer[0] == mBuffer[1] && mBuffer[1] == mBuffer[2]) + { + int cnt = 1; + while (cnt < 64 && cnt < mFill && mBuffer[cnt] == mBuffer[cnt - 1]) + cnt++; + + if (cnt <= 8 && cnt < mFill) + { + int rcnt = 1; + int rep = 1; + while (rcnt < 16 && cnt + rcnt < mFill && rep < 3) + { + if (mBuffer[cnt + rcnt] == mBuffer[cnt + rcnt - 1]) + rep++; + else + rep = 1; + rcnt++; + } + if (cnt + rcnt < mFill && rep >= 3) + rcnt -= rep; + + if (rcnt > 0) + { + sprintf_s(line, 1024, "0x%02x, 0x%02x, ", 0x80 + ((cnt - 1) << 4) + (rcnt - 1), (unsigned char)mBuffer[0]); + + assert(mFill >= 0 && mFill <= 256); + + for (int i = 0; i < rcnt; i++) + { + char buffer[16]; + sprintf_s(buffer, 16, "0x%02x, ", (unsigned char)mBuffer[cnt + i]); + + assert(mFill >= 0 && mFill <= 256); + + strcat_s(line, 1024, buffer); + + assert(mFill >= 0 && mFill <= 256); + } + + assert(mFill >= cnt + rcnt); + assert(mFill >= 0 && mFill <= 256); + + memmove(mBuffer, mBuffer + cnt + rcnt, mFill - cnt - rcnt); + mFill -= cnt + rcnt; + + assert(mFill >= 0 && mFill < 256); + } + else + { + sprintf_s(line, 1024, "0x%02x, 0x%02x, ", 0x00 + (cnt - 1), (unsigned char)mBuffer[0]); + memmove(mBuffer, mBuffer + cnt, mFill - cnt); + mFill -= cnt; + + assert(mFill >= 0 && mFill < 256); + } + } + else + { + sprintf_s(line, 1024, "0x%02x, 0x%02x, ", 0x00 + (cnt - 1), (unsigned char)mBuffer[0]); + memmove(mBuffer, mBuffer + cnt, mFill - cnt); + mFill -= cnt; + + assert(mFill >= 0 && mFill < 256); + } + + if (mFill == 0) + strcat_s(line, 1024, "0x00, "); + + return true; + } + else + { + int cnt = 1; + int rep = 1; + while (cnt < 64 && cnt < mFill && rep < 3) + { + if (mBuffer[cnt] == mBuffer[cnt - 1]) + rep++; + else + rep = 1; + cnt++; + } + if (cnt < mFill && rep >= 3) + cnt -= rep; + + sprintf_s(line, 1024, "0x%02x, ", 0x40 + (cnt - 1)); + + for (int i = 0; i < cnt; i++) + { + char buffer[16]; + sprintf_s(buffer, 16, "0x%02x, ", (unsigned char)mBuffer[i]); + strcat_s(line, 1024, buffer); + } + + memmove(mBuffer, mBuffer + cnt, mFill - cnt); + mFill -= cnt; + + assert(mFill >= 0 && mFill < 256); + + if (mFill == 0) + strcat_s(line, 1024, "0x00, "); + + return true; + } + } + + return false; +} + bool SourceFile::ReadLine(char* line) { if (mFile) { - if (mBinary) + switch (mMode) { + case SFM_TEXT: + if (fgets(line, 1024, mFile)) + return true; + break; + case SFM_BINARY: if (mLimit) { mLimit--; @@ -36,13 +166,11 @@ bool SourceFile::ReadLine(char* line) return true; } } - else - return false; - } - else - { - if (fgets(line, 1024, mFile)) + break; + case SFM_BINARY_RLE: + if (ReadLineRLE(line)) return true; + break; } fclose(mFile); @@ -74,7 +202,7 @@ SourceFile::~SourceFile(void) } } -bool SourceFile::Open(const char* name, const char* path, bool binary) +bool SourceFile::Open(const char* name, const char* path, SourceFileMode mode) { char fname[220]; @@ -102,8 +230,9 @@ bool SourceFile::Open(const char* name, const char* path, bool binary) *p = '/'; p++; } - mBinary = binary; + mMode = mode; mLimit = 0x10000; + mFill = 0; return true; } @@ -174,7 +303,7 @@ bool Preprocessor::NextLine(void) return false; } -bool Preprocessor::EmbedData(const char* reason, const char* name, bool local, int skip, int limit) +bool Preprocessor::EmbedData(const char* reason, const char* name, bool local, int skip, int limit, SourceFileMode mode) { if (strlen(name) > 200) { @@ -189,7 +318,7 @@ bool Preprocessor::EmbedData(const char* reason, const char* name, bool local, i bool ok = false; - if (source->Open(name, "", true)) + if (source->Open(name, "", mode)) ok = true; if (!ok && local && mSource) @@ -201,14 +330,14 @@ bool Preprocessor::EmbedData(const char* reason, const char* name, bool local, i i--; lpath[i] = 0; - if (source->Open(name, lpath, true)) + if (source->Open(name, lpath, mode)) ok = true; } SourcePath* p = mPaths; while (!ok && p) { - if (source->Open(name, p->mPathName, true)) + if (source->Open(name, p->mPathName, mode)) ok = true; else p = p->mNext; diff --git a/oscar64/Preprocessor.h b/oscar64/Preprocessor.h index dcded8e..39fcb50 100644 --- a/oscar64/Preprocessor.h +++ b/oscar64/Preprocessor.h @@ -14,6 +14,12 @@ public: Location mLocation; }; +enum SourceFileMode +{ + SFM_TEXT, + SFM_BINARY, + SFM_BINARY_RLE +}; class SourceFile { public: @@ -22,15 +28,20 @@ public: SourceFile * mUp, * mNext; Location mLocation; SourceStack * mStack; - bool mBinary; + SourceFileMode mMode; int mLimit; + char mBuffer[256]; + int mFill; + bool ReadLine(char* line); + bool ReadLineRLE(char* line); + SourceFile(void); ~SourceFile(void); - bool Open(const char* name, const char * path, bool binary = false); + bool Open(const char* name, const char * path, SourceFileMode mode = SFM_TEXT); void Close(void); void Limit(int skip, int limit); @@ -77,7 +88,7 @@ public: bool PopSource(void); bool DropSource(void); - bool EmbedData(const char* reason, const char* name, bool local, int skip, int limit); + bool EmbedData(const char* reason, const char* name, bool local, int skip, int limit, SourceFileMode mode); Preprocessor(Errors * errors); ~Preprocessor(void); diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index 50e8f3e..43b3571 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -637,6 +637,7 @@ void Scanner::NextToken(void) else if (mToken == TK_PREP_EMBED) { int limit = 65536, skip = 0; + SourceFileMode mode = SFM_BINARY; NextRawToken(); if (mToken == TK_INTEGER) @@ -651,16 +652,26 @@ void Scanner::NextToken(void) } } + if (mToken == TK_IDENT) + { + if (!strcmp(mTokenIdent->mString, "rle")) + mode = SFM_BINARY_RLE; + else + mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Invalid embed compression mode", mTokenIdent); + + NextRawToken(); + } + if (mToken == TK_STRING) { - if (!mPreprocessor->EmbedData("Embedding", mTokenString, true, skip, limit)) + if (!mPreprocessor->EmbedData("Embedding", mTokenString, true, skip, limit, mode)) mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString); } else if (mToken == TK_LESS_THAN) { mOffset--; StringToken('>', 'a'); - if (!mPreprocessor->EmbedData("Embedding", mTokenString, false, skip, limit)) + if (!mPreprocessor->EmbedData("Embedding", mTokenString, false, skip, limit, mode)) mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString); } }