From ee0e4d5428b50919ef771e08b8c795b48dcec346 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Sun, 23 Feb 2025 11:04:29 +0100 Subject: [PATCH] Fix void pointer arithmetic --- oscar64/Declaration.cpp | 4 +- oscar64/Errors.h | 3 +- oscar64/NativeCodeGenerator.cpp | 243 ++++++++++++++++++++++++++++---- oscar64/NativeCodeGenerator.h | 1 + oscar64/Parser.cpp | 18 +++ 5 files changed, 236 insertions(+), 33 deletions(-) diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index 750805b..b359692 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -1315,7 +1315,7 @@ int Declaration::Stride(void) const { if (mStride > 0) return mStride; - else if (mBase) + else if (mBase && mBase->mType != DT_TYPE_VOID) return mBase->mSize; else return 1; @@ -3028,9 +3028,11 @@ void InitDeclarations(void) { static Location noloc; TheVoidTypeDeclaration = new Declaration(noloc, DT_TYPE_VOID); + TheVoidTypeDeclaration->mSize = 0; TheVoidTypeDeclaration->mFlags = DTF_DEFINED; TheConstVoidTypeDeclaration = new Declaration(noloc, DT_TYPE_VOID); + TheConstVoidTypeDeclaration->mSize = 0; TheConstVoidTypeDeclaration->mFlags = DTF_DEFINED | DTF_CONST; TheVoidPointerTypeDeclaration = new Declaration(noloc, DT_TYPE_POINTER); diff --git a/oscar64/Errors.h b/oscar64/Errors.h index 7d28af1..2899936 100644 --- a/oscar64/Errors.h +++ b/oscar64/Errors.h @@ -44,6 +44,7 @@ enum ErrorID EWARN_DEFAULT_COPY_DEPRECATED, EWARN_INSUFFICIENT_MEMORY, EWARN_FUNCTION_NOT_INLINED, + EWARN_INVALID_VOID_POINTER_ARITHMETIC, EERR_GENERIC = 3000, EERR_FILE_NOT_FOUND, @@ -103,7 +104,7 @@ enum ErrorID ERRR_INSTANTIATE_ABSTRACT_CLASS, ERRR_INVALID_GOTO, EERR_INVALID_INITIALIZER, - + ERRR_INVALID_VOID_POINTER_ARITHMETIC, EERR_INVALID_CONSTEXPR, EERR_DOUBLE_FREE, diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 162d293..cd08c6c 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -37175,7 +37175,7 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc) return changed; } -bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) +bool NativeCodeBasicBlock::OptimizeLoopRegisterWrapAround(void) { bool changed = false; @@ -37187,31 +37187,6 @@ bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) { NativeCodeBasicBlock* hblock = nullptr; - if (mBranch == ASMIT_BCC && mTrueJump->mLoopHead) - hblock = mTrueJump; - else if (mBranch == ASMIT_BCS && mFalseJump->mLoopHead) - hblock = mFalseJump; - - if (hblock && hblock->mIns.Size() > 0 && hblock->mIns[0].mType == ASMIT_CLC && hblock->mNumEntries == 2) - { - NativeCodeBasicBlock* pblock; - if (hblock->mEntryBlocks[0] == this) - pblock = hblock->mEntryBlocks[1]; - else - pblock = hblock->mEntryBlocks[0]; - - if (!pblock->mFalseJump) - { - pblock->mIns.Push(NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_CLC)); - hblock->mIns.Remove(0); - - pblock->mExitRequiredRegs += CPU_REG_C; - hblock->mEntryRequiredRegs += CPU_REG_C; - mExitRequiredRegs += CPU_REG_C; - changed = true; - } - } - int sz = mIns.Size(); if (sz > 0) { @@ -37252,7 +37227,7 @@ bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) mExitRequiredRegs += CPU_REG_Y; changed = true; } - else if (sz > 1 && hblock->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 2].mType == ASMIT_LDA + else if (sz > 1 && hblock->mIns[0].mType == ASMIT_LDA && mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 2].mType == ASMIT_LDA && hblock->mIns[0].SameEffectiveAddress(mIns[sz - 2]) && !(hblock->mIns[0].mLive & LIVE_CPU_REG_Z) && !(hblock->mIns[0].mFlags & NCIF_VOLATILE)) { pblock->mIns.Push(hblock->mIns[0]); @@ -37263,11 +37238,126 @@ bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) mExitRequiredRegs += CPU_REG_A; changed = true; } + else + { + int finalA = -1, finalX = -1, finalY = -1; + for (int i = sz - 1; i >= 0; i--) + { + NativeCodeInstruction& ins(mIns[i]); + + if (finalA == -1 && (ins.mType == ASMIT_LDA || ins.mType == ASMIT_STA) && ins.mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(ins.mAddress, i + 1)) + finalA = ins.mAddress; + else if (finalX == -1 && (ins.mType == ASMIT_LDX || ins.mType == ASMIT_STX) && ins.mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(ins.mAddress, i + 1)) + finalX = ins.mAddress; + else if (finalY == -1 && (ins.mType == ASMIT_LDY || ins.mType == ASMIT_STY) && ins.mMode == ASMIM_ZERO_PAGE && !ChangesZeroPage(ins.mAddress, i + 1)) + finalY = ins.mAddress; + else if (finalA == -1 && ins.ChangesAccu()) + finalA = -2; + else if (finalX == -1 && ins.ChangesXReg()) + finalX = -2; + else if (finalY == -1 && ins.ChangesYReg()) + finalY = -2; + } + + bool usedA = false, usedX = false, usedY = false; + for (int i = 0; i < hblock->mIns.Size(); i++) + { + NativeCodeInstruction& ins(hblock->mIns[i]); + if (!usedX && ins.mType == ASMIT_LDX && ins.mMode == ASMIM_ZERO_PAGE) + { + if (ins.mAddress == finalA && !mExitRequiredRegs[CPU_REG_X]) + { + int k = sz - 1; + if (mIns[k].mType == ASMIT_CMP || mIns[k].mType == ASMIT_CPX || mIns[k].mType == ASMIT_CPY) + k--; + if (!(mIns[k].mLive & LIVE_CPU_REG_X)) + { + pblock->mIns.Push(ins); + mIns.Insert(k + 1, NativeCodeInstruction(ins.mIns, ASMIT_TAX)); + for (int j = k + 1; j < sz + 1; j++) + mIns[j].mLive |= LIVE_CPU_REG_X; + for (int j = 0; j < i; j++) + hblock->mIns[j].mLive |= LIVE_CPU_REG_X; + ins.mType = ASMIT_NOP; + ins.mMode = ASMIM_IMPLIED; + + mExitRequiredRegs += CPU_REG_X; + pblock->mExitRequiredRegs += CPU_REG_X; + hblock->mEntryRequiredRegs += CPU_REG_X; + changed = true; + } + + } + usedX = true; + } + + if (!usedA && ins.ReferencesAccu()) + usedA = true; + if (!usedX && ins.ReferencesXReg()) + usedX = true; + if (!usedY && ins.ReferencesYReg()) + usedY = true; + + if (finalA >= 0 && ins.ChangesZeroPage(finalA)) + finalA = -1; + if (finalX >= 0 && ins.ChangesZeroPage(finalX)) + finalX = -1; + if (finalY >= 0 && ins.ChangesZeroPage(finalY)) + finalY = -1; + } + } } } } } + if (mTrueJump && mTrueJump->OptimizeLoopRegisterWrapAround()) + changed = true; + if (mFalseJump && mFalseJump->OptimizeLoopRegisterWrapAround()) + changed = true; + } + + return changed; +} + +bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) +{ + bool changed = false; + + if (!mVisited) + { + mVisited = true; + + if (mFalseJump) + { + NativeCodeBasicBlock* hblock = nullptr; + + if (mBranch == ASMIT_BCC && mTrueJump->mLoopHead) + hblock = mTrueJump; + else if (mBranch == ASMIT_BCS && mFalseJump->mLoopHead) + hblock = mFalseJump; + + if (hblock && hblock->mIns.Size() > 0 && hblock->mIns[0].mType == ASMIT_CLC && hblock->mNumEntries == 2) + { + NativeCodeBasicBlock* pblock; + if (hblock->mEntryBlocks[0] == this) + pblock = hblock->mEntryBlocks[1]; + else + pblock = hblock->mEntryBlocks[0]; + + if (!pblock->mFalseJump) + { + pblock->mIns.Push(NativeCodeInstruction(hblock->mIns[0].mIns, ASMIT_CLC)); + hblock->mIns.Remove(0); + + pblock->mExitRequiredRegs += CPU_REG_C; + hblock->mEntryRequiredRegs += CPU_REG_C; + mExitRequiredRegs += CPU_REG_C; + changed = true; + } + } + } + if (mTrueJump && mTrueJump->OptimizeLoopCarryOver()) changed = true; if (mFalseJump && mFalseJump->OptimizeLoopCarryOver()) @@ -46661,6 +46751,17 @@ bool NativeCodeBasicBlock::PeepHoleOptimizerIterate3(int i, int pass) mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; return true; } + else if ( + mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && + mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_ZERO_PAGE && mIns[i + 0].mAddress == mIns[i + 2].mAddress && + !(mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_C))) + { + mIns[i + 0].mLive |= LIVE_CPU_REG_A; + mIns[i + 1].mType = ASMIT_CMP; mIns[i + 1].mLive |= LIVE_CPU_REG_Z; + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + return true; + } else if ( mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED && mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].mMode == ASMIM_IMPLIED && @@ -51147,6 +51248,20 @@ bool NativeCodeBasicBlock::PeepHoleOptimizerExits(int pass) mIns[sz - 2].mLive |= LIVE_CPU_REG_Z; changed = true; } + else if (sz >= 2 && + (mIns[sz - 2].ChangesAccuAndFlag() || mIns[sz - 2].mType == ASMIT_TAX || mIns[sz - 2].mType == ASMIT_TAY) && + mIns[sz - 1].mType == ASMIT_CMP && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && + (mBranch == ASMIT_BCC || mBranch == ASMIT_BCS) && !mExitRequiredRegs[CPU_REG_Z] && !mExitRequiredRegs[CPU_REG_C]) + { + if (mBranch == ASMIT_BCC) + mBranch = ASMIT_BPL; + else + mBranch = ASMIT_BMI; + + mIns[sz - 1].mType = ASMIT_NOP; mIns[sz - 1].mMode = ASMIM_IMPLIED; + mIns[sz - 2].mLive |= LIVE_CPU_REG_Z; + changed = true; + } #if 1 else if (sz >= 2 && mIns[sz - 2].ChangesAccuAndFlag() && @@ -52983,7 +53098,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) mInterProc->mLinkerObject->mNativeProc = this; - CheckFunc = !strcmp(mIdent->mString, "moveBy"); + CheckFunc = !strcmp(mIdent->mString, "shot_damage"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; @@ -54806,6 +54921,13 @@ void NativeCodeProcedure::Optimize(void) changed = true; } + if (step == 20) + { + ResetVisited(); + if (mEntryBlock->OptimizeLoopRegisterWrapAround()) + changed = true; + } + #if _DEBUG ResetVisited(); mEntryBlock->CheckAsmCode(); @@ -54831,7 +54953,7 @@ void NativeCodeProcedure::Optimize(void) } #if 1 - if (!changed && step < 20) + if (!changed && step < 21) { ResetIndexFlipped(); @@ -56111,6 +56233,8 @@ void NativeCodeGenerator::OutlineFunctions(void) return l.mBlock == r.mBlock ? l.mStart > r.mStart : ptrdiff_t(l.mBlock) < ptrdiff_t(r.mBlock); }); + bool mergeBlocks = false; + // Check for complete loop block replacement bool trueLoop = false, falseLoop = false; @@ -56128,7 +56252,6 @@ void NativeCodeGenerator::OutlineFunctions(void) falseLoop = true; } - if (trueLoop || falseLoop) { NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); @@ -56152,6 +56275,64 @@ void NativeCodeGenerator::OutlineFunctions(void) nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JSR; else nblock->mIns.Remove(nblock->mIns.Size() - 1); + + mergeBlocks = true; + } + else + { + bool falseDetour = false, trueDetour = false; + + int k = 0; + while (k < segs.Size() && + segs[k].mEnd == segs[k].mBlock->mIns.Size() && + segs[k].mBlock->mFalseJump && + !segs[k].mBlock->mFalseJump->mFalseJump && + segs[k].mBlock->mFalseJump->mIns.Size() == 1 && + segs[k].mBlock->mFalseJump->mTrueJump == segs[k].mBlock->mTrueJump && + segs[k].mBlock->mBranch == segs[0].mBlock->mBranch && + segs[k].mBlock->mIns[0].IsSame(segs[0].mBlock->mIns[0])) + k++; + + if (k == segs.Size()) + { + falseDetour = true; + } + + if (trueDetour || falseDetour) + { + NativeCodeBasicBlock* dblock = nproc->AllocateBlock(); + NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); + + dblock->Close(segs[0].mBlock->mBranchIns, eblock, nullptr, ASMIT_JMP); + if (trueDetour) + { + dblock->mIns.Push(segs[0].mBlock->mTrueJump->mIns[0]); + nblock->Close(segs[0].mBlock->mBranchIns, dblock, eblock, segs[0].mBlock->mBranch); + } + else + { + dblock->mIns.Push(segs[0].mBlock->mFalseJump->mIns[0]); + nblock->Close(segs[0].mBlock->mBranchIns, eblock, dblock, segs[0].mBlock->mBranch); + } + + for (int i = 0; i < segs.Size(); i++) + { + SuffixSegment& s(segs[i]); + if (trueDetour) + segs[i].mBlock->mTrueJump = segs[i].mBlock->mFalseJump; + segs[i].mBlock->mFalseJump = nullptr; + segs[i].mBlock->mBranch = ASMIT_JMP; + segs[i].mBlock->mTrueJump->mNumEntries--; + } + + eblock->mIns.Push(NativeCodeInstruction(nblock->mIns[nblock->mIns.Size() - 1].mIns, ASMIT_RTS)); + if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JMP) + nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JSR; + else + nblock->mIns.Remove(nblock->mIns.Size() - 1); + + mergeBlocks = true; + } } NativeCodeBasicBlock* pblock = nullptr; @@ -56171,7 +56352,7 @@ void NativeCodeGenerator::OutlineFunctions(void) mProcedures.Push(nproc); - if (trueLoop || falseLoop) + if (mergeBlocks) { ExpandingArray procs; diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 4554462..6911f38 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -341,6 +341,7 @@ public: bool OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock * prevBlock, NativeCodeBasicBlock* exitBlock, bool full); bool RemoveSimpleLoopUnusedIndex(void); bool OptimizeLoopCarryOver(void); + bool OptimizeLoopRegisterWrapAround(void); bool OptimizeSingleEntryLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prev, NativeCodeBasicBlock* tail, ExpandingArray& blocks); bool OptimizeSingleEntryLoop(NativeCodeProcedure* proc); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 43640a5..8479dee 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -8762,9 +8762,27 @@ Expression* Parser::ParseAddExpression(bool lhs) nexp->mRight = ParseMulExpression(false); if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER && nexp->mRight->mDecType->IsIntegerType()) + { + if (nexp->mLeft->mDecType->mBase->mType == DT_TYPE_VOID) + { + if (mCompilerOptions & COPT_CPLUSPLUS) + mErrors->Error(mScanner->mLocation, ERRR_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer"); + else + mErrors->Error(mScanner->mLocation, EWARN_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer"); + } nexp->mDecType = nexp->mLeft->mDecType; + } else if (nexp->mRight->mDecType->mType == DT_TYPE_POINTER && nexp->mLeft->mDecType->IsIntegerType()) + { + if (nexp->mRight->mDecType->mBase->mType == DT_TYPE_VOID) + { + if (mCompilerOptions & COPT_CPLUSPLUS) + mErrors->Error(mScanner->mLocation, ERRR_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer"); + else + mErrors->Error(mScanner->mLocation, EWARN_INVALID_VOID_POINTER_ARITHMETIC, "Invalid arithmetic on void pointer"); + } nexp->mDecType = nexp->mRight->mDecType; + } else if (nexp->mLeft->mDecType->mType == DT_TYPE_ARRAY && nexp->mRight->mDecType->IsIntegerType()) { Declaration* dec = new Declaration(nexp->mLocation, DT_TYPE_POINTER);