Added virtual functions

This commit is contained in:
drmortalwombat 2023-07-08 18:53:06 +02:00
parent 0b6a9c3584
commit ed9aa3503b
25 changed files with 740 additions and 129 deletions

View File

@ -62,6 +62,7 @@ Supported Features:
* single inheritance of class and struct
* const member functions
* new, delete, new[] and delete[]
* virtual member functions
## Installation and Usage
@ -97,6 +98,7 @@ The compiler is command line driven, and creates an executable .prg file.
* -Oi : enable auto inline of small functions (part of O2/O3)
* -Oa : optimize inline assembler (part of O2/O3)
* -Oz : enable auto placement of global variables in zero page (part of O3)
* -Op : optimize constant parameters
* -g : create source level debug info and add source line numbers to asm listing
* -tf : target format, may be prg, crt or bin
* -tm : target machine
@ -328,6 +330,8 @@ Set optimizer options that are active for the functions after it
* inline : inline if requesed with inline storage attribute
* autoinline : auto inline of small or only once used functions
* maxinline : inline any function suitable
* constparams : enable constant parameter folding into called functions
* noconstparams : disable constant parameter folding into called functions
* 0 : no optimization
* 1 : default optimizations
* 2 : aggressive optimizations

View File

@ -1,5 +1,11 @@
rem @echo off
@call :test vcalltest.cpp
@if %errorlevel% neq 0 goto :error
@call :test vcalltree.cpp
@if %errorlevel% neq 0 goto :error
@call :test constructortest.cpp
@if %errorlevel% neq 0 goto :error

93
autotest/vcalltest.cpp Normal file
View File

@ -0,0 +1,93 @@
#include <assert.h>
struct A
{
virtual int f(int x);
};
struct B : A
{
virtual int f(int x);
};
struct C : A
{
virtual int f(int x);
virtual int g(int y, int z);
};
struct D : B
{
virtual int f(int x);
};
struct E : C
{
virtual int f(int x);
virtual int g(int y, int z);
};
struct F : C
{
virtual int g(int y, int z);
};
int A::f(int x)
{
return x * 1;
}
int B::f(int x)
{
return x * 2;
}
int C::f(int x)
{
return x * 3;
}
int C::g(int y, int z)
{
return (y + z) * 3;
}
int D::f(int x)
{
return x * 4;
}
int E::f(int x)
{
return x * 5;
}
int E::g(int y, int z)
{
return (y + z) * 5;
}
int F::g(int y, int z)
{
return (y + z) * 6;
}
int main(void)
{
A a;
B b;
C c;
D d;
E e;
F f;
assert(a.f(3) == c.f(1));
assert(b.f(4) == d.f(2));
assert(e.f(2) == b.f(5));
assert(f.f(5) == e.f(3));
assert(c.g(3, 2) == e.g(1, 2));
assert(c.g(1, 5) == f.g(0, 3));
return 0;
}

79
autotest/vcalltree.cpp Normal file
View File

@ -0,0 +1,79 @@
#include <assert.h>
struct Node
{
virtual float eval(void)
{
return 1.0e6;
}
};
struct ConstNode : Node
{
float c;
ConstNode(float c_)
: c(c_) {}
virtual float eval(void)
{
return c;
}
};
struct BinopNode : Node
{
Node * left, * right;
BinopNode(Node * left_, Node * right_)
: left(left_), right(right_)
{}
};
struct AddNode : BinopNode
{
AddNode(Node * left_, Node * right_)
: BinopNode(left_, right_)
{}
virtual float eval(void)
{
return left->eval() + right->eval();
}
};
struct SubNode : BinopNode
{
SubNode(Node * left_, Node * right_)
: BinopNode(left_, right_)
{}
virtual float eval(void)
{
return left->eval() - right->eval();
}
};
struct MulNode : BinopNode
{
MulNode(Node * left_, Node * right_)
: BinopNode(left_, right_)
{}
virtual float eval(void)
{
return left->eval() * right->eval();
}
};
int main(void)
{
Node * n =
new SubNode(
new MulNode(new ConstNode(4), new ConstNode(5)),
new AddNode(new ConstNode(12), new ConstNode(7)));
assert(n->eval() == 1.0);
return 0;
}

View File

