1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Initial const eval feature release

This commit is contained in:
Brian Fiete 2020-12-23 08:53:38 -08:00
parent be929c3626
commit ff1f8aff3f
27 changed files with 887 additions and 178 deletions

View file

@ -260,6 +260,12 @@ namespace System
}
[AttributeUsage(.Method | .Invocation)]
public struct ConstEvalAttribute : Attribute
{
}
[AttributeUsage(.Method /*2*/)]
public struct IntrinsicAttribute : Attribute
{

View file

@ -34,5 +34,21 @@ namespace System
[LinkName("#IsConstEval")]
public static extern bool IsConstEval;
[LinkName("#IsBuilding")]
public static extern bool IsBuilding;
[LinkName("#IsReified")]
public static extern bool IsReified;
[LinkName("#CompileRev")]
public static extern int32 CompileRev;
[ConstEval]
public static void Assert(bool cond)
{
if (!cond)
Runtime.FatalError("Assert failed");
}
}
}

View file

@ -36,6 +36,30 @@ namespace System.Reflection
}
}
public bool IsConst
{
get
{
return mFieldData.mFlags.HasFlag(.Const);
}
}
public bool IsStatic
{
get
{
return mFieldData.mFlags.HasFlag(.Static);
}
}
public bool IsInstanceField
{
get
{
return !mFieldData.mFlags.HasFlag(.Static) && !mFieldData.mFlags.HasFlag(.Const);
}
}
public StringView Name
{
get
@ -520,6 +544,14 @@ namespace System.Reflection
}
}
public int32 Index
{
get
{
return mIdx;
}
}
public Result<FieldInfo> GetNext() mut
{
if (!MoveNext())

View file

@ -455,13 +455,19 @@ namespace System
return (int32)mTypeId;
}
static extern Type ConstEval_GetTypeById(int32 typeId);
protected static Type GetType(TypeId typeId)
{
if (Compiler.IsConstEval)
return ConstEval_GetTypeById((.)typeId);
return sTypes[(int32)typeId];
}
protected static Type GetType_(int32 typeId)
{
if (Compiler.IsConstEval)
return ConstEval_GetTypeById(typeId);
return sTypes[typeId];
}

View file

@ -148,6 +148,24 @@ public:
~AutoPerfRecordAndPrint();
};
class AutoTimer
{
public:
uint32 mStartTick;
int* mTimePtr;
public:
AutoTimer(int& timeRef)
{
mTimePtr = &timeRef;
mStartTick = BFTickCount();
}
~AutoTimer()
{
*mTimePtr += BFTickCount() - mStartTick;
}
};
class DebugTimeGuard
{

View file

@ -231,6 +231,12 @@ namespace System
}
[AttributeUsage(.Method | .Invocation)]
public struct ConstEvalAttribute : Attribute
{
}
[AttributeUsage(.Method /*2*/)]
public struct IntrinsicAttribute : Attribute
{

View file

@ -11781,6 +11781,9 @@ namespace IDE
bool didClean = false;
if (mWantsBeefClean)
{
mBfBuildCompiler?.CancelBackground();
mBfResolveCompiler?.CancelBackground();
if ((!mBfBuildCompiler.HasQueuedCommands()) &&
((mBfResolveCompiler == null) || (!mBfResolveCompiler.HasQueuedCommands())))
{
@ -11857,6 +11860,9 @@ namespace IDE
if (mWantsClean)
{
mBfBuildCompiler?.CancelBackground();
mBfResolveCompiler?.CancelBackground();
if ((!mBfBuildCompiler.HasQueuedCommands()) && (!mBfResolveCompiler.HasQueuedCommands())
#if IDE_C_SUPPORT
&& (!mDepClang.HasQueuedCommands()) && (!mResolveClang.HasQueuedCommands())

View file

@ -1027,6 +1027,18 @@ namespace IDE.ui
doBackground = true;
}
// If there's a long-running const eval then cancel that first
if (!mDeferredResolveResults.IsEmpty)
{
for (var result in mDeferredResolveResults)
{
if (result.mResolveType == .ClassifyFullRefresh)
{
bfCompiler.RequestCancelBackground();
}
}
}
if (mIsClang)
{
#if !IDE_C_SUPPORT

View file

@ -26,6 +26,9 @@ namespace IDE.ui
public int mDirtyDelay;
public int mStatusBoxUpdateCnt = -1;
public int32 mResolveStuckTicks;
public float mResolveLastPct = -1;
public this()
{
mConfigComboBox = new DarkComboBox();
@ -225,8 +228,19 @@ namespace IDE.ui
#endif
)
{
float completionPct = gApp.mBfResolveCompiler.GetCompletionPercentage();
if (completionPct != mResolveLastPct)
{
mResolveStuckTicks = 0;
mResolveLastPct = completionPct;
}
else
mResolveStuckTicks++;
MarkDirtyEx();
}
else
mResolveStuckTicks = 0;
}
public override void Draw(Graphics g)
@ -380,6 +394,10 @@ namespace IDE.ui
{
DrawStatusBox("Custom Build Commands...", gApp.mBuildContext.mUpdateCnt);
}
else if (mResolveStuckTicks > 300)
{
DrawStatusBox("Const Evaluation");
}
else
mStatusBoxUpdateCnt = -1;

View file

@ -471,7 +471,7 @@ void BfAutoComplete::AddMethod(BfTypeInstance* typeInstance, BfMethodDef* method
{
if (methodDecl != NULL)
{
if ((methodInstance != NULL) && (methodInstance->mMethodDef->mIsLocalMethod) && (GetCursorIdx(methodDecl) == methodDecl->mReturnType->mSrcEnd))
if ((methodInstance != NULL) && (methodInstance->mMethodDef->mIsLocalMethod) && (methodDecl->mReturnType != NULL) && (GetCursorIdx(methodDecl) == methodDecl->mReturnType->mSrcEnd))
{
// This isn't really a local method decl, it just looks like one
return;

View file

@ -397,6 +397,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mActionTypeDef = NULL;
mEnumTypeDef = NULL;
mFriendAttributeTypeDef = NULL;
mConstEvalAttributeTypeDef = NULL;
mNoExtensionAttributeTypeDef = NULL;
mCheckedAttributeTypeDef = NULL;
mUncheckedAttributeTypeDef = NULL;
@ -406,6 +407,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mGenericIEnumeratorTypeDef = NULL;
mGenericIRefEnumeratorTypeDef = NULL;
mInlineAttributeTypeDef = NULL;
mThreadTypeDef = NULL;
mInternalTypeDef = NULL;
mDiagnosticsDebugTypeDef = NULL;
mIDisposableTypeDef = NULL;
@ -6596,6 +6598,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mActionTypeDef = _GetRequiredType("System.Action");
mEnumTypeDef = _GetRequiredType("System.Enum");
mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute");
mConstEvalAttributeTypeDef = _GetRequiredType("System.ConstEvalAttribute");
mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute");
mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute");
mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute");
@ -6606,6 +6609,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1);
mGenericIRefEnumeratorTypeDef = _GetRequiredType("System.Collections.IRefEnumerator", 1);
mInlineAttributeTypeDef = _GetRequiredType("System.InlineAttribute");
mThreadTypeDef = _GetRequiredType("System.Threading.Thread");
mInternalTypeDef = _GetRequiredType("System.Internal");
mDiagnosticsDebugTypeDef = _GetRequiredType("System.Diagnostics.Debug");
mIDisposableTypeDef = _GetRequiredType("System.IDisposable");
@ -7259,6 +7263,11 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
numModulesWritten, (numModulesWritten != 1) ? "s" : "",
numObjFilesWritten, (numObjFilesWritten != 1) ? "s" : ""));
if ((mCEMachine != NULL) && (!mIsResolveOnly) && (mCEMachine->mRevisionExecuteTime > 0))
{
mPassInstance->OutputLine(StrFormat(":med Const evaluation time: %0.2fs", mCEMachine->mRevisionExecuteTime / 1000.0f));
}
BpLeave();
mPassInstance->WriteErrorSummary();

View file

@ -359,6 +359,7 @@ public:
BfTypeDef* mGenericIEnumeratorTypeDef;
BfTypeDef* mGenericIRefEnumeratorTypeDef;
BfTypeDef* mThreadTypeDef;
BfTypeDef* mInternalTypeDef;
BfTypeDef* mDiagnosticsDebugTypeDef;
BfTypeDef* mIDisposableTypeDef;
@ -401,6 +402,7 @@ public:
BfTypeDef* mDisableChecksAttributeTypeDef;
BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef;
BfTypeDef* mFriendAttributeTypeDef;
BfTypeDef* mConstEvalAttributeTypeDef;
BfTypeDef* mNoExtensionAttributeTypeDef;
BfTypeDef* mCheckedAttributeTypeDef;
BfTypeDef* mUncheckedAttributeTypeDef;

View file

@ -36,7 +36,7 @@ BfConstResolver::BfConstResolver(BfModule* bfModule) : BfExprEvaluator(bfModule)
BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfConstResolveFlags flags)
{
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstExpr);
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval);
// Handle the 'int[?] val = .(1, 2, 3)' case
if ((flags & BfConstResolveFlag_ArrayInitSize) != 0)
@ -76,7 +76,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
}
else
{
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_IntPtr)), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
return mResult;
}
}
@ -176,7 +176,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
BfTypedValue result;
result.mKind = BfTypedValueKind_Value;
result.mType = genericTypeConstraint;
result.mValue = mModule->mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode);
result.mValue = mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(primType->mTypeDef->mTypeCode));
return result;
}
}

