Fix void pointer arithmetic

This commit is contained in:
drmortalwombat 2025-02-23 11:04:29 +01:00
parent f6296e83e5
commit ee0e4d5428
5 changed files with 236 additions and 33 deletions

View File

@ -1315,7 +1315,7 @@ int Declaration::Stride(void) const
{ {
if (mStride > 0) if (mStride > 0)
return mStride; return mStride;
else if (mBase) else if (mBase && mBase->mType != DT_TYPE_VOID)
return mBase->mSize; return mBase->mSize;
else else
return 1; return 1;
@ -3028,9 +3028,11 @@ void InitDeclarations(void)
{ {
static Location noloc; static Location noloc;
TheVoidTypeDeclaration = new Declaration(noloc, DT_TYPE_VOID); TheVoidTypeDeclaration = new Declaration(noloc, DT_TYPE_VOID);
TheVoidTypeDeclaration->mSize = 0;
TheVoidTypeDeclaration->mFlags = DTF_DEFINED; TheVoidTypeDeclaration->mFlags = DTF_DEFINED;
TheConstVoidTypeDeclaration = new Declaration(noloc, DT_TYPE_VOID); TheConstVoidTypeDeclaration = new Declaration(noloc, DT_TYPE_VOID);
TheConstVoidTypeDeclaration->mSize = 0;
TheConstVoidTypeDeclaration->mFlags = DTF_DEFINED | DTF_CONST; TheConstVoidTypeDeclaration->mFlags = DTF_DEFINED | DTF_CONST;
TheVoidPointerTypeDeclaration = new Declaration(noloc, DT_TYPE_POINTER); TheVoidPointerTypeDeclaration = new Declaration(noloc, DT_TYPE_POINTER);

View File

@ -44,6 +44,7 @@ enum ErrorID
EWARN_DEFAULT_COPY_DEPRECATED, EWARN_DEFAULT_COPY_DEPRECATED,
EWARN_INSUFFICIENT_MEMORY, EWARN_INSUFFICIENT_MEMORY,
EWARN_FUNCTION_NOT_INLINED, EWARN_FUNCTION_NOT_INLINED,
EWARN_INVALID_VOID_POINTER_ARITHMETIC,
EERR_GENERIC = 3000, EERR_GENERIC = 3000,
EERR_FILE_NOT_FOUND, EERR_FILE_NOT_FOUND,
@ -103,7 +104,7 @@ enum ErrorID
ERRR_INSTANTIATE_ABSTRACT_CLASS, ERRR_INSTANTIATE_ABSTRACT_CLASS,
ERRR_INVALID_GOTO, ERRR_INVALID_GOTO,
EERR_INVALID_INITIALIZER, EERR_INVALID_INITIALIZER,
ERRR_INVALID_VOID_POINTER_ARITHMETIC,
EERR_INVALID_CONSTEXPR, EERR_INVALID_CONSTEXPR,
EERR_DOUBLE_FREE, EERR_DOUBLE_FREE,

View File

@ -37175,7 +37175,7 @@ bool NativeCodeBasicBlock::OptimizeSingleEntryLoop(NativeCodeProcedure* proc)
return changed; return changed;
} }
bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void) bool NativeCodeBasicBlock::OptimizeLoopRegisterWrapAround(void)
{ {
bool changed = false; bool changed = false;
@ -37187,31 +37187,6 @@ bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void)
{ {
NativeCodeBasicBlock* hblock = nullptr; 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(); int sz = mIns.Size();
if (sz > 0) if (sz > 0)
{ {
@ -37263,7 +37238,122 @@ bool NativeCodeBasicBlock::OptimizeLoopCarryOver(void)
mExitRequiredRegs += CPU_REG_A; mExitRequiredRegs += CPU_REG_A;
changed = true; 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;
} }
} }
} }
@ -46661,6 +46751,17 @@ bool NativeCodeBasicBlock::PeepHoleOptimizerIterate3(int i, int pass)
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
return true; 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 ( else if (
mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED && mIns[i + 0].mType == ASMIT_ROL && mIns[i + 0].mMode == ASMIM_IMPLIED &&
mIns[i + 1].mType == ASMIT_ASL && mIns[i + 1].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; mIns[sz - 2].mLive |= LIVE_CPU_REG_Z;
changed = true; 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 #if 1
else if (sz >= 2 && else if (sz >= 2 &&
mIns[sz - 2].ChangesAccuAndFlag() && mIns[sz - 2].ChangesAccuAndFlag() &&
@ -52983,7 +53098,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
mInterProc->mLinkerObject->mNativeProc = this; mInterProc->mLinkerObject->mNativeProc = this;
CheckFunc = !strcmp(mIdent->mString, "moveBy"); CheckFunc = !strcmp(mIdent->mString, "shot_damage");
int nblocks = proc->mBlocks.Size(); int nblocks = proc->mBlocks.Size();
tblocks = new NativeCodeBasicBlock * [nblocks]; tblocks = new NativeCodeBasicBlock * [nblocks];
@ -54806,6 +54921,13 @@ void NativeCodeProcedure::Optimize(void)
changed = true; changed = true;
} }
if (step == 20)
{
ResetVisited();
if (mEntryBlock->OptimizeLoopRegisterWrapAround())
changed = true;
}
#if _DEBUG #if _DEBUG
ResetVisited(); ResetVisited();
mEntryBlock->CheckAsmCode(); mEntryBlock->CheckAsmCode();
@ -54831,7 +54953,7 @@ void NativeCodeProcedure::Optimize(void)
} }
#if 1 #if 1
if (!changed && step < 20) if (!changed && step < 21)
{ {
ResetIndexFlipped(); 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); 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 // Check for complete loop block replacement
bool trueLoop = false, falseLoop = false; bool trueLoop = false, falseLoop = false;
@ -56128,7 +56252,6 @@ void NativeCodeGenerator::OutlineFunctions(void)
falseLoop = true; falseLoop = true;
} }
if (trueLoop || falseLoop) if (trueLoop || falseLoop)
{ {
NativeCodeBasicBlock* eblock = nproc->AllocateBlock(); NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
@ -56152,6 +56275,64 @@ void NativeCodeGenerator::OutlineFunctions(void)
nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JSR; nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JSR;
else else
nblock->mIns.Remove(nblock->mIns.Size() - 1); 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; NativeCodeBasicBlock* pblock = nullptr;
@ -56171,7 +56352,7 @@ void NativeCodeGenerator::OutlineFunctions(void)
mProcedures.Push(nproc); mProcedures.Push(nproc);
if (trueLoop || falseLoop) if (mergeBlocks)
{ {
ExpandingArray<NativeCodeProcedure *> procs; ExpandingArray<NativeCodeProcedure *> procs;

View File

@ -341,6 +341,7 @@ public:
bool OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock * prevBlock, NativeCodeBasicBlock* exitBlock, bool full); bool OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock * prevBlock, NativeCodeBasicBlock* exitBlock, bool full);
bool RemoveSimpleLoopUnusedIndex(void); bool RemoveSimpleLoopUnusedIndex(void);
bool OptimizeLoopCarryOver(void); bool OptimizeLoopCarryOver(void);
bool OptimizeLoopRegisterWrapAround(void);
bool OptimizeSingleEntryLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prev, NativeCodeBasicBlock* tail, ExpandingArray<NativeCodeBasicBlock*>& blocks); bool OptimizeSingleEntryLoopInvariant(NativeCodeProcedure* proc, NativeCodeBasicBlock* prev, NativeCodeBasicBlock* tail, ExpandingArray<NativeCodeBasicBlock*>& blocks);
bool OptimizeSingleEntryLoop(NativeCodeProcedure* proc); bool OptimizeSingleEntryLoop(NativeCodeProcedure* proc);

View File

@ -8762,9 +8762,27 @@ Expression* Parser::ParseAddExpression(bool lhs)
nexp->mRight = ParseMulExpression(false); nexp->mRight = ParseMulExpression(false);
if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER && nexp->mRight->mDecType->IsIntegerType()) 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; nexp->mDecType = nexp->mLeft->mDecType;
}
else if (nexp->mRight->mDecType->mType == DT_TYPE_POINTER && nexp->mLeft->mDecType->IsIntegerType()) 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; nexp->mDecType = nexp->mRight->mDecType;
}
else if (nexp->mLeft->mDecType->mType == DT_TYPE_ARRAY && nexp->mRight->mDecType->IsIntegerType()) else if (nexp->mLeft->mDecType->mType == DT_TYPE_ARRAY && nexp->mRight->mDecType->IsIntegerType())
{ {
Declaration* dec = new Declaration(nexp->mLocation, DT_TYPE_POINTER); Declaration* dec = new Declaration(nexp->mLocation, DT_TYPE_POINTER);