From db3c6a3135a856af075acf2836d08edc9fcfb1dd Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:15:09 +0200 Subject: [PATCH] Peephole optimizations --- oscar64/InterCode.cpp | 65 ++++++++++++- oscar64/NativeCodeGenerator.cpp | 163 +++++++++++++++++++++++++++++++- oscar64/NativeCodeGenerator.h | 3 + oscar64/Parser.cpp | 9 +- samples/particles/make.bat | 2 +- 5 files changed, 229 insertions(+), 13 deletions(-) diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index f128a3d..978cf3f 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -11082,6 +11082,47 @@ bool InterCodeBasicBlock::SimplifyIntegerNumeric(const GrowingInstructionPtrArra } } } + else if (ins->mSrc[0].mTemp >= 0 && ins->mSrc[1].mTemp >= 0 && + ltvalue[ins->mSrc[0].mTemp] && ltvalue[ins->mSrc[1].mTemp] && + ins->mSrc[0].mFinal && ins->mSrc[1].mFinal) + { + InterInstruction* ai0 = ltvalue[ins->mSrc[0].mTemp], * ai1 = ltvalue[ins->mSrc[1].mTemp]; + if (ai0->mCode == IC_BINARY_OPERATOR && ai0->mOperator == IA_SUB && ai0->mSrc[0].mTemp < 0 && ai0->mSrc[1].mFinal && + ai1->mCode == IC_BINARY_OPERATOR && ai1->mOperator == IA_SUB && ai1->mSrc[0].mTemp < 0 && ai1->mSrc[1].mFinal) + { + if (spareTemps + 2 >= ltvalue.Size()) + return true; + + InterInstruction* sins = new InterInstruction(ins->mLocation, IC_BINARY_OPERATOR); + sins->mOperator = IA_SUB; + sins->mDst = ins->mDst; + sins->mSrc[1].mType = IT_INT16; + sins->mSrc[1].mTemp = spareTemps++; + sins->mSrc[1].mFinal = true; + sins->mSrc[0] = ai0->mSrc[0]; + sins->mSrc[0].mIntConst += ai1->mSrc[0].mIntConst; + sins->mSrc[0].mRange.AddConstValue(IT_INT16, -ai1->mSrc[0].mIntConst); + mInstructions.Insert(i + 1, sins); + + ins->mDst = sins->mSrc[1]; + + ai0->mCode = IC_LOAD_TEMPORARY; + ai0->mSrc[0] = ai0->mSrc[1]; + ai0->mDst.mRange = ai0->mSrc[0].mRange; + ai0->mNumOperands = 1; + + ai1->mCode = IC_LOAD_TEMPORARY; + ai1->mSrc[0] = ai1->mSrc[1]; + ai1->mDst.mRange = ai1->mSrc[0].mRange; + ai1->mNumOperands = 1; + + ins->mSrc[0].mRange = ai0->mDst.mRange; + ins->mSrc[1].mRange = ai1->mDst.mRange; + + changed = true; + } + } + break; #endif @@ -20749,6 +20790,28 @@ void InterCodeBasicBlock::PeepholeOptimization(const GrowingVariableArray& stati mInstructions[i + 0] = ins; changed = true; } +#if 1 + else if (i + 2 < mInstructions.Size() && mInstructions[i + 0]->mCode == IC_STORE && mInstructions[i + 2]->mCode == IC_STORE && + mInstructions[i + 1]->mCode == IC_LOAD && + CanSwapInstructions(mInstructions[i + 0], mInstructions[i + 1]) && + mInstructions[i + 1]->mDst.mTemp == mInstructions[i + 2]->mSrc[0].mTemp && mInstructions[i + 2]->mSrc[0].mFinal && + !mInstructions[i + 0]->mVolatile && !mInstructions[i + 2]->mVolatile && + SameMemRegion(mInstructions[i + 0]->mSrc[1], mInstructions[i + 2]->mSrc[1]) && + + (mInstructions[i + 0]->mSrc[1].mVarIndex > mInstructions[i + 2]->mSrc[1].mVarIndex || + mInstructions[i + 0]->mSrc[1].mVarIndex == mInstructions[i + 2]->mSrc[1].mVarIndex && + mInstructions[i + 0]->mSrc[1].mIntConst > mInstructions[i + 2]->mSrc[1].mIntConst)) + { + InterInstruction* ins = mInstructions[i + 0]; + SwapInstructions(ins, mInstructions[i + 1]); + mInstructions[i + 0] = mInstructions[i + 1]; + SwapInstructions(ins, mInstructions[i + 2]); + mInstructions[i + 1] = mInstructions[i + 2]; + mInstructions[i + 2] = ins; + + changed = true; + } +#endif } } while (changed); @@ -22491,7 +22554,7 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "main"); + CheckFunc = !strcmp(mIdent->mString, "bm_init"); CheckCase = false; mEntryBlock = mBlocks[0]; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 0d0646a..0be979d 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -2,6 +2,7 @@ #include "CompilerTypes.h" #define JUMP_TO_BRANCH 1 +#define CHECK_NULLPTR 0 static bool CheckFunc; static bool CheckCase; @@ -21083,7 +21084,7 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) if (mFalseJump->mFalseJump == mTrueJump) { mBranch = ASMIT_BCS; - mFalseJump = mFalseJump->mFalseJump; + mFalseJump = mFalseJump->mTrueJump; changed = true; } } @@ -21092,7 +21093,7 @@ bool NativeCodeBasicBlock::ExpandADCToBranch(NativeCodeProcedure* proc) if (mFalseJump->mTrueJump == mTrueJump) { mBranch = ASMIT_BCS; - mFalseJump = mFalseJump->mTrueJump; + mFalseJump = mFalseJump->mFalseJump; changed = true; } } @@ -32863,6 +32864,88 @@ bool NativeCodeBasicBlock::Propagate16BitSum(const ExpandingArray= 0) + { + if ((mIns[i].mType == ASMIT_LDA || mIns[i].mType == ASMIT_STA) && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE)) + { + at = i; + i++; + while (i < mIns.Size()) + { + if (mIns[at].MayBeChangedOnAddress(mIns[i])) + return false; + i++; + } + return true; + } + else if (mIns[i].ChangesAccu()) + return false; + i--; + } + return false; +} + +bool NativeCodeBasicBlock::MoveLoadXAbsUpCrossBlock(int at) +{ + int i = at - 1; + while (i >= 0) + { + if ((mIns[i].mType == ASMIT_STA || mIns[i].mType == ASMIT_LDA) && mIns[i].SameEffectiveAddress(mIns[at])) + { + mIns[i].mLive |= LIVE_CPU_REG_A; + i++; + mIns.Insert(i, NativeCodeInstruction(mIns[at].mIns, ASMIT_TAX)); + mIns[at + 1].mType = ASMIT_NOP; + mIns[at + 1].mMode = ASMIM_IMPLIED; + while (i < at + 1) + { + mIns[i].mLive |= LIVE_CPU_REG_X; + i++; + } + + return true; + } + + if (mIns[i].RequiresXReg() || mIns[i].ChangesXReg() || (mIns[i].mLive & LIVE_CPU_REG_X)) + return false; + if (mIns[at].MayBeChangedOnAddress(mIns[i])) + return false; + i--; + } + + if (mEntryBlocks.Size() == 1) + { + NativeCodeBasicBlock* eb = mEntryBlocks[0]; + if (eb->FindAccuExitValue(i) && eb->mIns[i].SameEffectiveAddress(mIns[at])) + { + while (i < eb->mIns.Size()) + { + eb->mIns[i].mLive |= LIVE_CPU_REG_A; + i++; + } + eb->mExitRequiredRegs += CPU_REG_A; + mEntryRequiredRegs += CPU_REG_A; + + mIns.Insert(0, NativeCodeInstruction(mIns[at].mIns, ASMIT_TAX)); + mIns[at + 1].mType = ASMIT_NOP; + mIns[at + 1].mMode = ASMIM_IMPLIED; + i = 0; + while (i < at + 1) + { + mIns[i].mLive |= LIVE_CPU_REG_X; + i++; + } + + return true; + } + } + + return false; +} + bool NativeCodeBasicBlock::MoveLoadXUp(int at) { @@ -42680,6 +42763,23 @@ bool NativeCodeBasicBlock::PeepHoleOptimizerShuffle(int pass) #endif +#if 1 + if (pass > 10) + { + for (int i = 0; i < mIns.Size(); i++) + { + if (!(mIns[i].mFlags & NCIF_VOLATILE)) + { + if (mIns[i].mType == ASMIT_LDX && (mIns[i].mMode == ASMIM_ZERO_PAGE || mIns[i].mMode == ASMIM_ABSOLUTE) && !(mIns[i].mLive & LIVE_CPU_REG_Z)) + { + if (MoveLoadXAbsUpCrossBlock(i)) + changed = true; + } + } + } + CheckLive(); + } +#endif #if 1 // move ldy, sty down if live @@ -49923,6 +50023,58 @@ bool NativeCodeBasicBlock::PeepHoleOptimizerExits(int pass) } #endif +#if 1 + if (sz > 0 && mFalseJump && mIns[sz - 1].ChangesAccuAndFlag() && mBranch == ASMIT_BMI) + { + if (mFalseJump->mIns.Size() == 1 && mFalseJump->mIns[0].mType == ASMIT_CMP && mFalseJump->mBranch == ASMIT_BCS && mFalseJump->mTrueJump == mTrueJump) + { + mTrueJump->RemEntryBlock(this); + mTrueJump = mFalseJump; + mFalseJump = nullptr; + mBranch = ASMIT_JMP; + changed = true; + } + } +#endif +#if 1 + if (pass > 15 && sz > 0 && (mIns[sz - 1].mType == ASMIT_CMP || mIns[sz - 1].mType == ASMIT_CPX || mIns[sz - 1].mType == ASMIT_CPY)) + { + if (mTrueJump && mTrueJump->mEntryBlocks.Size() == 1 && mTrueJump->mIns.Size() > 0 && mTrueJump->mIns[0].IsSame(mIns[sz - 1])) + { + mTrueJump->mIns[0].mType = ASMIT_NOP; mTrueJump->mIns[0].mMode = ASMIM_IMPLIED; + if (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_Z) + { + mExitRequiredRegs += CPU_REG_Z; + mTrueJump->mEntryRequiredRegs += CPU_REG_Z; + mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; + } + if (mTrueJump->mIns[0].mLive & LIVE_CPU_REG_C) + { + mExitRequiredRegs += CPU_REG_C; + mTrueJump->mEntryRequiredRegs += CPU_REG_C; + mIns[sz - 1].mLive |= LIVE_CPU_REG_C; + } + changed = true; + } + if (mFalseJump && mFalseJump->mEntryBlocks.Size() == 1 && mFalseJump->mIns.Size() > 0 && mFalseJump->mIns[0].IsSame(mIns[sz - 1])) + { + mFalseJump->mIns[0].mType = ASMIT_NOP; mFalseJump->mIns[0].mMode = ASMIM_IMPLIED; + if (mFalseJump->mIns[0].mLive & LIVE_CPU_REG_Z) + { + mExitRequiredRegs += CPU_REG_Z; + mFalseJump->mEntryRequiredRegs += CPU_REG_Z; + mIns[sz - 1].mLive |= LIVE_CPU_REG_Z; + } + if (mFalseJump->mIns[0].mLive & LIVE_CPU_REG_C) + { + mExitRequiredRegs += CPU_REG_C; + mFalseJump->mEntryRequiredRegs += CPU_REG_C; + mIns[sz - 1].mLive |= LIVE_CPU_REG_C; + } + changed = true; + } + } +#endif CheckLive(); if (mTrueJump) mTrueJump->CheckLive(); @@ -50101,8 +50253,10 @@ void NativeCodeBasicBlock::CheckAsmCode(void) assert(HasAsmInstructionMode(mIns[j].mType, ASMIM_IMMEDIATE)); else assert(HasAsmInstructionMode(mIns[j].mType, mIns[j].mMode)); +#if CHECK_NULLPTR if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ABSOLUTE_Y || mIns[j].mMode == ASMIM_ABSOLUTE_X) assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0); +#endif } if (mTrueJump) mTrueJump->CheckAsmCode(); @@ -50189,9 +50343,10 @@ void NativeCodeBasicBlock::CheckLive(void) else assert(HasAsmInstructionMode(mIns[j].mType, mIns[j].mMode)); +#if CHECK_NULLPTR if (mIns[j].mMode == ASMIM_ABSOLUTE || mIns[j].mMode == ASMIM_ZERO_PAGE || mIns[j].mMode == ASMIM_ABSOLUTE_X || mIns[j].mMode == ASMIM_ABSOLUTE_Y) assert(mIns[j].mLinkerObject != nullptr || mIns[j].mAddress > 0); - +#endif if (mIns[j].mType != ASMIT_NOP) { assert(!(live & ~mIns[j].mLive)); @@ -50943,7 +51098,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) mInterProc = proc; mInterProc->mLinkerObject->mNativeProc = this; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "a"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "particle_add"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 025c702..bd2b2fc 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -504,6 +504,9 @@ public: bool MoveTXADCDown(int at); bool FoldShiftORAIntoLoadImmUp(int at); + bool FindAccuExitValue(int& at); + bool MoveLoadXAbsUpCrossBlock(int at); + bool MoveSimpleADCToINCDECDown(int at); bool MoveTAXADCSTADown(int at); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 6817085..e939634 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -1974,14 +1974,9 @@ Expression* Parser::ParseInitExpression(Declaration* dtype, bool inner) } else if (exp->mDecValue->mType == DT_CONST_INTEGER && exp->mDecValue->mInteger == 0) { - Declaration * ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_ADDRESS); - ndec->mBase = TheVoidPointerTypeDeclaration; - ndec->mInteger = 0; - dec = ndec; - Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTANT); - nexp->mDecValue = ndec; - nexp->mDecType = ndec->mBase; + nexp->mDecValue = TheNullptrConstDeclaration; + nexp->mDecType = TheNullPointerTypeDeclaration; exp = nexp; } else diff --git a/samples/particles/make.bat b/samples/particles/make.bat index dbba9e8..ec25dbf 100644 --- a/samples/particles/make.bat +++ b/samples/particles/make.bat @@ -1,4 +1,4 @@ call ..\..\bin\oscar64 -n fireworks_ptr.c call ..\..\bin\oscar64 -n fireworks_hires.c -call ..\..\bin\oscar64 -n fireworks_stripe.c +call ..\..\bin\oscar64 -n fireworks_stripe.c -O2