diff --git a/README.md b/README.md index a68139f..4e118ca 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/autotest/autotest.bat b/autotest/autotest.bat index 4ec42d3..f6aca82 100644 --- a/autotest/autotest.bat +++ b/autotest/autotest.bat @@ -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 diff --git a/autotest/vcalltest.cpp b/autotest/vcalltest.cpp new file mode 100644 index 0000000..2b1fd56 --- /dev/null +++ b/autotest/vcalltest.cpp @@ -0,0 +1,93 @@ +#include + +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; +} diff --git a/autotest/vcalltree.cpp b/autotest/vcalltree.cpp new file mode 100644 index 0000000..ef3ef13 --- /dev/null +++ b/autotest/vcalltree.cpp @@ -0,0 +1,79 @@ +#include + +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; +} diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index a966e7b..cc72866 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -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: diff --git a/oscar64/CompilationUnits.cpp b/oscar64/CompilationUnits.cpp index 11e381f..948964b 100644 --- a/oscar64/CompilationUnits.cpp +++ b/oscar64/CompilationUnits.cpp @@ -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++) diff --git a/oscar64/CompilationUnits.h b/oscar64/CompilationUnits.h index 16c334c..a68acbb 100644 --- a/oscar64/CompilationUnits.h +++ b/oscar64/CompilationUnits.h @@ -19,7 +19,7 @@ public: CompilationUnits(Errors * errors); ~CompilationUnits(void); - DeclarationScope* mScope; + DeclarationScope* mScope, * mVTableScope; CompilationUnit* mCompilationUnits, * mPendingUnits; Declaration* mStartup; diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 7215372..ad59d05 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -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"); diff --git a/oscar64/Compiler.h b/oscar64/Compiler.h index 0928278..b14571f 100644 --- a/oscar64/Compiler.h +++ b/oscar64/Compiler.h @@ -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); }; diff --git a/oscar64/CompilerTypes.h b/oscar64/CompilerTypes.h index 9d8436e..5d0d66f 100644 --- a/oscar64/CompilerTypes.h +++ b/oscar64/CompilerTypes.h @@ -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 { diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index 520abe9..925ad2f 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -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) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 8f44b7d..360a62a 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -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 void Iterate(F && f); + ScopeLevel mLevel; const Ident * mName; @@ -144,6 +149,15 @@ protected: ExpandingArray mUsed; }; +template 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; diff --git a/oscar64/GlobalAnalyzer.cpp b/oscar64/GlobalAnalyzer.cpp index 8d0bf1a..20fd213 100644 --- a/oscar64/GlobalAnalyzer.cpp +++ b/oscar64/GlobalAnalyzer.cpp @@ -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; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index e28d5c0..874252d 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -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); diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 8d45c16..b54cee6 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -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; diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index b909701..bd1a538 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -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; diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index de92f06..b0a1fe5 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -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 & npairs) { bool changed = false; @@ -27133,6 +27128,8 @@ bool NativeCodeBasicBlock::AbsoluteValueForwarding(void) mVisited = true; ExpandingArray 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 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; diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 3cf5e56..6db7ec7 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -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& npairs); void MarkLocalUsedLinkerObjects(void); bool RemoveLocalUnusedLinkerObjects(void); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index c99c46e..dcedd38 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -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"); diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index a072620..b27e571 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -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(); diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index 580c5ee..580ef40 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -159,6 +159,7 @@ enum Token TK_PRIVATE, TK_NEW, TK_DELETE, + TK_VIRTUAL, NUM_TOKENS }; diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index 18aa475..18bcde9 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -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') { diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index abb5828..3dca3fd 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -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" diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index 9350e86..6d0410c 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -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:" diff --git a/samples/sprites/sprmux64.c b/samples/sprites/sprmux64.c index 8191f0b..09099c2 100644 --- a/samples/sprites/sprmux64.c +++ b/samples/sprites/sprmux64.c @@ -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)