View file

@ -821,6 +821,8 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef
methodDef->mIsNoReturn = true;
else if (typeRefName == "SkipCall")
methodDef->mIsSkipCall = true;
else if (typeRefName == "ConstEval")
methodDef->mIsConstEval = true;
else if (typeRefName == "NoShow")
methodDef->mIsNoShow = true;
else if (typeRefName == "NoDiscard")

View file

@ -2630,14 +2630,14 @@ BfAutoComplete* BfExprEvaluator::GetAutoComplete()
bool BfExprEvaluator::IsConstEval()
{
return (mModule->mIsConstModule) || ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0);
return (mModule->mIsConstModule) || ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0);
}
bool BfExprEvaluator::IsConstEvalEntry()
{
if (mModule->mIsConstModule)
return false;
return ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0);
return ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0);
}
int BfExprEvaluator::GetStructRetIdx(BfMethodInstance* methodInstance, bool forceStatic)
@ -3263,6 +3263,11 @@ void BfExprEvaluator::Visit(BfLiteralExpression* literalExpr)
void BfExprEvaluator::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
{
if (IsConstEvalEntry())
{
mModule->Fail("Const evaluation of string interpolation not allowed", stringInterpolationExpression);
}
if ((mBfEvalExprFlags & BfEvalExprFlags_StringInterpolateFormat) != 0)
{
BfVariant variant;
@ -4993,6 +4998,20 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
}
}
if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0)
{
if (methodInstance->mReturnType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef))
{
if (mExpectingType->IsSizedArray())
{
return BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(mExpectingType)), mExpectingType);
}
}
if (methodInstance->mReturnType->IsValuelessType())
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), methodInstance->mReturnType);
return BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(methodInstance->mReturnType)), methodInstance->mReturnType);
}
BfTypedValue result;
if (sret != NULL)
result = *sret;
@ -5009,15 +5028,15 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
{
mModule->mCompiler->mCEMachine->QueueMethod(methodInstance, func);
}
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0)
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0)
{
if (mFunctionBindResult != NULL)
{
forceBind = true;
}
else if (mUsedAsStatement)
else if ((mBfEvalExprFlags & BfEvalExprFlags_InCascade) != 0)
{
// Don't allow use in a cascade
mModule->Fail("Const evaluation not allowed with cascade operator", targetSrc);
}
else
{
@ -5648,7 +5667,7 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl<BfIRValue>& ir
{
if (argVal.mType->IsComposite())
{
if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0)
if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0)
{
// Const eval entry - we want any incoming consts as they are
}
@ -6121,7 +6140,24 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
if (methodDef->mMethodType == BfMethodType_Extension)
numElements++;
if (wantType->IsArray())
if (IsConstEvalEntry())
{
if ((wantType->IsArray()) || (wantType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef)))
{
auto genericTypeInst = wantType->ToGenericTypeInstance();
expandedParamsElementType = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0];
auto irSizedArrayType = mModule->mBfIRBuilder->GetSizedArrayType(mModule->mBfIRBuilder->MapType(expandedParamsElementType), numElements);
Array<BfIRValue> values;
for (int i = 0; i < numElements; i++)
values.Add(mModule->mBfIRBuilder->GetFakeVal());
expandedParamsArray = BfTypedValue(mModule->mBfIRBuilder->CreateConstAgg(irSizedArrayType, values), wantType);
PushArg(expandedParamsArray, irArgs);
}
}
else if (wantType->IsArray())
{
BfArrayType* arrayType = (BfArrayType*)wantType;
mModule->PopulateType(arrayType, BfPopulateType_DataAndMethods);
@ -6152,7 +6188,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
PushArg(expandedParamsArray, irArgs);
}
else
else if (wantType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef))
{
auto genericTypeInst = wantType->ToGenericTypeInstance();
expandedParamsElementType = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0];
@ -6538,7 +6574,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
{
if (argValue)
{
if (expandedParamAlloca)
if (IsConstEvalEntry())
{
auto constant = mModule->mBfIRBuilder->GetConstant(expandedParamsArray.mValue);
BF_ASSERT(constant->mConstType == BfConstType_Agg);
auto constAgg = (BfConstantAgg*)constant;
constAgg->mValues[extendedParamIdx] = argValue.mValue;
}
else if (expandedParamAlloca)
{
argValue = mModule->LoadValue(argValue);
auto addr = mModule->mBfIRBuilder->CreateInBoundsGEP(expandedParamAlloca, extendedParamIdx);
@ -7965,7 +8008,9 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
mResultLocalVar = NULL;
mResultFieldInstance = NULL;
mResultLocalVarRefNode = NULL;
MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false);
auto result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false);
if ((result) && (!result.mType->IsVoid()))
return result;
mModule->ValidateAllocation(resolvedTypeInstance, targetSrc);
mModule->AddDependency(resolvedTypeInstance, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_LocalUsage);
@ -8368,7 +8413,26 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str(), mModule->MethodToString(mModule->mCurMethodInstance).c_str()), targetSrc);
}
auto result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, skipThis);
BfTypedValue result;
//
{
SetAndRestoreValue<BfEvalExprFlags> prevEvalExprFlag(mBfEvalExprFlags);
if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mConstEvalAttributeTypeDef)))
{
mModule->mAttributeState->mUsed = true;
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval);
}
else if (moduleMethodInstance.mMethodInstance->mMethodDef->mIsConstEval)
{
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_ConstEval);
}
result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, skipThis);
}
if (result)
{
if (result.mType->IsRef())
@ -9474,7 +9538,7 @@ void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfToken token)
// We do this so we know it's a constant but we can't assume anything about its value
// We make the value an Int32 which doesn't match the IntPtr type, but it allows us to
// assume it can be implicitly cased to int32
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_Int32), sizeType);
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(sizeType)), sizeType);
}
else
mResult = BfTypedValue(mModule->GetConstValue(attrVal, sizeType), sizeType);
@ -12022,6 +12086,8 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
mModule->mCurMethodState->mHotDataReferenceBuilder->mInnerMethods.Add(dtorMethodInstance->mHotMethod);
lambdaInstance->mDtorMethodInstance = dtorMethodInstance;
lambdaInstance->mDtorFunc = dtorFunc;
dtorMethodInstance->mMethodInstanceGroup = NULL;
}
prevClosureState.Restore();
@ -13199,7 +13265,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
{
allocValue = mModule->AllocFromType(resolvedTypeRef, allocTarget, appendSizeValue, BfIRValue(), 0, BfAllocFlags_None, allocAlign);
}
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) && (mModule->mCompiler->mCEMachine != NULL))
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) && (mModule->mCompiler->mCEMachine != NULL))
{
mModule->mCompiler->mCEMachine->SetAppendAllocInfo(mModule, allocValue, appendSizeValue);
}
@ -13250,7 +13316,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
{
mModule->AssertErrorState();
}
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) == 0)
else if ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) == 0)
{
SizedArray<BfIRValue, 1> irArgs;
irArgs.push_back(mResult.mValue);
@ -13328,7 +13394,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
}
}
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0) && (mModule->mCompiler->mCEMachine != NULL))
if (((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0) && (mModule->mCompiler->mCEMachine != NULL))
{
mModule->mCompiler->mCEMachine->ClearAppendAllocInfo();
}
@ -15362,6 +15428,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
int methodCount = 0;
bool mayBeSkipCall = false;
bool mayBeConstEvalCall = false;
if (thisValue.mType != NULL)
{
if (thisValue.mType->IsAllocType())
@ -15379,6 +15446,8 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
{
if (methodDef->mIsSkipCall)
mayBeSkipCall = true;
if (methodDef->mIsConstEval)
mayBeConstEvalCall = true;
methodDef = methodDef->mNextWithSameName;
}
}
@ -15404,7 +15473,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
BfResolveArgFlags resolveArgsFlags = (BfResolveArgFlags)(BfResolveArgFlag_DeferFixits | BfResolveArgFlag_AllowUnresolvedTypes);
resolveArgsFlags = (BfResolveArgFlags)(resolveArgsFlags | BfResolveArgFlag_DeferParamEval);
if (mayBeSkipCall)
if ((mayBeSkipCall) || (mayBeConstEvalCall))
resolveArgsFlags = (BfResolveArgFlags)(resolveArgsFlags | BfResolveArgFlag_DeferParamValues);
static int sCallIdx = 0;
@ -15430,10 +15499,13 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
}
}
if ((isCascade) && (cascadeOperatorToken != NULL) && ((mBfEvalExprFlags & BfEvalExprFlags_ConstExpr) != 0))
if ((isCascade) && (cascadeOperatorToken != NULL) && ((mBfEvalExprFlags & BfEvalExprFlags_ConstEval) != 0))
mModule->Fail("Cascade operator cannot be used in const evaluation", cascadeOperatorToken);
SetAndRestoreValue<bool> prevUsedAsStatement(mUsedAsStatement, mUsedAsStatement || isCascade);
SetAndRestoreValue<BfEvalExprFlags> prevEvalExprFlags(mBfEvalExprFlags);
if (isCascade)
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_InCascade);
ResolveArgValues(argValues, resolveArgsFlags);
mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArguments, checkedKind);
argValues.HandleFixits(mModule);
@ -15840,7 +15912,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
else
{
BF_ASSERT(mModule->mCurMethodInstance->mIsUnspecialized);
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_IntPtr)), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
handled = true;
}
}
@ -17166,8 +17238,8 @@ void BfExprEvaluator::InitializedSizedArray(BfSizedArrayType* arrayType, BfToken
{
if (checkArrayType->mElementCount == -1)
{
mModule->Fail("Initializers not supported for unknown-sized arrays", valueExprs[0]);
failedAt.Add(depth);
// mModule->Fail("Initializers not supported for unknown-sized arrays", valueExprs[0]);
// failedAt.Add(depth);
}
else if (initCountDiff > 0)
{
@ -17453,6 +17525,10 @@ void BfExprEvaluator::InitializedSizedArray(BfSizedArrayType* arrayType, BfToken
members.push_back(defaultVal.mValue);
}
auto allocArrayType = checkArrayType;
if (checkArrayType->IsUndefSizedArray())
allocArrayType = mModule->CreateSizedArrayType(checkArrayType->GetUnderlyingType(), (int)members.size());
if (checkArrayType->mElementType->IsStruct())
{
// This fixed cases where we have non-size-aligned initializers. Assume zero-initialized
@ -17632,16 +17708,60 @@ void BfExprEvaluator::Visit(BfTupleExpression* tupleExpr)
}
else
{
int valueIdx = -1;
bool isExactConst = true;
for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
{
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
if (fieldInstance->mDataIdx < 0)
continue;
++valueIdx;
auto typedValue = typedValues[valueIdx];
if (typedValue.mType != fieldInstance->mResolvedType)
{
isExactConst = false;
break;
}
if (!typedValue.mValue.IsConst())
{
isExactConst = false;
break;
}
}
if (isExactConst)
{
mModule->PopulateType(tupleType);
Array<BfIRValue> irValues;
irValues.Resize(typedValues.mSize + 1);
irValues[0] = mModule->mBfIRBuilder->CreateConstStructZero(mModule->mBfIRBuilder->MapType(tupleType->mBaseType));
for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
{
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
if (fieldInstance->mDataIdx < 0)
continue;
irValues[fieldInstance->mDataIdx] = typedValues[fieldIdx].mValue;
}
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(tupleType), irValues), tupleType);
return;
}
curTupleValue = mModule->CreateAlloca(tupleType);
mResultIsTempComposite = true;
mResult = BfTypedValue(curTupleValue, tupleType, BfTypedValueKind_TempAddr);
}
for (int valueIdx = 0; valueIdx < (int)typedValues.size(); valueIdx++)
int valueIdx = -1;
for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
{
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[valueIdx];
BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
if (fieldInstance->mResolvedType->IsValuelessType())
continue;
++valueIdx;
auto typedVal = typedValues[valueIdx];
if (!typedVal)
{
@ -20511,6 +20631,20 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
if (!handled)
{
if ((leftValue.mType->IsUndefSizedArray()) || (rightValue.mType->IsUndefSizedArray()))
{
if ((leftValue.mType->IsSizedArray()) && (rightValue.mType->IsSizedArray() &&
(leftValue.mType->GetUnderlyingType() == rightValue.mType->GetUnderlyingType())))
{
if (BfBinOpEqualityCheck(binaryOp))
{
auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean);
mResult = mModule->GetDefaultTypedValue(boolType, false, BfDefaultValueKind_Undef);
return;
}
}
}
mModule->Fail(StrFormat("Operator '%s' cannot be applied to operands of type '%s' and '%s'",
BfGetOpName(binaryOp),
mModule->TypeToString(leftValue.mType).c_str(),

View file

@ -175,9 +175,7 @@ USING_NS_BF;
auto constRHS = GetConstantById(rhs.mId); \
if ((constLHS->mConstType == BfConstType_Undef) || (constRHS->mConstType == BfConstType_Undef)) \
{ \
if (((constLHS->mConstType == BfConstType_Undef) || (constLHS->mTypeCode < BfTypeCode_Length)) && \
((constRHS->mConstType == BfConstType_Undef) || (constRHS->mTypeCode < BfTypeCode_Length))) \
return GetUndefConstValue(BfTypeCode_Boolean); \
return GetUndefConstValue(MapType(mModule->GetPrimitiveType(BfTypeCode_Boolean))); \
} \
if ((constLHS->mTypeCode < BfTypeCode_Length) && (constRHS->mTypeCode < BfTypeCode_Length)) \
{ \
@ -654,6 +652,14 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
}
return CreateConstAgg(constAgg->mType, copiedVals);
}
else if (fromConst->mConstType == BfConstType_Undef)
{
auto constUndef = (BfConstantUndef*)fromConst;
BF_ASSERT(constUndef->mType.mKind != BfIRTypeData::TypeKind_Stream);
if (constUndef->mType.mKind == BfIRTypeData::TypeKind_Stream)
return GetUndefConstValue(BfIRValue());
return GetUndefConstValue(constUndef->mType);
}
else if ((IsInt(fromConst->mTypeCode)) || (fromConst->mTypeCode == BfTypeCode_Boolean) || (fromConst->mTypeCode == BfTypeCode_StringId))
{
return CreateConst(fromConst->mTypeCode, fromConst->mUInt64);
@ -778,11 +784,11 @@ BfIRValue BfIRConstHolder::CreateTypeOf(BfType* type)
return irValue;
}
BfIRValue BfIRConstHolder::GetUndefConstValue(BfTypeCode typeCode)
BfIRValue BfIRConstHolder::GetUndefConstValue(BfIRType irType)
{
auto constUndef = mTempAlloc.Alloc<BfConstantUndef>();
constUndef->mConstType = BfConstType_Undef;
constUndef->mTypeCode = typeCode;
constUndef->mType = irType;
BfIRValue undefVal(BfIRValueFlags_Const, mTempAlloc.GetChunkedId(constUndef));
#ifdef CHECK_CONSTHOLDER
@ -3462,11 +3468,10 @@ BfIRFunction BfIRBuilder::GetFakeFunction()
BfIRType BfIRBuilder::GetPrimitiveType(BfTypeCode typeCode)
{
FixTypeCode(typeCode);
BfIRType retType = WriteCmd(BfIRCmd_PrimitiveType, typeCode);
NEW_CMD_INSERTED_IRTYPE;
return retType;
BfIRType retType = WriteCmd(BfIRCmd_PrimitiveType, typeCode);
NEW_CMD_INSERTED_IRTYPE;
return retType;
}
BfIRType BfIRBuilder::CreateStructType(const StringImpl& name)
@ -3495,6 +3500,7 @@ BfIRType BfIRBuilder::MapType(BfType* type, BfIRPopulateType populateType)
{
PopulateType(type, populateType);
}
BF_ASSERT(type->mTypeId > 0);
BfIRType retType;
retType.mKind = BfIRType::TypeKind_TypeId;
retType.mId = type->mTypeId;

View file

@ -815,7 +815,7 @@ struct BfConstantSizedArrayType
struct BfConstantUndef
{
BfConstType mConstType;
BfTypeCode mTypeCode;
BfIRType mType;
};
struct BfConstantBitCast
@ -903,7 +903,7 @@ public:
BfIRValue CreateConstArrayZero(BfIRType type, int count);
BfIRValue CreateConstArrayZero(int count);
BfIRValue CreateTypeOf(BfType* type);
BfIRValue GetUndefConstValue(BfTypeCode typeCode);
BfIRValue GetUndefConstValue(BfIRType type);
};
enum BfIRPopulateType

View file

@ -83,8 +83,8 @@ BfLocalMethod::~BfLocalMethod()
BF_ASSERT(mSource->mRefCount >= 0);
}
delete mMethodDef;
delete mMethodInstanceGroup;
delete mMethodDef;
}
void BfDeferredLocalAssignData::ExtendFrom(BfDeferredLocalAssignData* outerLocalAssignData, bool doChain)
@ -1134,7 +1134,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen)
// code as we walk the AST
//mBfIRBuilder->mDbgVerifyCodeGen = true;
if (
(mModuleName == "-")
(mModuleName == "System_StringView")
//|| (mModuleName == "BeefTest2_ClearColorValue")
//|| (mModuleName == "Tests_FuncRefs")
)
@ -1441,12 +1441,12 @@ BfTypedValue BfModule::GetDefaultTypedValue(BfType* type, bool allowRef, BfDefau
if (defaultValueKind == BfDefaultValueKind_Undef)
{
auto primType = type->ToPrimitiveType();
if (primType != NULL)
{
return BfTypedValue(mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode), type);
}
return BfTypedValue(mBfIRBuilder->CreateUndefValue(mBfIRBuilder->MapType(type)), type);
// auto primType = type->ToPrimitiveType();
// if (primType != NULL)
// {
// return BfTypedValue(mBfIRBuilder->GetUndefConstValue( primType), type);
// }
return BfTypedValue(mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(type)), type);
}
BfTypedValue typedValue;
@ -5390,7 +5390,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
}
}
if ((!typeInstance->IsInterface()) && (typeInstance->mVirtualMethodTableSize > 0) && (needsVData))
if ((!mIsConstModule) && (!typeInstance->IsInterface()) && (typeInstance->mVirtualMethodTableSize > 0) && (needsVData))
{
int startTabIdx = (int)vData.size();
@ -7925,7 +7925,7 @@ BfTypedValue BfModule::CreateValueFromExpression(BfExprEvaluator& exprEvaluator,
BfTypedValue result;
result.mKind = BfTypedValueKind_Value;
result.mType = genericTypeConstraint;
result.mValue = mBfIRBuilder->GetUndefConstValue(primType->mTypeDef->mTypeCode);
result.mValue = mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(primType));
typedVal = result;
handled = true;
}
@ -12064,6 +12064,11 @@ void BfModule::AddMethodReference(const BfMethodRef& methodRef, BfGetMethodInsta
BfModuleMethodInstance BfModule::ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags)
{
if (mIsConstModule)
{
NOP;
}
if ((flags & BfGetMethodInstanceFlag_ResultNotUsed) != 0)
return BfModuleMethodInstance(methodInstance, BfIRValue());
@ -12257,6 +12262,11 @@ BfModule* BfModule::GetOrCreateMethodModule(BfMethodInstance* methodInstance)
BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags, BfTypeInstance* foreignType)
{
if (mIsConstModule)
{
NOP;
}
if (methodDef->mMethodType == BfMethodType_Init)
return BfModuleMethodInstance();
@ -12338,7 +12348,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL) && (mCurMethodInstance->mMethodInfoEx->mMinDependDepth >= 32))
flags = (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_DepthExceeded);
if ((!mIsReified) && (instModule->mIsReified))
if ((!mIsConstModule) && (!mIsReified) && (instModule->mIsReified))
{
BF_ASSERT(!mCompiler->mIsResolveOnly);
// A resolve-only module is specializing a method from a type in a reified module,
@ -12351,7 +12361,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
}
else
{
if ((mIsReified) && (!instModule->mIsReified))
if ((!mIsConstModule) && (mIsReified) && (!instModule->mIsReified))
{
if (!typeInst->IsUnspecializedTypeVariation())
{
@ -13080,6 +13090,10 @@ void BfModule::SetupMethodIdHash(BfMethodInstance* methodInstance)
}
methodInstance->mIdHash = (int64)hashCtx.Finish64();
if (methodInstance->mIdHash == 0x3400000029LL)
{
NOP;
}
}
BfIRValue BfModule::GetInterfaceSlotNum(BfTypeInstance* ifaceType)
@ -13134,6 +13148,18 @@ BfTypedValue BfModule::GetCompilerFieldValue(const StringImpl& str)
{
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, mIsConstModule ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean));
}
if (str == "#IsBuilding")
{
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, (!mCompiler->mIsResolveOnly) ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean));
}
if (str == "#IsReified")
{
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Boolean, mIsReified ? 1 : 0), GetPrimitiveType(BfTypeCode_Boolean));
}
if (str == "#CompileRev")
{
return BfTypedValue(mBfIRBuilder->CreateConst(BfTypeCode_Int32, mCompiler->mRevision), GetPrimitiveType(BfTypeCode_Int32));
}
if (str == "#ModuleName")
{
return BfTypedValue(GetStringObjectValue(mModuleName), ResolveTypeDef(mCompiler->mStringTypeDef));
@ -14504,7 +14530,7 @@ void BfModule::CreateDelegateInvokeMethod()
if (mCurMethodInstance->mReturnType->IsValueType())
mBfIRBuilder->PopulateType(mCurMethodInstance->mReturnType, BfIRPopulateType_Full);
if ((!mIsConstModule) && (mCurMethodInstance->GetStructRetIdx() != 0))
if ((mIsConstModule) || (mCurMethodInstance->GetStructRetIdx() != 0))
memberFuncArgs.push_back(BfIRValue()); // Push 'target'
int thisIdx = 0;
@ -17078,11 +17104,13 @@ void BfModule::ProcessMethod_ProcessDeferredLocals(int startIdx)
BP_ZONE_F("ProcessMethod lambdaInstance %s", lambdaInstance->mMethodInstance->mMethodDef->mName.c_str());
lambdaInstance->mMethodInstance->mMethodInstanceGroup = &methodInstanceGroup;
ProcessMethod(lambdaInstance->mMethodInstance);
lambdaInstance->mMethodInstance->mMethodInstanceGroup = NULL;
if (lambdaInstance->mDtorMethodInstance != NULL)
{
lambdaInstance->mDtorMethodInstance->mMethodInstanceGroup = &methodInstanceGroup;
ProcessMethod(lambdaInstance->mDtorMethodInstance);
lambdaInstance->mDtorMethodInstance->mMethodInstanceGroup = NULL;
}
}
}
@ -17546,22 +17574,25 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
BF_ASSERT(methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_NotSet);
if ((methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_AlwaysInclude) &&
(methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_Referenced))
if (!mIsConstModule)
{
methodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Referenced;
auto owningModule = methodInstance->GetOwner()->mModule;
if (owningModule->mIsScratchModule)
if ((methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_AlwaysInclude) &&
(methodInstance->mMethodInstanceGroup->mOnDemandKind != BfMethodOnDemandKind_Referenced))
{
BF_ASSERT(owningModule->mOnDemandMethodCount == 0);
}
else
{
BF_ASSERT((owningModule->mOnDemandMethodCount > 0) || (!HasCompiledOutput()) || (owningModule->mExtensionCount > 0));
if (owningModule->mOnDemandMethodCount > 0)
owningModule->mOnDemandMethodCount--;
methodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Referenced;
auto owningModule = methodInstance->GetOwner()->mModule;
if (owningModule->mIsScratchModule)
{
BF_ASSERT(owningModule->mOnDemandMethodCount == 0);
}
else
{
BF_ASSERT((owningModule->mOnDemandMethodCount > 0) || (!HasCompiledOutput()) || (owningModule->mExtensionCount > 0));
if (owningModule->mOnDemandMethodCount > 0)
owningModule->mOnDemandMethodCount--;
}
}
}