@ -4384,6 +4384,7 @@ void ByteCodeBasicBlock::Compile(InterCodeProcedure* iproc, ByteCodeProcedure* p
LoadConstant(iproc, ins);
break;
case IC_CALL:
case IC_DISPATCH:
CallFunction(iproc, ins);
break;
case IC_CALL_NATIVE:

View File

@ -14,6 +14,7 @@ CompilationUnits::CompilationUnits(Errors * errors)
mPendingUnits = nullptr;
mScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
mRuntimeScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
mVTableScope = new DeclarationScope(nullptr, SLEVEL_GLOBAL);
mStartup = nullptr;
for (int i = 0; i < 256; i++)

View File

@ -19,7 +19,7 @@ public:
CompilationUnits(Errors * errors);
~CompilationUnits(void);
DeclarationScope* mScope;
DeclarationScope* mScope, * mVTableScope;
CompilationUnit* mCompilationUnits, * mPendingUnits;
Declaration* mStartup;

View File

@ -200,6 +200,152 @@ void Compiler::RegisterRuntime(const Location & loc, const Ident* ident)
}
}
static void IndexVTableTree(Declaration* vdec, int & index)
{
vdec->mVarIndex = index;
vdec->mDefaultConstructor->mInteger = index;
index++;
Declaration* cvdec = vdec->mParams;
while (cvdec)
{
IndexVTableTree(cvdec, index);
cvdec = cvdec->mNext;
}
vdec->mSize = index - vdec->mVarIndex;
}
static void FillVTableTree(Declaration* vdec)
{
Declaration* cdec = vdec->mClass;
cdec->mScope->Iterate([=](const Ident* mident, Declaration* mdec)
{
if (mdec->mType == DT_CONST_FUNCTION)
{
while (mdec)
{
if (mdec->mBase->mFlags & DTF_VIRTUAL)
{
for (int i = 0; i < vdec->mSize; i++)
mdec->mVTable->mCalled[vdec->mVarIndex + i - mdec->mVTable->mDefaultConstructor->mVarIndex] = mdec;
}
mdec = mdec->mNext;
}
}
});
Declaration* cvdec = vdec->mParams;
while (cvdec)
{
FillVTableTree(cvdec);
cvdec = cvdec->mNext;
}
}
void Compiler::BuildVTables(void)
{
// Connect vdecs with parents
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
if (vdec->mBase)
{
vdec->mNext = vdec->mBase->mParams;
vdec->mBase->mParams = vdec;
}
});
// Number the child vtables
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
if (!vdec->mBase)
{
int index = 0;
IndexVTableTree(vdec, index);
}
});
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
if (!vdec->mBase)
{
FillVTableTree(vdec);
}
});
// Build vtables for functions
mCompilationUnits->mVTableScope->Iterate([=](const Ident* ident, Declaration* vdec)
{
vdec->mScope->Iterate([=](const Ident* mident, Declaration* mdec)
{
Declaration* vtabt = new Declaration(mdec->mLocation, DT_TYPE_ARRAY);
vtabt->mBase = mdec->mBase->ToStriped(vdec->mSize);
vtabt->mSize = vdec->mSize * 2;
vtabt->mStride = 1;
vtabt->mStripe = 1;
vtabt->mFlags |= DTF_CONST | DTF_DEFINED;
Declaration* vtaba = new Declaration(mdec->mLocation, DT_VARIABLE);
vtaba->mFlags = DTF_CONST | DTF_GLOBAL | DTF_DEFINED;
vtaba->mBase = vtabt;
vtaba->mSize = vtabt->mSize;
vtaba->mValue = new Expression(mdec->mLocation, EX_CONSTANT);
vtaba->mValue->mDecType = vtabt;
vtaba->mValue->mDecValue = new Declaration(mdec->mLocation, DT_CONST_STRUCT);
vtaba->mIdent = mdec->mIdent;
vtaba->mQualIdent = mdec->mQualIdent->Mangle("$vtable");
vtaba->mSection = mdec->mSection;
vtaba->mOffset = - vdec->mVarIndex;
Declaration* last = nullptr;
for (int i = 0; i < vdec->mSize; i++)
{
Declaration* vmdec = mdec->mCalled[i];
Expression* texp = new Expression(vmdec->mLocation, EX_CONSTANT);
texp->mDecType = vtabt->mBase;
texp->mDecValue = vmdec;
Declaration* cdec = new Declaration(vmdec->mLocation, DT_CONST_POINTER);
cdec->mValue = texp;
cdec->mBase = vtabt->mBase;
cdec->mOffset = i;
if (last)
last->mNext = cdec;
else
vtaba->mValue->mDecValue->mParams = cdec;
last = cdec;
}
// mCompilationUnits->AddReferenced(vtaba);
Expression* vexp = new Expression(mdec->mLocation, EX_QUALIFY);
vexp->mLeft = new Expression(mdec->mLocation, EX_PREFIX);
vexp->mLeft->mDecType = mdec->mBase->mParams->mBase->mBase;
vexp->mLeft->mToken = TK_MUL;
vexp->mLeft->mLeft = new Expression(mdec->mLocation, EX_VARIABLE);
vexp->mLeft->mLeft->mDecType = mdec->mBase->mParams->mBase;
vexp->mLeft->mLeft->mDecValue = mdec->mBase->mParams;
vexp->mDecValue = new Declaration(mdec->mLocation, DT_ELEMENT);
vexp->mDecValue->mBase = TheCharTypeDeclaration;
vexp->mDecValue->mOffset = vdec->mOffset;
vexp->mDecValue->mSize = 1;
vexp->mDecType = TheCharTypeDeclaration;
Expression* ecall = new Expression(mdec->mLocation, EX_DISPATCH);
ecall->mLeft = new Expression(mdec->mLocation, EX_INDEX);
ecall->mDecType = vtabt->mBase;
ecall->mLeft->mLeft = new Expression(mdec->mLocation, EX_VARIABLE);
ecall->mLeft->mLeft->mDecType = vtabt;
ecall->mLeft->mLeft->mDecValue = vtaba;
ecall->mLeft->mRight = vexp;
mdec->mFlags |= DTF_DEFINED;
mdec->mValue = ecall;
});
});
}
void Compiler::CompileProcedure(InterCodeProcedure* proc)
{
if (!proc->mCompiled)
@ -591,6 +737,14 @@ bool Compiler::GenerateCode(void)
mGlobalAnalyzer->mCompilerOptions = mCompilerOptions;
if (mCompilerOptions & COPT_CPLUSPLUS)
{
if (mCompilerOptions & COPT_VERBOSE)
printf("Build VTables\n");
BuildVTables();
}
if (mCompilerOptions & COPT_VERBOSE)
printf("Global analyzer\n");

View File

@ -51,6 +51,7 @@ public:
void RegisterRuntime(const Location& loc, const Ident* ident);
void CompileProcedure(InterCodeProcedure* proc);
void BuildVTables(void);
bool WriteDbjFile(const char* filename);
};

View File

@ -11,6 +11,7 @@ static const uint64 COPT_OPTIMIZE_AUTO_INLINE_ALL = 1ULL << 5;
static const uint64 COPT_OPTIMIZE_AUTO_UNROLL = 1ULL << 6;
static const uint64 COPT_OPTIMIZE_CONST_EXPRESSIONS = 1ULL << 7;
static const uint64 COPT_OPTIMIZE_AUTO_ZEROPAGE = 1ULL << 8;
static const uint64 COPT_OPTIMIZE_CONST_PARAMS = 1ULL << 9;
static const uint64 COPT_OPTIMIZE_CODE_SIZE = 1ULL << 16;
static const uint64 COPT_NATIVE = 1ULL << 17;
@ -42,11 +43,11 @@ static const uint64 COPT_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE |
static const uint64 COPT_OPTIMIZE_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS;
static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE;
static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE | COPT_OPTIMIZE_CONST_PARAMS;
static const uint64 COPT_OPTIMIZE_SPEED = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER;
static const uint64 COPT_OPTIMIZE_SPEED = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER | COPT_OPTIMIZE_CONST_PARAMS;
static const uint64 COPT_OPTIMIZE_ALL = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER | COPT_OPTIMIZE_AUTO_ZEROPAGE;
static const uint64 COPT_OPTIMIZE_ALL = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER | COPT_OPTIMIZE_AUTO_ZEROPAGE | COPT_OPTIMIZE_CONST_PARAMS;
enum TargetMachine
{

View File

@ -192,6 +192,12 @@ void Expression::Dump(int ident) const
case EX_INLINE:
printf("INLINE");
break;
case EX_VCALL:
printf("VCALL");
break;
case EX_DISPATCH:
printf("DISPATCH");
break;
case EX_LIST:
printf("LIST");
break;
@ -788,6 +794,7 @@ Declaration::Declaration(const Location& loc, DecType type)
mConst(nullptr), mMutable(nullptr),
mDefaultConstructor(nullptr), mDestructor(nullptr), mCopyConstructor(nullptr), mCopyAssignment(nullptr),
mVectorConstructor(nullptr), mVectorDestructor(nullptr), mVectorCopyConstructor(nullptr), mVectorCopyAssignment(nullptr),
mVTable(nullptr),
mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1),
mInteger(0), mNumber(0), mMinValue(-0x80000000LL), mMaxValue(0x7fffffffLL), mFastCallBase(0), mFastCallSize(0), mStride(0), mStripe(1),
mCompilerOptions(0), mUseCount(0)
@ -852,6 +859,7 @@ Declaration* Declaration::Clone(void)
ndec->mLinkerObject = mLinkerObject;
ndec->mAlignment = mAlignment;
ndec->mSection = mSection;
ndec->mVTable = mVTable;
return ndec;
}
@ -930,6 +938,10 @@ Declaration* Declaration::ToStriped(int stripe)
p = p->mNext;
}
}
else if (mType == DT_TYPE_FUNCTION)
{
ndec->mParams = mParams;
}
else if (mType == DT_TYPE_ARRAY)
{
ndec->mStride = stripe;
@ -965,6 +977,7 @@ Declaration* Declaration::ToConstType(void)
ndec->mCopyConstructor = mCopyConstructor;
ndec->mVectorConstructor = mVectorConstructor;
ndec->mVectorCopyConstructor = mVectorCopyConstructor;
ndec->mVTable = mVTable;
ndec->mMutable = this;
mConst = ndec;
@ -994,6 +1007,7 @@ Declaration* Declaration::ToMutableType(void)
ndec->mCopyConstructor = mCopyConstructor;
ndec->mVectorConstructor = mVectorConstructor;
ndec->mVectorCopyConstructor = mVectorCopyConstructor;
ndec->mVTable = mVTable;
ndec->mConst = this;
mMutable = ndec;
@ -1011,7 +1025,7 @@ bool Declaration::IsSubType(const Declaration* dec) const
if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY)
{
if (dec->mType == DT_TYPE_POINTER)
return this->Stride() == dec->Stride() && mBase->IsSubType(dec->mBase);
return /*this->Stride() == dec->Stride() &&*/ mBase->IsSubType(dec->mBase);
}
if (mType != dec->mType)

