oscar64/oscar64/GlobalOptimizer.cpp

1023 lines
26 KiB
C++

#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);
static const uint64 OPTF_VAR_NO_FORWARD = (1UL << 13);
static const uint64 OPTF_SINGLE_CALL = (1ULL << 14);
static const uint64 OPTF_MULTI_CALL = (1ULL << 15);
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->mForwardParam = nullptr;
pdec = pdec->mNext;
}
}
for (int i = 0; i < mGlobalVariables.Size(); i++)
{
mGlobalVariables[i]->mOptFlags = 0;
}
mFunctions.SetSize(0);
mGlobalVariables.SetSize(0);
mCalledFunctions.SetSize(0);
mCallingFunctions.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->ConstCast(exp->mDecType);
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;
lexp->mDecType = lexp->mRight->mDecType;
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->mRight->IsVolatile())
{
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 (ReplaceParamConst(exp->mLeft, param))
changed = true;
if (ReplaceParamConst(exp->mRight, param))
changed = true;
if (changed)
{
if (exp->mLeft)
exp->mLeft = exp->mLeft->ConstantFold(mErrors, nullptr);
if (exp->mRight)
exp->mRight = exp->mRight->ConstantFold(mErrors, nullptr);
}
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;
}
}
return changed;
}
bool GlobalOptimizer::ReplaceGlobalConst(Expression* exp)
{
bool changed = false;
if (exp)
{
if (exp->mType == EX_VARIABLE && (exp->mDecValue->mFlags & (DTF_GLOBAL | DTF_STATIC)) && !(exp->mDecValue->mOptFlags & (OPTF_VAR_MODIFIED | OPTF_VAR_ADDRESS)) && exp->mDecValue->mValue)
{
Expression* cexp = exp->mDecValue->mValue;
if (cexp->mType == EX_CONSTANT &&
(cexp->mDecValue->mType == DT_CONST_ADDRESS || cexp->mDecValue->mType == DT_CONST_INTEGER ||
cexp->mDecValue->mType == DT_CONST_POINTER || cexp->mDecValue->mType == DT_CONST_FLOAT))
{
exp->mType = EX_CONSTANT;
exp->mDecValue = cexp->mDecValue->ConstCast(exp->mDecType);
changed = true;
}
}
if (ReplaceGlobalConst(exp->mLeft))
changed = true;
if (ReplaceGlobalConst(exp->mRight))
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 (ReplaceGlobalConst(func->mValue))
changed = true;
if (func->mOptFlags & OPTF_MULTI_CALL)
{
Declaration* pdata = ftype->mParams;
while (pdata)
{
pdata->mForwardCall = nullptr;
pdata->mForwardParam = nullptr;
pdata = pdata->mNext;
}
}
if (!(func->mOptFlags & OPTF_FUNC_VARIABLE) && !(func->mBase->mFlags & DTF_VIRTUAL))
{
if (!(func->mOptFlags & (OPTF_VAR_USED | OPTF_VAR_ADDRESS)) && 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;
}
if (!(ftype->mFlags & DTF_VARIADIC))
{
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;
pdec->mVarIndex = func->mNumVars++;
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))
{
func->mValue = func->mValue->ConstantFold(mErrors, nullptr);
#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);
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);
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);
static const uint32 ANAFL_ASSIGN = (1U << 2);
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);
}
if (flags & ANAFL_RHS)
exp->mDecValue->mOptFlags |= OPTF_VAR_USED;
if (flags & ANAFL_LHS)
exp->mDecValue->mOptFlags |= OPTF_VAR_ADDRESS;
if (exp->mDecValue->mBase->IsReference() && (flags & ANAFL_ASSIGN))
exp->mDecValue->mOptFlags |= OPTF_VAR_USED;
if (exp->mDecValue->mType == DT_ARGUMENT && (flags & ANAFL_LHS))
{
exp->mDecValue->mOptFlags |= OPTF_VAR_NO_FORWARD;
exp->mDecValue->mForwardParam = nullptr;
exp->mDecValue->mForwardCall = nullptr;
}
return exp->mDecValue;
case EX_INITIALIZATION:
case EX_ASSIGNMENT:
if (exp->mToken == TK_ASSIGN)
{
if (exp->mType == EX_ASSIGNMENT)
ldec = Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_ASSIGN | flags);
else
ldec = Analyze(exp->mLeft, procDec, ANAFL_LHS | flags);
}
else
ldec = Analyze(exp->mLeft, procDec, ANAFL_LHS | ANAFL_RHS | flags);
if (exp->mLeft->mDecType->IsReference())
rdec = Analyze(exp->mRight, procDec, ANAFL_LHS | ANAFL_RHS);
else
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
{
if (procDec->mOptFlags & OPTF_SINGLE_CALL)
procDec->mOptFlags |= OPTF_MULTI_CALL;
else
procDec->mOptFlags |= OPTF_SINGLE_CALL;
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 || !pex->mDecValue->IsNullConst()))
{
if (pdec->mBase->IsSimpleType())
{
pex = new Expression(pex->mLocation, EX_CONSTANT);
switch (pdec->mBase->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:
case DT_TYPE_FUNCTION:
pex->mDecValue = TheNullptrConstDeclaration;
break;
}
pex->mDecType = pdec->mBase;
}
}
if (!(pdec->mFlags & DTF_FPARAM_UNUSED) && !(pdec->mOptFlags & OPTF_VAR_NOCONST))
{
if (pex->mType == EX_CONSTANT && pdec->mBase->IsSimpleType() && pdec->mBase->CanAssign(pex->mDecType))
{
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())
{
if (!(procDec->mBase->mFlags & DTF_VIRTUAL) && pdec && pex && pex->mType == EX_VARIABLE && pex->mDecValue->mType == DT_ARGUMENT && pex->mDecValue->mBase->IsReference() && !pex->mDecValue->mForwardParam && !(pex->mDecValue->mOptFlags & OPTF_VAR_NO_FORWARD))
{
pex->mDecValue->mOptFlags |= OPTF_VAR_USED | OPTF_VAR_ADDRESS;
pex->mDecValue->mForwardParam = pdec;
pex->mDecValue->mForwardCall = ldec;
}
else
RegisterProc(Analyze(pex, procDec, ANAFL_LHS | ANAFL_RHS));
}
else if (!(procDec->mBase->mFlags & DTF_VIRTUAL) && pdec && pex && pex->mType == EX_VARIABLE && pex->mDecValue->mType == DT_ARGUMENT && !pex->mDecValue->mForwardParam && !(pex->mDecValue->mOptFlags & OPTF_VAR_NO_FORWARD))
{
pex->mDecValue->mOptFlags |= OPTF_VAR_USED;
pex->mDecValue->mForwardParam = pdec;
pex->mDecValue->mForwardCall = ldec;
}
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->mRight, procDec, 0);
rdec = Analyze(exp->mLeft, procDec, ANAFL_RHS);
break;
case EX_BREAK:
case EX_CONTINUE:
break;
case EX_ASSUME:
return Analyze(exp->mLeft, procDec, ANAFL_RHS);
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;
}