View file

@ -69,7 +69,8 @@ enum BfEvalExprFlags
BfEvalExprFlags_AllowNonConst = 0x10000,
BfEvalExprFlags_StringInterpolateFormat = 0x20000,
BfEvalExprFlags_NoLookupError = 0x40000,
BfEvalExprFlags_ConstExpr = 0x80000,
BfEvalExprFlags_ConstEval = 0x80000,
BfEvalExprFlags_InCascade = 0x100000,
};
enum BfCastFlags
@ -904,13 +905,15 @@ public:
~BfLambdaInstance()
{
delete mMethodInstance->mMethodDef;
auto methodDef = mMethodInstance->mMethodDef;
delete mMethodInstance;
delete methodDef;
if (mDtorMethodInstance != NULL)
{
delete mDtorMethodInstance->mMethodDef;
auto methodDef = mDtorMethodInstance->mMethodDef;
delete mDtorMethodInstance;
delete methodDef;
}
}
};

View file

@ -10169,7 +10169,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
if (allowCast)
{
if (ignoreWrites)
if ((ignoreWrites) && (!typedVal.mValue.IsConst()))
return mBfIRBuilder->GetFakeVal();
return mBfIRBuilder->CreateBitCast(typedVal.mValue, mBfIRBuilder->MapType(toType));
}
@ -10566,12 +10566,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
auto undefConst = (BfConstantUndef*)constant;
auto fakeVal = GetFakeTypedValue(GetPrimitiveType(undefConst->mTypeCode));
// Why did we have this BfCastFlags_Explicit? It broke creating errors on things like "int16 val = TCount;"
//auto val = CastToValue(srcNode, fakeVal, toType, (BfCastFlags)(castFlags | BfCastFlags_Explicit));
BF_ASSERT(undefConst->mType.mKind == BfIRTypeData::TypeKind_TypeId);
auto bfType = mContext->mTypes[undefConst->mType.mId];
auto fakeVal = GetFakeTypedValue(bfType);
auto val = CastToValue(srcNode, fakeVal, toType, castFlags);
if (val)
return val;
return mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(toType));
}
}
}