View File

@ -49,7 +49,9 @@ enum DecType
DT_FUNCTION_REF,
DT_LABEL_REF,
DT_NAMESPACE,
DT_BASECLASS
DT_BASECLASS,
DT_VTABLE
};
// TypeFlags
@ -82,6 +84,7 @@ static const uint64 DTF_STRIPED = (1ULL << 24);
static const uint64 DTF_DYNSTACK = (1ULL << 25);
static const uint64 DTF_PRIVATE = (1ULL << 26);
static const uint64 DTF_PROTECTED = (1ULL << 27);
static const uint64 DTF_VIRTUAL = (1ULL << 28);
static const uint64 DTF_FUNC_VARIABLE = (1ULL << 32);
static const uint64 DTF_FUNC_ASSEMBLER = (1ULL << 33);
@ -129,6 +132,8 @@ public:
void UseScope(DeclarationScope* scope);
template<typename F> void Iterate(F && f);
ScopeLevel mLevel;
const Ident * mName;
@ -144,6 +149,15 @@ protected:
ExpandingArray<DeclarationScope*> mUsed;
};
template<typename F> void DeclarationScope::Iterate(F&& f)
{
for (int i = 0; i < mHashSize; i++)
{
if (mHash[i].mIdent)
f(mHash[i].mIdent, mHash[i].mDec);
}
}
enum ExpressionType
{
EX_ERROR,
@ -162,6 +176,8 @@ enum ExpressionType
EX_QUALIFY,
EX_CALL,
EX_INLINE,
EX_VCALL,
EX_DISPATCH,
EX_LIST,
EX_RETURN,
EX_SEQUENCE,
@ -227,6 +243,7 @@ public:
Declaration * mBase, * mParams, * mNext, * mPrev, * mConst, * mMutable;
Declaration * mDefaultConstructor, * mDestructor, * mCopyConstructor, * mCopyAssignment;
Declaration * mVectorConstructor, * mVectorDestructor, * mVectorCopyConstructor, * mVectorCopyAssignment;
Declaration * mVTable, * mClass;
Expression* mValue;
DeclarationScope* mScope;

View File

@ -656,6 +656,13 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
case EX_QUALIFY:
Analyze(exp->mLeft, procDec, lhs);
return exp->mDecValue->mBase;
case EX_DISPATCH:
Analyze(exp->mLeft, procDec, lhs);
break;
case EX_VCALL:
exp->mType = EX_CALL;
exp->mLeft->mDecValue = exp->mLeft->mDecValue->mVTable;
// intentional fall through
case EX_CALL:
case EX_INLINE:
ldec = Analyze(exp->mLeft, procDec, false);
@ -688,7 +695,7 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
if (pdec && !(ldec->mBase->mFlags & DTF_VARIADIC) && !(ldec->mFlags & (DTF_INTRINSIC | DTF_FUNC_ASSEMBLER)))
{
#if 1
if (mCompilerOptions & COPT_OPTIMIZE_BASIC)
if (mCompilerOptions & COPT_OPTIMIZE_CONST_PARAMS)
{
if (!(pdec->mFlags & DTF_FPARAM_NOCONST))
{
@ -922,6 +929,13 @@ void GlobalAnalyzer::RegisterProc(Declaration* to)
{
if (to->mType == DT_CONST_FUNCTION)
{
#if 0
if (to->mBase->mFlags & DTF_VIRTUAL)
{
}
else
#endif
if (!(to->mFlags & DTF_FUNC_VARIABLE))
{
to->mFlags |= DTF_FUNC_VARIABLE;

View File

@ -626,7 +626,7 @@ static bool SameInstruction(const InterInstruction* ins1, const InterInstruction
bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, const InterInstruction* ins1) const
{
// Cannot swap branches
if (ins1->mCode == IC_JUMP || ins1->mCode == IC_BRANCH)
if (ins1->mCode == IC_JUMP || ins1->mCode == IC_BRANCH || ins1->mCode == IC_DISPATCH)
return false;
// Check function call
@ -1180,7 +1180,7 @@ static bool IsMoveable(InterCode code)
{
if (HasSideEffect(code) || code == IC_COPY || code == IC_STRCPY || code == IC_STORE || code == IC_BRANCH || code == IC_POP_FRAME || code == IC_PUSH_FRAME || code == IC_MALLOC || code == IC_FREE)
return false;
if (code == IC_RETURN || code == IC_RETURN_STRUCT || code == IC_RETURN_VALUE)
if (code == IC_RETURN || code == IC_RETURN_STRUCT || code == IC_RETURN_VALUE || code == IC_DISPATCH)
return false;
return true;
@ -2945,6 +2945,7 @@ InterInstruction::InterInstruction(const Location& loc, InterCode code)
case IC_RETURN_VALUE:
case IC_RETURN_STRUCT:
case IC_CONVERSION_OPERATOR:
case IC_DISPATCH:
mNumOperands = 1;
break;
@ -3141,7 +3142,7 @@ void InterInstruction::FilterStaticVarsUsage(const GrowingVariableArray& staticV
requiredVars += mSrc[1].mVarIndex;
}
}
else if (mCode == IC_COPY || mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_STRCPY)
else if (mCode == IC_COPY || mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_STRCPY || mCode == IC_DISPATCH)
{
requiredVars.OrNot(providedVars);
}
@ -3509,7 +3510,7 @@ void InterInstruction::BuildCallerSaveTempSet(NumberSet& requiredTemps, NumberSe
if (mDst.mTemp >= 0)
requiredTemps -= mDst.mTemp;
if (mCode == IC_CALL || mCode == IC_CALL_NATIVE)
if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_DISPATCH)
callerSaveTemps |= requiredTemps;
for (int i = 0; i < mNumOperands; i++)
@ -3700,7 +3701,7 @@ bool InterInstruction::RemoveUnusedStaticStoreInstructions(InterCodeBasicBlock*
requiredVars.Fill();
storeIns.SetSize(0);
}
else if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE)
else if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_RETURN || mCode == IC_RETURN_STRUCT || mCode == IC_RETURN_VALUE || mCode == IC_DISPATCH)
{
requiredVars.Fill();
storeIns.SetSize(0);
@ -4322,6 +4323,9 @@ void InterInstruction::Disassemble(FILE* file)
case IC_ASSEMBLER:
fprintf(file, "JSR");
break;
case IC_DISPATCH:
fprintf(file, "DISPATCH");
break;
case IC_RETURN_VALUE:
assert(mNumOperands == 1);
fprintf(file, "RETV");
@ -9640,6 +9644,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray&
{
ins->mCode = IC_LOAD_TEMPORARY;
ins->mSrc[0] = lins->mSrc[0];
ins->mDst.mRange.Limit(ins->mSrc[0].mRange);
ins->mNumOperands = 1;
assert(ins->mSrc[0].mTemp >= 0);
changed = true;
@ -9702,6 +9707,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray&
assert(lins->mDst.mTemp >= 0);
ins->mCode = IC_LOAD_TEMPORARY;
ins->mSrc[0] = lins->mDst;
ins->mDst.mRange.Limit(ins->mSrc[0].mRange);
ins->mNumOperands = 1;
changed = true;
}
@ -10091,7 +10097,7 @@ bool InterCodeBasicBlock::CanMoveInstructionDown(int si, int ti) const
#if 1
if (ins->mCode == IC_COPY || ins->mCode == IC_PUSH_FRAME || ins->mCode == IC_POP_FRAME ||
ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE)
ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE || ins->mCode == IC_DISPATCH)
return false;
for (int i = si + 1; i < ti; i++)
@ -10153,7 +10159,7 @@ bool InterCodeBasicBlock::CanMoveInstructionBeforeBlock(int ii, const InterInstr
#if 1
if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE || ins->mCode == IC_COPY || ins->mCode == IC_PUSH_FRAME || ins->mCode == IC_POP_FRAME ||
ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE)
ins->mCode == IC_RETURN || ins->mCode == IC_RETURN_STRUCT || ins->mCode == IC_RETURN_VALUE || ins->mCode == IC_DISPATCH)
return false;
for (int i = 0; i < ii; i++)
@ -10919,7 +10925,7 @@ bool InterCodeBasicBlock::IsLeafProcedure(void)
mVisited = true;
for (i = 0; i < mInstructions.Size(); i++)
if (mInstructions[i]->mCode == IC_CALL || mInstructions[i]->mCode == IC_CALL_NATIVE)
if (mInstructions[i]->mCode == IC_CALL || mInstructions[i]->mCode == IC_CALL_NATIVE || mInstructions[i]->mCode == IC_DISPATCH)
return false;
if (mTrueJump && !mTrueJump->IsLeafProcedure())
@ -11080,6 +11086,8 @@ bool InterCodeBasicBlock::CheckStaticStack(void)
else if (!(mInstructions[i]->mSrc[0].mLinkerObject->mFlags & LOBJF_STATIC_STACK))
return false;
}
else if (mInstructions[i]->mCode == IC_DISPATCH)
return false;
}
if (mTrueJump && !mTrueJump->CheckStaticStack())
@ -14899,7 +14907,7 @@ void InterCodeBasicBlock::CheckValueReturn(void)
for (int i = 0; i < mInstructions.Size(); i++)
{
InterInstruction* ins = mInstructions[i];
if (ins->mCode == IC_ASSEMBLER)
if (ins->mCode == IC_ASSEMBLER || ins->mCode == IC_DISPATCH)
return;
else if (ins->mCode == IC_RETURN)
mProc->mModule->mErrors->Error(ins->mLocation, EWARN_MISSING_RETURN_STATEMENT, "Missing return statement");
@ -15242,7 +15250,7 @@ void InterCodeBasicBlock::Disassemble(FILE* file, bool dumpSets)
void InterCodeBasicBlock::WarnUnreachable(void)
{
if (mNumEntries == 0)
if (mNumEntries == 0 && mProc->mCheckUnreachable)
{
int i = 0;
while (i < mInstructions.Size() && !IsObservable(mInstructions[i]->mCode))
@ -15262,6 +15270,7 @@ InterCodeProcedure::InterCodeProcedure(InterCodeModule * mod, const Location & l
mNativeProcedure(false), mLeafProcedure(false), mCallsFunctionPointer(false), mCalledFunctions(nullptr), mFastCallProcedure(false),
mInterrupt(false), mHardwareInterrupt(false), mCompiled(false), mInterruptCalled(false), mDynamicStack(false),
mSaveTempsLinkerObject(nullptr), mValueReturn(false), mFramePointer(false),
mCheckUnreachable(true),
mDeclaration(nullptr)
{
mID = mModule->mProcedures.Size();
@ -16106,7 +16115,7 @@ void InterCodeProcedure::Close(void)
{
GrowingTypeArray tstack(IT_NONE);
CheckFunc = !strcmp(mIdent->mString, "print");
CheckFunc = !strcmp(mIdent->mString, "setspr");
mEntryBlock = mBlocks[0];
@ -16373,6 +16382,9 @@ void InterCodeProcedure::Close(void)
BuildDataFlowSets();
TempForwarding();
RemoveUnusedInstructions();
#if 1
ResetVisited();
mEntryBlock->BuildLocalIntegerRangeSets(mTemporaries.Size(), mLocalVars, mParamVars);
@ -16383,6 +16395,9 @@ void InterCodeProcedure::Close(void)
ResetVisited();
} while (mEntryBlock->BuildGlobalIntegerRangeSets(true, mLocalVars, mParamVars));
TempForwarding();
RemoveUnusedInstructions();
do {
DisassembleDebug("tq");
@ -16392,6 +16407,7 @@ void InterCodeProcedure::Close(void)
DisassembleDebug("Estimated value range");
GrowingInstructionPtrArray pipa(nullptr);
ResetVisited();
mEntryBlock->LinkerObjectForwarding(pipa);

View File

@ -40,6 +40,7 @@ enum InterCode
IC_ASSEMBLER,
IC_JUMPF,
IC_SELECT,
IC_DISPATCH,
IC_UNREACHABLE
};
@ -588,6 +589,7 @@ public:
int mTempSize, mCommonFrameSize, mCallerSavedTemps, mFreeCallerSavedTemps, mFastCallBase;
bool mLeafProcedure, mNativeProcedure, mCallsFunctionPointer, mHasDynamicStack, mHasInlineAssembler, mCallsByteCode, mFastCallProcedure;
bool mInterrupt, mHardwareInterrupt, mCompiled, mInterruptCalled, mValueReturn, mFramePointer, mDynamicStack;
bool mCheckUnreachable;
GrowingInterCodeProcedurePtrArray mCalledFunctions;
InterCodeModule * mModule;

View File

@ -894,6 +894,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro
Expression* fexp = fdec->mValue;
Declaration* ftype = fdec->mBase;
proc->mCheckUnreachable = false;
InlineMapper nmapper;
nmapper.mReturn = new InterCodeBasicBlock(proc);
nmapper.mVarIndex = proc->mNumLocals;
@ -1610,6 +1612,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
if (inlineMapper)
ins->mConst.mVarIndex += inlineMapper->mVarIndex;
InitLocalVariable(proc, dec, ins->mConst.mVarIndex);
proc->mCheckUnreachable = false;
}
else if (inlineMapper)
{
@ -2665,6 +2668,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
return ExValue(TheBoolTypeDeclaration, ins->mDst.mTemp);
}
case EX_VCALL:
case EX_CALL:
case EX_INLINE:
{
@ -2854,7 +2858,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
bool canInline = exp->mLeft->mType == EX_CONSTANT &&
exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION &&
(mCompilerOptions & COPT_OPTIMIZE_INLINE) &&
!(inlineMapper && inlineMapper->mDepth > 10);
!(inlineMapper && inlineMapper->mDepth > 10) &&
exp->mType != EX_VCALL;
bool doInline = false, inlineConstexpr = false;
if (canInline)
@ -2902,7 +2907,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
}
else
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper);
Expression * funcexp = exp->mLeft;
vl = TranslateExpression(procType, proc, block, funcexp, destack, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, exp, block, vl);
int atotal = 0;
@ -2992,8 +3000,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
atotal = 2;
}
if (exp->mLeft->mDecValue && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION)
proc->AddCalledFunction(proc->mModule->mProcedures[exp->mLeft->mDecValue->mVarIndex]);
if (funcexp->mDecValue && funcexp->mDecValue->mType == DT_CONST_FUNCTION)
proc->AddCalledFunction(proc->mModule->mProcedures[funcexp->mDecValue->mVarIndex]);
else
proc->CallsFunctionPointer();
@ -3187,15 +3195,15 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
block->Append(defins[i]);
InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CALL);
if (exp->mLeft->mDecValue && (exp->mLeft->mDecValue->mFlags & DTF_NATIVE))
if (funcexp->mDecValue && (funcexp->mDecValue->mFlags & DTF_NATIVE))
cins->mCode = IC_CALL_NATIVE;
else
cins->mCode = IC_CALL;
if (exp->mLeft->mDecValue && (exp->mLeft->mDecValue->mFlags & DTF_FUNC_PURE))
if (funcexp->mDecValue && (funcexp->mDecValue->mFlags & DTF_FUNC_PURE))
cins->mNoSideEffects = true;
if (exp->mLeft->mType == EX_CONSTANT && (exp->mLeft->mDecValue->mFlags & DTF_FUNC_CONSTEXPR))
if (funcexp->mType == EX_CONSTANT && (funcexp->mDecValue->mFlags & DTF_FUNC_CONSTEXPR))
cins->mConstExpr = true;
cins->mSrc[0].mType = IT_POINTER;
@ -4059,6 +4067,30 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
} break;
case EX_DISPATCH:
{
vl = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper);
vl = Dereference(proc, exp, block, vl);
InterInstruction* ins = new InterInstruction(exp->mLocation, IC_DISPATCH);
ins->mSrc[0].mType = IT_POINTER;
ins->mSrc[0].mTemp = vl.mTemp;
block->Append(ins);
Declaration* dinit = exp->mLeft->mLeft->mDecValue->mValue->mDecValue->mParams;
while (dinit)
{
proc->AddCalledFunction(proc->mModule->mProcedures[dinit->mValue->mDecValue->mVarIndex]);
dinit = dinit->mNext;
}
// proc->CallsFunctionPointer();
return ExValue(TheVoidTypeDeclaration);
}
case EX_WHILE:
{
DestructStack* odestack = destack;

View File

@ -27069,11 +27069,6 @@ bool NativeCodeBasicBlock::ReverseBitfieldForwarding(void)
return changed;
}
struct NativeCodeLoadStorePair
{
NativeCodeInstruction mLoad, mStore;
};
bool NativeCodeBasicBlock::RemoveLocalUnusedLinkerObjects(void)
{
bool changed = false;
@ -27124,7 +27119,7 @@ void NativeCodeBasicBlock::MarkLocalUsedLinkerObjects(void)
}
}
bool NativeCodeBasicBlock::AbsoluteValueForwarding(void)
bool NativeCodeBasicBlock::AbsoluteValueForwarding(const ExpandingArray<NativeCodeLoadStorePair> & npairs)
{
bool changed = false;
@ -27133,6 +27128,8 @@ bool NativeCodeBasicBlock::AbsoluteValueForwarding(void)
mVisited = true;
ExpandingArray<NativeCodeLoadStorePair> pairs;
if (mNumEntries == 1)
pairs = npairs;
int ains = -1;
@ -27205,9 +27202,9 @@ bool NativeCodeBasicBlock::AbsoluteValueForwarding(void)
}
}
if (mTrueJump && mTrueJump->AbsoluteValueForwarding())
if (mTrueJump && mTrueJump->AbsoluteValueForwarding(pairs))
changed = true;
if (mFalseJump && mFalseJump->AbsoluteValueForwarding())
if (mFalseJump && mFalseJump->AbsoluteValueForwarding(pairs))
changed = true;
}
@ -28674,6 +28671,8 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc
mIns[1].mType = ASMIT_LDA; mIns[1].mLive |= LIVE_CPU_REG_A;
mIns[0].mType = ASMIT_CMP; mIns[0].mLive |= LIVE_CPU_REG_Z;
prevBlock->mIns.Push(mIns[1]);
prevBlock->mExitRequiredRegs += CPU_REG_A;
mEntryRequiredRegs += CPU_REG_A;
mIns.Remove(1);
CheckLive();
@ -37703,7 +37702,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_STX; mIns[i + 1].CopyMode(mIns[i + 3]);
mIns[i + 3].mType = mIns[i + 2].mType;
mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
progress = true;
@ -37717,7 +37716,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(NativeCodeProcedure* proc, int pass
{
mIns[i + 0].mType = ASMIT_NOP; mIns[i + 0].mMode = ASMIM_IMPLIED;
mIns[i + 1].mType = ASMIT_STY; mIns[i + 1].CopyMode(mIns[i + 3]);
mIns[i + 3].mType = mIns[i + 2].mType;
mIns[i + 3].mType = mIns[i + 2].mType; mIns[i + 3].mLive |= LIVE_CPU_REG_A;
mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED;
mIns[i + 4].mType = ASMIT_NOP; mIns[i + 4].mMode = ASMIM_IMPLIED;
progress = true;
@ -40878,7 +40877,8 @@ void NativeCodeProcedure::Optimize(void)
if (step == 9)
{
ResetVisited();
if (mEntryBlock->AbsoluteValueForwarding())
ExpandingArray<NativeCodeLoadStorePair> pairs;
if (mEntryBlock->AbsoluteValueForwarding(pairs))
{
changed = true;
@ -41889,6 +41889,7 @@ void NativeCodeProcedure::CompileInterBlock(InterCodeProcedure* iproc, InterCode
case IC_CONSTANT:
block->LoadConstant(iproc, ins);
break;
case IC_DISPATCH:
case IC_CALL:
block->CallFunction(iproc, this, ins);
break;

View File

@ -207,6 +207,12 @@ public:
uint32 NeedsLive(void) const;
};
struct NativeCodeLoadStorePair
{
NativeCodeInstruction mLoad, mStore;
};
class NativeCodeBasicBlock
{
public:
@ -474,7 +480,7 @@ public:
bool BitFieldForwarding(const NativeRegisterDataSet& data);
bool ReverseBitfieldForwarding(void);
bool OffsetValueForwarding(const ValueNumberingDataSet & data);
bool AbsoluteValueForwarding(void);
bool AbsoluteValueForwarding(const ExpandingArray<NativeCodeLoadStorePair>& npairs);
void MarkLocalUsedLinkerObjects(void);
bool RemoveLocalUnusedLinkerObjects(void);

View File

@ -64,6 +64,8 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt)
Declaration * dec = new Declaration(mScanner->mLocation, dt);
bool needVTable = false;
mScanner->NextToken();
if (mScanner->mToken == TK_IDENT)
{
@ -119,6 +121,9 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt)
bcdec->mBase = pdec;
bcdec->mFlags = pflags;
if (pdec->mVTable)
needVTable = true;
dec->mSize = pdec->mSize;
dec->mBase = bcdec;
@ -141,109 +146,205 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt)
}
mScanner->NextToken();
Declaration* mlast = nullptr;
for (;;)
if (ConsumeTokenIf(TK_CLOSE_BRACE))
{
if (ConsumeTokenIf(TK_PUBLIC))
dec->mParams = nullptr;
}
else
{
Declaration* mlast = nullptr;
for (;;)
{
flags &= ~(DTF_PRIVATE | DTF_PROTECTED);
ConsumeToken(TK_COLON);
}
else if (ConsumeTokenIf(TK_PROTECTED))
{
flags &= ~DTF_PRIVATE;
flags |= DTF_PROTECTED;
ConsumeToken(TK_COLON);
}
else if (ConsumeTokenIf(TK_PRIVATE))
{
flags |= DTF_PRIVATE | DTF_PROTECTED;
ConsumeToken(TK_COLON);
}
else
{
Declaration* mdec = ParseDeclaration(nullptr, false, false, pthis);
mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED);
mdec->mQualIdent = dec->mScope->Mangle(mdec->mIdent);
int offset = dec->mSize;
if (dt == DT_TYPE_UNION)
offset = 0;
if (mdec->mBase->mType == DT_TYPE_FUNCTION)
if (ConsumeTokenIf(TK_PUBLIC))
{
mdec->mType = DT_CONST_FUNCTION;
mdec->mSection = mCodeSection;
mdec->mFlags |= DTF_GLOBAL;
mdec->mBase->mFlags |= DTF_FUNC_THIS;
if (mCompilerOptions & COPT_NATIVE)
mdec->mFlags |= DTF_NATIVE;
if (!(mdec->mFlags & DTF_DEFINED))
ConsumeToken(TK_SEMICOLON);
AddMemberFunction(dec, mdec);
flags &= ~(DTF_PRIVATE | DTF_PROTECTED);
ConsumeToken(TK_COLON);
}
else if (ConsumeTokenIf(TK_PROTECTED))
{
flags &= ~DTF_PRIVATE;
flags |= DTF_PROTECTED;
ConsumeToken(TK_COLON);
}
else if (ConsumeTokenIf(TK_PRIVATE))
{
flags |= DTF_PRIVATE | DTF_PROTECTED;
ConsumeToken(TK_COLON);
}
else
{
while (mdec)
Declaration* mdec = ParseDeclaration(nullptr, false, false, pthis);
mdec->mFlags |= flags & (DTF_PRIVATE | DTF_PROTECTED);
mdec->mQualIdent = dec->mScope->Mangle(mdec->mIdent);
int offset = dec->mSize;
if (dt == DT_TYPE_UNION)
offset = 0;
if (mdec->mBase->mType == DT_TYPE_FUNCTION)
{
if (!(mdec->mBase->mFlags & DTF_DEFINED))
mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Undefined type used in struct member declaration");
if (mdec->mBase->mFlags & DTF_VIRTUAL)
needVTable = true;
if (mdec->mType != DT_VARIABLE)
{
mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Named structure element expected");
break;
}
mdec->mType = DT_CONST_FUNCTION;
mdec->mSection = mCodeSection;
mdec->mFlags |= DTF_GLOBAL;
mdec->mBase->mFlags |= DTF_FUNC_THIS;
mdec->mType = DT_ELEMENT;
mdec->mOffset = offset;
if (mCompilerOptions & COPT_NATIVE)
mdec->mFlags |= DTF_NATIVE;
offset += mdec->mBase->mSize;
if (offset > dec->mSize)
dec->mSize = offset;
if (!(mdec->mFlags & DTF_DEFINED))
ConsumeToken(TK_SEMICOLON);
if (dec->mScope->Insert(mdec->mIdent, mdec))
mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent);
if (mlast)
mlast->mNext = mdec;
else
dec->mParams = mdec;
mlast = mdec;
mdec = mdec->mNext;
AddMemberFunction(dec, mdec);
}
if (mScanner->mToken == TK_SEMICOLON)
mScanner->NextToken();
else
{
mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected");
while (mdec)
{
if (!(mdec->mBase->mFlags & DTF_DEFINED))
mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Undefined type used in struct member declaration");
if (mdec->mType != DT_VARIABLE)
{
mErrors->Error(mdec->mLocation, EERR_UNDEFINED_OBJECT, "Named structure element expected");
break;
}
mdec->mType = DT_ELEMENT;
mdec->mOffset = offset;
offset += mdec->mBase->mSize;
if (offset > dec->mSize)
dec->mSize = offset;
if (dec->mScope->Insert(mdec->mIdent, mdec))
mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent);
if (mlast)
mlast->mNext = mdec;
else
dec->mParams = mdec;
mlast = mdec;
mdec = mdec->mNext;
}
if (mScanner->mToken == TK_SEMICOLON)
mScanner->NextToken();
else
{
mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "';' expected");
break;
}
}
if (mScanner->mToken == TK_CLOSE_BRACE)
{
mScanner->NextToken();
break;
}
}
if (mScanner->mToken == TK_CLOSE_BRACE)
{
mScanner->NextToken();
break;
}
}
}
if (mlast)
mlast->mNext = nullptr;
else
dec->mParams = nullptr;
if (mlast)
mlast->mNext = nullptr;
else
dec->mParams = nullptr;
}
dec->SetDefined();
if ((mCompilerOptions & COPT_CPLUSPLUS) && dec->mType == DT_TYPE_STRUCT && dec->mIdent)
{
if (needVTable)
{
Declaration* vdec = mCompilationUnits->mVTableScope->Lookup(dec->mQualIdent);
if (!vdec)
{
vdec = new Declaration(dec->mLocation, DT_VTABLE);
if (dec->mBase)
{
vdec->mBase = dec->mBase->mBase->mVTable;
vdec->mSize = vdec->mBase->mSize;
vdec->mOffset = vdec->mBase->mOffset;
}
else
{
Declaration* mdec = dec->mParams;
while (mdec)
{
mdec->mOffset++;
mdec = mdec->mNext;
}
vdec->mOffset = 0;
dec->mSize++;
}
vdec->mDefaultConstructor = new Declaration(dec->mLocation, DT_CONST_INTEGER);
vdec->mDefaultConstructor->mBase = TheConstCharTypeDeclaration;
vdec->mDefaultConstructor->mSize = 1;
vdec->mDefaultConstructor->mInteger = -1;
vdec->mClass = dec;
vdec->mScope = new DeclarationScope(nullptr, SLEVEL_CLASS);
vdec->mIdent = dec->mIdent;
vdec->mQualIdent = dec->mQualIdent;
mCompilationUnits->mVTableScope->Insert(vdec->mQualIdent, vdec);
dec->mVTable = vdec;
}
dec->mScope->Iterate([=](const Ident* ident, Declaration* mdec)
{
if (mdec->mType == DT_CONST_FUNCTION)
{
while (mdec)
{
if (mdec->mBase->mFlags & DTF_VIRTUAL)
{
Declaration* vpdec = vdec;
Declaration* vmdec = vpdec->mScope->Lookup(ident);
while (!vmdec && vpdec->mBase)
{
vpdec = vpdec->mBase;
vmdec = vpdec->mScope->Lookup(ident);
}
Declaration* vmpdec = nullptr;
while (vmdec && vmdec->mBase->IsSame(mdec->mBase))
{
vmpdec = vmdec;
vmdec = vmdec->mNext;
}
if (!vmdec)
{
vmdec = mdec->Clone();
vmdec->mNext = nullptr;
vmdec->mDefaultConstructor = dec->mVTable;
vmdec->mFlags |= DTF_NATIVE;
if (vmpdec)
vmpdec->mNext = vmdec;
else
vdec->mScope->Insert(ident, vmdec);
}
mdec->mVTable = vmdec;
}
mdec = mdec->mNext;
}
}
}
);
}
AddDefaultConstructors(pthis);
// Lookup constructors, have same name as class
@ -256,6 +357,7 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt)
}
AppendMemberDestructor(pthis);
}
}
@ -1409,6 +1511,31 @@ void Parser::PrependMemberConstructor(Declaration* pthis, Declaration* cfunc)
dec = dec->mPrev;
}
}
if (pthis->mBase->mVTable)
{
Expression* sexp = new Expression(cfunc->mLocation, EX_SEQUENCE);
sexp->mLeft = cfunc->mValue;
Expression* vexp = new Expression(pthis->mLocation, EX_QUALIFY);
vexp->mLeft = thisexp;
vexp->mDecValue = new Declaration(pthis->mLocation, DT_ELEMENT);
vexp->mDecValue->mBase = TheCharTypeDeclaration;
vexp->mDecValue->mOffset = pthis->mBase->mVTable->mOffset;
vexp->mDecValue->mSize = 1;
vexp->mDecType = TheCharTypeDeclaration;
Expression* nexp = new Expression(cfunc->mLocation, EX_INITIALIZATION);
nexp->mToken = TK_ASSIGN;
nexp->mDecType = TheCharTypeDeclaration;
nexp->mLeft = vexp;
nexp->mRight = new Expression(cfunc->mLocation, EX_CONSTANT);
nexp->mRight->mDecType = TheCharTypeDeclaration;
nexp->mRight->mDecValue = pthis->mBase->mVTable->mDefaultConstructor;
sexp->mRight = nexp;
cfunc->mValue = sexp;
}
}
void Parser::BuildMemberConstructor(Declaration* pthis, Declaration* cfunc)
@ -1492,6 +1619,7 @@ void Parser::BuildMemberConstructor(Declaration* pthis, Declaration* cfunc)
void Parser::AddDefaultConstructors(Declaration* pthis)
{
bool simpleDestructor = true, simpleAssignment = true, simpleConstructor = true, simpleCopy = true;
bool inlineConstructor = true;
char dname[100];
strcpy_s(dname, "~");
@ -1537,7 +1665,11 @@ void Parser::AddDefaultConstructors(Declaration* pthis)
if (bcdec->mBase->mDestructor)
simpleDestructor = false;
if (bcdec->mBase->mDefaultConstructor)
{
simpleConstructor = false;
if (!(bcdec->mBase->mDefaultConstructor->mBase->mFlags & DTF_REQUEST_INLINE))
inlineConstructor = false;
}
if (bcdec->mBase->mCopyConstructor)
simpleCopy = false;
if (bcdec->mBase->mCopyAssignment)
@ -1545,6 +1677,9 @@ void Parser::AddDefaultConstructors(Declaration* pthis)
bcdec = bcdec->mNext;
}
if (pthis->mBase->mVTable)
simpleConstructor = false;
Declaration* dec = pthis->mBase->mParams;
while (dec)
{
@ -1561,7 +1696,11 @@ void Parser::AddDefaultConstructors(Declaration* pthis)
if (bdec->mDestructor)
simpleDestructor = false;
if (bdec->mDefaultConstructor)
{
simpleConstructor = false;
if (!(bdec->mDefaultConstructor->mBase->mFlags & DTF_REQUEST_INLINE))
inlineConstructor = false;
}
if (bdec->mCopyConstructor)
simpleCopy = false;
if (bdec->mCopyAssignment)
@ -1616,6 +1755,7 @@ void Parser::AddDefaultConstructors(Declaration* pthis)
{
Declaration* ctdec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
ctdec->mSize = 0;
Declaration* pdec = nullptr;
ctdec->mBase = TheVoidTypeDeclaration;
ctdec->mFlags |= DTF_DEFINED;
@ -1626,6 +1766,8 @@ void Parser::AddDefaultConstructors(Declaration* pthis)
cdec->mBase = ctdec;
cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
if (inlineConstructor)
cdec->mFlags |= DTF_REQUEST_INLINE;
cdec->mSection = mCodeSection;
@ -2782,7 +2924,12 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
{
for (;;)
{
if (mScanner->mToken == TK_STATIC)
if (mScanner->mToken == TK_VIRTUAL)
{
storageFlags |= DTF_VIRTUAL;
mScanner->NextToken();
}
else if (mScanner->mToken == TK_STATIC)
{
storageFlags |= DTF_STATIC;
mScanner->NextToken();
@ -3120,7 +3267,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
}
if (npdec->mBase->mType == DT_TYPE_FUNCTION)
npdec->mBase->mFlags |= storageFlags & (DTF_INTERRUPT | DTF_NATIVE | TK_FASTCALL);
npdec->mBase->mFlags |= storageFlags & (DTF_INTERRUPT | DTF_NATIVE | DTF_FASTCALL | DTF_VIRTUAL);
if (definingType)
{
@ -3850,9 +3997,12 @@ Expression* Parser::ParseSimpleExpression(bool lhs)
mScanner->NextToken();
break;
case TK_IDENT:
if (mThisPointer && !mScope->Lookup(mScanner->mTokenIdent, SLEVEL_FUNCTION))
if (mThisPointer && mThisPointer->mType == DT_ARGUMENT && !mScope->Lookup(mScanner->mTokenIdent, SLEVEL_FUNCTION))
{
dec = mThisPointer->mBase->mBase->mScope->Lookup(mScanner->mTokenIdent);
int offset;
uint64 flags;
dec = MemberLookup(mThisPointer->mBase->mBase, mScanner->mTokenIdent, offset, flags);
if (dec)
{
Expression * texp = new Expression(mScanner->mLocation, EX_VARIABLE);
@ -4115,6 +4265,9 @@ Expression* Parser::ParseQualify(Expression* exp)
ResolveOverloadCall(nexp->mLeft, nexp->mRight);
nexp->mDecType = nexp->mLeft->mDecType->mBase;
if (nexp->mLeft->mDecType->mFlags & DTF_VIRTUAL)
nexp->mType = EX_VCALL;
exp = nexp;
}
}
@ -4408,6 +4561,9 @@ Expression* Parser::ParsePostfixExpression(bool lhs)
ResolveOverloadCall(exp, nexp->mRight);
nexp->mDecType = exp->mDecType->mBase;
if (nexp->mLeft->mDecType->mFlags & DTF_VIRTUAL)
nexp->mType = EX_VCALL;
exp = nexp;
}
}
@ -4593,6 +4749,7 @@ Expression* Parser::ParsePrefixExpression(bool lhs)
Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
sexp->mLeft = iexp;
sexp->mRight = coexp;
sexp->mDecType = coexp->mDecType;
nexp = sexp;
}
@ -4653,6 +4810,7 @@ Expression* Parser::ParsePrefixExpression(bool lhs)
sexp->mLeft = dexp;
sexp->mRight = vexp;
sexp->mDecType = vexp->mDecType;
Expression * coexp = nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL);
coexp->mLeft = new Expression(mScanner->mLocation, EX_RELATIONAL);
@ -4670,6 +4828,7 @@ Expression* Parser::ParsePrefixExpression(bool lhs)
nexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
nexp->mLeft = iexp;
nexp->mRight = coexp;
nexp->mDecType = coexp->mDecType;
}
}
}
@ -7337,6 +7496,10 @@ void Parser::ParsePragma(void)
mCompilerOptions |= COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE;
else if (ConsumeIdentIf("maxinline"))
mCompilerOptions |= COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL;
else if (ConsumeIdentIf("constparams"))
mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS;
else if (ConsumeIdentIf("noconstparams"))
mCompilerOptions &= ~COPT_OPTIMIZE_CONST_PARAMS;
else
mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid option");

