1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Predetermine enum discriminator during comptime

This commit is contained in:
Brian Fiete 2021-12-21 12:52:51 -05:00
parent 8807c1ea83
commit 326c33eaa1
4 changed files with 228 additions and 159 deletions

View file

@ -2136,7 +2136,7 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn
}
}
void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> foundAttributes)
void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> foundAttributes, bool underlyingTypeDeferred)
{
BfTypeInstance* iComptimeTypeApply = NULL;
for (auto& customAttribute : customAttributes->mAttributes)
@ -2170,6 +2170,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
args.Add(attrVal);
args.Add(mBfIRBuilder->CreateTypeOf(typeInstance));
DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred);
auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL);
if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted)
@ -2300,18 +2301,18 @@ void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code)
FinishCEParseContext(refNode, mCurTypeInstance, &ceParseContext);
}
void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind)
void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred)
{
HashSet<BfTypeInstance*> foundAttributes;
if (ceEmitContext != NULL)
{
if (typeInstance->mCustomAttributes != NULL)
HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes);
HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes, underlyingTypeDeferred);
for (auto& fieldInstance : typeInstance->mFieldInstances)
{
if (fieldInstance.mCustomAttributes != NULL)
HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes);
HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes, underlyingTypeDeferred);
}
}
@ -2353,7 +2354,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
if (onCompileAttribute == NULL)
continue;
HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes);
HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes, underlyingTypeDeferred);
if (onCompileAttribute->mCtorArgs.size() < 1)
continue;
@ -2381,6 +2382,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
mCompiler->mCEMachine->mCurEmitContext = ceEmitContext;
}
DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred);
auto methodInstance = GetRawMethodInstanceAtIdx(typeInstance, methodDef->mIdx);
auto result = mCompiler->mCEMachine->Call(methodDef->GetRefNode(), this, methodInstance, {}, (CeEvalFlags)(CeEvalFlags_PersistantError | CeEvalFlags_DeferIfNotOnlyError), NULL);
@ -2449,11 +2451,11 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
// }
}
void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers)
void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred)
{
CeEmitContext ceEmitContext;
ceEmitContext.mType = typeInstance;
ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit);
ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit, underlyingTypeDeferred);
hadNewMembers = (typeInstance->mTypeDef->mEmitParent != NULL);
if (ceEmitContext.mFailed)
@ -2607,7 +2609,7 @@ void BfModule::DoPopulateType_SetGenericDependencies(BfTypeInstance* genericType
}
void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias)
{
{
SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeAlias);
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
SetAndRestoreValue<BfMethodState*> prevMethodState(mCurMethodState, NULL);
@ -2683,6 +2685,176 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias)
DoPopulateType_SetGenericDependencies(typeAlias);
}
void BfModule::DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType)
{
if (typeInstance->IsEnum())
{
int64 min = 0;
int64 max = 0;
bool isFirst = true;
if (typeInstance->mTypeInfoEx == NULL)
typeInstance->mTypeInfoEx = new BfTypeInfoEx();
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
{
auto fieldInstance = &fieldInstanceRef;
auto fieldDef = fieldInstance->GetFieldDef();
if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry()))
{
if (fieldInstance->mConstIdx == -1)
continue;
auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred));
if (isFirst)
{
min = constant->mInt64;
max = constant->mInt64;
isFirst = false;
}
else
{
min = BF_MIN(constant->mInt64, min);
max = BF_MAX(constant->mInt64, max);
}
}
}
typeInstance->mTypeInfoEx->mMinValue = min;
typeInstance->mTypeInfoEx->mMaxValue = max;
if (underlyingTypeDeferred)
{
BfTypeCode typeCode;
if ((min >= -0x80) && (max <= 0x7F))
typeCode = BfTypeCode_Int8;
else if ((min >= 0) && (max <= 0xFF))
typeCode = BfTypeCode_UInt8;
else if ((min >= -0x8000) && (max <= 0x7FFF))
typeCode = BfTypeCode_Int16;
else if ((min >= 0) && (max <= 0xFFFF))
typeCode = BfTypeCode_UInt16;
else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF))
typeCode = BfTypeCode_Int32;
else if ((min >= 0) && (max <= 0xFFFFFFFFLL))
typeCode = BfTypeCode_UInt32;
else
typeCode = BfTypeCode_Int64;
if (typeCode != BfTypeCode_Int64)
{
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
{
auto fieldInstance = &fieldInstanceRef;
if (fieldInstance->mConstIdx == -1)
continue;
if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry())
continue;
auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64);
fieldInstance->mConstIdx = newConstant.mId;
}
}
BfType* underlyingType = GetPrimitiveType(typeCode);
auto fieldInstance = &typeInstance->mFieldInstances.back();
fieldInstance->mResolvedType = underlyingType;
fieldInstance->mDataSize = underlyingType->mSize;
typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType;
typeInstance->mSize = underlyingType->mSize;
typeInstance->mAlign = underlyingType->mAlign;
typeInstance->mInstSize = underlyingType->mSize;
typeInstance->mInstAlign = underlyingType->mAlign;
typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred);
}
}
else
{
BF_ASSERT(!underlyingTypeDeferred);
}
if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed()))
{
typeInstance->mAlign = unionInnerType->mAlign;
int lastTagId = -1;
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
{
auto fieldInstance = &fieldInstanceRef;
auto fieldDef = fieldInstance->GetFieldDef();
if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0))
{
BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1);
typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign);
lastTagId = -fieldInstance->mDataIdx - 1;
}
}
auto fieldInstance = &typeInstance->mFieldInstances.back();
//BF_ASSERT(fieldInstance->mResolvedType == NULL);
BfPrimitiveType* discriminatorType;
if (lastTagId > 0x7FFFFFFF) // HOW?
discriminatorType = GetPrimitiveType(BfTypeCode_Int64);
else if (lastTagId > 0x7FFF)
discriminatorType = GetPrimitiveType(BfTypeCode_Int32);
else if (lastTagId > 0x7F)
discriminatorType = GetPrimitiveType(BfTypeCode_Int16);
else
discriminatorType = GetPrimitiveType(BfTypeCode_Int8);
fieldInstance->mResolvedType = discriminatorType;
fieldInstance->mDataOffset = unionInnerType->mSize;
fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator
if (!typeInstance->mIsPacked)
{
if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0)
{
fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign);
fieldInstance->mDataIdx++; // Add room for explicit padding
}
}
typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign);
typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize;
typeInstance->mInstSize = typeInstance->mSize;
typeInstance->mInstAlign = typeInstance->mAlign;
if (dataMemberHashCtx != NULL)
{
dataMemberHashCtx->Mixin(unionInnerType->mTypeId);
dataMemberHashCtx->Mixin(discriminatorType->mTypeId);
}
typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry
}
}
void BfModule::DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred)
{
if (!typeInstance->IsEnum())
return;
if ((!underlyingTypeDeferred) && (!typeInstance->IsPayloadEnum()))
return;
if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL))
return;
BfType* unionInnerType = NULL;
if (typeInstance->mIsUnion)
{
SetAndRestoreValue<BfTypeState::ResolveKind> prevResolveKind(mContext->mCurTypeState->mResolveKind, BfTypeState::ResolveKind_UnionInnerType);
unionInnerType = typeInstance->GetUnionInnerType();
}
DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, NULL, unionInnerType);
}
void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType)
{
if (populateType == BfPopulateType_Identity)
@ -4055,7 +4227,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
typeInstance->mDefineState = BfTypeDefineState_CETypeInit;
bool hadNewMembers = false;
DoCEEmit(typeInstance, hadNewMembers);
DoCEEmit(typeInstance, hadNewMembers, underlyingTypeDeferred);
if (typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit)
typeInstance->mDefineState = BfTypeDefineState_CEPostTypeInit;
@ -4659,7 +4831,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
typeInstance->mDefineState = BfTypeDefineState_Defined;
if (!typeInstance->IsBoxed())
{
ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone);
ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone, underlyingTypeDeferred);
if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted)
return;
}
@ -4830,151 +5002,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
BfLogSysM("Setting underlying type %p %d\n", typeInstance, underlyingTypeDeferred);
}
if (typeInstance->IsEnum())
{
int64 min = 0;
int64 max = 0;
bool isFirst = true;
if (typeInstance->mTypeInfoEx == NULL)
typeInstance->mTypeInfoEx = new BfTypeInfoEx();
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
{
auto fieldInstance = &fieldInstanceRef;
auto fieldDef = fieldInstance->GetFieldDef();
if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry()))
{
if (fieldInstance->mConstIdx == -1)
continue;
auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred));
if (isFirst)
{
min = constant->mInt64;
max = constant->mInt64;
isFirst = false;
}
else
{
min = BF_MIN(constant->mInt64, min);
max = BF_MAX(constant->mInt64, max);
}
}
}
typeInstance->mTypeInfoEx->mMinValue = min;
typeInstance->mTypeInfoEx->mMaxValue = max;
if (underlyingTypeDeferred)
{
BfTypeCode typeCode;
if ((min >= -0x80) && (max <= 0x7F))
typeCode = BfTypeCode_Int8;
else if ((min >= 0) && (max <= 0xFF))
typeCode = BfTypeCode_UInt8;
else if ((min >= -0x8000) && (max <= 0x7FFF))
typeCode = BfTypeCode_Int16;
else if ((min >= 0) && (max <= 0xFFFF))
typeCode = BfTypeCode_UInt16;
else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF))
typeCode = BfTypeCode_Int32;
else if ((min >= 0) && (max <= 0xFFFFFFFFLL))
typeCode = BfTypeCode_UInt32;
else
typeCode = BfTypeCode_Int64;
if (typeCode != BfTypeCode_Int64)
{
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
{
auto fieldInstance = &fieldInstanceRef;
if (fieldInstance->mConstIdx == -1)
continue;
if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry())
continue;
auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64);
fieldInstance->mConstIdx = newConstant.mId;
}
}
underlyingType = GetPrimitiveType(typeCode);
auto fieldInstance = &typeInstance->mFieldInstances.back();
fieldInstance->mResolvedType = underlyingType;
fieldInstance->mDataSize = underlyingType->mSize;
typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType;
typeInstance->mSize = underlyingType->mSize;
typeInstance->mAlign = underlyingType->mAlign;
typeInstance->mInstSize = underlyingType->mSize;
typeInstance->mInstAlign = underlyingType->mAlign;
typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred);
}
}
else
{
BF_ASSERT(!underlyingTypeDeferred);
}
if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed()))
{
typeInstance->mAlign = unionInnerType->mAlign;
int lastTagId = -1;
for (auto& fieldInstanceRef : typeInstance->mFieldInstances)
{
auto fieldInstance = &fieldInstanceRef;
auto fieldDef = fieldInstance->GetFieldDef();
if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0))
{
BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1);
typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign);
lastTagId = -fieldInstance->mDataIdx - 1;
}
}
auto fieldInstance = &typeInstance->mFieldInstances.back();
BF_ASSERT(fieldInstance->mResolvedType == NULL);
BfPrimitiveType* discriminatorType;
if (lastTagId > 0x7FFFFFFF) // HOW?
discriminatorType = GetPrimitiveType(BfTypeCode_Int64);
else if (lastTagId > 0x7FFF)
discriminatorType = GetPrimitiveType(BfTypeCode_Int32);
else if (lastTagId > 0x7F)
discriminatorType = GetPrimitiveType(BfTypeCode_Int16);
else
discriminatorType = GetPrimitiveType(BfTypeCode_Int8);
fieldInstance->mResolvedType = discriminatorType;
fieldInstance->mDataOffset = unionInnerType->mSize;
fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator
if (!isPacked)
{
if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0)
{
fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign);
fieldInstance->mDataIdx++; // Add room for explicit padding
}
}
typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign);
typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize;
typeInstance->mInstSize = typeInstance->mSize;
typeInstance->mInstAlign = typeInstance->mAlign;
dataMemberHashCtx.Mixin(unionInnerType->mTypeId);
dataMemberHashCtx.Mixin(discriminatorType->mTypeId);
typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry
}
DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, &dataMemberHashCtx, unionInnerType);
if (!typeInstance->IsBoxed())
{