View file

@ -5441,7 +5441,7 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
if (!onlyAllowIdentifier)
{
BfExpression* expr = CreateExpressionAfter(attrib);
BfExpression* expr = CreateExpressionAfter(attrib, CreateExprFlags_EarlyExit);
if (expr != NULL)
{
if (auto identifier = BfNodeDynCast<BfIdentifierNode>(expr))

View file

@ -535,6 +535,13 @@ BfMethodInfoEx::~BfMethodInfoEx()
BfMethodInstance::~BfMethodInstance()
{
if (mMethodInstanceGroup != NULL)
BfLogSys(GetOwner()->mModule->mSystem, "BfMethodInstance::~BfMethodInstance %p Local:%d InCEMachine:%d\n", this, mMethodDef->mIsLocalMethod, mInCEMachine);
else
{
BF_ASSERT(!mMethodDef->mIsLocalMethod);
}
if (mInCEMachine)
{
auto module = GetOwner()->mModule;

View file

@ -6441,7 +6441,12 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
auto retVal = exprEvaluator.CreateCall(&methodMatcher, itr);
if (exprEvaluator.mReceivingValue != NULL)
{
AssertErrorState();
if (mIsConstModule)
{
mBfIRBuilder->CreateStore(retVal.mValue, nextResult.mValue);
}
else
AssertErrorState();
}
if ((retVal) && (!retVal.mType->IsVar()))
{

View file

@ -733,6 +733,7 @@ public:
bool mIsNoSplat;
bool mIsNoReflect;
bool mIsSkipCall;
bool mIsConstEval;
bool mIsOperator;
bool mIsExtern;
bool mIsNoDiscard;
@ -761,6 +762,7 @@ public:
mIsNoSplat = false;
mIsNoReflect = false;
mIsSkipCall = false;
mIsConstEval = false;
mIsOperator = false;
mIsExtern = false;
mIsNoDiscard = false;

View file

@ -214,6 +214,13 @@ CeFunction::~CeFunction()
//////////////////////////////////////////////////////////////////////////
CeFunctionInfo::~CeFunctionInfo()
{
delete mCeFunction;
}
//////////////////////////////////////////////////////////////////////////
#define CE_GET(T) *((T*)(mPtr += sizeof(T)) - 1)
void CeDumpContext::DumpOperandInfo(CeOperandInfoKind operandInfoKind)
@ -2151,6 +2158,10 @@ void CeBuilder::Build()
break;
}
else
{
mcAgg = GetOperand(castedInst->mAggVal);
}
auto aggType = mcAgg.mType;
int byteOffset = 0;
@ -2590,8 +2601,10 @@ CeMachine::CeMachine(BfCompiler* compiler)
mCeModule = NULL;
mRevision = 0;
mExecuteId = 0;
mRevisionExecuteTime = 0;
mCurTargetSrc = NULL;
mCurModule = NULL;
mCurMethodInstance = NULL;
mCurExpectingType = NULL;
mHeap = NULL;
mStringCharsOffset = -1;
@ -2613,7 +2626,7 @@ CeMachine::~CeMachine()
BfError* CeMachine::Fail(const StringImpl& error)
{
auto bfError = mCurModule->Fail("Unable to const-evaluate function", mCurTargetSrc);
auto bfError = mCurModule->Fail(StrFormat("Unable to const-evaluate %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc);
if (bfError == NULL)
return NULL;
mCompiler->mPassInstance->MoreInfo(error);
@ -2622,7 +2635,7 @@ BfError* CeMachine::Fail(const StringImpl& error)
BfError* CeMachine::Fail(const CeFrame& curFrame, const StringImpl& str)
{
auto bfError = mCurModule->Fail("Unable to const-evaluate function", mCurTargetSrc);
auto bfError = mCurModule->Fail(StrFormat("Unable to const-evaluate %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc);
if (bfError == NULL)
return NULL;
@ -2696,7 +2709,11 @@ void CeMachine::Init()
mCeModule->mIsSpecialModule = true;
//mCeModule->mIsScratchModule = true;
mCeModule->mIsConstModule = true;
mCeModule->mIsReified = true;
//mCeModule->mIsReified = true;
if (mCompiler->mIsResolveOnly)
mCeModule->mIsReified = true;
else
mCeModule->mIsReified = false;
mCeModule->Init();
mCeModule->mBfIRBuilder = new BfIRBuilder(mCeModule);
@ -2731,6 +2748,28 @@ bool CeMachine::CeFree(addr_ce addr)
#endif
}
addr_ce CeMachine::CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr)
{
mCeModule->PopulateType(arrayType);
BfType* elemType = arrayType->GetUnderlyingType();
auto countOffset = arrayType->mBaseType->mFieldInstances[0].mDataOffset;
auto elemOffset = arrayType->mFieldInstances[0].mDataOffset;
int allocSize = elemOffset + elemType->GetStride() * count;
uint8* mem = CeMalloc(allocSize);
memset(mem, 0, allocSize);
*(int32*)(mem) = arrayType->mTypeId;
*(int32*)(mem + countOffset) = count;
elemsAddr = (addr_ce)(mem + elemOffset - mMemory.mVals);
return (addr_ce)(mem - mMemory.mVals);
}
addr_ce CeMachine::GetConstantData(BeConstant* constant)
{
auto writeConstant = constant;
@ -2889,6 +2928,7 @@ BeModule* CeMachine::GetBeModule()
void CeMachine::CompileStarted()
{
mRevisionExecuteTime = 0;
mRevision++;
if (mCeModule != NULL)
{
@ -2912,37 +2952,48 @@ void CeMachine::DerefMethodInfo(CeFunctionInfo* ceFunctionInfo)
void CeMachine::RemoveMethod(BfMethodInstance* methodInstance)
{
BfLogSys(methodInstance->GetOwner()->mModule->mSystem, "CeMachine::RemoveMethod %p\n", methodInstance);
auto itr = mFunctions.Find(methodInstance);
auto ceFunctionInfo = itr->mValue;
BF_ASSERT(itr != mFunctions.end());
if (itr != mFunctions.end())
{
auto ceFunction = ceFunctionInfo->mCeFunction;
for (auto& callEntry : ceFunction->mCallTable)
if (ceFunctionInfo->mMethodInstance == methodInstance)
{
if (callEntry.mFunctionInfo != NULL)
DerefMethodInfo(callEntry.mFunctionInfo);
}
delete ceFunction;
ceFunctionInfo->mCeFunction = NULL;
ceFunctionInfo->mMethodInstance = NULL;
auto ceFunction = ceFunctionInfo->mCeFunction;
for (auto& callEntry : ceFunction->mCallTable)
{
if (callEntry.mFunctionInfo != NULL)
DerefMethodInfo(callEntry.mFunctionInfo);
}
delete ceFunction;
ceFunctionInfo->mCeFunction = NULL;
ceFunctionInfo->mMethodInstance = NULL;
if (ceFunctionInfo->mRefCount > 1)
{
// Generate a methodref
ceFunctionInfo->mMethodRef = methodInstance;
}
if (methodInstance->mMethodDef->mIsLocalMethod)
{
// We can't rebuild these anyway
}
else if (ceFunctionInfo->mRefCount > 1)
{
// Generate a methodref
ceFunctionInfo->mMethodRef = methodInstance;
}
DerefMethodInfo(ceFunctionInfo);
DerefMethodInfo(ceFunctionInfo);
}
mFunctions.Remove(itr);
}
CheckFunctions();
}
//#define CE_GETC(T) *((T*)(addr += sizeof(T)) - 1)
#define CE_GETC(T) *(T*)(mMemory.mVals + addr)
bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type)
bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type, bool isParams)
{
switch (constant->mTypeCode)
{
@ -2987,6 +3038,54 @@ bool CeMachine::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
{
return false;
}
else if (type->IsArray())
{
auto elemType = type->GetUnderlyingType();
addr_ce elemsAddr = 0;
addr_ce arrayAddr = CeAllocArray((BfArrayType*)type, aggConstant->mValues.size(), elemsAddr);
for (int i = 0; i < (int)aggConstant->mValues.size(); i++)
{
auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]);
if (fieldConstant == NULL)
return false;
WriteConstant(module, elemsAddr + i * elemType->GetStride(), fieldConstant, elemType);
}
if (mCeModule->mSystem->mPtrSize == 4)
CE_GETC(int32) = arrayAddr;
else
CE_GETC(int64) = arrayAddr;
return true;
}
else if ((type->IsInstanceOf(module->mCompiler->mSpanTypeDef)) && (isParams))
{
auto elemType = type->GetUnderlyingType();
addr_ce elemsAddr = CeMalloc(elemType->GetStride() * aggConstant->mValues.size()) - mMemory.mVals;
for (int i = 0; i < (int)aggConstant->mValues.size(); i++)
{
auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[i]);
if (fieldConstant == NULL)
return false;
WriteConstant(module, elemsAddr + i * elemType->GetStride(), fieldConstant, elemType);
}
if (mCeModule->mSystem->mPtrSize == 4)
{
CE_GETC(int32) = elemsAddr;
addr += 4;
CE_GETC(int32) = (int32)aggConstant->mValues.size();
}
else
{
CE_GETC(int32) = elemsAddr;
addr += 8;
CE_GETC(int64) = (int32)aggConstant->mValues.size();
}
}
else
{
BF_ASSERT(type->IsStruct());
@ -3087,7 +3186,40 @@ CeErrorKind CeMachine::WriteConstant(CeConstStructData& data, BeConstant* constV
}
if (globalVar->mInitializer == NULL)
return CeErrorKind_GlobalVariable;
{
auto ptr = data.mData.GrowUninitialized(mCeModule->mSystem->mPtrSize);
int64 addr64 = (addr_ce)0;
memcpy(ptr, &addr64, mCeModule->mSystem->mPtrSize);
return CeErrorKind_None;
//TODO: Add this global variable in there and fixup
// CeStaticFieldInfo* staticFieldInfoPtr = NULL;
// if (mCeMachine->mStaticFieldMap.TryGetValue(globalVar->mName, &staticFieldInfoPtr))
// {
// CeStaticFieldInfo* staticFieldInfo = staticFieldInfoPtr;
//
// int* staticFieldTableIdxPtr = NULL;
// if (mStaticFieldMap.TryAdd(globalVar, NULL, &staticFieldTableIdxPtr))
// {
// CeStaticFieldEntry staticFieldEntry;
// staticFieldEntry.mTypeId = staticFieldInfo->mFieldInstance->mOwner->mTypeId;
// staticFieldEntry.mName = globalVar->mName;
// staticFieldEntry.mSize = globalVar->mType->mSize;
// *staticFieldTableIdxPtr = (int)mCeFunction->mStaticFieldTable.size();
// mCeFunction->mStaticFieldTable.Add(staticFieldEntry);
// }
//
// auto result = FrameAlloc(mCeMachine->GetBeContext()->GetPointerTo(globalVar->mType));
//
// Emit(CeOp_GetStaticField);
// EmitFrameOffset(result);
// Emit((int32)*staticFieldTableIdxPtr);
//
// return result;
// }
// return CeErrorKind_GlobalVariable;
}
BF_ASSERT(!data.mQueueFixups);
@ -3375,7 +3507,7 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
if (typeInst->IsInstanceOf(mCeModule->mCompiler->mSpanTypeDef))
{
if ((outType != NULL) && (mCurExpectingType->IsSizedArray()))
if ((outType != NULL) && ((mCurExpectingType == NULL) || (mCurExpectingType->IsSizedArray())))
{
module->PopulateType(typeInst);
@ -3402,6 +3534,9 @@ BfIRValue CeMachine::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
*outType = module->CreateSizedArrayType(elemType, lenVal);
return instResult;
}
Fail(StrFormat("Span return type '%s' must be received by a sized array", module->TypeToString(typeInst).c_str()));
return BfIRValue();
}
if (typeInst->IsObjectOrInterface())
@ -3599,6 +3734,8 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
uint8* stackPtr = startStackPtr;
uint8* framePtr = startFramePtr;
volatile bool* cancelPtr = &mCompiler->mCanceling;
auto _GetCurFrame = [&]()
{
CeFrame ceFrame;
@ -3659,32 +3796,6 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite)
{
int32 ptrVal = *(int32*)((uint8*)stackPtr + 0);
auto size = *(int32*)(stackPtr + mCeModule->mSystem->mPtrSize);
CE_CHECKADDR(ptrVal, size);
char* strPtr = (char*)(ptrVal + memStart);
String str;
str.Insert(0, strPtr, size);
OutputDebugStr(str);
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int)
{
int32 intVal = *(int32*)((uint8*)stackPtr + 0);
OutputDebugStrF("Debug Val: %d\n", intVal);
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType)
{
int32 typeId = *(int32*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize);
auto reflectType = GetReflectType(typeId);
_FixVariables();
*(addr_ce*)(stackPtr + 0) = reflectType;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_FatalError)
{
int32 strInstAddr = *(int32*)((uint8*)stackPtr + 0);
@ -3725,6 +3836,67 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
return false;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite)
{
int32 ptrVal = *(int32*)((uint8*)stackPtr + 0);
auto size = *(int32*)(stackPtr + mCeModule->mSystem->mPtrSize);
CE_CHECKADDR(ptrVal, size);
char* strPtr = (char*)(ptrVal + memStart);
String str;
str.Insert(0, strPtr, size);
OutputDebugStr(str);
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int)
{
int32 intVal = *(int32*)((uint8*)stackPtr + 0);
OutputDebugStrF("Debug Val: %d\n", intVal);
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType)
{
addr_ce objAddr = *(addr_ce*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize);
CE_CHECKADDR(addr_ce, 4);
int32 typeId = *(int32*)(objAddr + memStart);
auto reflectType = GetReflectType(typeId);
_FixVariables();
*(addr_ce*)(stackPtr + 0) = reflectType;
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectTypeById)
{
int32 typeId = *(int32*)((uint8*)stackPtr + mCeModule->mSystem->mPtrSize);
auto reflectType = GetReflectType(typeId);
_FixVariables();
*(addr_ce*)(stackPtr + 0) = reflectType;
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_Sleep)
{
int32 sleepMS = *(int32*)((uint8*)stackPtr);
while (sleepMS > 0)
{
if (*cancelPtr)
break;
if (sleepMS > 200)
{
Sleep(200);
sleepMS -= 200;
continue;
}
Sleep(sleepMS);
break;
}
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_Char32_ToLower)
{
int32& result = *(int32*)((uint8*)stackPtr + 0);
@ -3849,8 +4021,6 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
return true;
}
volatile bool* cancelPtr = &mCompiler->mCanceling;
int callCount = 0;
int instIdx = 0;
@ -3858,7 +4028,7 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
{
if (*cancelPtr)
{
_Fail("Cancelled");
_Fail("Compilation cancelled");
return false;
}
@ -4989,6 +5159,8 @@ bool CeMachine::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder)
{
AutoTimer autoTimer(mRevisionExecuteTime);
if (mHeap == NULL)
mHeap = new ContiguousHeap();
@ -5007,6 +5179,13 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
ceFunction->mFunctionKind = CeFunctionKind_GetReflectType;
}
}
else if (owner->IsInstanceOf(mCeModule->mCompiler->mTypeTypeDef))
{
if (methodDef->mName == "ConstEval_GetTypeById")
{
ceFunction->mFunctionKind = CeFunctionKind_GetReflectTypeById;
}
}
else if (owner->IsInstanceOf(mCeModule->mCompiler->mDiagnosticsDebugTypeDef))
{
if (methodDef->mName == "Write")
@ -5017,6 +5196,11 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
ceFunction->mFunctionKind = CeFunctionKind_DebugWrite;
}
}
else if (owner->IsInstanceOf(mCeModule->mCompiler->mThreadTypeDef))
{
if (methodDef->mName == "SleepInternal")
ceFunction->mFunctionKind = CeFunctionKind_Sleep;
}
else if (owner->IsInstanceOf(mCeModule->mCompiler->mInternalTypeDef))
{
if (methodDef->mName == "ThrowIndexOutOfRange")
@ -5063,7 +5247,7 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
ceBuilder.mCeFunction = ceFunction;
ceBuilder.Build();
if (!ceFunction->mCode.IsEmpty())
/*if (!ceFunction->mCode.IsEmpty())
{
CeDumpContext dumpCtx;
dumpCtx.mCeFunction = ceFunction;
@ -5073,6 +5257,14 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
dumpCtx.Dump();
OutputDebugStrF("Code for %s:\n%s\n", ceBuilder.mBeFunction->mName.c_str(), dumpCtx.mStr.c_str());
}*/
}
void CeMachine::CheckFunctions()
{
for (auto kv : mFunctions)
{
BF_ASSERT((((intptr)(void*)kv.mKey->mMethodDef) & 0xFF) != 0xDD);
}
}
@ -5084,6 +5276,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
return NULL;
}
CheckFunctions();
CeFunctionInfo** functionInfoPtr = NULL;
CeFunctionInfo* ceFunctionInfo = NULL;
CeFunction* ceFunction = NULL;
@ -5094,6 +5288,11 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
return ceFunctionInfo->mCeFunction;
}
BF_ASSERT(!methodInstance->mInCEMachine);
methodInstance->mInCEMachine = true;
BfLogSys(mCeModule->mSystem, "CeMachine::GetFunction %p\n", methodInstance);
if (!func)
{
ceFunctionInfo = new CeFunctionInfo();
@ -5130,8 +5329,7 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
added = true;
auto module = methodInstance->GetOwner()->mModule;
BF_ASSERT(!methodInstance->mInCEMachine);
methodInstance->mInCEMachine = true;
BF_ASSERT(ceFunctionInfo->mCeFunction == NULL);
ceFunction = new CeFunction();
ceFunction->mCeFunctionInfo = ceFunctionInfo;
@ -5140,6 +5338,8 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
ceFunctionInfo->mMethodInstance = methodInstance;
ceFunctionInfo->mCeFunction = ceFunction;
}
return ceFunction;
}
@ -5189,13 +5389,23 @@ void CeMachine::ClearAppendAllocInfo()
BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType)
{
AutoTimer autoTimer(mRevisionExecuteTime);
// DISABLED
return BfTypedValue();
//return BfTypedValue();
SetAndRestoreValue<BfAstNode*> prevTargetSrc(mCurTargetSrc, targetSrc);
SetAndRestoreValue<BfModule*> prevModule(mCurModule, module);
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, methodInstance);
SetAndRestoreValue<BfType*> prevExpectingType(mCurExpectingType, expectingType);
if (mAppendAllocInfo != NULL)
{
if ((mAppendAllocInfo->mAppendSizeValue) && (!mAppendAllocInfo->mAppendSizeValue.IsConst()))
{
Fail("Non-constant append alloc");
return BfTypedValue();
}
}
int thisArgIdx = -1;
@ -5208,20 +5418,37 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
appendAllocIdx = 1;
}
for (int argIdx = 0; argIdx < (int)args.size(); argIdx++)
int paramCompositeSize = 0;
int paramIdx = methodInstance->GetParamCount();
for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--)
{
BfType* paramType = NULL;
while (true)
{
paramIdx--;
paramType = methodInstance->GetParamType(paramIdx);
if (paramType->IsTypedPrimitive())
paramType = paramType->GetUnderlyingType();
if (!paramType->IsValuelessType())
break;
}
if (paramType->IsComposite())
{
auto paramTypeInst = paramType->ToTypeInstance();
paramCompositeSize += paramTypeInst->mInstSize;
}
auto arg = args[argIdx];
if (!arg.IsConst())
{
if ((argIdx != thisArgIdx) && (argIdx != appendAllocIdx))
{
Fail(StrFormat("Non-constant argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
return BfTypedValue();
}
}
}
SetAndRestoreValue<BfAstNode*> prevTargetSrc(mCurTargetSrc, targetSrc);
SetAndRestoreValue<BfModule*> prevModule(mCurModule, module);
SetAndRestoreValue<BfType*> prevExpectingType(mCurExpectingType, expectingType);
BF_ASSERT(mCallStack.IsEmpty());
auto methodDef = methodInstance->mMethodDef;
@ -5287,26 +5514,7 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
};
addr_ce compositeStartAddr = stackPtr - memStart;
int paramIdx = methodInstance->GetParamCount();
for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--)
{
BfType* paramType = NULL;
while (true)
{
paramIdx--;
paramType = methodInstance->GetParamType(paramIdx);
if (paramType->IsTypedPrimitive())
paramType = paramType->GetUnderlyingType();
if (!paramType->IsValuelessType())
break;
}
if (paramType->IsComposite())
{
auto paramTypeInst = paramType->ToTypeInstance();
stackPtr -= paramTypeInst->mInstSize;
}
}
stackPtr -= paramCompositeSize;
addr_ce useCompositeAddr = compositeStartAddr;
paramIdx = methodInstance->GetParamCount();
for (int argIdx = (int)args.size() - 1; argIdx >= 0; argIdx--)
@ -5322,6 +5530,7 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
break;
}
bool isParams = methodInstance->GetParamKind(paramIdx) == BfParamKind_Params;
auto arg = args[argIdx];
if (!arg.IsConst())
{
@ -5351,8 +5560,11 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
{
auto paramTypeInst = paramType->ToTypeInstance();
useCompositeAddr -= paramTypeInst->mInstSize;
if (!WriteConstant(module, useCompositeAddr, constant, paramType))
if (!WriteConstant(module, useCompositeAddr, constant, paramType, isParams))
{
Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
return BfTypedValue();
}
_FixVariables();
stackPtr -= mCeModule->mSystem->mPtrSize;
@ -5362,8 +5574,11 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
else
{
stackPtr -= paramType->mSize;
if (!WriteConstant(module, stackPtr - memStart, constant, paramType))
if (!WriteConstant(module, stackPtr - memStart, constant, paramType, isParams))
{
Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
return BfTypedValue();
}
_FixVariables();
}
}
@ -5405,6 +5620,10 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
BfIRValue constVal = CreateConstant(module, retPtr, returnType, &usedReturnType);
if (constVal)
returnValue = BfTypedValue(constVal, usedReturnType);
else
{
Fail("Failed to encode return argument");
}
}
else
{

View file

@ -202,6 +202,8 @@ public:
mCeFunction = NULL;
mRefCount = 0;
}
~CeFunctionInfo();
};
class CeCallEntry
@ -247,6 +249,8 @@ enum CeFunctionKind
CeFunctionKind_DebugWrite,
CeFunctionKind_DebugWrite_Int,
CeFunctionKind_GetReflectType,
CeFunctionKind_GetReflectTypeById,
CeFunctionKind_Sleep,
CeFunctionKind_Char32_ToLower,
CeFunctionKind_Char32_ToUpper,
CeFunctionKind_Char32_IsLower,
@ -595,6 +599,7 @@ public:
BfCompiler* mCompiler;
BfModule* mCeModule;
int mRevision;
int mRevisionExecuteTime;
int mExecuteId;
// These are only valid for the current execution
@ -610,6 +615,7 @@ public:
CeAppendAllocInfo* mAppendAllocInfo;
BfAstNode* mCurTargetSrc;
BfMethodInstance* mCurMethodInstance;
BfModule* mCurModule;
BfType* mCurExpectingType;
@ -623,6 +629,7 @@ public:
void Init();
uint8* CeMalloc(int size);
bool CeFree(addr_ce addr);
addr_ce CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr);
addr_ce GetReflectType(int typeId);
addr_ce GetString(int stringId);
addr_ce GetConstantData(BeConstant* constant);
@ -633,13 +640,15 @@ public:
BeModule* GetBeModule();
void DerefMethodInfo(CeFunctionInfo* ceFunctionInfo);
void RemoveMethod(BfMethodInstance* methodInstance);
bool WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type);
bool WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type, bool isParams = false);
CeErrorKind WriteConstant(CeConstStructData& data, BeConstant* constVal);
BfIRValue CreateConstant(BfModule* module, uint8* ptr, BfType* type, BfType** outType = NULL);
void CreateFunction(BfMethodInstance* methodInstance, CeFunction* ceFunction);
bool Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr);
void PrepareFunction(CeFunction* methodInstance, CeBuilder* parentBuilder);
void CheckFunctions();
CeFunction* GetFunction(BfMethodInstance* methodInstance, BfIRValue func, bool& added);
CeFunction* GetPreparedFunction(BfMethodInstance* methodInstance);

