Optimize struct copies

This commit is contained in:
drmortalwombat 2023-10-29 17:55:26 +01:00
parent 75301fa12d
commit 1d4eb70414
7 changed files with 310 additions and 52 deletions

View File

@ -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
}

View File

@ -19,6 +19,7 @@ enum ErrorID
{
EINFO_GENERIC = 1000,
EINFO_EXPANDED = 1001,
EINFO_ORIGINAL_DEFINITION = 1002,
EWARN_GENERIC = 2000,
EWARN_CONSTANT_TRUNCATED,

View File

@ -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,11 +4574,20 @@ 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;
}
}
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]);
@ -10497,10 +10592,25 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray&
}
}
}
else
{
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)
{
int j = 0, k = 0;
@ -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,25 +10747,39 @@ 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; k<lins->mNumOperands; k++)
{
if (op->mTemp >= 0)
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)
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_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)
mLoadStoreInstructions[k++] = mLoadStoreInstructions[j];
@ -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(;;)

View File

@ -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);

View File

@ -642,6 +642,12 @@ void Linker::Link(void)
for(int i=0; i<lsec->mSections.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;

View File

@ -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];

View File

@ -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);