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 * single inheritance of class and struct
* const member functions * const member functions
* new, delete, new[] and delete[] * new, delete, new[] and delete[]
* virtual member functions
## Installation and Usage ## 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) * -Oi : enable auto inline of small functions (part of O2/O3)
* -Oa : optimize inline assembler (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) * -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 * -g : create source level debug info and add source line numbers to asm listing
* -tf : target format, may be prg, crt or bin * -tf : target format, may be prg, crt or bin
* -tm : target machine * -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 * inline : inline if requesed with inline storage attribute
* autoinline : auto inline of small or only once used functions * autoinline : auto inline of small or only once used functions
* maxinline : inline any function suitable * maxinline : inline any function suitable
* constparams : enable constant parameter folding into called functions
* noconstparams : disable constant parameter folding into called functions
* 0 : no optimization * 0 : no optimization
* 1 : default optimizations * 1 : default optimizations
* 2 : aggressive optimizations * 2 : aggressive optimizations

View File

@ -1,5 +1,11 @@
rem @echo off 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 @call :test constructortest.cpp
@if %errorlevel% neq 0 goto :error @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); LoadConstant(iproc, ins);
break; break;
case IC_CALL: case IC_CALL:
case IC_DISPATCH:
CallFunction(iproc, ins); CallFunction(iproc, ins);
break; break;
case IC_CALL_NATIVE: case IC_CALL_NATIVE:

View File

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

View File