View File

@ -160,6 +160,7 @@ const char* TokenNames[] =
"'private'",
"'new'",
"'delete'",
"'virtual'",
};
@ -1412,6 +1413,8 @@ void Scanner::NextRawToken(void)
mToken = TK_NEW;
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "delete"))
mToken = TK_DELETE;
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "virtual"))
mToken = TK_VIRTUAL;
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "operator"))
{
NextRawToken();

View File

@ -159,6 +159,7 @@ enum Token
TK_PRIVATE,
TK_NEW,
TK_DELETE,
TK_VIRTUAL,
NUM_TOKENS
};

View File

@ -74,7 +74,7 @@ int main2(int argc, const char** argv)
#else
strcpy(strProductName, "oscar64");
strcpy(strProductVersion, "1.21.209");
strcpy(strProductVersion, "1.22.210");
#ifdef __APPLE__
uint32_t length = sizeof(basePath);
@ -202,6 +202,8 @@ int main2(int argc, const char** argv)
compiler->mCompilerOptions |= COPT_OPTIMIZE_AUTO_INLINE;
else if (arg[2] == 'z')
compiler->mCompilerOptions |= COPT_OPTIMIZE_AUTO_ZEROPAGE;
else if (arg[2] == 'p')
compiler->mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS;
}
else if (arg[1] == 'e')
{

View File

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,21,209,0
PRODUCTVERSION 1,21,209,0
FILEVERSION 1,22,210,0
PRODUCTVERSION 1,22,210,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -43,12 +43,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "oscar64"
VALUE "FileDescription", "oscar64 compiler"
VALUE "FileVersion", "1.21.209.0"
VALUE "FileVersion", "1.22.210.0"
VALUE "InternalName", "oscar64.exe"
VALUE "LegalCopyright", "Copyright (C) 2021"
VALUE "OriginalFilename", "oscar64.exe"
VALUE "ProductName", "oscar64"
VALUE "ProductVersion", "1.21.209.0"
VALUE "ProductVersion", "1.22.210.0"
END
END
BLOCK "VarFileInfo"

View File

@ -5296,15 +5296,15 @@
{
"Name" = "8:Microsoft Visual Studio"
"ProductName" = "8:oscar64"
"ProductCode" = "8:{30BEED33-B5ED-4443-B82C-B365168D7780}"
"PackageCode" = "8:{46BC17E9-3B6D-4E1E-A1E7-42B0AD7512D8}"
"ProductCode" = "8:{9E7AB7F5-BA83-4377-B177-3D121EF176EB}"
"PackageCode" = "8:{2B7BCA1C-B5B7-47D2-8A8A-A8C694463BE0}"
"UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}"
"AspNetVersion" = "8:2.0.50727.0"
"RestartWWWService" = "11:FALSE"
"RemovePreviousVersions" = "11:TRUE"
"DetectNewerInstalledVersion" = "11:TRUE"
"InstallAllUsers" = "11:FALSE"
"ProductVersion" = "8:1.21.209"
"ProductVersion" = "8:1.22.210"
"Manufacturer" = "8:oscar64"
"ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:"

View File

@ -100,7 +100,7 @@ __interrupt void setspr(void)
// Wait for end of current sprite, xpos will take effect
// at start of line, so we need to patch it after the last
// pixel line has started
vic_waitLine(yoffset - 4);
vic_waitLine(yoffset - 3);
// Left to right or right to left to get a matching z order
if (phase & 0x80)