From fdcaf546667365fc11d6eee22ebc38de43cca298 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Thu, 30 Jun 2022 09:33:11 +0200 Subject: [PATCH] Add unroll pragma for simple loops --- include/fixmath.c | 6 + include/fixmath.h | 4 + oscar64/Declaration.cpp | 15 + oscar64/Declaration.h | 2 + oscar64/InterCode.cpp | 151 ++++++++ oscar64/InterCode.h | 2 + oscar64/NativeCodeGenerator.cpp | 628 ++++++++++++++++++++++++++++++- oscar64/NativeCodeGenerator.h | 18 + oscar64/Parser.cpp | 116 +++++- oscar64/Parser.h | 1 + oscar64setup/oscar64setup.vdproj | 28 +- samples/fractals/build.sh | 1 + samples/fractals/make.bat | 2 +- samples/fractals/mbfixed.c | 100 +++++ samples/scrolling/grid2d.c | 2 +- 15 files changed, 1052 insertions(+), 24 deletions(-) create mode 100644 samples/fractals/mbfixed.c diff --git a/include/fixmath.c b/include/fixmath.c index 4a6d493..19e9066 100644 --- a/include/fixmath.c +++ b/include/fixmath.c @@ -106,6 +106,12 @@ inline int lmul8f8s(int x, int y) return (int)(lmul16s(x, y) >> 8); } +inline unsigned long lsqr4f12s(int x) +{ + if (x < 0) x = -x; + return lmul16u(x, x); +} + int lmul4f12s(int x, int y) { __asm diff --git a/include/fixmath.h b/include/fixmath.h index 7d14636..190f311 100644 --- a/include/fixmath.h +++ b/include/fixmath.h @@ -10,12 +10,16 @@ __native long lmul16s(int x, int y) // Multiply two 12.4 fixpoint numbers and return a 12.4 fixpoint result inline int lmul12f4s(int x, int y); + // Multiply two 8.8 fixpoint numbers and return an 8.8 fixpoint result inline int lmul8f8s(int x, int y); // Multiply two 4.12 fixpoint numbers and return a 12.4 fixpoint result __native int lmul4f12s(int x, int y) +// Square of a 4.12 sigend fixpoint number and return an 8.24 fixpoint result +inline unsigned long lsqr4f12s(int x); + // Divide a 32bit unsigned number by a 16bit number and return a 16bit number __native unsigned ldiv16u(unsigned long x, unsigned y) diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index 7da13b7..d3eecfa 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -94,6 +94,21 @@ Expression::~Expression(void) } +bool Expression::IsSame(const Expression* exp) const +{ + if (!exp || mType != exp->mType) + return false; + + switch (mType) + { + case EX_VARIABLE: + return mDecValue == exp->mDecValue; + + default: + return false; + } +} + Expression* Expression::LogicInvertExpression(void) { if (mType == EX_LOGICAL_NOT) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 2ce4716..999b953 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -164,6 +164,8 @@ public: Expression* LogicInvertExpression(void); Expression* ConstantFold(Errors * errors); + + bool IsSame(const Expression* exp) const; }; class Declaration diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index aa6810a..9d40e47 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -6875,6 +6875,103 @@ bool InterCodeBasicBlock::EliminateAliasValues(const GrowingInstructionPtrArray& return changed; } +bool InterCodeBasicBlock::MergeIndexedLoadStore(const GrowingInstructionPtrArray& tvalue) +{ + bool changed = false; + + if (!mVisited) + { + GrowingInstructionPtrArray ltvalue(tvalue); + + if (mNumEntries > 1) + ltvalue.Clear(); + + mVisited = true; + + // Move lea to front + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + if (ins->mCode == IC_LEA) + { + int j = i; + while (j > 0 && CanBypassUp(ins, mInstructions[j - 1])) + { + mInstructions[j] = mInstructions[j - 1]; + j--; + } + mInstructions[j] = ins; + } + } + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + + if (ins->mCode == IC_STORE || ins->mCode == IC_LOAD) + { + int pi = ins->mCode == IC_LOAD ? 0 : 1; + + if (ins->mSrc[pi].mTemp >= 0 && ltvalue[ins->mSrc[pi].mTemp]) + { + InterInstruction* lins = ltvalue[ins->mSrc[pi].mTemp]; + + if (lins->mSrc[0].mTemp >= 0) + { + InterInstruction* bins = lins; + + for (int j = 0; j < ltvalue.Size(); j++) + { + InterInstruction* cins = ltvalue[j]; + if (cins && + cins->mSrc[0].mTemp == bins->mSrc[0].mTemp && + cins->mSrc[1].mTemp < 0 && bins->mSrc[1].mTemp < 0 && + cins->mSrc[1].mMemory == bins->mSrc[1].mMemory && + cins->mSrc[1].mVarIndex == bins->mSrc[1].mVarIndex && + cins->mSrc[1].mIntConst < bins->mSrc[1].mIntConst && + cins->mSrc[1].mMemory != IM_ABSOLUTE) + + bins = cins; + } + + if (bins != lins && ins->mSrc[pi].mIntConst + lins->mSrc[1].mIntConst - bins->mSrc[1].mIntConst < 252) + { + ins->mSrc[pi].mTemp = bins->mDst.mTemp; + ins->mSrc[pi].mIntConst += lins->mSrc[1].mIntConst - bins->mSrc[1].mIntConst; + changed = true; + } + } + } + } + + int dtemp = ins->mDst.mTemp; + + if (dtemp >= 0) + { + + for (int i = 0; i < ltvalue.Size(); i++) + { + if (ltvalue[i] && ltvalue[i]->ReferencesTemp(dtemp)) + ltvalue[i] = nullptr; + } + + if (!ins->UsesTemp(dtemp)) + ltvalue[dtemp] = ins; + } + } + + if (mTrueJump && mTrueJump->MergeIndexedLoadStore(ltvalue)) + changed = true; + + if (mFalseJump && mFalseJump->MergeIndexedLoadStore(ltvalue)) + changed = true; + } + + return changed; +} + bool InterCodeBasicBlock::SimplifyIntegerNumeric(const GrowingInstructionPtrArray& tvalue, int& spareTemps) { bool changed = false; @@ -7142,6 +7239,22 @@ bool InterCodeBasicBlock::SimplifyIntegerNumeric(const GrowingInstructionPtrArra } } break; +#endif +#if 1 + case IC_LOAD: + if (ins->mSrc[0].mTemp >= 0 && ltvalue[ins->mSrc[0].mTemp]) + { + InterInstruction* pins = ltvalue[ins->mSrc[0].mTemp]; + + if (pins->mCode == IC_LEA && pins->mSrc[0].mTemp < 0) + { + ins->mSrc[0].Forward(pins->mSrc[1]); + pins->mSrc[1].mFinal = false; + ins->mSrc[0].mIntConst += pins->mSrc[0].mIntConst; + changed = true; + } + } + break; #endif } @@ -9922,6 +10035,19 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa ains->mSrc[0].mTemp = -1; ains->mSrc[0].mIntConst = indexStep[ins->mSrc[0].mTemp]; + if (tailBlock->mEntryRequiredTemps[ains->mDst.mTemp]) + { + InterInstruction* dins = new InterInstruction(); + dins->mCode = IC_LEA; + dins->mDst = ins->mDst; + dins->mSrc[1] = ins->mDst; + dins->mSrc[1].mMemory = IM_INDIRECT; + dins->mSrc[1].mIntConst = 0; + dins->mSrc[0].mType = IT_INT16; + dins->mSrc[0].mTemp = -1; + dins->mSrc[0].mIntConst = - indexStep[ins->mSrc[0].mTemp]; + tailBlock->mInstructions.Insert(0, dins); + } indexins.Push(ains); } } @@ -11515,6 +11641,25 @@ void InterCodeProcedure::PromoteSimpleLocalsToTemp(InterMemory paramMemory, int mEntryBlock->CompactInstructions(); } +void InterCodeProcedure::MergeIndexedLoadStore(void) +{ + GrowingInstructionPtrArray silvalues(nullptr); + + do + { + BuildDataFlowSets(); + + TempForwarding(); + RemoveUnusedInstructions(); + + silvalues.SetSize(mTemporaries.Size(), true); + + ResetVisited(); + } while (mEntryBlock->MergeIndexedLoadStore(silvalues)); + + DisassembleDebug("MergeIndexedLoadStore"); +} + void InterCodeProcedure::SimplifyIntegerNumeric(FastNumberSet& activeSet) { GrowingInstructionPtrArray silvalues(nullptr); @@ -11738,6 +11883,8 @@ void InterCodeProcedure::Close(void) DisassembleDebug("interval compare"); + MergeIndexedLoadStore(); + BuildDataFlowSets(); ResetVisited(); @@ -11760,6 +11907,10 @@ void InterCodeProcedure::Close(void) BuildDataFlowSets(); + RenameTemporaries(); + + BuildDataFlowSets(); + ResetEntryBlocks(); ResetVisited(); mEntryBlock->CollectEntryBlocks(nullptr); diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index ff85320..8ebee37 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -428,6 +428,7 @@ public: void PerformMachineSpecificValueUsageCheck(const GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid, const GrowingVariableArray& staticVars); bool EliminateDeadBranches(void); + bool MergeIndexedLoadStore(const GrowingInstructionPtrArray& tvalue); bool SimplifyIntegerNumeric(const GrowingInstructionPtrArray& tvalue, int& spareTemps); bool EliminateAliasValues(const GrowingInstructionPtrArray& tvalue, const GrowingInstructionPtrArray& avalue); @@ -563,6 +564,7 @@ protected: void PushSinglePathResultInstructions(void); void PromoteSimpleLocalsToTemp(InterMemory paramMemory, int nlocals, int nparams); void SimplifyIntegerNumeric(FastNumberSet& activeSet); + void MergeIndexedLoadStore(void); void EliminateAliasValues(); void LoadStoreForwarding(InterMemory paramMemory); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 53b3826..6dff860 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -901,8 +901,18 @@ bool NativeCodeInstruction::ChangesZeroPage(int address) const { if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END) return true; - if (address >= BC_REG_TMP && address < BC_REG_TMP_SAVED) - return true; + + if (mLinkerObject && mLinkerObject->mProc) + { + if (address >= BC_REG_TMP && address < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps) + return true; + } + else + { + if (address >= BC_REG_TMP && address < BC_REG_TMP_SAVED) + return true; + } + } return false; @@ -941,6 +951,9 @@ bool NativeCodeInstruction::UsesZeroPage(int address) const } else { + if (address >= BC_REG_FPARAMS && address < BC_REG_FPARAMS_END) + return true; + if (mLinkerObject) { for (int i = 0; i < mLinkerObject->mNumTemporaries; i++) @@ -2293,8 +2306,17 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data, AsmInsT if (!(mFlags & NCIF_RUNTIME) || (mFlags & NCIF_FEXEC)) { - for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) - data.ResetZeroPage(i); + if (mLinkerObject && mLinkerObject->mProc) + { + for (int i = BC_REG_TMP; i < BC_REG_TMP + mLinkerObject->mProc->mCallerSavedTemps; i++) + data.ResetZeroPage(i); + } + else + { + 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); } @@ -7166,6 +7188,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p int shift = ins->mSrc[0].mIntConst & 31; int sreg = BC_REG_TMP + proc->mTempOffset[ins->mSrc[1].mTemp]; + int nregs = 4; if (shift >= 24) { @@ -7177,6 +7200,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 24; + nregs = 1; } else if (shift >= 16) { @@ -7189,6 +7213,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 16; + nregs = 2; } else if (shift >= 8) { @@ -7203,6 +7228,7 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); sreg = treg; shift -= 8; + nregs = 3; } if (shift == 0) @@ -7258,21 +7284,24 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 2)); mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, sreg + 3)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); } - else - mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + 3)); + + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, treg + nregs - 1)); mIns.Push(NativeCodeInstruction(ASMIT_LDX, ASMIM_IMMEDIATE, shift)); this->Close(lblock, nullptr, ASMIT_JMP); lblock->mIns.Push(NativeCodeInstruction(ASMIT_LSR, ASMIM_IMPLIED)); - lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 2)); - lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); - lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); + for(int i=nregs -1; i>0 ; i--) + lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + i - 1)); + +// lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 1)); +// lblock->mIns.Push(NativeCodeInstruction(ASMIT_ROR, ASMIM_ZERO_PAGE, treg + 0)); lblock->mIns.Push(NativeCodeInstruction(ASMIT_DEX, ASMIM_IMPLIED)); lblock->Close(lblock, eblock, ASMIT_BNE); - eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + 3)); + eblock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, treg + nregs - 1)); return eblock; } } @@ -12339,7 +12368,7 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) } } - if (mFalseJump->mNumEntries == 1 && mTrueJump->mNumEntries == 2 && mFalseJump->mIns.Size() == 0) + if (mFalseJump->mNumEntries == 1/* && mTrueJump->mNumEntries == 2*/ && mFalseJump->mIns.Size() == 0) { if (mFalseJump->mBranch == ASMIT_BCC) { @@ -12393,7 +12422,7 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) } } - if (mTrueJump->mNumEntries == 1 && mFalseJump->mNumEntries == 2 && mTrueJump->mIns.Size() == 0) + if (mTrueJump->mNumEntries == 1/* && mFalseJump->mNumEntries == 2*/ && mTrueJump->mIns.Size() == 0) { if (mTrueJump->mBranch == ASMIT_BCC) { @@ -13351,6 +13380,43 @@ bool NativeCodeBasicBlock::JoinTailCodeSequences(NativeCodeProcedure* proc, bool } } } + + if (mEntryBlocks.Size() >= 1) + { + NativeCodeBasicBlock* eb = mEntryBlocks[0]; + + if (eb->mIns.Size()) + { + NativeCodeInstruction& ins(eb->mIns[eb->mIns.Size() - 1]); + if (ins.mType == ASMIT_STA && ins.mMode == ASMIM_ZERO_PAGE && + (eb->mBranch == ASMIT_JMP || + eb->mTrueJump == this && eb->mFalseJump && !eb->mFalseJump->mEntryRequiredRegs[ins.mAddress] || + eb->mFalseJump == this && eb->mTrueJump && !eb->mTrueJump->mEntryRequiredRegs[ins.mAddress])) + { + int i = 1; + while (i < mEntryBlocks.Size() && mEntryBlocks[i]->mIns.Size() > 0 && mEntryBlocks[i]->mIns.Last().IsSame(ins) && + (mEntryBlocks[i]->mBranch == ASMIT_JMP || + mEntryBlocks[i]->mTrueJump == this && mEntryBlocks[i]->mFalseJump && !mEntryBlocks[i]->mFalseJump->mEntryRequiredRegs[ins.mAddress] || + mEntryBlocks[i]->mFalseJump == this && mEntryBlocks[i]->mTrueJump && !mEntryBlocks[i]->mTrueJump->mEntryRequiredRegs[ins.mAddress])) + i++; + if (i == mEntryBlocks.Size()) + { + mEntryRequiredRegs += CPU_REG_A; + mEntryRequiredRegs -= ins.mAddress; + + mIns.Insert(0, ins); + for (int i = 0; i < mEntryBlocks.Size(); i++) + { + NativeCodeBasicBlock* meb = mEntryBlocks[i]; + meb->mExitRequiredRegs += CPU_REG_A; + meb->mIns.SetSize(meb->mIns.Size() - 1); + } + + changed = true; + } + } + } + } if (mEntryBlocks.Size() > 2) { @@ -14388,6 +14454,41 @@ bool NativeCodeBasicBlock::FindGlobalAddressSumY(int at, int reg, bool direct, i return flags != 0; } + else if ( + mIns[j + 1].mType == ASMIT_CLC && + mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 2].mFlags & NCIF_LOWER) && mIns[j + 2].mLinkerObject && + mIns[j + 3].mType == ASMIT_STA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == reg && + mIns[j + 4].mType == ASMIT_LDA && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 && + mIns[j + 5].mType == ASMIT_ADC && mIns[j + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && (mIns[j + 5].mFlags & NCIF_UPPER) && mIns[j + 5].mLinkerObject == mIns[j + 2].mLinkerObject && + mIns[j + 6].mType == ASMIT_STA && mIns[j + 6].mMode == ASMIM_ZERO_PAGE && mIns[j + 6].mAddress == reg + 1) + { + ains = &(mIns[j + 2]); + iins = nullptr; + apos = j + 1; + + if (!direct) + return false; + + flags = (LIVE_CPU_REG_X | LIVE_CPU_REG_Y) & ~mIns[j + 1].mLive; + + if (mIns[j + 0].mType == ASMIT_TAX) + flags |= LIVE_CPU_REG_X; + if (mIns[j + 0].mType == ASMIT_TAY) + flags |= LIVE_CPU_REG_Y; + + int k = j + 7; + while (k < at) + { + assert(!(flags & LIVE_CPU_REG_Y) || mIns[k].mType != ASMIT_TYA); + if (mIns[k].ChangesYReg()) + flags &= ~LIVE_CPU_REG_Y; + if (mIns[k].ChangesXReg()) + flags &= ~LIVE_CPU_REG_X; + k++; + } + + return flags != 0; + } else if (mIns[j + 0].mType == ASMIT_CLC && mIns[j + 1].mType == ASMIT_LDA && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mType == ASMIT_ADC && mIns[j + 2].mMode == ASMIM_IMMEDIATE && @@ -15093,6 +15194,59 @@ bool NativeCodeBasicBlock::PatchAddressSumY(int at, int reg, int apos, int breg, return true; } +bool NativeCodeBasicBlock::FindBypassAddressSumY(int at, int reg, int& apos, int& breg) +{ + int j = at - 6; + while (j >= 0) + { + if ( + mIns[j + 0].mType == ASMIT_CLC && + mIns[j + 1].mType == ASMIT_ADC && mIns[j + 1].mMode == ASMIM_ZERO_PAGE && + mIns[j + 2].mType == ASMIT_STA && mIns[j + 2].mMode == ASMIM_ZERO_PAGE && mIns[j + 2].mAddress == reg && + mIns[j + 3].mType == ASMIT_LDA && mIns[j + 3].mMode == ASMIM_ZERO_PAGE && mIns[j + 3].mAddress == mIns[j + 1].mAddress + 1 && + mIns[j + 4].mType == ASMIT_ADC && mIns[j + 4].mMode == ASMIM_IMMEDIATE && mIns[j + 4].mAddress == 0 && + mIns[j + 5].mType == ASMIT_STA && mIns[j + 5].mMode == ASMIM_ZERO_PAGE && mIns[j + 5].mAddress == reg + 1) + { + breg = mIns[j + 1].mAddress; + int k = j + 6; + while (k < at) + { + if (mIns[k].ChangesZeroPage(breg) || mIns[k].ChangesZeroPage(breg + 1)) + return false; + + k++; + } + + apos = j; + + return true; + } + + if (mIns[j + 5].ReferencesZeroPage(reg) || mIns[j + 5].ReferencesZeroPage(reg + 1)) + return false; + + j--; + } + + return false; +} + +bool NativeCodeBasicBlock::PatchBypassAddressSumY(int at, int reg, int apos, int breg) +{ + mIns[apos + 0].mType = ASMIT_NOP; mIns[apos + 0].mMode = ASMIM_IMPLIED; + mIns[apos + 1].mType = ASMIT_NOP; mIns[apos + 1].mMode = ASMIM_IMPLIED; + mIns[apos + 3].mType = ASMIT_NOP; mIns[apos + 3].mMode = ASMIM_IMPLIED; + mIns[apos + 4].mType = ASMIT_NOP; mIns[apos + 4].mMode = ASMIM_IMPLIED; + mIns[apos + 5].mType = ASMIT_NOP; mIns[apos + 5].mMode = ASMIM_IMPLIED; + + mIns[at + 0].mMode = ASMIM_ZERO_PAGE; + mIns[at + 0].mAddress = reg; + mIns[at + 1].mAddress = breg; + mIns[at + 1].mLive |= LIVE_MEM; + + return true; +} + bool NativeCodeBasicBlock::FindDirectAddressSumY(int at, int reg, int& apos, int& breg) { int j = at - 6; @@ -15713,6 +15867,30 @@ bool NativeCodeBasicBlock::MoveAbsoluteLoadStoreUp(int at) return false; } +bool NativeCodeBasicBlock::ReplaceZeroPageDown(int at) +{ + int i = at + 2; + while (i < mIns.Size()) + { + if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[at].mAddress) + { + mIns[at + 1].mLive |= mIns[i].mLive; + mIns.Insert(i + 1, mIns[at + 1]); + mIns.Remove(at, 2); + return true; + } + + if (mIns[i].ChangesZeroPage(mIns[at].mAddress)) + return false; + if (mIns[i].ReferencesZeroPage(mIns[at + 1].mAddress)) + return false; + + i++; + } + + return false; +} + bool NativeCodeBasicBlock::ReplaceZeroPageUp(int at) { int i = at - 1; @@ -15749,6 +15927,374 @@ bool NativeCodeBasicBlock::ReplaceZeroPageUp(int at) return false; } +bool NativeCodeBasicBlock::MoveZeroPageCrossBlockUp(int at, const NativeCodeInstruction& lins, const NativeCodeInstruction& sins) +{ + if (!mPatched) + { + mPatched = true; + + if (at == -2) + { + for (int i = 0; i < mIns.Size(); i++) + { + if (mIns[i].ChangesZeroPage(lins.mAddress)) + return false; + if (mIns[i].ReferencesZeroPage(sins.mAddress)) + return false; + } + + at = mIns.Size(); + } + else + { + if (at == -1) + at = mIns.Size(); + + int i = at; + while (i > 0) + { + i--; + if (mIns[i].mType == ASMIT_STA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == lins.mAddress) + { + while (i < at) + { + if (mIns[i].mAddress == lins.mAddress) + mIns[i].mAddress = sins.mAddress; + i++; + } + return true; + } + + if (mIns[i].ChangesZeroPage(lins.mAddress)) + return false; + else if (mIns[i].mMode == ASMIM_ZERO_PAGE && !mIns[i].ChangesAddress() && mIns[i].mAddress == lins.mAddress) + ; + else if (mIns[i].ReferencesZeroPage(sins.mAddress)) + return false; + } + } + + int pat = -1; + NativeCodeBasicBlock* eb = nullptr; + + if (mEntryBlocks.Size() == 1 || mEntryBlocks.Size() == 2 && mEntryBlocks[1] == this) + { + eb = mEntryBlocks[0]; + if (!eb->mFalseJump) + ; + else if (eb->mTrueJump == eb || eb->mFalseJump == eb) + pat = -2; + else if (eb->mFalseJump->mPatched && eb->mTrueJump->mPatched) + ; + else if ( + eb->mTrueJump == this && !eb->mFalseJump->mEntryRequiredRegs[lins.mAddress] && !eb->mFalseJump->mEntryRequiredRegs[sins.mAddress] || + eb->mFalseJump == this && !eb->mTrueJump->mEntryRequiredRegs[lins.mAddress] && !eb->mTrueJump->mEntryRequiredRegs[sins.mAddress]) + ; + else + return false; + } + else if (mEntryBlocks.Size() == 2) + { + NativeCodeBasicBlock* eb0 = mEntryBlocks[0]; + NativeCodeBasicBlock* eb1 = mEntryBlocks[1]; + + if (eb0->mEntryBlocks.Size() == 1 && eb0->mEntryBlocks[0] == eb1) + eb = eb0; + else if (eb1->mEntryBlocks.Size() == 1 && eb1->mEntryBlocks[0] == eb0) + eb = eb1; + else + return false; + + pat = -2; + } + else + return false; + + if (!eb->MoveZeroPageCrossBlockUp(pat, lins, sins)) + return false; + + for(int i=0; iResetPatched(); + if (MoveZeroPageCrossBlockUp(i, mIns[i + 0], mIns[i + 1])) + { + changed = true; + mIns.Remove(i, 2); + } + else + i++; + } + else + i++; + } + + CheckLive(); + } + + if (mTrueJump && mTrueJump->ShortcutCrossBlockMoves(proc)) + changed = true; + if (mFalseJump && mFalseJump->ShortcutCrossBlockMoves(proc)) + changed = true; + } + + return changed; +} + +bool NativeCodeBasicBlock::Check16BitSum(int at, NativeRegisterSum16Info& info) +{ + if (at + 6 < mIns.Size()) + { + if (mIns[at + 0].mType == ASMIT_CLC && + mIns[at + 1].mType == ASMIT_LDA && + mIns[at + 2].mType == ASMIT_ADC && + mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && + mIns[at + 4].mType == ASMIT_LDA && + mIns[at + 5].mType == ASMIT_ADC && + mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE) + { + info.mDstL = &(mIns[at + 3]); + info.mDstH = &(mIns[at + 6]); + + if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && (mIns[at + 5].mMode == ASMIM_ZERO_PAGE || mIns[at + 5].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mAddress == 0)) + { + if (mIns[at + 1].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mMode == ASMIM_IMMEDIATE) + { + info.mAddress = (mIns[at + 1].mAddress & 0xff) + (mIns[at + 4].mAddress << 8); + info.mLinkerObject = nullptr; + info.mSrcL = &(mIns[at + 2]); + info.mSrcH = &(mIns[at + 5]); + info.mAddL = &(mIns[at + 1]); + info.mAddH = &(mIns[at + 4]); + + return true; + } + else if (mIns[at + 1].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 1].mLinkerObject == mIns[at + 4].mLinkerObject && mIns[at + 1].mAddress == mIns[at + 4].mAddress) + { + info.mAddress = mIns[at + 1].mAddress; + info.mLinkerObject = mIns[at + 1].mLinkerObject; + info.mSrcL = &(mIns[at + 2]); + info.mSrcH = &(mIns[at + 5]); + info.mAddL = &(mIns[at + 1]); + info.mAddH = &(mIns[at + 4]); + + return true; + } + } + else if (mIns[at + 1].mMode == ASMIM_ZERO_PAGE && (mIns[at + 4].mMode == ASMIM_ZERO_PAGE || mIns[at + 4].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mAddress == 0)) + { + if (mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mMode == ASMIM_IMMEDIATE) + { + info.mAddress = (mIns[at + 2].mAddress & 0xff) + (mIns[at + 5].mAddress << 8); + info.mLinkerObject = nullptr; + info.mSrcL = &(mIns[at + 1]); + info.mSrcH = &(mIns[at + 4]); + info.mAddL = &(mIns[at + 2]); + info.mAddH = &(mIns[at + 5]); + + return true; + } + else if (mIns[at + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 2].mLinkerObject == mIns[at + 5].mLinkerObject && mIns[at + 2].mAddress == mIns[at + 5].mAddress) + { + info.mAddress = mIns[at + 2].mAddress; + info.mLinkerObject = mIns[at + 2].mLinkerObject; + info.mSrcL = &(mIns[at + 1]); + info.mSrcH = &(mIns[at + 4]); + info.mAddL = &(mIns[at + 2]); + info.mAddH = &(mIns[at + 5]); + + return true; + } + } + } + else if (mIns[at + 0].mType == ASMIT_LDA && + mIns[at + 1].mType == ASMIT_CLC && + mIns[at + 2].mType == ASMIT_ADC && + mIns[at + 3].mType == ASMIT_STA && mIns[at + 3].mMode == ASMIM_ZERO_PAGE && + mIns[at + 4].mType == ASMIT_LDA && + mIns[at + 5].mType == ASMIT_ADC && + mIns[at + 6].mType == ASMIT_STA && mIns[at + 6].mMode == ASMIM_ZERO_PAGE) + { + info.mDstL = &(mIns[at + 3]); + info.mDstH = &(mIns[at + 6]); + + if (mIns[at + 2].mMode == ASMIM_ZERO_PAGE && mIns[at + 5].mMode == ASMIM_ZERO_PAGE) + { + if (mIns[at + 0].mMode == ASMIM_IMMEDIATE && mIns[at + 4].mMode == ASMIM_IMMEDIATE) + { + info.mAddress = (mIns[at + 0].mAddress & 0xff) + (mIns[at + 4].mAddress << 8); + info.mLinkerObject = nullptr; + info.mSrcL = &(mIns[at + 2]); + info.mSrcH = &(mIns[at + 5]); + info.mAddL = &(mIns[at + 0]); + info.mAddH = &(mIns[at + 4]); + + return true; + } + else if (mIns[at + 0].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 4].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 0].mLinkerObject == mIns[at + 4].mLinkerObject && mIns[at + 0].mAddress == mIns[at + 4].mAddress) + { + info.mAddress = mIns[at + 0].mAddress; + info.mLinkerObject = mIns[at + 0].mLinkerObject; + info.mSrcL = &(mIns[at + 2]); + info.mSrcH = &(mIns[at + 5]); + info.mAddL = &(mIns[at + 0]); + info.mAddH = &(mIns[at + 4]); + + return true; + } + } + else if (mIns[at + 0].mMode == ASMIM_ZERO_PAGE && mIns[at + 4].mMode == ASMIM_ZERO_PAGE) + { + if (mIns[at + 2].mMode == ASMIM_IMMEDIATE && mIns[at + 5].mMode == ASMIM_IMMEDIATE) + { + info.mAddress = (mIns[at + 2].mAddress & 0xff) + (mIns[at + 5].mAddress << 8); + info.mLinkerObject = nullptr; + info.mSrcL = &(mIns[at + 0]); + info.mSrcH = &(mIns[at + 4]); + info.mAddL = &(mIns[at + 2]); + info.mAddH = &(mIns[at + 5]); + + return true; + } + else if (mIns[at + 2].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 5].mMode == ASMIM_IMMEDIATE_ADDRESS && mIns[at + 2].mLinkerObject == mIns[at + 5].mLinkerObject && mIns[at + 2].mAddress == mIns[at + 5].mAddress) + { + info.mAddress = mIns[at + 2].mAddress; + info.mLinkerObject = mIns[at + 2].mLinkerObject; + info.mSrcL = &(mIns[at + 0]); + info.mSrcH = &(mIns[at + 4]); + info.mAddL = &(mIns[at + 2]); + info.mAddH = &(mIns[at + 5]); + + return true; + } + } + } + } + + return false; +} + +bool NativeCodeBasicBlock::Propagate16BitSum(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + GrowingArray infos(NativeRegisterSum16Info{}); + + for (int i = 0; i < mIns.Size(); i++) + { + NativeRegisterSum16Info info; + + if (Check16BitSum(i, info)) + { + for (int j = 0; j < infos.Size(); j++) + { + if (info.mSrcL->mAddress == infos[j].mDstL->mAddress && info.mSrcH->mAddress == infos[j].mDstH->mAddress) + { + if (!info.mLinkerObject && !infos[j].mLinkerObject) + { + info.mAddress += infos[j].mAddress; + info.mAddL->mAddress = info.mAddress & 0xff; + info.mAddH->mAddress = info.mAddress >> 8; + info.mSrcL->mAddress = infos[j].mSrcL->mAddress; + info.mSrcH->mAddress = infos[j].mSrcH->mAddress; + info.mSrcH->mMode = infos[j].mSrcH->mMode; + changed = true; + } + else if (!infos[j].mLinkerObject) + { + info.mAddress += infos[j].mAddress; + info.mAddL->mAddress = info.mAddress; + info.mAddH->mAddress = info.mAddress; + info.mSrcL->mAddress = infos[j].mSrcL->mAddress; + info.mSrcH->mAddress = infos[j].mSrcH->mAddress; + info.mSrcH->mMode = infos[j].mSrcH->mMode; + changed = true; + } + else if (!info.mLinkerObject) + { + info.mAddress += infos[j].mAddress; + info.mLinkerObject = infos[j].mLinkerObject; + info.mAddL->mAddress = info.mAddress; + info.mAddL->mLinkerObject = info.mLinkerObject; + info.mAddL->mMode = ASMIM_IMMEDIATE_ADDRESS; + info.mAddL->mFlags = NCIF_LOWER; + info.mAddH->mAddress = info.mAddress; + info.mAddH->mLinkerObject = info.mLinkerObject; + info.mAddH->mMode = ASMIM_IMMEDIATE_ADDRESS; + info.mAddH->mFlags = NCIF_UPPER; + info.mSrcL->mAddress = infos[j].mSrcL->mAddress; + info.mSrcH->mAddress = infos[j].mSrcH->mAddress; + info.mSrcH->mMode = infos[j].mSrcH->mMode; + changed = true; + } + } + } + + if (info.mSrcL->mAddress != info.mDstL->mAddress && (info.mSrcH->mMode == ASMIM_IMMEDIATE || info.mSrcH->mAddress != info.mDstH->mAddress)) + infos.Push(info); + } + + int j = 0; + while (j < infos.Size()) + { + if (infos[j].mDstL != &(mIns[i]) && infos[j].mDstH != &(mIns[i])) + { + if ( + infos[j].mSrcL->MayBeChangedOnAddress(mIns[i]) || + infos[j].mSrcH->MayBeChangedOnAddress(mIns[i]) || + infos[j].mDstL->MayBeChangedOnAddress(mIns[i]) || + infos[j].mDstH->MayBeChangedOnAddress(mIns[i])) + { + infos.Remove(j); + } + else + j++; + } + else + j++; + } + } + + if (mTrueJump && mTrueJump->Propagate16BitSum()) + changed = true; + if (mFalseJump && mFalseJump->Propagate16BitSum()) + changed = true; + } + return changed; +} + bool NativeCodeBasicBlock::MoveLoadXUp(int at) { @@ -16605,8 +17151,17 @@ bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data, bo if (!(ins.mFlags & NCIF_RUNTIME) || (ins.mFlags & NCIF_FEXEC)) { - for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) - mNDataSet.ResetZeroPage(i); + if (ins.mLinkerObject && ins.mLinkerObject->mProc) + { + for (int i = BC_REG_TMP; i < BC_REG_TMP + ins.mLinkerObject->mProc->mCallerSavedTemps; i++) + mNDataSet.ResetZeroPage(i); + } + else + { + for (int i = BC_REG_TMP; i < BC_REG_TMP_SAVED; i++) + mNDataSet.ResetZeroPage(i); + } + for (int i = BC_REG_FPARAMS; i < BC_REG_FPARAMS_END; i++) mNDataSet.ResetZeroPage(i); } @@ -20388,6 +20943,23 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass CheckLive(); #endif + if (pass > 1) + { +#if 1 + // replace zero page down + + for (int i = 1; i + 1 < mIns.Size(); i++) + { + if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_STA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && !(mIns[i + 1].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z)) && (mIns[i + 0].mLive & LIVE_MEM)) + { + if (ReplaceZeroPageDown(i)) + changed = true; + } + } + CheckLive(); + +#endif + } #endif CheckLive(); @@ -23822,7 +24394,17 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass progress = true; } } - + + if (i + 1 < mIns.Size() && mIns[i + 0].mType == ASMIT_LDY && mIns[i + 0].mMode == ASMIM_IMMEDIATE && mIns[i + 0].mAddress == 0 && mIns[i + 1].mMode == ASMIM_INDIRECT_Y && !(mIns[i + 1].mLive & (LIVE_MEM | LIVE_CPU_REG_Y))) + { + int apos, breg; + if (FindBypassAddressSumY(i, mIns[i + 1].mAddress, apos, breg)) + { + if (PatchBypassAddressSumY(i, mIns[i + 1].mAddress, apos, breg)) + progress = true; + } + } + if (mIns[i + 0].mMode == ASMIM_INDIRECT_Y && (mIns[i + 0].mFlags & NCIF_YZERO)) { int apos, breg; @@ -25267,6 +25849,12 @@ void NativeCodeProcedure::Optimize(void) NativeRegisterDataSet data; if (mEntryBlock->ValueForwarding(data, step > 0, step == 7)) changed = true; + else + { + ResetVisited(); + if (mEntryBlock->Propagate16BitSum()) + changed = true; + } } while (changed); #endif @@ -25330,6 +25918,16 @@ void NativeCodeProcedure::Optimize(void) } #endif +#if 1 + if (step > 4 && !changed) + { + ResetVisited(); + if (mEntryBlock->ShortcutCrossBlockMoves(this)) + changed = true; + } +#endif + + #if 1 if (step > 2 && !changed) { diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index a3d524d..ce433c2 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -7,6 +7,7 @@ class NativeCodeProcedure; class NativeCodeBasicBlock; class NativeCodeGenerator; +class NativeCodeInstruction; enum NativeRegisterDataMode { @@ -46,6 +47,14 @@ struct NativeRegisterDataSet void IntersectMask(const NativeRegisterDataSet& set); }; +struct NativeRegisterSum16Info +{ + NativeCodeInstruction * mSrcL, * mSrcH, * mDstL, * mDstH, * mAddL, * mAddH; + + int mAddress; + LinkerObject * mLinkerObject; +}; + static const uint32 NCIF_LOWER = 0x00000001; static const uint32 NCIF_UPPER = 0x00000002; @@ -278,6 +287,8 @@ public: bool FindGlobalAddressSumY(int at, int reg, bool direct, int& apos, const NativeCodeInstruction * & ains, const NativeCodeInstruction*& iins, uint32 & flags, int & addr); bool FindExternAddressSumY(int at, int reg, int& breg, int& ireg); bool FindPageStartAddress(int at, int reg, int& addr); + bool FindBypassAddressSumY(int at, int reg, int& apos, int& breg); + bool PatchBypassAddressSumY(int at, int reg, int apos, int breg); bool MoveStoreXUp(int at); bool MoveLoadXUp(int at); bool MoveStoreYUp(int at); @@ -286,10 +297,14 @@ public: bool MoveAddHighByteDown(int at); bool ReverseLoadCommutativeOpUp(int aload, int aop); bool ReplaceZeroPageUp(int at); + bool ReplaceZeroPageDown(int at); bool ReplaceYRegWithXReg(int start, int end); bool ReplaceXRegWithYReg(int start, int end); bool MoveASLMemUp(int start); + bool MoveZeroPageCrossBlockUp(int at, const NativeCodeInstruction & lins, const NativeCodeInstruction & sins); + bool ShortcutCrossBlockMoves(NativeCodeProcedure* proc); + bool CanReplaceYRegWithXReg(int start, int end); bool CanReplaceXRegWithYReg(int start, int end); @@ -324,6 +339,9 @@ public: bool HasTailSTA(int& addr, int& index) const; bool PropagateSinglePath(void); + bool Check16BitSum(int at, NativeRegisterSum16Info& info); + bool Propagate16BitSum(void); + NativeRegisterDataSet mEntryRegisterDataSet; void BuildEntryDataSet(const NativeRegisterDataSet& set); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 874497a..f232664 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -13,6 +13,8 @@ Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUn mDataSection = compilationUnits->mSectionData; mBSSection = compilationUnits->mSectionBSS; + mUnrollLoop = 0; + for (int i = 0; i < 256; i++) mCharMap[i] = i; } @@ -2017,6 +2019,12 @@ Expression* Parser::ParseStatement(void) { Expression* exp = nullptr; + while (mScanner->mToken == TK_PREP_PRAGMA) + { + mScanner->NextToken(); + ParsePragma(); + } + if (mScanner->mToken == TK_OPEN_BRACE) { DeclarationScope* scope = new DeclarationScope(mScope); @@ -2111,12 +2119,16 @@ Expression* Parser::ParseStatement(void) mScanner->NextToken(); exp = new Expression(mScanner->mLocation, EX_FOR); - exp->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE); - exp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE); + + int unrollLoop = mUnrollLoop; + mUnrollLoop = 0; + + Expression* initExp = nullptr, * iterateExp = nullptr, * conditionExp = nullptr, * bodyExp = nullptr, * finalExp = nullptr; + // Assignment if (mScanner->mToken != TK_SEMICOLON) - exp->mLeft->mRight = ParseExpression(); + initExp = ParseExpression(); if (mScanner->mToken == TK_SEMICOLON) mScanner->NextToken(); else @@ -2124,7 +2136,8 @@ Expression* Parser::ParseStatement(void) // Condition if (mScanner->mToken != TK_SEMICOLON) - exp->mLeft->mLeft->mLeft = ParseExpression(); + conditionExp = ParseExpression(); + if (mScanner->mToken == TK_SEMICOLON) mScanner->NextToken(); else @@ -2132,12 +2145,83 @@ Expression* Parser::ParseStatement(void) // Iteration if (mScanner->mToken != TK_CLOSE_PARENTHESIS) - exp->mLeft->mLeft->mRight = ParseExpression(); + iterateExp = ParseExpression(); if (mScanner->mToken == TK_CLOSE_PARENTHESIS) mScanner->NextToken(); else mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "')' expected"); - exp->mRight = ParseStatement(); + bodyExp = ParseStatement(); + + exp->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE); + exp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE); + + if (unrollLoop > 1 && initExp && iterateExp && conditionExp) + { + if ((initExp->mType == EX_ASSIGNMENT || initExp->mType == EX_INITIALIZATION) && initExp->mLeft->mType == EX_VARIABLE && initExp->mRight->mType == EX_CONSTANT && + (iterateExp->mType == EX_POSTINCDEC || iterateExp->mType == EX_PREINCDEC) && iterateExp->mLeft->IsSame(initExp->mLeft) && + conditionExp->mType == EX_RELATIONAL && conditionExp->mToken == TK_LESS_THAN && conditionExp->mLeft->IsSame(initExp->mLeft) && conditionExp->mRight->mType == EX_CONSTANT) + { + if (initExp->mRight->mDecValue->mType == DT_CONST_INTEGER && conditionExp->mRight->mDecValue->mType == DT_CONST_INTEGER) + { + int startValue = initExp->mRight->mDecValue->mInteger; + int endValue = conditionExp->mRight->mDecValue->mInteger; + + int remain = (endValue - startValue) % unrollLoop; + endValue -= remain; + + conditionExp->mRight->mDecValue->mInteger = endValue; + + Expression * unrollBody = new Expression(mScanner->mLocation, EX_SEQUENCE); + unrollBody->mLeft = bodyExp; + Expression* bexp = unrollBody; + if (endValue > startValue) + { + for (int i = 1; i < unrollLoop; i++) + { + bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + bexp = bexp->mRight; + bexp->mLeft = iterateExp; + bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + bexp = bexp->mRight; + bexp->mLeft = bodyExp; + } + } + + if (remain) + { + finalExp = new Expression(mScanner->mLocation, EX_SEQUENCE); + finalExp->mLeft = bodyExp; + Expression* bexp = finalExp; + + for (int i = 1; i < remain; i++) + { + bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + bexp = bexp->mRight; + bexp->mLeft = iterateExp; + bexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + bexp = bexp->mRight; + bexp->mLeft = bodyExp; + } + } + + bodyExp = unrollBody; + } + } + } + + exp->mLeft->mRight = initExp; + exp->mLeft->mLeft->mLeft = conditionExp; + exp->mLeft->mLeft->mRight = iterateExp; + exp->mRight = bodyExp; + + if (finalExp) + { + Expression* nexp = new Expression(mScanner->mLocation, EX_SEQUENCE); + nexp->mLeft = exp; + nexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE); + nexp->mRight->mLeft = finalExp; + exp = nexp; + } mScope = mScope->mParent; } @@ -3574,6 +3658,26 @@ void Parser::ParsePragma(void) ConsumeToken(TK_CLOSE_PARENTHESIS); } + else if (!strcmp(mScanner->mTokenIdent->mString, "unroll")) + { + mScanner->NextToken(); + ConsumeToken(TK_OPEN_PARENTHESIS); + + if (mScanner->mToken == TK_INTEGER) + { + mUnrollLoop = mScanner->mTokenInteger; + mScanner->NextToken(); + } + else if (mScanner->mToken == TK_IDENT && !strcmp(mScanner->mTokenIdent->mString, "full")) + { + mUnrollLoop = 0x10000; + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_PRAGMA_PARAMETER, "Integer literal expected"); + + ConsumeToken(TK_CLOSE_PARENTHESIS); + } else { mScanner->NextToken(); diff --git a/oscar64/Parser.h b/oscar64/Parser.h index 07ba2e1..288e33d 100644 --- a/oscar64/Parser.h +++ b/oscar64/Parser.h @@ -24,6 +24,7 @@ protected: bool ConsumeTokenIf(Token token); char mCharMap[256]; + int mUnrollLoop; uint8* ParseStringLiteral(int msize); diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index 5ef543c..d7e1e46 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -640,6 +640,12 @@ } "Entry" { + "MsmKey" = "8:_BFAE73A1432845AB83CAA44F3A7EC9C3" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_C239EFB1C3A646809AD2740ABDE747B0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -3051,6 +3057,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BFAE73A1432845AB83CAA44F3A7EC9C3" + { + "SourcePath" = "8:..\\samples\\fractals\\mbfixed.c" + "TargetName" = "8:mbfixed.c" + "Tag" = "8:" + "Folder" = "8:_BDDE04AB523C4059AABE326807998F7A" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C239EFB1C3A646809AD2740ABDE747B0" { "SourcePath" = "8:..\\include\\c64\\types.h" @@ -4128,7 +4154,7 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" "ProductCode" = "8:{4AC1A78B-6BCA-4D2F-A54D-DEA5F627B017}" - "PackageCode" = "8:{AA95DD46-0812-483A-92A4-D1A34E57D713}" + "PackageCode" = "8:{ED70C89A-F338-434F-9FB2-90C1BD8EB020}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" diff --git a/samples/fractals/build.sh b/samples/fractals/build.sh index 8803577..1be9907 100644 --- a/samples/fractals/build.sh +++ b/samples/fractals/build.sh @@ -3,4 +3,5 @@ ../../bin/oscar64 mbhires.c -n ../../bin/oscar64 mbmulti.c -n ../../bin/oscar64 mbmulti3d.c -n +../../bin/oscar64 mbfixed.c -n -O3 diff --git a/samples/fractals/make.bat b/samples/fractals/make.bat index 2ebecfe..86f59e0 100644 --- a/samples/fractals/make.bat +++ b/samples/fractals/make.bat @@ -2,4 +2,4 @@ call ..\..\bin\oscar64 mbtext.c -n call ..\..\bin\oscar64 mbhires.c -n call ..\..\bin\oscar64 mbmulti.c -n call ..\..\bin\oscar64 mbmulti3d.c -n - +call ..\..\bin\oscar64 mbfixed.c -n -O3 diff --git a/samples/fractals/mbfixed.c b/samples/fractals/mbfixed.c new file mode 100644 index 0000000..570a64d --- /dev/null +++ b/samples/fractals/mbfixed.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include + +// Address of hires buffer and color buffers +#define Screen ((char *)0xe000) +#define Color ((char *)0xc800) +#define Color2 ((char *)0xd800) + +// Bit patters for eight different color pairs +char colors[] = { + 0xff, 0xff, + 0xee, 0xbb, + 0xaa, 0xaa, + 0x88, 0x22, + + 0x44, 0x11, + 0x55, 0x55, + 0xdd, 0x77, + 0x33, 0xcc +}; + +int main(void) +{ + // Install the IRQ trampoline + mmap_trampoline(); + + // Turn of the kernal ROM + mmap_set(MMAP_NO_ROM); + + // Switch VIC into multicolor bitmap mode + vic_setmode(VICM_HIRES_MC, Color, Screen); + + // Clear the screen and set the colors + vic.color_back = 0x00; + + memset(Screen, 0, 8000); + memset(Color, 0x27, 1000); + memset(Color2, 0x03, 1000); + + // Loop over all pixels + int py, px; + + for(py=0; py<100; py++) + { + for(px=0; px<160; px++) + { + // Value in the complex plane + +// int xz = (int)(((float)px * (3.5 / 160.0) - 2.5) * 4096 + 0.5); +// int yz = (int)(((float)py * (2.4 / 100.0) - 1.2) * 4096 + 0.5); + + int xz = lmul8f8s(px, (int)((3.5 / 160.0) * 4096 * 256)) - (int)(2.5 * 4096); + int yz = lmul8f8s(py, (int)((2.4 / 100.0) * 4096 * 256)) - (int)(1.2 * 4096); + + // Iterate up to 32 times + int x = 0, y = 0; + int i; + for(i=0; i<32; i++) + { + unsigned long xq = lsqr4f12s(x), yq = lsqr4f12s(y); + + if (xq + yq >= 0x04000000UL) break; + + int xt = (int)(xq >> 12) - (int)(yq >> 12) + xz; + y = 2 * lmul4f12s(x, y) + yz; + x = xt; + } + + if (i < 32) + { + // Position on screen + char * dp = Screen + 320 * (py >> 2) + 2 * (py & 3) + 2 * (px & ~3); + + // Mask of pixels to change + char mask = 0xc0 >> (2 * (px & 3)); + + // Get the two color patterns for upper and lower half + char c0 = colors[2 * (i & 7)], c1 = colors[2 * (i & 7) + 1]; + + // Put the pixels into the image + dp[0] |= c0 & mask; + dp[1] |= c1 & mask; + } + } + } + + // Re-enable the kernal + mmap_set(MMAP_NO_BASIC); + + // Wait for key press + getch(); + + // Restore VIC state + vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); + + return 0; +} diff --git a/samples/scrolling/grid2d.c b/samples/scrolling/grid2d.c index e3c8eb5..0b4122c 100644 --- a/samples/scrolling/grid2d.c +++ b/samples/scrolling/grid2d.c @@ -251,7 +251,7 @@ int main(void) dy += ay; // New force - if ((rand() & 127) == 0) + if ((rand() & 63) == 0) { ax = (rand() & 63) - 32; ay = (rand() & 63) - 32;