From 1d4eb70414cba6c9a53b953e0ce9139be2b89d7d Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Sun, 29 Oct 2023 17:55:26 +0100 Subject: [PATCH] Optimize struct copies --- oscar64/Errors.cpp | 2 - oscar64/Errors.h | 1 + oscar64/InterCode.cpp | 283 +++++++++++++++++++++++++++----- oscar64/InterCode.h | 12 +- oscar64/Linker.cpp | 6 + oscar64/NativeCodeGenerator.cpp | 5 +- oscar64/Parser.cpp | 53 +++++- 7 files changed, 310 insertions(+), 52 deletions(-) diff --git a/oscar64/Errors.cpp b/oscar64/Errors.cpp index e77fbb0..5ace50a 100644 --- a/oscar64/Errors.cpp +++ b/oscar64/Errors.cpp @@ -41,7 +41,6 @@ void Errors::Error(const Location& loc, ErrorID eid, const char* msg, const char fprintf(stderr, "%s(%d, %d) : %s %d: %s '%s' != '%s'\n", loc.mFileName, loc.mLine, loc.mColumn, level, eid, msg, info1, info2); if (loc.mFrom) - Error(*(loc.mFrom), EINFO_EXPANDED, "While expanding here"); if (mErrorCount > 10 || eid >= EFATAL_GENERIC) @@ -49,4 +48,3 @@ void Errors::Error(const Location& loc, ErrorID eid, const char* msg, const char } - diff --git a/oscar64/Errors.h b/oscar64/Errors.h index 5a62749..e8b3afb 100644 --- a/oscar64/Errors.h +++ b/oscar64/Errors.h @@ -19,6 +19,7 @@ enum ErrorID { EINFO_GENERIC = 1000, EINFO_EXPANDED = 1001, + EINFO_ORIGINAL_DEFINITION = 1002, EWARN_GENERIC = 2000, EWARN_CONSTANT_TRUNCATED, diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 4addbe3..3b13296 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -737,6 +737,24 @@ static bool SameInstruction(const InterInstruction* ins1, const InterInstruction return false; } +static void SwapInstructions(InterInstruction* it, InterInstruction* ib) +{ + for (int i = 0; i < ib->mNumOperands; i++) + { + if (ib->mSrc[i].mTemp >= 0 && ib->mSrc[i].mFinal) + { + for (int j = 0; j < it->mNumOperands; j++) + { + if (it->mSrc[j].mTemp == ib->mSrc[i].mTemp) + { + it->mSrc[j].mFinal = true; + ib->mSrc[i].mFinal = false; + } + } + } + } +} + bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, const InterInstruction* ins1) const { // Cannot swap branches @@ -4520,15 +4538,22 @@ void InterOperand::Disassemble(FILE* file, InterCodeProcedure* proc) else if (mType == IT_POINTER) { const char* vname = ""; + bool aliased = false; if (mMemory == IM_LOCAL) { if (!proc->mLocalVars[mVarIndex]) vname = "null"; else if (!proc->mLocalVars[mVarIndex]->mIdent) + { vname = ""; + aliased = proc->mLocalVars[mVarIndex]->mAliased; + } else + { vname = proc->mLocalVars[mVarIndex]->mIdent->mString; + aliased = proc->mLocalVars[mVarIndex]->mAliased; + } } else if (mMemory == IM_PROCEDURE) { @@ -4549,12 +4574,21 @@ void InterOperand::Disassemble(FILE* file, InterCodeProcedure* proc) else if (!proc->mModule->mGlobalVars[mVarIndex]) vname = "null"; else if (!proc->mModule->mGlobalVars[mVarIndex]->mIdent) + { vname = ""; + aliased = proc->mModule->mGlobalVars[mVarIndex]->mAliased; + } else + { vname = proc->mModule->mGlobalVars[mVarIndex]->mIdent->mString; + aliased = proc->mModule->mGlobalVars[mVarIndex]->mAliased; + } } - - fprintf(file, "V(%d '%s')+%d ", mVarIndex, vname, int(mIntConst)); + + if (aliased) + fprintf(file, "V(%d '%s' A)+%d ", mVarIndex, vname, int(mIntConst)); + else + fprintf(file, "V(%d '%s')+%d ", mVarIndex, vname, int(mIntConst)); } else if (IsIntegerType(mType) || mType == IT_BOOL) { @@ -5938,6 +5972,47 @@ void InterCodeBasicBlock::CollectLocalAddressTemps(GrowingIntArray& localTable, } } +void InterCodeBasicBlock::RecheckLocalAliased(void) +{ + if (!mVisited) + { + mVisited = true; + + for (int i = 0; i < mInstructions.Size(); i++) + { + InterVariable* v = nullptr; + + InterInstruction* ins = mInstructions[i]; + if (ins->mCode == IC_LEA) + { + if (ins->mSrc[1].mTemp < 0) + { + if (ins->mSrc[1].mMemory == IM_LOCAL) + v = mProc->mLocalVars[ins->mSrc[1].mVarIndex]; + else if (ins->mSrc[1].mMemory == IM_PARAM || ins->mSrc[1].mMemory == IM_FPARAM) + v = mProc->mParamVars[ins->mSrc[1].mVarIndex]; + } + } + else if (ins->mCode == IC_CONSTANT && ins->mDst.mType == IT_POINTER) + { + if (ins->mConst.mMemory == IM_LOCAL) + v = mProc->mLocalVars[ins->mConst.mVarIndex]; + else if (ins->mConst.mMemory == IM_PARAM || ins->mConst.mMemory == IM_FPARAM) + v = mProc->mParamVars[ins->mConst.mVarIndex]; + } + + if (v) + { + if (!v->mNotAliased) + v->mAliased = true; + } + } + + if (mTrueJump) mTrueJump->RecheckLocalAliased(); + if (mFalseJump) mFalseJump->RecheckLocalAliased(); + } +} + void InterCodeBasicBlock::MarkAliasedLocalTemps(const GrowingIntArray& localTable, NumberSet& aliasedLocals, const GrowingIntArray& paramTable, NumberSet& aliasedParams) { int i; @@ -10450,6 +10525,26 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& mVisited = true; +#if 1 + // move loads up as far as possible to avoid false aliasing + for (int i = 1; i < mInstructions.Size(); i++) + { + InterInstruction* ins(mInstructions[i]); + if (ins->mCode == IC_LOAD) + { + int j = i; + while (j > 0 && CanSwapInstructions(mInstructions[j - 1], ins)) + { + SwapInstructions(mInstructions[j - 1], ins); + mInstructions[j] = mInstructions[j - 1]; + j--; + } + if (i != j) + mInstructions[j] = ins; + } + } +#endif + for (int i = 0; i < mInstructions.Size(); i++) { InterInstruction* ins(mInstructions[i]); @@ -10498,7 +10593,22 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& } } else - nins = ins; + { + j = 0; + while (j < mLoadStoreInstructions.Size() && !(mLoadStoreInstructions[j]->mCode == IC_COPY && SameMemSegment(mLoadStoreInstructions[j]->mSrc[1], ins->mSrc[0]))) + j++; + if (j < mLoadStoreInstructions.Size()) + { + InterInstruction* cins = mLoadStoreInstructions[j]; + + int64 offset = ins->mSrc->mIntConst - cins->mSrc[1].mIntConst; + ins->mSrc[0] = cins->mSrc[0]; + ins->mSrc[0].mIntConst += offset; + changed = true; + } + else + nins = ins; + } } } else if (ins->mCode == IC_STORE) @@ -10539,6 +10649,52 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& j++; } mLoadStoreInstructions.SetSize(k); +#if 1 + uint64 fillmask = 0; + if (ins->mSrc[0].mOperandSize < 64 && ins->mSrc[0].mStride == 1 && ins->mSrc[1].mStride == 1) + { + for (int j = 0; j < mLoadStoreInstructions.Size(); j++) + { + InterInstruction* sins = mLoadStoreInstructions[j]; + if (sins->mCode == IC_STORE && SameMemSegment(ins->mSrc[0], sins->mSrc[1])) + { + int64 offset = sins->mSrc[1].mIntConst - ins->mSrc[0].mIntConst; + if (offset >= 0 && offset < ins->mSrc[0].mOperandSize) + { + for (int k = 0; k < InterTypeSize[sins->mSrc[0].mType]; k++) + fillmask |= 1ULL << (k + offset); + } + } + } + + if (fillmask + 1 == (1ULL << ins->mSrc[0].mOperandSize)) + { + int n = 0; + for (int j = 0; j < mLoadStoreInstructions.Size(); j++) + { + InterInstruction* sins = mLoadStoreInstructions[j]; + if (sins->mCode == IC_STORE && SameMemSegment(ins->mSrc[0], sins->mSrc[1])) + { + int64 offset = sins->mSrc->mIntConst - ins->mSrc[0].mIntConst; + if (offset >= 0 && offset < ins->mSrc[0].mOperandSize) + { + InterInstruction* tins = sins->Clone(); + tins->mSrc[1] = ins->mSrc[1]; + tins->mSrc[1].mIntConst = sins->mSrc[1].mIntConst - ins->mSrc[0].mIntConst + ins->mSrc[1].mIntConst; + n++; + mInstructions.Insert(i + n, tins); + } + } + } + ins->mCode = IC_NONE; + ins->mNumOperands = 0; + } + else if (!ins->mVolatile && ins->mSrc[0].mStride == 1 && ins->mSrc[1].mStride == 1) + nins = ins; + } + else if (!ins->mVolatile && ins->mSrc[0].mStride == 1 && ins->mSrc[1].mStride == 1) + nins = ins; +#endif } else if (ins->mCode == IC_STRCPY) flushMem = true; @@ -10591,24 +10747,38 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& int j = 0, k = 0; while (j < mLoadStoreInstructions.Size()) { - InterOperand* op = nullptr; - if (mLoadStoreInstructions[j]->mCode == IC_LOAD) - op = mLoadStoreInstructions[j]->mSrc + 0; - else if (mLoadStoreInstructions[j]->mCode == IC_STORE) - op = mLoadStoreInstructions[j]->mSrc + 1; + int opmask = 0; + + InterInstruction* lins = mLoadStoreInstructions[j]; + + if (lins->mCode == IC_LOAD) + opmask = 1; + else if (lins->mCode == IC_STORE) + opmask = 2; + else if (lins->mCode == IC_COPY) + opmask = 3; bool flush = false; - if (op) + for(int k=0; kmNumOperands; k++) { - if (op->mTemp >= 0) - flush = proc->mStoresIndirect; - else if (op->mMemory == IM_FFRAME || op->mMemory == IM_FRAME) - flush = true; - else if (op->mMemory == IM_GLOBAL) - flush = proc->ModifiesGlobal(op->mVarIndex); - else - flush = true; + if ((1 << k) & opmask) + { + InterOperand& op(lins->mSrc[k]); + + if (op.mTemp >= 0) + flush = proc->mStoresIndirect; + else if (op.mMemory == IM_FFRAME || op.mMemory == IM_FRAME) + flush = true; + else if (op.mMemory == IM_GLOBAL) + flush = proc->ModifiesGlobal(op.mVarIndex); + else if (op.mMemory == IM_LOCAL && !mProc->mLocalVars[op.mVarIndex]->mAliased) + flush = false; + else if ((op.mMemory == IM_PARAM || op.mMemory == IM_FPARAM) && !mProc->mParamVars[op.mVarIndex]->mAliased) + flush = false; + else + flush = true; + } } if (!flush) @@ -10625,7 +10795,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& while (j < mLoadStoreInstructions.Size()) { - if (flushMem && (mLoadStoreInstructions[j]->mCode == IC_LOAD || mLoadStoreInstructions[j]->mCode == IC_STORE)) + if (flushMem && (mLoadStoreInstructions[j]->mCode == IC_LOAD || mLoadStoreInstructions[j]->mCode == IC_STORE || mLoadStoreInstructions[j]->mCode == IC_COPY)) ; else if (t < 0) mLoadStoreInstructions[k++] = mLoadStoreInstructions[j]; @@ -10656,6 +10826,26 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray& mLoadStoreInstructions.Push(nins); } +#if 1 + // move loads down as far as possible to avoid false aliasing + for (int i = mInstructions.Size() - 2; i >= 0; i--) + { + InterInstruction* ins(mInstructions[i]); + if (ins->mCode == IC_LOAD) + { + int j = i; + while (j + 1 < mInstructions.Size() && CanSwapInstructions(ins, mInstructions[j + 1])) + { + SwapInstructions(ins, mInstructions[j + 1]); + mInstructions[j] = mInstructions[j + 1]; + j++; + } + if (i != j) + mInstructions[j] = ins; + } + } +#endif + if (mTrueJump && mTrueJump->LoadStoreForwarding(mLoadStoreInstructions, staticVars)) changed = true; if (mFalseJump && mFalseJump->LoadStoreForwarding(mLoadStoreInstructions, staticVars)) @@ -15048,24 +15238,6 @@ void InterCodeBasicBlock::CompactInstructions(void) } } -static void SwapInstructions(InterInstruction* it, InterInstruction* ib) -{ - for (int i = 0; i < ib->mNumOperands; i++) - { - if (ib->mSrc[i].mTemp >= 0 && ib->mSrc[i].mFinal) - { - for (int j = 0; j < it->mNumOperands; j++) - { - if (it->mSrc[j].mTemp == ib->mSrc[i].mTemp) - { - it->mSrc[j].mFinal = true; - ib->mSrc[i].mFinal = false; - } - } - } - } -} - void InterCodeBasicBlock::CheckFinalLocal(void) { #if _DEBUG @@ -18259,7 +18431,7 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "drawCube"); + CheckFunc = !strcmp(mIdent->mString, "fill"); CheckCase = false; mEntryBlock = mBlocks[0]; @@ -18413,10 +18585,14 @@ void InterCodeProcedure::Close(void) if (i < mLocalAliasedSet.Size() && mLocalAliasedSet[i]) mLocalVars[i]->mAliased = true; + RecheckLocalAliased(); + BuildDataFlowSets(); LoadStoreForwarding(paramMemory); + RecheckLocalAliased(); + ResetVisited(); mEntryBlock->OptimizeIntervalCompare(); @@ -18520,6 +18696,8 @@ void InterCodeProcedure::Close(void) LoadStoreForwarding(paramMemory); + RecheckLocalAliased(); + ResetVisited(); mEntryBlock->FollowJumps(); @@ -19676,6 +19854,37 @@ void InterCodeProcedure::RemoveUnusedMallocs(void) mEntryBlock->RemoveUnusedMallocs(); } +void InterCodeProcedure::RecheckLocalAliased(void) +{ + for (int i = 0; i < mLocalVars.Size(); i++) + { + InterVariable* v = mLocalVars[i]; + if (v) + { + if (v->mAliased) + v->mAliased = false; + else + v->mNotAliased = true; + } + } + for (int i = 0; i < mParamVars.Size(); i++) + { + InterVariable* v = mParamVars[i]; + if (v) + { + if (v->mAliased) + v->mAliased = false; + else + v->mNotAliased = true; + } + } + ResetVisited(); + mEntryBlock->RecheckLocalAliased(); + + DisassembleDebug("RecheckLocalAliased"); +} + + void InterCodeProcedure::HoistCommonConditionalPath(void) { for(;;) diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 34ed462..27f7c8b 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -19,10 +19,10 @@ enum InterCode IC_UNARY_OPERATOR, IC_RELATIONAL_OPERATOR, IC_CONVERSION_OPERATOR, - IC_STORE, - IC_LOAD, + IC_STORE, // store src[0] into src[1] + IC_LOAD, // load from src[0] IC_LEA, - IC_COPY, + IC_COPY, // Copy from src[0] to src[1] IC_STRCPY, IC_MALLOC, IC_FREE, @@ -247,7 +247,7 @@ public: class InterVariable { public: - bool mUsed, mAliased, mTemp; + bool mUsed, mAliased, mTemp, mNotAliased; int mIndex, mSize, mOffset, mTempIndex, mByteIndex; int mNumReferences; const Ident * mIdent; @@ -255,7 +255,7 @@ public: Declaration * mDeclaration; InterVariable(void) - : mUsed(false), mAliased(false), mTemp(false), mIndex(-1), mSize(0), mOffset(0), mIdent(nullptr), mLinkerObject(nullptr), mTempIndex(-1), mDeclaration(nullptr) + : mUsed(false), mAliased(false), mTemp(false), mNotAliased(false), mIndex(-1), mSize(0), mOffset(0), mIdent(nullptr), mLinkerObject(nullptr), mTempIndex(-1), mDeclaration(nullptr) { } }; @@ -415,6 +415,7 @@ public: void CollectLocalAddressTemps(GrowingIntArray& localTable, GrowingIntArray& paramTable, int & nlocals, int & nparams); void MarkAliasedLocalTemps(const GrowingIntArray& localTable, NumberSet& aliasedLocals, const GrowingIntArray& paramTable, NumberSet& aliasedParams); + void RecheckLocalAliased(void); void CollectLocalUsedTemps(int numTemps); bool PropagateNonLocalUsedConstTemps(void); @@ -707,6 +708,7 @@ protected: void SingleTailLoopOptimization(InterMemory paramMemory); void HoistCommonConditionalPath(void); void RemoveUnusedMallocs(void); + void RecheckLocalAliased(void); void MergeBasicBlocks(void); void CheckUsedDefinedTemps(void); diff --git a/oscar64/Linker.cpp b/oscar64/Linker.cpp index 030b9c1..fb9cf6a 100644 --- a/oscar64/Linker.cpp +++ b/oscar64/Linker.cpp @@ -642,6 +642,12 @@ void Linker::Link(void) for(int i=0; imSections.Size(); i++) lrgn->PlaceStackSection(lsec, lsec->mSections[i]); + if (lsec->mStart < lrgn->mEnd) + { + Location loc; + mErrors->Error(loc, ERRR_INSUFFICIENT_MEMORY, "Static stack usage exceeds stack segment"); + } + lsec->mEnd = lsec->mStart; lsec->mStart = lrgn->mEnd; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index 4f11a58..d078946 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -6200,7 +6200,7 @@ bool NativeCodeBasicBlock::LoadLoadOpStoreIndirectValue(InterCodeProcedure* proc { int size = InterTypeSize[wins->mSrc[0].mType]; - if (wins->mSrc[0].mFinal) + if (!wins->mSrc[0].mFinal) { if (wins->mSrc[0].mTemp == rins1->mSrc[0].mTemp || wins->mSrc[0].mTemp == rins0->mSrc[0].mTemp) return false; @@ -36323,6 +36323,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass mIns[i + 0].mType = ASMIT_AND; mIns[i + 0].mMode = ASMIM_IMMEDIATE; mIns[i + 0].mAddress = 0xfe; + mIns[i + 0].mLive |= mIns[i + 1].mLive & LIVE_CPU_REG_C; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; } @@ -42041,7 +42042,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "enemies_move_show"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "particle_move"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks]; diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index e4e5793..c4261d3 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -118,7 +118,10 @@ void Parser::AddMemberFunction(Declaration* dec, Declaration* mdec) } else + { mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + mErrors->Error(gdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } } else dec->mScope->Insert(mdec->mIdent, mdec); @@ -162,6 +165,7 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt, Declaratio else { mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Error duplicate struct declaration", structName); + mErrors->Error(pdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); } } } @@ -337,8 +341,12 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt, Declaratio if (pdec) mdec = pdec; - if (dec->mScope->Insert(mdec->mIdent, mdec)) + Declaration* odec = dec->mScope->Insert(mdec->mIdent, mdec); + if (odec) + { mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } } else { @@ -445,8 +453,12 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt, Declaratio if (offset > dec->mSize) dec->mSize = offset; - if (dec->mScope->Insert(mdec->mIdent, mdec)) + Declaration* odec = dec->mScope->Insert(mdec->mIdent, mdec); + if (odec) + { mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } if (dec->mConst) { @@ -849,8 +861,12 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified, Decl dec->mIdent = mScanner->mTokenIdent; dec->mQualIdent = mScope->Mangle(dec->mIdent); - if (mScope->Insert(dec->mIdent, dec)) + Declaration* odec = mScope->Insert(dec->mIdent, dec); + if (odec) + { mErrors->Error(dec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate name", dec->mIdent); + mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } mScanner->NextToken(); } @@ -871,8 +887,12 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified, Decl { cdec->mIdent = mScanner->mTokenIdent; cdec->mQualIdent = mScope->Mangle(cdec->mIdent); - if (mScope->Insert(cdec->mIdent, cdec) != nullptr) + Declaration* odec = mScope->Insert(cdec->mIdent, cdec); + if (odec) + { mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate declaration", mScanner->mTokenIdent->mString); + mErrors->Error(odec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } mScanner->NextToken(); } if (mScanner->mToken == TK_ASSIGN) @@ -3663,7 +3683,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex mScope->UseScope(dec->mScope); } else + { mErrors->Error(mScanner->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a class or namespace"); + mErrors->Error(dec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } } return dec; @@ -3952,7 +3975,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex if (mScanner->mToken == TK_OPEN_BRACE) { if (cdec->mFlags & DTF_DEFINED) - mErrors->Error(cdec->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body"); + { + mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body"); + mErrors->Error(cdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } cdec->mCompilerOptions = mCompilerOptions; cdec->mBase->mCompilerOptions = mCompilerOptions; @@ -4023,7 +4049,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex } if (cdec->mFlags & DTF_DEFINED) - mErrors->Error(cdec->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body"); + { + mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body"); + mErrors->Error(cdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } cdec->mCompilerOptions = mCompilerOptions; cdec->mBase->mCompilerOptions = mCompilerOptions; @@ -4255,7 +4284,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex #endif if (ldec && ldec != pdec) + { mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition"); + mErrors->Error(ldec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } } else if (ptempl && mTemplateScope && pthis) { @@ -4371,7 +4403,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex else if (ndec->mBase->mType == DT_TYPE_POINTER && pdec->mBase->mType == DT_TYPE_ARRAY && ndec->mBase->mBase->IsSame(pdec->mBase->mBase)) ; else + { mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Variable declaration differs", ndec->mIdent); + mErrors->Error(pdec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } } pdec->mFlags |= ndec->mFlags & DTF_ZEROPAGE; @@ -4599,7 +4634,10 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex if (ndec->mBase->mType == DT_TYPE_FUNCTION) { if ((ndec->mFlags & DTF_DEFINED) && !(ndec->mFlags & DTF_REQUEST_INLINE)) + { mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate function definition", ndec->mQualIdent); + mErrors->Error(ndec->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } ndec->mCompilerOptions = mCompilerOptions; ndec->mBase->mCompilerOptions = mCompilerOptions; @@ -11690,7 +11728,10 @@ void Parser::ParseNamespace(void) { Declaration* ns = mScope->Insert(ident, dec); if (ns) + { mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition", ident); + mErrors->Error(ns->mLocation, EINFO_ORIGINAL_DEFINITION, "Original definition"); + } } else mErrors->Error(mScanner->mLocation, ERRO_NOT_A_NAMESPACE, "Not a namespace", ident);