View file

@ -0,0 +1,159 @@
using System;
using System.Collections;
using System.Diagnostics;
namespace Tests
{
class ConstEval
{
struct StructA
{
public int32 mA;
public int32 mB;
public static int32 sVal = 1000;
public this(int32 a, int32 b)
{
mA = a + sVal;
mB = b;
}
}
const String cStrA = "Abc";
const String cStrB = GetStringA(cStrA, 12, 23);
[ConstEval]
static String GetStringA(String str, int a, int b)
{
// Const-eval functions can return scope-allocated data
return scope $"{str}:{a}:{b}";
}
static int32 Factorial(int32 n)
{
return n <= 1 ? 1 : (n * Factorial(n - 1));
}
static int32 Fibonacci(int32 n)
{
return n <= 1 ? n : Fibonacci(n - 1) + Fibonacci(n - 2);
}
public static String GetTypeDesc<T>()
{
String str = scope .();
T val = default;
val.GetType().GetFullName(str);
str.Append(" ");
for (var fieldInfo in typeof(T).GetFields())
{
if (!fieldInfo.IsInstanceField)
continue;
if (@fieldInfo.Index > 0)
str.Append(", ");
fieldInfo.FieldType.GetFullName(str);
str.Append(" ");
str.Append(fieldInfo.Name);
}
return str;
}
public static Span<int32> GetSorted(String numList)
{
List<int32> list = scope .();
for (var sv in numList.Split(','))
{
sv.Trim();
if (int32.Parse(sv) case .Ok(let val))
list.Add(val);
}
list.Sort();
return list;
}
public static int32 MethodA()
{
mixin Add10(var a)
{
a += 10
}
int32 a = 1;
void Inc()
{
a++;
}
for (int i < 2)
{
defer { a *= 2; }
Inc();
Add10!(a);
}
return a;
}
// This method can only be const evaluated
[ConstEval]
public static int32 ConstSum(params int32[] vals)
{
int32 sum = 0;
for (let val in vals)
sum += val;
return sum;
}
public static int32 MethodB()
{
// Returns different results depending on whether we are const-evaluating
return Compiler.IsConstEval ? 1 : 0;
}
public static int32 MethodC(StructA sa = .(1, 2), (int32, int32) tup = (20, 30), int32[2] arr = .(300, 400))
{
return sa.mA + sa.mB + tup.0 + tup.1 + arr[0] + arr[1];
}
[Test]
public static void TestBasics()
{
const int fac = Factorial(8);
Test.Assert(fac == 40320);
const int fib = Fibonacci(27);
Test.Assert(fib == 196418);
// Generated string has reference equality to equivalent literal
Test.Assert(cStrB === "Abc:12:23");
const String strC = GetTypeDesc<StructA>();
Test.Assert(strC === "Tests.ConstEval.StructA int32 mA, int32 mB");
// Const Span<T> results can be used to initialize statically-sized arrays
const int32[?] iArr = GetSorted("8, 1, 3, 7");
Compiler.Assert(iArr == .(1, 3, 7, 8));
Test.Assert(iArr == .(1, 3, 7, 8));
let val0 = [ConstEval]MethodA();
Compiler.Assert(val0 == 70);
let val1 = MethodA();
// 'val1' is a read-only variable, but not const, so the following line would fail
//Compiler.Assert(val1 == 24);
Test.Assert(val1 == 70);
// This method is marked as ConstEval so it always evaluates as const
let val2 = ConstSum(3, 20, 100);
Compiler.Assert(val2 == 123);
Test.Assert(MethodB() == 0);
Test.Assert([ConstEval]MethodB() == 1);
Test.Assert(MethodC() == 1753);
}
}
}