Add global optimizer for parameter/return optimizations

This commit is contained in:
drmortalwombat 2023-09-23 14:56:04 +02:00
parent c7f919e22e
commit 9d8c6991e8
19 changed files with 1258 additions and 49 deletions

View File

@ -559,7 +559,11 @@ This sample fills a single screen column with a given color, by generating 25 as
This sample initially assigns the value 0 to the pre processor macro ry and increments it each time the loop body is replicated. The loop generates 25 copies of the body, each with a different value for ry.
A simpler loop with only a single line template expansion is provided with the #for(iterator, count) preprocessor command:
A simpler loop with only a single line template expansion is provided with the for preprocessor command:
#for(<iterator>, <count>) <text>
This sample generates an array with pointers to screen rows:
char * const ScreenRows2[] = {
#for(i,SCREEN_HEIGHT) Screen + SCREEN_WIDTH * i,

View File

@ -9,7 +9,7 @@ class ios
{
public:
ios(void);
constexpr ios(void);
virtual ~ios(void);
char fill() const;
@ -85,7 +85,7 @@ typedef ostream & (* manip)(ostream &);
class ostream : public ios
{
public:
ostream(void);
constexpr ostream(void);
ostream & put(char c);
ostream & write(const char * s, int n);
@ -150,7 +150,7 @@ protected:
class costream : public ostream
{
public:
costream(void);
constexpr costream(void);
protected:
void bput(char ch);

View File

@ -33,6 +33,7 @@ Compiler::Compiler(void)
mNativeCodeGenerator = new NativeCodeGenerator(mErrors, mLinker, mCompilationUnits->mSectionCode);
mInterCodeModule = new InterCodeModule(mErrors, mLinker);
mGlobalAnalyzer = new GlobalAnalyzer(mErrors, mLinker);
mGlobalOptimizer = new GlobalOptimizer(mErrors, mLinker);
mCartridgeID = 0x0000;
}
@ -835,8 +836,6 @@ bool Compiler::GenerateCode(void)
dcrtstart->mSection = sectionStartup;
mGlobalAnalyzer->mCompilerOptions = mCompilerOptions;
if (mCompilerOptions & COPT_CPLUSPLUS)
{
if (mCompilerOptions & COPT_VERBOSE)
@ -845,6 +844,32 @@ bool Compiler::GenerateCode(void)
BuildVTables();
}
if (mCompilerOptions & COPT_OPTIMIZE_GLOBAL)
{
mGlobalOptimizer->mCompilerOptions = mCompilerOptions;
if (mCompilerOptions & COPT_VERBOSE)
printf("Global optimizer\n");
do {
mGlobalOptimizer->Reset();
mGlobalOptimizer->AnalyzeAssembler(dcrtstart->mValue, nullptr);
for (int i = 0; i < mCompilationUnits->mReferenced.Size(); i++)
{
Declaration* dec = mCompilationUnits->mReferenced[i];
if (dec->mType == DT_CONST_FUNCTION)
mGlobalOptimizer->AnalyzeProcedure(dec->mValue, dec);
else
mGlobalOptimizer->AnalyzeGlobalVariable(dec);
}
} while (mGlobalOptimizer->Optimize());
}
mGlobalAnalyzer->mCompilerOptions = mCompilerOptions;
if (mCompilerOptions & COPT_VERBOSE)
printf("Global analyzer\n");

View File

@ -7,6 +7,7 @@
#include "NativeCodeGenerator.h"
#include "InterCodeGenerator.h"
#include "GlobalAnalyzer.h"
#include "GlobalOptimizer.h"
#include "Linker.h"
#include "CompilerTypes.h"
@ -25,6 +26,7 @@ public:
InterCodeGenerator* mInterCodeGenerator;
InterCodeModule* mInterCodeModule;
GlobalAnalyzer* mGlobalAnalyzer;
GlobalOptimizer* mGlobalOptimizer;
GrowingArray<ByteCodeProcedure*> mByteCodeFunctions;
ExpandingArray<NativeCodeProcedure*> mNativeProcedures;

View File

@ -13,6 +13,7 @@ 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_MERGE_CALLS = 1ULL << 10;
static const uint64 COPT_OPTIMIZE_GLOBAL = 1ULL << 11;
static const uint64 COPT_OPTIMIZE_CODE_SIZE = 1ULL << 16;
static const uint64 COPT_NATIVE = 1ULL << 17;
@ -44,11 +45,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 | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS;
static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
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 | COPT_OPTIMIZE_MERGE_CALLS;
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 | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
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 | COPT_OPTIMIZE_MERGE_CALLS;
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 | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
enum TargetMachine
{

View File

@ -434,6 +434,7 @@ Declaration* ConstexprInterpreter::Value::GetConst(int offset, Declaration* type
{
case DT_TYPE_INTEGER:
case DT_TYPE_BOOL:
case DT_TYPE_ENUM:
dec = new Declaration(mLocation, DT_CONST_INTEGER);
dec->mBase = type;
dec->mFlags = type->mFlags & DTF_SIGNED;
@ -454,20 +455,25 @@ Declaration* ConstexprInterpreter::Value::GetConst(int offset, Declaration* type
dec->mSection = dataSection;
dec->mOffset = offset;
Declaration* ldec = nullptr;
while (type)
{
for (Declaration* mdec = type->mParams; mdec; mdec = mdec->mNext)
{
Declaration* cdec = GetConst(offset + mdec->mOffset, mdec->mBase, dataSection);
cdec->mOffset = mdec->mOffset;
cdec->mNext = dec->mParams;
dec->mParams = cdec;
}
if (ldec)
ldec->mNext = cdec;
else
dec->mParams = cdec;
ldec = cdec;
if (type->mVTable)
{
Declaration * cdec = new Declaration(mLocation, DT_CONST_INTEGER);
cdec->mBase = TheConstCharTypeDeclaration;
cdec->mSize = 1;
cdec->mInteger = type->mVTable->mDefaultConstructor->mInteger;
cdec->mOffset = offset + type->mVTable->mOffset;
cdec->mNext = dec->mParams;
dec->mParams = cdec;
}
if (type->mBase)
@ -587,6 +593,29 @@ void ConstexprInterpreter::DeleteValue(Value* v)
mErrors->Error(v->mLocation, EERR_DOUBLE_FREE, "Freeing not allocated memory");
}
Expression* ConstexprInterpreter::EvalConstructor(Expression* exp)
{
mProcType = exp->mLeft->mDecType;
Declaration* cdec = exp->mLeft->mDecType->mParams;
int pos = 0;
mResult = Value(exp->mLocation, cdec->mBase->mBase);
mParams[pos] = Value(exp->mLocation, cdec->mBase);
mParams[pos].PutPtr(Value(&mResult));
pos = 2;
mHeap = new ExpandingArray<Value*>();
Execute(exp->mLeft->mDecValue->mValue);
if (mHeap->Size() > 0)
mErrors->Error(exp->mLocation, EERR_UNBALANCED_HEAP_USE, "Unbalanced heap use in constexpr");
delete mHeap;
return mResult.ToExpression(mDataSection);
}
Expression* ConstexprInterpreter::EvalCall(Expression* exp)
{
mProcType = exp->mLeft->mDecType;
@ -1118,6 +1147,7 @@ ConstexprInterpreter::Value ConstexprInterpreter::Eval(Expression* exp)
}
case EX_LIST:
case EX_COMMA:
Eval(exp->mLeft);
return Eval(exp->mRight);
@ -1191,6 +1221,7 @@ ConstexprInterpreter::Value ConstexprInterpreter::Eval(Expression* exp)
Value v = Eval(exp->mLeft);
if (v.mBaseValue)
return Value(exp->mLocation, v.mBaseValue, exp->mDecType, v.mOffset + exp->mDecValue->mOffset);
break;
}
case EX_INDEX:
@ -1208,6 +1239,7 @@ ConstexprInterpreter::Value ConstexprInterpreter::Eval(Expression* exp)
Value p = v.GetPtr();
return Value(exp->mLocation, p.mBaseValue, exp->mDecType, p.mOffset + v.mDecType->mBase->mSize * int(vi.GetInt()));
}
break;
}
case EX_RESULT:
@ -1256,6 +1288,7 @@ ConstexprInterpreter::Flow ConstexprInterpreter::Execute(Expression* exp)
case EX_PREFIX:
case EX_TYPECAST:
case EX_CALL:
case EX_COMMA:
case EX_LIST:
case EX_CONDITIONAL:
case EX_LOGICAL_AND:

View File

@ -9,6 +9,7 @@ public:
~ConstexprInterpreter(void);
Expression* EvalCall(Expression* exp);
Expression* EvalConstructor(Expression* exp);
protected:
struct Value;

View File

@ -222,6 +222,9 @@ void Expression::Dump(int ident) const
case EX_LIST:
printf("LIST");
break;
case EX_COMMA:
printf("COMMA");
break;
case EX_RETURN:
printf("RETURN");
break;
@ -523,6 +526,10 @@ Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSectio
ex->mDecType = mDecType;
return ex;
}
else if (mType == EX_PREFIX && mToken == TK_BINARY_AND && mLeft->mType == EX_PREFIX && mLeft->mToken == TK_MUL)
{
return mLeft->mLeft;
}
#endif
else if (mType == EX_TYPECAST && mLeft->mType == EX_CONSTANT)
{
@ -888,7 +895,7 @@ Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSectio
return ex;
}
}
else if (mType == EX_CALL && mLeft->mType == EX_CONSTANT && (mLeft->mDecValue->mFlags & DTF_CONSTEXPR))
else if (mType == EX_CALL && mLeft->mType == EX_CONSTANT && (mLeft->mDecValue->mFlags & DTF_CONSTEXPR) && dataSection)
{
ConstexprInterpreter cinter(mLocation, errors, dataSection);
return cinter.EvalCall(this);
@ -900,7 +907,7 @@ Expression* Expression::ConstantFold(Errors * errors, LinkerSection * dataSectio
Declaration::Declaration(const Location& loc, DecType type)
: mLocation(loc), mEndLocation(loc), mType(type), mScope(nullptr), mData(nullptr), mIdent(nullptr), mQualIdent(nullptr), mMangleIdent(nullptr),
mSize(0), mOffset(0), mFlags(0), mComplexity(0), mLocalSize(0), mNumVars(0),
mBase(nullptr), mParams(nullptr), mParamPack(nullptr), mValue(nullptr), mNext(nullptr), mPrev(nullptr),
mBase(nullptr), mParams(nullptr), mParamPack(nullptr), mValue(nullptr), mReturn(nullptr), mNext(nullptr), mPrev(nullptr),
mConst(nullptr), mMutable(nullptr),
mDefaultConstructor(nullptr), mDestructor(nullptr), mCopyConstructor(nullptr), mCopyAssignment(nullptr), mMoveConstructor(nullptr), mMoveAssignment(nullptr),
mVectorConstructor(nullptr), mVectorDestructor(nullptr), mVectorCopyConstructor(nullptr), mVectorCopyAssignment(nullptr),
@ -908,7 +915,7 @@ Declaration::Declaration(const Location& loc, DecType type)
mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1), mFriends(nullptr),
mInteger(0), mNumber(0), mMinValue(-0x80000000LL), mMaxValue(0x7fffffffLL), mFastCallBase(0), mFastCallSize(0), mStride(0), mStripe(1),
mCompilerOptions(0), mUseCount(0), mTokens(nullptr), mParser(nullptr),
mShift(0), mBits(0)
mShift(0), mBits(0), mOptFlags(0)
{}
Declaration::~Declaration(void)
@ -960,6 +967,71 @@ Declaration* Declaration::BuildArrayPointer(void)
return this;
}
Declaration* Declaration::ConstCast(Declaration* ntype)
{
if (ntype == mBase)
return this;
else if (ntype->mType == DT_TYPE_POINTER)
{
if (mBase->mType == DT_TYPE_POINTER)
{
if (mBase->mBase->IsSame(ntype->mBase))
return this;
Declaration* pdec = this->Clone();
pdec->mBase = ntype;
return pdec;
}
else if (mType == DT_TYPE_INTEGER)
{
Declaration* pdec = this->Clone();
pdec->mType = DT_CONST_ADDRESS;
pdec->mBase = ntype;
pdec->mSize = 2;
return pdec;
}
else
return this;
}
else if (ntype->mType == DT_TYPE_INTEGER || ntype->mType == DT_TYPE_BOOL || ntype->mType == DT_TYPE_ENUM)
{
if (mType == DT_TYPE_FLOAT)
{
Declaration* pdec = this->Clone();
pdec->mInteger = int64(mNumber);
pdec->mBase = ntype;
pdec->mSize = ntype->mSize;
return pdec;
}
else
{
Declaration* pdec = this->Clone();
pdec->mBase = ntype;
pdec->mSize = ntype->mSize;
return pdec;
}
}
else if (ntype->mType == DT_TYPE_FLOAT)
{
if (mType == DT_TYPE_FLOAT)
{
Declaration* pdec = this->Clone();
pdec->mBase = ntype;
return pdec;
}
else
{
Declaration* pdec = this->Clone();
pdec->mNumber = float(mInteger);
pdec->mBase = ntype;
pdec->mSize = ntype->mSize;
return pdec;
}
}
else
return this;
}
Declaration* Declaration::BuildPointer(const Location& loc)
{
Declaration* pdec = new Declaration(loc, DT_TYPE_POINTER);
@ -2263,6 +2335,7 @@ Declaration* TheBoolTypeDeclaration, * TheFloatTypeDeclaration, * TheConstVoidPo
Declaration* TheVoidFunctionTypeDeclaration, * TheConstVoidValueDeclaration;
Declaration* TheCharPointerTypeDeclaration, * TheConstCharPointerTypeDeclaration;
Expression* TheVoidExpression;
Declaration* TheNullptrConstDeclaration, * TheZeroIntegerConstDeclaration, * TheZeroFloatConstDeclaration;
void InitDeclarations(void)
{
@ -2345,4 +2418,16 @@ void InitDeclarations(void)
TheVoidExpression = new Expression(noloc, EX_CONSTANT);
TheVoidExpression->mDecType = TheConstVoidTypeDeclaration;
TheVoidExpression->mDecValue = TheConstVoidValueDeclaration;
TheNullptrConstDeclaration = new Declaration(noloc, DT_CONST_ADDRESS);
TheNullptrConstDeclaration->mBase = TheVoidPointerTypeDeclaration;
TheNullptrConstDeclaration->mSize = 2;
TheZeroIntegerConstDeclaration = new Declaration(noloc, DT_CONST_INTEGER);
TheZeroIntegerConstDeclaration->mBase = TheSignedIntTypeDeclaration;
TheZeroIntegerConstDeclaration->mSize = 2;
TheZeroFloatConstDeclaration = new Declaration(noloc, DT_CONST_FLOAT);
TheZeroFloatConstDeclaration->mBase = TheFloatTypeDeclaration;
TheZeroFloatConstDeclaration->mSize = 4;
}

View File

@ -116,6 +116,7 @@ static const uint64 DTF_VAR_ADDRESS = (1ULL << 46);
static const uint64 DTF_FUNC_THIS = (1ULL << 47);
static const uint64 DTF_VAR_ALIASING = (1ULL << 48);
static const uint64 DTF_FPARAM_UNUSED = (1ULL << 49);
class Declaration;
@ -196,6 +197,7 @@ enum ExpressionType
EX_VCALL,
EX_DISPATCH,
EX_LIST,
EX_COMMA,
EX_RETURN,
EX_SEQUENCE,
EX_WHILE,
@ -267,13 +269,13 @@ public:
Declaration * mVectorConstructor, * mVectorDestructor, * mVectorCopyConstructor, * mVectorCopyAssignment;
Declaration * mVTable, * mClass, * mTemplate;
Expression* mValue;
Expression* mValue, * mReturn;
DeclarationScope* mScope;
int mOffset, mSize, mVarIndex, mNumVars, mComplexity, mLocalSize, mAlignment, mFastCallBase, mFastCallSize, mStride, mStripe;
uint8 mShift, mBits;
int64 mInteger, mMinValue, mMaxValue;
double mNumber;
uint64 mFlags, mCompilerOptions;
uint64 mFlags, mCompilerOptions, mOptFlags;
const Ident * mIdent, * mQualIdent, * mMangleIdent;
LinkerSection * mSection;
const uint8 * mData;
@ -322,6 +324,7 @@ public:
Declaration* NonRefBase(void);
Declaration* BuildArrayPointer(void);
Declaration* DeduceAuto(Declaration* dec);
Declaration* ConstCast(Declaration* ntype);
bool IsAuto(void) const;
DecType ValueType(void) const;
@ -343,5 +346,6 @@ extern Declaration* TheVoidTypeDeclaration, * TheConstVoidTypeDeclaration, * The
extern Declaration* TheBoolTypeDeclaration, * TheFloatTypeDeclaration, * TheVoidPointerTypeDeclaration, * TheConstVoidPointerTypeDeclaration, * TheSignedLongTypeDeclaration, * TheUnsignedLongTypeDeclaration;
extern Declaration* TheVoidFunctionTypeDeclaration, * TheConstVoidValueDeclaration;
extern Declaration* TheCharPointerTypeDeclaration, * TheConstCharPointerTypeDeclaration;
extern Declaration* TheNullptrConstDeclaration, * TheZeroIntegerConstDeclaration, * TheZeroFloatConstDeclaration;
extern Expression* TheVoidExpression;

View File

@ -219,6 +219,8 @@ void GlobalAnalyzer::AutoInline(void)
{
if (pdec->mFlags & DTF_FPARAM_CONST)
{
pdec->mFlags |= DTF_FPARAM_UNUSED;
pdec->mVarIndex = dec->mNumVars++;
Expression* aexp = new Expression(pdec->mLocation, EX_INITIALIZATION);
@ -897,6 +899,7 @@ Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec, boo
}
break;
case EX_LIST:
case EX_COMMA:
RegisterProc(Analyze(exp->mLeft, procDec, false));
return Analyze(exp->mRight, procDec, false);
case EX_RETURN:

925
oscar64/GlobalOptimizer.cpp Normal file
View File

@ -0,0 +1,925 @@
#include "GlobalOptimizer.h"
#include "Constexpr.h"
#define DUMP_OPTS 0
static const uint64 OPTF_ANALYZED = (1ULL << 0);
static const uint64 OPTF_ANALYZING = (1ULL << 1);
static const uint64 OPTF_RECURSIVE = (1ULL << 2);
static const uint64 OPTF_FUNC_VARIABLE = (1ULL << 3);
static const uint64 OPTF_CALLED = (1ULL << 4);
static const uint64 OPTF_CALLING = (1ULL << 5);
static const uint64 OPTF_VAR_MODIFIED = (1ULL << 6);
static const uint64 OPTF_VAR_ADDRESS = (1ULL << 7);
static const uint64 OPTF_VAR_USED = (1ULL << 8);
static const uint64 OPTF_VAR_CONST = (1ULL << 9);
static const uint64 OPTF_VAR_NOCONST = (1ULL << 10);
static const uint64 OPTF_SINGLE_RETURN = (1ULL << 11);
static const uint64 OPTF_MULTI_RETURN = (1ULL << 12);
GlobalOptimizer::GlobalOptimizer(Errors* errors, Linker* linker)
: mErrors(errors), mLinker(linker)
{
}
GlobalOptimizer::~GlobalOptimizer(void)
{
}
void GlobalOptimizer::Reset(void)
{
for (int i = 0; i < mFunctions.Size(); i++)
{
Declaration* func = mFunctions[i];
Declaration* ftype = func->mBase;
func->mOptFlags = 0;
ftype->mOptFlags = 0;
func->mReturn = nullptr;
Declaration* pdec = ftype->mParams;
while (pdec)
{
pdec->mOptFlags = 0;
pdec = pdec->mNext;
}
}
for (int i = 0; i < mGlobalVariables.Size(); i++)
{
mGlobalVariables[i]->mOptFlags = 0;
}
mFunctions.SetSize(0);
mGlobalVariables.SetSize(0);
mCalledFunctions.SetSize(0);
mCalledFunctions.SetSize(0);
}
void GlobalOptimizer::PropagateParamCommas(Expression*& fexp, Expression*& exp)
{
PropagateCommas(exp);
if (exp->mType == EX_COMMA)
{
Expression* cexp = exp;
exp = cexp->mRight;
cexp->mRight = fexp;
fexp = cexp;
fexp->mDecType = cexp->mRight->mDecType;
}
}
void GlobalOptimizer::PropagateCommas(Expression*& exp)
{
if (exp->mType == EX_PREFIX && exp->mLeft->mType == EX_COMMA)
{
Expression* cexp = exp->mLeft;
exp->mLeft = cexp->mRight;
cexp->mDecType = exp->mDecType;
cexp->mRight = exp->ConstantFold(mErrors, nullptr);
exp = cexp;
}
else if (exp->mType == EX_CALL)
{
Expression* pexp = exp;
Expression* rexp = pexp->mRight;
if (rexp)
{
while (rexp && rexp->mType == EX_LIST)
{
PropagateParamCommas(exp, rexp->mLeft);
if (rexp->mLeft-> mType == EX_COMMA)
pexp = rexp;
rexp = rexp->mRight;
}
if (rexp)
PropagateParamCommas(exp, pexp->mRight);
}
}
else
{
if (exp->mLeft)
PropagateCommas(exp->mLeft);
if (exp->mRight)
PropagateCommas(exp->mRight);
}
}
bool GlobalOptimizer::CheckConstReturns(Expression*& exp)
{
bool changed = false;
if (exp->mType == EX_CALL && exp->mDecType && exp->mDecType->mType != DT_TYPE_VOID)
{
if (exp->mLeft->mType == EX_CONSTANT)
{
Declaration* pcall = exp->mLeft->mDecValue;
if ((pcall->mOptFlags & OPTF_SINGLE_RETURN) && pcall->mReturn->mLeft)
{
Expression * rexp = pcall->mReturn->mLeft;
if (rexp->mType == EX_CONSTANT)
{
#if DUMP_OPTS
printf("Extract const return\n");
#endif
Expression* lexp = new Expression(exp->mLocation, EX_COMMA);
lexp->mLeft = exp;
lexp->mRight = new Expression(pcall->mReturn->mLocation, EX_CONSTANT);
lexp->mRight->mDecValue = pcall->mReturn->mLeft->mDecValue;
lexp->mRight->mDecType = exp->mDecType;
lexp->mDecType = exp->mDecType;
exp->mDecType = TheVoidTypeDeclaration;
exp = lexp;
return true;
}
else if (rexp->mType == EX_PREFIX && rexp->mToken == TK_MUL && rexp->mLeft->mType == EX_VARIABLE && rexp->mLeft->mDecValue->mType == DT_ARGUMENT)
{
Declaration* pdec = rexp->mLeft->mDecValue;
if (pdec->mVarIndex == 0 && !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
Expression* pex = exp->mRight;
if (pex->mType == EX_LIST)
pex = pex->mLeft;
if (pex->mType == EX_CONSTANT)
{
#if DUMP_OPTS
printf("Forward this pointer\n");
#endif
Expression* lexp = new Expression(exp->mLocation, EX_COMMA);
lexp->mLeft = exp;
lexp->mRight = new Expression(pcall->mReturn->mLocation, EX_PREFIX);
lexp->mRight->mToken = TK_MUL;
lexp->mRight->mLeft = pex;
lexp->mRight->mDecType = pcall->mBase->mBase;
exp->mDecType = TheVoidTypeDeclaration;
exp = lexp;
return true;
}
}
}
}
}
}
if (exp->mLeft && CheckConstReturns(exp->mLeft))
changed = true;
if (exp->mRight && CheckConstReturns(exp->mRight))
changed = true;
return changed;
}
bool GlobalOptimizer::CheckUnusedLocals(Expression*& exp)
{
bool changed = false;
if (exp->mType == EX_INITIALIZATION)
{
Expression* vexp = exp->mLeft;
if (vexp->mType == EX_VARIABLE)
{
Declaration* vdec = vexp->mDecValue;
if (vdec->mType == DT_VARIABLE && !(vdec->mFlags & (DTF_GLOBAL | DTF_STATIC)) && !(vdec->mOptFlags & OPTF_VAR_USED))
{
exp = exp->mRight;
return true;
}
}
}
if (exp->mLeft && CheckUnusedLocals(exp->mLeft))
changed = true;
if (exp->mRight && CheckUnusedLocals(exp->mRight))
changed = true;
return changed;
}
void GlobalOptimizer::RemoveValueReturn(Expression* exp)
{
if (exp->mType == EX_RETURN && exp->mLeft)
{
if (exp->mLeft->HasSideEffects())
{
exp->mType = EX_SEQUENCE;
exp->mRight = new Expression(exp->mLocation, EX_RETURN);
}
else
exp->mLeft = nullptr;
}
if (exp->mLeft)
RemoveValueReturn(exp->mLeft);
if (exp->mRight)
RemoveValueReturn(exp->mRight);
}
void GlobalOptimizer::UndoParamReference(Expression* exp, Declaration* param)
{
if (exp)
{
if (exp->mType == EX_VARIABLE && exp->mDecValue == param)
{
exp->mDecType = param->mBase;
}
UndoParamReference(exp->mLeft, param);
UndoParamReference(exp->mRight, param);
}
}
bool GlobalOptimizer::ReplaceParamConst(Expression* exp, Declaration* param)
{
bool changed = false;
if (exp)
{
if (exp->mType == EX_VARIABLE && exp->mDecValue == param)
{
exp->mType = EX_CONSTANT;
exp->mDecType = param->mBase;
exp->mDecValue = param->mValue->mDecValue->ConstCast(param->mBase);
changed = true;
}
if (ReplaceParamConst(exp->mLeft, param))
changed = true;
if (ReplaceParamConst(exp->mRight, param))
changed = true;
}
return changed;
}
bool GlobalOptimizer::Optimize(void)
{
bool changed = false;
#if DUMP_OPTS
printf("OPT---\n");
#endif
for (int i = 0; i < mFunctions.Size(); i++)
{
Declaration* func = mFunctions[i];
Declaration* ftype = func->mBase;
if (func->mValue && func->mValue->mType != EX_DISPATCH)
{
#if DUMP_OPTS
printf("%s %08llx\n", mFunctions[i]->mQualIdent->mString, mFunctions[i]->mOptFlags);
#endif
if (CheckUnusedLocals(func->mValue))
changed = true;
if (CheckConstReturns(func->mValue))
changed = true;
if (!(func->mOptFlags & OPTF_FUNC_VARIABLE) && !(func->mBase->mFlags & DTF_VIRTUAL))
{
if (!(func->mOptFlags & OPTF_VAR_USED) && func->mBase->mBase && (func->mBase->mBase->IsSimpleType() || func->mBase->mBase->IsReference()))
{
#if DUMP_OPTS
printf("Remove return value\n");
#endif
RemoveValueReturn(func->mValue);
func->mBase->mBase = TheVoidTypeDeclaration;
changed = true;
}
else if (!(func->mOptFlags & OPTF_VAR_ADDRESS) && func->mBase->mBase && func->mBase->mBase->IsReference() && func->mBase->mBase->mBase->IsSimpleType())
{
#if DUMP_OPTS
printf("Demote reference return\n");
#endif
func->mBase->mBase = func->mBase->mBase->mBase;
changed = true;
}
Declaration* pdec = ftype->mParams;
int vi = 0;
while (pdec)
{
pdec->mVarIndex += vi;
if (!(pdec->mOptFlags & OPTF_VAR_USED) && !(pdec->mFlags & DTF_FPARAM_UNUSED))
{
if (!pdec->mBase->IsReference() || !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
#if DUMP_OPTS
printf("Unused parameter %s\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
vi -= pdec->mSize;
pdec->mFlags |= DTF_FPARAM_UNUSED;
changed = true;
}
}
else if (!(pdec->mOptFlags & OPTF_VAR_ADDRESS) && pdec->mBase->IsReference() && pdec->mBase->mBase->IsSimpleType())
{
#if DUMP_OPTS
printf("Reference parameter %s to value\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
vi += pdec->mSize - 2;
pdec->mBase = pdec->mBase->mBase;
pdec->mSize = pdec->mBase->mSize;
UndoParamReference(func->mValue, pdec);
changed = true;
}
else if ((pdec->mOptFlags & OPTF_VAR_CONST) && !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
if (ReplaceParamConst(func->mValue, pdec))
{
#if DUMP_OPTS
printf("Const parameter %s\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
changed = true;
}
}
pdec->mOptFlags = 0;
pdec = pdec->mNext;
}
}
PropagateCommas(func->mValue);
}
else if (func->mValue && func->mValue->mType == EX_DISPATCH)
{
if (!(func->mOptFlags & OPTF_FUNC_VARIABLE))
{
Declaration* pdec = ftype->mParams;
while (pdec)
{
if ((pdec->mOptFlags & OPTF_VAR_CONST) && !(pdec->mOptFlags & OPTF_VAR_ADDRESS))
{
if (ReplaceParamConst(func->mValue, pdec))
{
#if DUMP_OPTS
printf("Const parameter %s\n", pdec->mIdent ? pdec->mIdent->mString : "_");
#endif
changed = true;
}
}
pdec->mOptFlags = 0;
pdec = pdec->mNext;
}
}
}
}
return changed;
}
void GlobalOptimizer::AnalyzeProcedure(Expression* exp, Declaration* procDec)
{
if (procDec->mOptFlags & OPTF_ANALYZING)
{
procDec->mOptFlags |= OPTF_RECURSIVE;
}
else if (!(procDec->mOptFlags & OPTF_ANALYZED))
{
procDec->mOptFlags |= OPTF_ANALYZING | OPTF_ANALYZED;
mFunctions.Push(procDec);
if ((procDec->mFlags & DTF_INTRINSIC) && !procDec->mValue)
;
else if (procDec->mFlags & DTF_DEFINED)
{
Analyze(exp, procDec, false);
}
else
mErrors->Error(procDec->mLocation, EERR_UNDEFINED_OBJECT, "Calling undefined function", procDec->mQualIdent);
procDec->mOptFlags &= ~OPTF_ANALYZING;
}
}
void GlobalOptimizer::AnalyzeAssembler(Expression* exp, Declaration* procDec)
{
while (exp)
{
if (exp->mLeft && exp->mLeft->mDecValue)
{
Declaration* adec = exp->mLeft->mDecValue;
if (adec->mType == DT_LABEL_REF)
{
}
else if (adec->mType == DT_VARIABLE_REF)
{
if (adec->mBase->mFlags & DTF_GLOBAL)
AnalyzeGlobalVariable(adec->mBase);
else
adec->mBase->mOptFlags |= OPTF_VAR_USED | OPTF_VAR_ADDRESS;
}
else if (adec->mType == DT_LABEL)
{
}
else if (adec->mType == DT_VARIABLE)
{
if (adec->mFlags & DTF_GLOBAL)
AnalyzeGlobalVariable(adec);
else
adec->mOptFlags |= OPTF_VAR_USED | OPTF_VAR_ADDRESS;
}
else if (adec->mType == DT_ARGUMENT)
{
adec->mOptFlags |= OPTF_VAR_USED;
}
else if (adec->mType == DT_FUNCTION_REF)
{
adec->mBase->mOptFlags |= OPTF_VAR_USED;
AnalyzeProcedure(adec->mBase->mValue, adec->mBase);
RegisterProc(adec->mBase);
}
else if (adec->mType == DT_CONST_FUNCTION)
{
adec->mOptFlags |= OPTF_VAR_USED;
AnalyzeProcedure(adec->mValue, adec);
RegisterCall(procDec, adec);
}
}
exp = exp->mRight;
}
}
void GlobalOptimizer::AnalyzeGlobalVariable(Declaration* dec)
{
while (dec->mType == DT_VARIABLE_REF)
dec = dec->mBase;
if (!(dec->mOptFlags & OPTF_ANALYZED))
{
dec->mOptFlags |= OPTF_ANALYZED;
if (dec->mValue && dec->mValue->mType == EX_CONSTRUCT)
{
if (dec->mValue->mLeft->mLeft->mType == EX_CALL && (dec->mValue->mLeft->mLeft->mLeft->mDecValue->mFlags & DTF_CONSTEXPR))
{
ConstexprInterpreter cinter(dec->mLocation, mErrors, dec->mSection);
dec->mValue = cinter.EvalConstructor(dec->mValue->mLeft->mLeft);
}
}
mGlobalVariables.Push(dec);
if (dec->mValue)
{
Analyze(dec->mValue, dec, false);
}
}
}
void GlobalOptimizer::AnalyzeInit(Declaration* mdec)
{
while (mdec)
{
if (mdec->mValue)
RegisterProc(Analyze(mdec->mValue, mdec, false));
else if (mdec->mParams)
AnalyzeInit(mdec->mParams);
mdec = mdec->mNext;
}
}
void GlobalOptimizer::RegisterCall(Declaration* from, Declaration* to)
{
if (from)
{
if (to->mType == DT_VARIABLE || to->mType == DT_ARGUMENT)
to = to->mBase;
if (to->mType == DT_CONST_FUNCTION)
{
if (!(to->mOptFlags & OPTF_CALLED))
{
to->mOptFlags |= OPTF_CALLED;
mCalledFunctions.Push(to);
}
if (!(from->mOptFlags & OPTF_CALLING))
{
from->mOptFlags |= OPTF_CALLING;
mCallingFunctions.Push(from);
}
}
else if (to->mType == DT_TYPE_FUNCTION)
{
if (!(from->mOptFlags & OPTF_CALLING))
{
from->mOptFlags |= OPTF_CALLING;
mCallingFunctions.Push(from);
}
}
else if (to->mType == DT_TYPE_POINTER && to->mBase->mType == DT_TYPE_FUNCTION)
{
if (!(from->mOptFlags & OPTF_CALLING))
{
from->mOptFlags |= OPTF_CALLING;
mCallingFunctions.Push(from);
}
}
}
}
void GlobalOptimizer::RegisterProc(Declaration* to)
{
if (to->mType == DT_CONST_FUNCTION)
{
if (to->mBase->mFlags & DTF_VIRTUAL)
{
}
else if (!(to->mOptFlags & OPTF_FUNC_VARIABLE))
{
to->mOptFlags |= OPTF_FUNC_VARIABLE;
mVariableFunctions.Push(to);
}
}
}
static const uint32 ANAFL_LHS = (1U << 0);
static const uint32 ANAFL_RHS = (1U << 1);
Declaration* GlobalOptimizer::Analyze(Expression* exp, Declaration* procDec, uint32 flags)
{
Declaration* ldec, * rdec;
switch (exp->mType)
{
case EX_ERROR:
case EX_VOID:
break;
case EX_CONSTANT:
if (exp->mDecValue->mType == DT_CONST_FUNCTION)
{
AnalyzeProcedure(exp->mDecValue->mValue, exp->mDecValue);
}
else if (exp->mDecValue->mType == DT_CONST_STRUCT)
{
AnalyzeInit(exp->mDecValue->mParams);
}
else if (exp->mDecValue->mType == DT_CONST_POINTER)
{
ldec = Analyze(exp->mDecValue->mValue, procDec, ANAFL_LHS | ANAFL_RHS);
RegisterProc(ldec);
}
else if (exp->mDecValue->mType == DT_CONST_ADDRESS)
{
}
else if (exp->mDecValue->mType == DT_CONST_ASSEMBLER)
{
AnalyzeAssembler(exp->mDecValue->mValue, procDec);
}
return exp->mDecValue;
case EX_VARIABLE:
if ((exp->mDecValue->mFlags & DTF_STATIC) || (exp->mDecValue->mFlags & DTF_GLOBAL))
{
Declaration* type = exp->mDecValue->mBase;
while (type->mType == DT_TYPE_ARRAY)
type = type->mBase;
AnalyzeGlobalVariable(exp->mDecValue);
}
else
{
if (flags & ANAFL_RHS)
exp->mDecValue->mOptFlags |= OPTF_VAR_USED;
if (flags & ANAFL_LHS)
exp->mDecValue->mOptFlags |= OPTF_VAR_ADDRESS;
}
return exp->mDecValue;
case EX_INITIALIZATION:
case EX_ASSIGNMENT:
ldec = Analyze(exp->mLeft, procDec, ANAFL_LHS | flags);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
RegisterProc(rdec);
return ldec;
case EX_BINARY:
ldec = Analyze(exp->mLeft, procDec, flags);
rdec = Analyze(exp->mRight, procDec, flags);
return ldec;
case EX_RELATIONAL:
ldec = Analyze(exp->mLeft, procDec, flags);
rdec = Analyze(exp->mRight, procDec, flags);
return TheBoolTypeDeclaration;
case EX_PREINCDEC:
return Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS);
case EX_PREFIX:
if (exp->mToken == TK_BINARY_AND)
ldec = Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS);
else if (exp->mToken == TK_MUL)
{
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
return exp->mDecType;
}
else
return Analyze(exp->mLeft, procDec, flags);
break;
case EX_POSTFIX:
break;
case EX_POSTINCDEC:
return Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS);
case EX_INDEX:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
if (ldec->mType == DT_VARIABLE || ldec->mType == DT_ARGUMENT)
ldec = ldec->mBase;
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
if (ldec->mBase)
return ldec->mBase;
break;
case EX_QUALIFY:
Analyze(exp->mLeft, procDec, flags);
return exp->mDecValue->mBase;
case EX_DISPATCH:
Analyze(exp->mLeft, procDec, flags);
break;
case EX_VCALL:
exp->mType = EX_CALL;
exp->mLeft->mDecValue = exp->mLeft->mDecValue->mVTable;
// intentional fall through
case EX_CALL:
case EX_INLINE:
if (exp->mLeft->mType == EX_CONSTANT)
{
if (flags & ANAFL_RHS)
exp->mLeft->mDecValue->mOptFlags |= OPTF_VAR_USED;
if (flags & ANAFL_LHS)
exp->mLeft->mDecValue->mOptFlags |= OPTF_VAR_ADDRESS;
}
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
if ((ldec->mFlags & DTF_INTRINSIC) && !ldec->mValue)
{
}
else
{
RegisterCall(procDec, ldec);
}
if (exp->mRight)
{
// Check for struct to struct forwarding
Expression* rex = exp->mRight;
if (rex)
{
Expression* prex = exp;
while (rex && rex->mType == EX_LIST)
{
rex->mLeft = rex->mLeft->ConstantFold(mErrors, nullptr);
prex = rex;
rex = rex->mRight;
}
if (rex)
prex->mRight = rex->ConstantFold(mErrors, nullptr);
rex = exp->mRight;
}
Declaration* pdec = ldec->mBase->mParams;
while (rex)
{
Expression* pex = rex->mType == EX_LIST ? rex->mLeft : rex;
if (pdec)
{
if ((pdec->mFlags & DTF_FPARAM_UNUSED) && !pex->HasSideEffects() && pex->mType != EX_CONSTANT)
{
if (pdec->mBase->IsSimpleType())
{
pex->mType = EX_CONSTANT;
pex->mLeft = nullptr;
pex->mRight = nullptr;
switch (pex->mDecType->mType)
{
case DT_TYPE_INTEGER:
case DT_TYPE_ENUM:
case DT_TYPE_BOOL:
pex->mDecValue = TheZeroIntegerConstDeclaration;
break;
case DT_TYPE_FLOAT:
pex->mDecValue = TheZeroFloatConstDeclaration;
break;
case DT_TYPE_POINTER:
pex->mDecValue = TheNullptrConstDeclaration;
break;
}
}
}
if (!(pdec->mFlags & DTF_FPARAM_UNUSED) && !(pdec->mOptFlags & OPTF_VAR_NOCONST))
{
if (pex->mType == EX_CONSTANT && pdec->mBase->IsSimpleType())
{
if (pdec->mOptFlags & OPTF_VAR_CONST)
{
if (!pex->mDecValue->IsSameValue(pdec->mValue->mDecValue))
{
pdec->mOptFlags |= OPTF_VAR_NOCONST;
pdec->mOptFlags &= ~OPTF_VAR_CONST;
}
}
else
{
pdec->mValue = pex;
pdec->mOptFlags |= OPTF_VAR_CONST;
}
}
else
{
pdec->mOptFlags |= OPTF_VAR_NOCONST;
pdec->mOptFlags &= ~OPTF_VAR_CONST;
}
}
if (pdec->mBase->mType == DT_TYPE_STRUCT && pdec->mBase->mCopyConstructor)
{
if (pdec->mBase->mMoveConstructor)
{
AnalyzeProcedure(pdec->mBase->mMoveConstructor->mValue, pdec->mBase->mMoveConstructor);
RegisterCall(procDec, pdec->mBase->mMoveConstructor);
}
AnalyzeProcedure(pdec->mBase->mCopyConstructor->mValue, pdec->mBase->mCopyConstructor);
RegisterCall(procDec, pdec->mBase->mCopyConstructor);
}
}
if (pdec && (pdec->mFlags & DTF_FPARAM_UNUSED))
RegisterProc(Analyze(pex, procDec, 0));
else if (pdec && pdec->mBase->IsReference())
RegisterProc(Analyze(pex, procDec, ANAFL_LHS | ANAFL_RHS));
else
RegisterProc(Analyze(pex, procDec, ANAFL_RHS));
if (pdec)
pdec = pdec->mNext;
if (rex->mType == EX_LIST)
rex = rex->mRight;
else
rex = nullptr;
}
}
break;
case EX_LIST:
case EX_COMMA:
{
RegisterProc(Analyze(exp->mLeft, procDec, 0));
Declaration* dec = Analyze(exp->mRight, procDec, flags);
RegisterProc(dec);
return dec;
}
case EX_RETURN:
if (exp->mLeft)
{
exp->mLeft = exp->mLeft->ConstantFold(mErrors, nullptr);
if (procDec->mOptFlags & OPTF_SINGLE_RETURN)
{
procDec->mOptFlags &= ~OPTF_SINGLE_RETURN;
procDec->mOptFlags |= OPTF_MULTI_RETURN;
}
else if (!(procDec->mOptFlags & OPTF_MULTI_RETURN))
{
procDec->mOptFlags |= OPTF_SINGLE_RETURN;
procDec->mReturn = exp;
}
if (procDec->mBase->mBase->IsReference())
RegisterProc(Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS));
else
RegisterProc(Analyze(exp->mLeft, procDec, ANAFL_RHS));
if (procDec->mBase->mBase && procDec->mBase->mBase->mType == DT_TYPE_STRUCT && procDec->mBase->mBase->mCopyConstructor)
{
if (procDec->mBase->mBase->mMoveConstructor)
{
AnalyzeProcedure(procDec->mBase->mBase->mMoveConstructor->mValue, procDec->mBase->mBase->mMoveConstructor);
RegisterCall(procDec, procDec->mBase->mBase->mMoveConstructor);
}
AnalyzeProcedure(procDec->mBase->mBase->mCopyConstructor->mValue, procDec->mBase->mBase->mCopyConstructor);
RegisterCall(procDec, procDec->mBase->mBase->mCopyConstructor);
}
}
break;
case EX_SEQUENCE:
do
{
if (exp->mType == EX_SEQUENCE)
{
if (exp->mLeft)
ldec = Analyze(exp->mLeft, procDec, 0);
exp = exp->mRight;
}
else
return Analyze(exp, procDec, 0);
} while (exp);
break;
case EX_SCOPE:
Analyze(exp->mLeft, procDec, 0);
break;
case EX_CONSTRUCT:
if (exp->mLeft->mLeft)
Analyze(exp->mLeft->mLeft, procDec, 0);
if (exp->mLeft->mRight)
Analyze(exp->mLeft->mRight, procDec, 0);
if (exp->mRight)
return Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_CLEANUP:
Analyze(exp->mRight, procDec, 0);
return Analyze(exp->mLeft, procDec, flags);
case EX_WHILE:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, 0);
break;
case EX_IF:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight->mLeft, procDec, 0);
if (exp->mRight->mRight)
rdec = Analyze(exp->mRight->mRight, procDec, 0);
break;
case EX_ELSE:
break;
case EX_FOR:
if (exp->mLeft->mRight)
ldec = Analyze(exp->mLeft->mRight, procDec, 0);
if (exp->mLeft->mLeft->mLeft)
ldec = Analyze(exp->mLeft->mLeft->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, 0);
if (exp->mLeft->mLeft->mRight)
ldec = Analyze(exp->mLeft->mLeft->mRight, procDec, 0);
break;
case EX_DO:
ldec = Analyze(exp->mLeft, procDec, 0);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_BREAK:
case EX_CONTINUE:
case EX_ASSUME:
break;
case EX_TYPE:
break;
case EX_TYPECAST:
return Analyze(exp->mLeft, procDec, ANAFL_RHS);
break;
case EX_LOGICAL_AND:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_LOGICAL_OR:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
rdec = Analyze(exp->mRight, procDec, ANAFL_RHS);
break;
case EX_LOGICAL_NOT:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
break;
case EX_ASSEMBLER:
AnalyzeAssembler(exp, procDec);
break;
case EX_UNDEFINED:
break;
case EX_SWITCH:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
exp = exp->mRight;
while (exp)
{
if (exp->mLeft->mRight)
rdec = Analyze(exp->mLeft->mRight, procDec, 0);
exp = exp->mRight;
}
break;
case EX_CASE:
break;
case EX_DEFAULT:
break;
case EX_CONDITIONAL:
ldec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
RegisterProc(Analyze(exp->mRight->mLeft, procDec, flags));
RegisterProc(Analyze(exp->mRight->mRight, procDec, flags));
break;
}
return TheVoidTypeDeclaration;
}

43
oscar64/GlobalOptimizer.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include "Declaration.h"
#include "Linker.h"
#include "CompilerTypes.h"
class GlobalOptimizer
{
public:
GlobalOptimizer(Errors* errors, Linker* linker);
~GlobalOptimizer(void);
void Reset(void);
bool Optimize(void);
void AnalyzeProcedure(Expression* exp, Declaration* dec);
void AnalyzeAssembler(Expression* exp, Declaration* dec);
void AnalyzeGlobalVariable(Declaration* dec);
uint64 mCompilerOptions;
protected:
Errors* mErrors;
Linker* mLinker;
ExpandingArray<Declaration*> mCalledFunctions, mCallingFunctions, mVariableFunctions, mFunctions;
ExpandingArray<Declaration*> mGlobalVariables;
void AnalyzeInit(Declaration* mdec);
Declaration* Analyze(Expression* exp, Declaration* procDec, uint32 flags);
void RegisterCall(Declaration* from, Declaration* to);
void RegisterProc(Declaration* to);
void RemoveValueReturn(Expression* exp);
bool CheckConstReturns(Expression*& exp);
bool CheckUnusedLocals(Expression*& exp);
void UndoParamReference(Expression* exp, Declaration* param);
bool ReplaceParamConst(Expression* exp, Declaration* param);
void PropagateCommas(Expression*& exp);
void PropagateParamCommas(Expression *& fexp, Expression*& exp);
};

View File

@ -4379,7 +4379,12 @@ void InterOperand::Disassemble(FILE* file, InterCodeProcedure* proc)
else if (mMemory == IM_GLOBAL)
{
if (mVarIndex < 0)
vname = "";
{
if (mLinkerObject && mLinkerObject->mIdent)
vname = mLinkerObject->mIdent->mString;
else
vname = "";
}
else if (!proc->mModule->mGlobalVars[mVarIndex])
vname = "null";
else if (!proc->mModule->mGlobalVars[mVarIndex]->mIdent)
@ -4563,7 +4568,12 @@ void InterInstruction::Disassemble(FILE* file, InterCodeProcedure* proc)
else if (mConst.mMemory == IM_GLOBAL)
{
if (mConst.mVarIndex < 0)
vname = "";
{
if (mConst.mLinkerObject && mConst.mLinkerObject->mIdent)
vname = mConst.mLinkerObject->mIdent->mString;
else
vname = "";
}
else if (!proc->mModule->mGlobalVars[mConst.mVarIndex])
vname = "null";
else if (!proc->mModule->mGlobalVars[mConst.mVarIndex]->mIdent)
@ -6415,7 +6425,10 @@ bool InterCodeBasicBlock::BuildGlobalIntegerRangeSets(bool initial, const Growin
else
{
for (int i = 0; i < mLocalValueRange.Size(); i++)
mLocalValueRange[i].Merge(range[i], mLoopHead, initial);
{
if (this != from || IsTempModified(i))
mLocalValueRange[i].Merge(range[i], mLoopHead, initial);
}
for (int i = 0; i < mLocalParamValueRange.Size(); i++)
mLocalParamValueRange[i].Merge(prange[i], mLoopHead, initial);
}
@ -12262,6 +12275,45 @@ static InterInstruction * FindSourceInstruction(InterCodeBasicBlock* block, int
}
}
bool InterCodeBasicBlock::MoveLoopHeadCheckToTail(void)
{
bool modified = false;
if (!mVisited)
{
mVisited = true;
if (mLoopHead && mEntryBlocks.Size() == 2 && mInstructions.Size() == 2)
{
if (mInstructions[0]->mCode == IC_RELATIONAL_OPERATOR && mInstructions[1]->mCode == IC_BRANCH &&
mInstructions[1]->mSrc[0].mTemp == mInstructions[0]->mDst.mTemp)
{
if (mFalseJump != this && mTrueJump->mTrueJump == this && !mTrueJump->mFalseJump)
{
mTrueJump->mInstructions.SetSize(mTrueJump->mInstructions.Size() - 1);
mTrueJump->mInstructions.Push(mInstructions[0]->Clone());
mTrueJump->mInstructions.Push(mInstructions[1]->Clone());
mTrueJump->mTrueJump = mTrueJump;
mTrueJump->mFalseJump = mFalseJump;
mTrueJump->mEntryBlocks.Push(mTrueJump);
mTrueJump->mNumEntries++;
mFalseJump->mEntryBlocks.Push(mTrueJump);
mFalseJump->mNumEntries++;
mNumEntries--;
mEntryBlocks.Remove(mEntryBlocks.IndexOf(mTrueJump));
modified = true;
}
}
}
if (mTrueJump && mTrueJump->MoveLoopHeadCheckToTail())
modified = true;
if (mFalseJump && mFalseJump->MoveLoopHeadCheckToTail())
modified = true;
}
return modified;
}
bool InterCodeBasicBlock::SingleTailLoopOptimization(const NumberSet& aliasedParams, const GrowingVariableArray& staticVars)
{
bool modified = false;
@ -17606,6 +17658,12 @@ void InterCodeProcedure::Close(void)
#endif
#if 1
ResetVisited();
mEntryBlock->MoveLoopHeadCheckToTail();
#endif
#if 1
BuildLoopPrefix();
DisassembleDebug("added dominators");
@ -18110,7 +18168,7 @@ void InterCodeProcedure::Close(void)
#if 1
case IC_CONSTANT:
if (ins->mConst.mType == IT_POINTER && (ins->mConst.mMemory == IM_FPARAM || ins->mConst.mMemory == IM_PARAM || ins->mConst.mMemory == IM_LOCAL))
if (ins->mDst.mType == IT_POINTER && (ins->mConst.mMemory == IM_FPARAM || ins->mConst.mMemory == IM_PARAM || ins->mConst.mMemory == IM_LOCAL))
nother++;
else
nconst++;

View File

@ -543,6 +543,7 @@ public:
void PeepholeOptimization(const GrowingVariableArray& staticVars);
bool PeepholeReplaceOptimization(const GrowingVariableArray& staticVars);
bool MoveLoopHeadCheckToTail(void);
void SingleBlockLoopOptimisation(const NumberSet& aliasedParams, const GrowingVariableArray& staticVars);
void SingleBlockLoopUnrolling(void);
bool SingleBlockLoopPointerSplit(int& spareTemps);

View File

@ -1,4 +1,5 @@
#include "InterCodeGenerator.h"
#include "Constexpr.h"
InterCodeGenerator::InterCodeGenerator(Errors* errors, Linker* linker)
: mErrors(errors), mLinker(linker), mCompilerOptions(COPT_DEFAULT)
@ -1200,7 +1201,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro
if (pdec)
{
if (!(pdec->mFlags & DTF_FPARAM_CONST))
if (!(pdec->mFlags & DTF_FPARAM_UNUSED))
nmapper.mParams[pdec->mVarIndex] = nindex;
vdec->mVarIndex = nindex;
@ -1317,7 +1318,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro
else
wins->mSrc[1].mOperandSize = 2;
if (!pdec || !(pdec->mFlags & DTF_FPARAM_CONST))
if (!pdec || !(pdec->mFlags & DTF_FPARAM_UNUSED))
block->Append(wins);
}
@ -1444,7 +1445,7 @@ void InterCodeGenerator::CopyStruct(InterCodeProcedure* proc, Expression* exp, I
ains->mConst.mMemory = IM_LOCAL;
ains->mConst.mVarIndex = nindex;
if (!(pdec->mFlags & DTF_FPARAM_CONST))
if (!(pdec->mFlags & DTF_FPARAM_UNUSED))
nmapper.mParams[pdec->mVarIndex] = nindex;
vdec->mVarIndex = nindex;
@ -1463,7 +1464,7 @@ void InterCodeGenerator::CopyStruct(InterCodeProcedure* proc, Expression* exp, I
wins->mSrc[1].mType = IT_POINTER;
wins->mSrc[1].mTemp = ains->mDst.mTemp;
wins->mSrc[1].mOperandSize = 2;
if (!(pdec->mFlags & DTF_FPARAM_CONST))
if (!(pdec->mFlags & DTF_FPARAM_UNUSED))
block->Append(wins);
pdec = pdec->mNext;
@ -1479,7 +1480,7 @@ void InterCodeGenerator::CopyStruct(InterCodeProcedure* proc, Expression* exp, I
ains->mConst.mMemory = IM_LOCAL;
ains->mConst.mVarIndex = nindex;
if (!(pdec->mFlags & DTF_FPARAM_CONST))
if (!(pdec->mFlags & DTF_FPARAM_UNUSED))
nmapper.mParams[pdec->mVarIndex] = nindex;
vdec->mVarIndex = nindex;
@ -1498,7 +1499,7 @@ void InterCodeGenerator::CopyStruct(InterCodeProcedure* proc, Expression* exp, I
wins->mSrc[1].mType = IT_POINTER;
wins->mSrc[1].mTemp = ains->mDst.mTemp;
wins->mSrc[1].mOperandSize = 2;
if (!(pdec->mFlags & DTF_FPARAM_CONST))
if (!(pdec->mFlags & DTF_FPARAM_UNUSED))
block->Append(wins);
TranslateExpression(ftype, proc, block, fexp, destack, BranchTarget(), BranchTarget(), &nmapper);
@ -1620,6 +1621,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
case EX_SEQUENCE:
case EX_LIST:
case EX_COMMA:
if (exp->mLeft)
vr = TranslateExpression(procType, proc, block, exp->mLeft, destack, breakBlock, continueBlock, inlineMapper);
exp = exp->mRight;
@ -1948,7 +1950,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
int ref = 1;
if (dec->mType == DT_ARGUMENT)
{
if (dec->mFlags & DTF_FPARAM_CONST)
if (dec->mFlags & DTF_FPARAM_UNUSED)
{
ins->mConst.mMemory = IM_LOCAL;
if (inlineMapper)
@ -3543,7 +3545,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
if (pdec)
{
if (!pdec->mBase->CanAssign(vr.mType))
if (!(pdec->mFlags & DTF_FPARAM_UNUSED) && !pdec->mBase->CanAssign(vr.mType))
{
pdec->mBase->CanAssign(vr.mType);
mErrors->Error(texp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign incompatible types");
@ -3577,7 +3579,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
else
wins->mSrc[1].mOperandSize = 2;
if (!pdec || !(pdec->mFlags & DTF_FPARAM_CONST))
if (!pdec || !(pdec->mFlags & DTF_FPARAM_UNUSED))
{
if (ftype->mFlags & DTF_FASTCALL)
defins.Push(wins);
@ -3702,7 +3704,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
if (vdec->mType == DT_ARGUMENT)
{
vins->mConst.mVarIndex = vdec->mVarIndex;
if (vdec->mFlags & DTF_FPARAM_CONST)
if (vdec->mFlags & DTF_FPARAM_UNUSED)
{
vins->mConst.mMemory = IM_LOCAL;
if (inlineMapper)
@ -5016,10 +5018,15 @@ void InterCodeGenerator::TranslateLogic(Declaration* procType, InterCodeProcedur
default:
{
ExValue vr = TranslateExpression(procType, proc, block, exp, destack, BranchTarget(), BranchTarget(), inlineMapper);
vr = Dereference(proc, exp, block, vr);
if (!vr.mType->IsSimpleType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Not a valid condition value");
if (vr.mType->mType == DT_TYPE_ARRAY)
vr = Dereference(proc, exp, block, vr, 1);
else
{
vr = Dereference(proc, exp, block, vr);
if (!vr.mType->IsSimpleType())
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Not a valid condition value");
}
InterInstruction* ins = new InterInstruction(exp->mLocation, IC_BRANCH);
ins->mSrc[0].mType = InterTypeOf(vr.mType);

View File

@ -2,6 +2,7 @@
#include <string.h>
#include "Assembler.h"
#include "MachineTypes.h"
#include "Constexpr.h"
Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUnits)
: mErrors(errors), mScanner(scanner), mCompilationUnits(compilationUnits)
@ -3455,13 +3456,10 @@ Expression* Parser::AddFunctionCallRefReturned(Expression* exp)
// A simple constant is passed by const ref
if (pex->mDecValue->mType == DT_CONST_INTEGER || pex->mDecValue->mType == DT_CONST_FLOAT || pex->mDecValue->mType == DT_CONST_POINTER || pex->mDecValue->mType == DT_CONST_ADDRESS)
{
int nindex = mLocalIndex++;
if (pdec->mType == DT_TYPE_REFERENCE && !(pdec->mBase->mFlags & DTF_CONST))
mErrors->Error(pex->mLocation, EERR_INCOMPATIBLE_TYPES, "Can't pass constant as non constante reference");
Declaration* vdec = new Declaration(exp->mLocation, DT_VARIABLE);
vdec->mVarIndex = nindex;
vdec->mBase = pdec->mBase->mBase;
vdec->mSize = pdec->mBase->mBase->mSize;
Declaration* vdec = AllocTempVar(pdec->mBase->mBase);
Expression* vexp = new Expression(pex->mLocation, EX_VARIABLE);
vexp->mDecType = pdec->mBase->mBase;
@ -3771,7 +3769,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
cdec->mBase = ctdec;
cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
ctdec->mFlags |= storageFlags & DTF_VIRTUAL;
ctdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR | DTF_VIRTUAL);
cdec->mSection = mCodeSection;
cdec->mBase->mFlags |= typeFlags;
@ -3821,7 +3819,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
cdec->mBase = ctdec;
cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
ctdec->mFlags |= storageFlags & DTF_VIRTUAL;
ctdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR | DTF_VIRTUAL);
cdec->mSection = mCodeSection;
cdec->mBase->mFlags |= typeFlags;
@ -3866,6 +3864,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
cdec->mBase = ctdec;
cdec->mFlags |= cdec->mBase->mFlags & (DTF_CONST | DTF_VOLATILE);
cdec->mFlags |= storageFlags & (DTF_INLINE | DTF_CONSTEXPR);
cdec->mSection = mCodeSection;
cdec->mBase->mFlags |= typeFlags;
@ -3964,7 +3963,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
if (cdec)
{
cdec->mFlags |= storageFlags & DTF_REQUEST_INLINE;
cdec->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR);
// Initializer list
if (mScanner->mToken == TK_COLON)
@ -4042,7 +4041,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
if (bdec->mDestructor)
{
bdec->mDestructor->mFlags |= storageFlags & DTF_REQUEST_INLINE;
bdec->mDestructor->mFlags |= storageFlags & (DTF_REQUEST_INLINE | DTF_CONSTEXPR);
Declaration* bthis = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
bthis->mFlags |= DTF_CONST | DTF_DEFINED;
@ -4411,7 +4410,7 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
{
ParseVariableInit(ndec);
}
else if ((mCompilerOptions & COPT_CPLUSPLUS) && ndec->mType == DT_VARIABLE && !pthis)
else if ((mCompilerOptions & COPT_CPLUSPLUS) && ndec->mType == DT_VARIABLE && !pthis && !(storageFlags & DTF_EXTERN))
{
// Find default constructor
@ -4445,6 +4444,9 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
fexp->mLeft = cexp;
fexp->mRight = texp;
if (bdec->mDefaultConstructor->mFlags & DTF_CONSTEXPR)
ndec->mSection = mDataSection;
Expression* dexp = nullptr;
if (ndec->mBase->mDestructor)
{

View File

@ -205,6 +205,8 @@ int main2(int argc, const char** argv)
compiler->mCompilerOptions |= COPT_OPTIMIZE_AUTO_ZEROPAGE;
else if (arg[2] == 'p')
compiler->mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS;
else if (arg[2] == 'g')
compiler->mCompilerOptions |= COPT_OPTIMIZE_GLOBAL;
}
else if (arg[1] == 'e')
{
@ -276,6 +278,11 @@ int main2(int argc, const char** argv)
compiler->AddDefine(Ident::Unique("OSCAR_NATIVE_ALL"), "1");
}
// REMOVE ME
// compiler->mCompilerOptions |= COPT_OPTIMIZE_GLOBAL;
// REMOVE ME
char basicStart[10];
strcpy_s(basicStart, "0x0801");

View File

@ -165,6 +165,7 @@
<ClCompile Include="Emulator.cpp" />
<ClCompile Include="Errors.cpp" />
<ClCompile Include="GlobalAnalyzer.cpp" />
<ClCompile Include="GlobalOptimizer.cpp" />
<ClCompile Include="Ident.cpp" />
<ClCompile Include="InterCode.cpp" />
<ClCompile Include="InterCodeGenerator.cpp" />
@ -192,6 +193,7 @@
<ClInclude Include="Emulator.h" />
<ClInclude Include="Errors.h" />
<ClInclude Include="GlobalAnalyzer.h" />
<ClInclude Include="GlobalOptimizer.h" />
<ClInclude Include="Ident.h" />
<ClInclude Include="InterCode.h" />
<ClInclude Include="InterCodeGenerator.h" />

View File

@ -81,6 +81,9 @@
<ClCompile Include="Constexpr.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GlobalOptimizer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Array.h">
@ -158,6 +161,9 @@
<ClInclude Include="Constexpr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GlobalOptimizer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="oscar64.rc">