@ -19,7 +19,7 @@ public:
CompilationUnits(Errors * errors); CompilationUnits(Errors * errors);
~CompilationUnits(void); ~CompilationUnits(void);
DeclarationScope* mScope; DeclarationScope* mScope, * mVTableScope;
CompilationUnit* mCompilationUnits, * mPendingUnits; CompilationUnit* mCompilationUnits, * mPendingUnits;
Declaration* mStartup; 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) void Compiler::CompileProcedure(InterCodeProcedure* proc)
{ {
if (!proc->mCompiled) if (!proc->mCompiled)
@ -591,6 +737,14 @@ bool Compiler::GenerateCode(void)
mGlobalAnalyzer->mCompilerOptions = mCompilerOptions; mGlobalAnalyzer->mCompilerOptions = mCompilerOptions;
if (mCompilerOptions & COPT_CPLUSPLUS)
{
if (mCompilerOptions & COPT_VERBOSE)
printf("Build VTables\n");
BuildVTables();
}
if (mCompilerOptions & COPT_VERBOSE) if (mCompilerOptions & COPT_VERBOSE)
printf("Global analyzer\n"); printf("Global analyzer\n");

View File

@ -51,6 +51,7 @@ public:
void RegisterRuntime(const Location& loc, const Ident* ident); void RegisterRuntime(const Location& loc, const Ident* ident);
void CompileProcedure(InterCodeProcedure* proc); void CompileProcedure(InterCodeProcedure* proc);
void BuildVTables(void);
bool WriteDbjFile(const char* filename); 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_AUTO_UNROLL = 1ULL << 6;
static const uint64 COPT_OPTIMIZE_CONST_EXPRESSIONS = 1ULL << 7; static const uint64 COPT_OPTIMIZE_CONST_EXPRESSIONS = 1ULL << 7;
static const uint64 COPT_OPTIMIZE_AUTO_ZEROPAGE = 1ULL << 8; 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_OPTIMIZE_CODE_SIZE = 1ULL << 16;
static const uint64 COPT_NATIVE = 1ULL << 17; 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_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 enum TargetMachine
{ {

View File

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

View File

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

View File

@ -656,6 +656,13 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
case EX_QUALIFY: case EX_QUALIFY:
Analyze(exp->mLeft, procDec, lhs); Analyze(exp->mLeft, procDec, lhs);
return exp->mDecValue->mBase; 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_CALL:
case EX_INLINE: case EX_INLINE:
ldec = Analyze(exp->mLeft, procDec, false); 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 (pdec && !(ldec->mBase->mFlags & DTF_VARIADIC) && !(ldec->mFlags & (DTF_INTRINSIC | DTF_FUNC_ASSEMBLER)))
{ {
#if 1 #if 1
if (mCompilerOptions & COPT_OPTIMIZE_BASIC) if (mCompilerOptions & COPT_OPTIMIZE_CONST_PARAMS)
{ {
if (!(pdec->mFlags & DTF_FPARAM_NOCONST)) if (!(pdec->mFlags & DTF_FPARAM_NOCONST))
{ {
@ -922,6 +929,13 @@ void GlobalAnalyzer::RegisterProc(Declaration* to)
{ {
if (to->mType == DT_CONST_FUNCTION) if (to->mType == DT_CONST_FUNCTION)
{ {
#if 0
if (to->mBase->mFlags & DTF_VIRTUAL)
{
}
else
#endif
if (!(to->mFlags & DTF_FUNC_VARIABLE)) if (!(to->mFlags & DTF_FUNC_VARIABLE))
{ {
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 bool InterCodeBasicBlock::CanSwapInstructions(const InterInstruction* ins0, const InterInstruction* ins1) const
{ {
// Cannot swap branches // 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; return false;
// Check function call // 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) 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; 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 false;
return true; return true;
@ -2945,6 +2945,7 @@ InterInstruction::InterInstruction(const Location& loc, InterCode code)
case IC_RETURN_VALUE: case IC_RETURN_VALUE:
case IC_RETURN_STRUCT: case IC_RETURN_STRUCT:
case IC_CONVERSION_OPERATOR: case IC_CONVERSION_OPERATOR:
case IC_DISPATCH:
mNumOperands = 1; mNumOperands = 1;
break; break;
@ -3141,7 +3142,7 @@ void InterInstruction::FilterStaticVarsUsage(const GrowingVariableArray& staticV
requiredVars += mSrc[1].mVarIndex; 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); requiredVars.OrNot(providedVars);
} }
@ -3509,7 +3510,7 @@ void InterInstruction::BuildCallerSaveTempSet(NumberSet& requiredTemps, NumberSe
if (mDst.mTemp >= 0) if (mDst.mTemp >= 0)
requiredTemps -= mDst.mTemp; requiredTemps -= mDst.mTemp;
if (mCode == IC_CALL || mCode == IC_CALL_NATIVE) if (mCode == IC_CALL || mCode == IC_CALL_NATIVE || mCode == IC_DISPATCH)
callerSaveTemps |= requiredTemps; callerSaveTemps |= requiredTemps;
for (int i = 0; i < mNumOperands; i++) for (int i = 0; i < mNumOperands; i++)
@ -3700,7 +3701,7 @@ bool InterInstruction::RemoveUnusedStaticStoreInstructions(InterCodeBasicBlock*
requiredVars.Fill(); requiredVars.Fill();
storeIns.SetSize(0); 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(); requiredVars.Fill();
storeIns.SetSize(0); storeIns.SetSize(0);
@ -4322,6 +4323,9 @@ void InterInstruction::Disassemble(FILE* file)
case IC_ASSEMBLER: case IC_ASSEMBLER:
fprintf(file, "JSR"); fprintf(file, "JSR");
break; break;
case IC_DISPATCH:
fprintf(file, "DISPATCH");
break;
case IC_RETURN_VALUE: case IC_RETURN_VALUE:
assert(mNumOperands == 1); assert(mNumOperands == 1);
fprintf(file, "RETV"); fprintf(file, "RETV");
@ -9640,6 +9644,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray&
{ {
ins->mCode = IC_LOAD_TEMPORARY; ins->mCode = IC_LOAD_TEMPORARY;
ins->mSrc[0] = lins->mSrc[0]; ins->mSrc[0] = lins->mSrc[0];
ins->mDst.mRange.Limit(ins->mSrc[0].mRange);
ins->mNumOperands = 1; ins->mNumOperands = 1;
assert(ins->mSrc[0].mTemp >= 0); assert(ins->mSrc[0].mTemp >= 0);
changed = true; changed = true;
@ -9702,6 +9707,7 @@ bool InterCodeBasicBlock::LoadStoreForwarding(const GrowingInstructionPtrArray&
assert(lins->mDst.mTemp >= 0); assert(lins->mDst.mTemp >= 0);
ins->mCode = IC_LOAD_TEMPORARY; ins->mCode = IC_LOAD_TEMPORARY;
ins->mSrc[0] = lins->mDst; ins->mSrc[0] = lins->mDst;
ins->mDst.mRange.Limit(ins->mSrc[0].mRange);
ins->mNumOperands = 1; ins->mNumOperands = 1;
changed = true; changed = true;
} }
@ -10091,7 +10097,7 @@ bool InterCodeBasicBlock::CanMoveInstructionDown(int si, int ti) const
#if 1 #if 1
if (ins->mCode == IC_COPY || ins->mCode == IC_PUSH_FRAME || ins->mCode == IC_POP_FRAME || 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; return false;
for (int i = si + 1; i < ti; i++) for (int i = si + 1; i < ti; i++)
@ -10153,7 +10159,7 @@ bool InterCodeBasicBlock::CanMoveInstructionBeforeBlock(int ii, const InterInstr
#if 1 #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 || 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; return false;
for (int i = 0; i < ii; i++) for (int i = 0; i < ii; i++)
@ -10919,7 +10925,7 @@ bool InterCodeBasicBlock::IsLeafProcedure(void)
mVisited = true; mVisited = true;
for (i = 0; i < mInstructions.Size(); i++) 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; return false;
if (mTrueJump && !mTrueJump->IsLeafProcedure()) if (mTrueJump && !mTrueJump->IsLeafProcedure())
@ -11080,6 +11086,8 @@ bool InterCodeBasicBlock::CheckStaticStack(void)
else if (!(mInstructions[i]->mSrc[0].mLinkerObject->mFlags & LOBJF_STATIC_STACK)) else if (!(mInstructions[i]->mSrc[0].mLinkerObject->mFlags & LOBJF_STATIC_STACK))
return false; return false;
} }
else if (mInstructions[i]->mCode == IC_DISPATCH)
return false;
} }
if (mTrueJump && !mTrueJump->CheckStaticStack()) if (mTrueJump && !mTrueJump->CheckStaticStack())
@ -14899,7 +14907,7 @@ void InterCodeBasicBlock::CheckValueReturn(void)
for (int i = 0; i < mInstructions.Size(); i++) for (int i = 0; i < mInstructions.Size(); i++)
{ {
InterInstruction* ins = mInstructions[i]; InterInstruction* ins = mInstructions[i];
if (ins->mCode == IC_ASSEMBLER) if (ins->mCode == IC_ASSEMBLER || ins->mCode == IC_DISPATCH)
return; return;
else if (ins->mCode == IC_RETURN) else if (ins->mCode == IC_RETURN)
mProc->mModule->mErrors->Error(ins->mLocation, EWARN_MISSING_RETURN_STATEMENT, "Missing return statement"); 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) void InterCodeBasicBlock::WarnUnreachable(void)
{ {
if (mNumEntries == 0) if (mNumEntries == 0 && mProc->mCheckUnreachable)
{ {
int i = 0; int i = 0;
while (i < mInstructions.Size() && !IsObservable(mInstructions[i]->mCode)) 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), mNativeProcedure(false), mLeafProcedure(false), mCallsFunctionPointer(false), mCalledFunctions(nullptr), mFastCallProcedure(false),
mInterrupt(false), mHardwareInterrupt(false), mCompiled(false), mInterruptCalled(false), mDynamicStack(false), mInterrupt(false), mHardwareInterrupt(false), mCompiled(false), mInterruptCalled(false), mDynamicStack(false),
mSaveTempsLinkerObject(nullptr), mValueReturn(false), mFramePointer(false), mSaveTempsLinkerObject(nullptr), mValueReturn(false), mFramePointer(false),
mCheckUnreachable(true),
mDeclaration(nullptr) mDeclaration(nullptr)
{ {
mID = mModule->mProcedures.Size(); mID = mModule->mProcedures.Size();
@ -16106,7 +16115,7 @@ void InterCodeProcedure::Close(void)
{ {
GrowingTypeArray tstack(IT_NONE); GrowingTypeArray tstack(IT_NONE);
CheckFunc = !strcmp(mIdent->mString, "print"); CheckFunc = !strcmp(mIdent->mString, "setspr");
mEntryBlock = mBlocks[0]; mEntryBlock = mBlocks[0];
@ -16373,6 +16382,9 @@ void InterCodeProcedure::Close(void)
BuildDataFlowSets(); BuildDataFlowSets();
TempForwarding();
RemoveUnusedInstructions();
#if 1 #if 1
ResetVisited(); ResetVisited();
mEntryBlock->BuildLocalIntegerRangeSets(mTemporaries.Size(), mLocalVars, mParamVars); mEntryBlock->BuildLocalIntegerRangeSets(mTemporaries.Size(), mLocalVars, mParamVars);
@ -16383,6 +16395,9 @@ void InterCodeProcedure::Close(void)
ResetVisited(); ResetVisited();
} while (mEntryBlock->BuildGlobalIntegerRangeSets(true, mLocalVars, mParamVars)); } while (mEntryBlock->BuildGlobalIntegerRangeSets(true, mLocalVars, mParamVars));
TempForwarding();
RemoveUnusedInstructions();
do { do {
DisassembleDebug("tq"); DisassembleDebug("tq");
@ -16392,6 +16407,7 @@ void InterCodeProcedure::Close(void)
DisassembleDebug("Estimated value range"); DisassembleDebug("Estimated value range");
GrowingInstructionPtrArray pipa(nullptr); GrowingInstructionPtrArray pipa(nullptr);
ResetVisited(); ResetVisited();
mEntryBlock->LinkerObjectForwarding(pipa); mEntryBlock->LinkerObjectForwarding(pipa);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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