mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +02:00
Allow '[Align(X)]' on fields. Support '[Packed(X)]'
This commit is contained in:
parent
90f34b6bee
commit
58eec21fbf
9 changed files with 134 additions and 38 deletions
|
@ -366,10 +366,18 @@ namespace System
|
|||
[AttributeUsage(.Class | .Struct)]
|
||||
public struct PackedAttribute : Attribute
|
||||
{
|
||||
public this()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public this(int align)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Class | .Struct | .Alloc)]
|
||||
[AttributeUsage(.Class | .Struct | .Alloc | .Field)]
|
||||
public struct AlignAttribute : Attribute
|
||||
{
|
||||
public this(int align)
|
||||
|
|
|
@ -1070,7 +1070,7 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild
|
|||
typeInst->mLookupResults.Clear();
|
||||
typeInst->mIsUnion = false;
|
||||
typeInst->mIsCRepr = false;
|
||||
typeInst->mIsPacked = false;
|
||||
typeInst->mPacking = 0;
|
||||
typeInst->mIsSplattable = false;
|
||||
typeInst->mHasUnderlyingArray = false;
|
||||
|
||||
|
|
|
@ -2966,7 +2966,7 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
|
|||
|
||||
llvm::SmallVector<BfIRMDNode, 8> diFieldTypes;
|
||||
|
||||
bool isPacked = false;
|
||||
int packing = 0;
|
||||
bool isUnion = false;
|
||||
bool isCRepr = false;
|
||||
BfType* underlyingArrayType = NULL;
|
||||
|
@ -2980,7 +2980,7 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
|
|||
else
|
||||
{
|
||||
isCRepr = typeInstance->mIsCRepr;
|
||||
isPacked = typeInstance->mIsPacked;
|
||||
packing = typeInstance->mPacking;
|
||||
isUnion = typeInstance->mIsUnion;
|
||||
typeInstance->GetUnderlyingArray(underlyingArrayType, underlyingArraySize, underlyingArrayIsVector);
|
||||
// if (underlyingArrayType != NULL)
|
||||
|
@ -3493,7 +3493,7 @@ void BfIRBuilder::CreateTypeDefinition_Data(BfModule* populateModule, BfTypeInst
|
|||
|
||||
llvm::SmallVector<BfIRMDNode, 8> diFieldTypes;
|
||||
|
||||
bool isPacked = false;
|
||||
int packing = 0;
|
||||
bool isUnion = false;
|
||||
bool isCRepr = false;
|
||||
|
||||
|
@ -3514,7 +3514,7 @@ void BfIRBuilder::CreateTypeDefinition_Data(BfModule* populateModule, BfTypeInst
|
|||
else
|
||||
{
|
||||
isCRepr = typeInstance->mIsCRepr;
|
||||
isPacked = typeInstance->mIsPacked;
|
||||
packing = typeInstance->mPacking;
|
||||
isUnion = typeInstance->mIsUnion;
|
||||
}
|
||||
|
||||
|
|
|
@ -6706,7 +6706,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
|
|||
{
|
||||
// Add discriminator
|
||||
auto dscrType = checkTypeInstance->GetDiscriminatorType();
|
||||
if (!checkTypeInstance->mIsPacked)
|
||||
if (checkTypeInstance->mPacking > 0)
|
||||
dataEnd = BF_ALIGN(dataEnd, dscrType->mAlign);
|
||||
_CheckSplat(dscrType, dataEnd);
|
||||
}
|
||||
|
@ -11896,7 +11896,7 @@ void BfModule::FinishAttributeState(BfAttributeState* attributeState)
|
|||
Warn(0, "Unused attributes", attributeState->mSrc);
|
||||
}
|
||||
|
||||
void BfModule::ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bool& isCRepr, bool& isOrdered, int& alignOverride, BfType*& underlyingArrayType, int& underlyingArraySize)
|
||||
void BfModule::ProcessTypeInstCustomAttributes(int& packing, bool& isUnion, bool& isCRepr, bool& isOrdered, int& alignOverride, BfType*& underlyingArrayType, int& underlyingArraySize)
|
||||
{
|
||||
if (mCurTypeInstance->mTypeDef->mIsAlwaysInclude)
|
||||
mCurTypeInstance->mAlwaysIncludeFlags = (BfAlwaysIncludeFlags)(mCurTypeInstance->mAlwaysIncludeFlags | BfAlwaysIncludeFlag_Type);
|
||||
|
@ -11907,7 +11907,17 @@ void BfModule::ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bo
|
|||
String typeName = TypeToString(customAttribute.mType);
|
||||
if (typeName == "System.PackedAttribute")
|
||||
{
|
||||
isPacked = true;
|
||||
packing = 1;
|
||||
if (customAttribute.mCtorArgs.size() >= 1)
|
||||
{
|
||||
auto alignConstant = mCurTypeInstance->mConstHolder->GetConstant(customAttribute.mCtorArgs[0]);
|
||||
|
||||
int checkPacking = alignConstant->mInt32;
|
||||
if (((checkPacking & (checkPacking - 1)) == 0) && (packing > 0) && (packing < 256))
|
||||
packing = checkPacking;
|
||||
else
|
||||
Fail("Packing must be a power of 2", customAttribute.GetRefNode());
|
||||
}
|
||||
}
|
||||
else if (typeName == "System.UnionAttribute")
|
||||
{
|
||||
|
@ -11948,7 +11958,12 @@ void BfModule::ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bo
|
|||
if (customAttribute.mCtorArgs.size() >= 1)
|
||||
{
|
||||
auto alignConstant = mCurTypeInstance->mConstHolder->GetConstant(customAttribute.mCtorArgs[0]);
|
||||
alignOverride = alignConstant->mInt32;
|
||||
|
||||
int checkAlign = alignConstant->mInt32;
|
||||
if ((checkAlign & (checkAlign - 1)) == 0)
|
||||
alignOverride = checkAlign;
|
||||
else
|
||||
Fail("Alignment must be a power of 2", customAttribute.GetRefNode());
|
||||
}
|
||||
}
|
||||
else if (typeName == "System.UnderlyingArrayAttribute")
|
||||
|
|
|
@ -1587,7 +1587,7 @@ public:
|
|||
BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL);
|
||||
BfCustomAttributes* GetCustomAttributes(BfTypeDef* typeDef);
|
||||
void FinishAttributeState(BfAttributeState* attributeState);
|
||||
void ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bool& isCRepr, bool& isOrdered, int& alignOverride, BfType*& underlyingArrayType, int& underlyingArraySize);
|
||||
void ProcessTypeInstCustomAttributes(int& packing, bool& isUnion, bool& isCRepr, bool& isOrdered, int& alignOverride, BfType*& underlyingArrayType, int& underlyingArraySize);
|
||||
void ProcessCustomAttributeData();
|
||||
bool TryGetConstString(BfIRConstHolder* constHolder, BfIRValue irValue, StringImpl& str);
|
||||
BfVariant TypedValueToVariant(BfAstNode* refNode, const BfTypedValue& value, bool allowUndef = false);
|
||||
|
|
|
@ -2932,7 +2932,7 @@ void BfModule::DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool unde
|
|||
|
||||
fieldInstance->mDataOffset = unionInnerType->mSize;
|
||||
fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator
|
||||
if (!typeInstance->mIsPacked)
|
||||
if (typeInstance->mPacking == 0)
|
||||
{
|
||||
if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0)
|
||||
{
|
||||
|
@ -3890,25 +3890,25 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
typeInstance->mInstAlign = std::max(0, typeInstance->mInstAlign);
|
||||
|
||||
ProcessCustomAttributeData();
|
||||
bool isPacked = false;
|
||||
int packing = 0;
|
||||
bool isUnion = false;
|
||||
bool isCRepr = false;
|
||||
bool isOrdered = false;
|
||||
int alignOverride = 0;
|
||||
BfType* underlyingArrayType = NULL;
|
||||
int underlyingArraySize = -1;
|
||||
ProcessTypeInstCustomAttributes(isPacked, isUnion, isCRepr, isOrdered, alignOverride, underlyingArrayType, underlyingArraySize);
|
||||
ProcessTypeInstCustomAttributes(packing, isUnion, isCRepr, isOrdered, alignOverride, underlyingArrayType, underlyingArraySize);
|
||||
if (underlyingArraySize > 0)
|
||||
{
|
||||
typeInstance->mHasUnderlyingArray = true;
|
||||
curFieldDataIdx = 0;
|
||||
}
|
||||
if (isPacked) // Packed infers ordered
|
||||
if (packing > 0) // Packed infers ordered
|
||||
isOrdered = true;
|
||||
typeInstance->mIsUnion = isUnion;
|
||||
if ((typeInstance->IsEnum()) && (typeInstance->IsStruct()))
|
||||
typeInstance->mIsUnion = true;
|
||||
typeInstance->mIsPacked = isPacked;
|
||||
typeInstance->mPacking = (uint8)packing;
|
||||
typeInstance->mIsCRepr = isCRepr;
|
||||
|
||||
if (typeInstance->mTypeOptionsIdx >= 0)
|
||||
|
@ -4434,7 +4434,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
dataMemberHashCtx.Mixin(ver->mDataHash);
|
||||
}
|
||||
}
|
||||
dataMemberHashCtx.Mixin(typeInstance->mIsPacked);
|
||||
dataMemberHashCtx.Mixin(typeInstance->mPacking);
|
||||
dataMemberHashCtx.Mixin(typeInstance->mIsCRepr);
|
||||
dataMemberHashCtx.Mixin(typeInstance->mIsUnion);
|
||||
|
||||
|
@ -4588,12 +4588,11 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
{
|
||||
BF_ASSERT(resolvedFieldType->mSize >= 0);
|
||||
|
||||
if ((alignSize > 1) && (!isPacked))
|
||||
if (alignSize > 1)
|
||||
dataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
|
||||
fieldInstance->mDataOffset = dataPos;
|
||||
|
||||
if (!isPacked)
|
||||
typeInstance->mInstAlign = std::max(typeInstance->mInstAlign, alignSize);
|
||||
|
||||
typeInstance->mInstAlign = std::max(typeInstance->mInstAlign, alignSize);
|
||||
dataPos += dataSize;
|
||||
|
||||
if (dataPos > maxDataPos)
|
||||
|
@ -4678,7 +4677,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
Array<Deque<BfFieldInstance*>> alignBuckets;
|
||||
for (auto fieldInst : dataFieldVec)
|
||||
{
|
||||
int alignBits = GetHighestBitSet(fieldInst->mResolvedType->mAlign);
|
||||
int alignBits = GetHighestBitSet(fieldInst->GetAlign(packing));
|
||||
while (alignBits >= alignBuckets.size())
|
||||
alignBuckets.Add({});
|
||||
alignBuckets[alignBits].Add(fieldInst);
|
||||
|
@ -4711,7 +4710,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
auto fieldInst = alignBuckets[alignBits][0];
|
||||
alignBuckets[alignBits].RemoveAt(0);
|
||||
dataFieldVec.push_back(fieldInst);
|
||||
curSize = BF_ALIGN(curSize, fieldInst->mResolvedType->mAlign);
|
||||
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
||||
curSize += fieldInst->mResolvedType->mSize;
|
||||
foundEntry = true;
|
||||
|
||||
|
@ -4732,7 +4731,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
auto fieldInst = alignBuckets[alignBits][0];
|
||||
alignBuckets[alignBits].RemoveAt(0);
|
||||
dataFieldVec.push_back(fieldInst);
|
||||
curSize = BF_ALIGN(curSize, fieldInst->mResolvedType->mAlign);
|
||||
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
||||
curSize += fieldInst->mResolvedType->mSize;
|
||||
break;
|
||||
}
|
||||
|
@ -4752,25 +4751,23 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
|
||||
BF_ASSERT(resolvedFieldType->mSize >= 0);
|
||||
int dataSize = resolvedFieldType->mSize;
|
||||
int alignSize = resolvedFieldType->mAlign;
|
||||
int alignSize = fieldInstance->GetAlign(packing);
|
||||
fieldInstance->mDataSize = dataSize;
|
||||
|
||||
//bool needsExplicitAlignment = !isCRepr || resolvedFieldType->NeedsExplicitAlignment();
|
||||
|
||||
int nextDataPos = dataPos;
|
||||
if (!isPacked)
|
||||
nextDataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
|
||||
int nextDataPos = dataPos;
|
||||
nextDataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
|
||||
int padding = nextDataPos - dataPos;
|
||||
if ((alignSize > 1) && (needsExplicitAlignment) && (padding > 0))
|
||||
{
|
||||
curFieldDataIdx++;
|
||||
curFieldDataIdx++;
|
||||
}
|
||||
dataPos = nextDataPos;
|
||||
fieldInstance->mDataOffset = dataPos;
|
||||
fieldInstance->mDataIdx = curFieldDataIdx++;
|
||||
|
||||
if (!isPacked)
|
||||
typeInstance->mInstAlign = std::max(typeInstance->mInstAlign, alignSize);
|
||||
|
||||
typeInstance->mInstAlign = std::max(typeInstance->mInstAlign, alignSize);
|
||||
dataPos += dataSize;
|
||||
}
|
||||
|
||||
|
@ -4786,8 +4783,6 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
|
||||
if (alignOverride > 0)
|
||||
typeInstance->mInstAlign = alignOverride;
|
||||
else if (isPacked)
|
||||
typeInstance->mInstAlign = 1;
|
||||
else
|
||||
typeInstance->mInstAlign = std::max(1, typeInstance->mInstAlign);
|
||||
int alignSize = typeInstance->mInstAlign;
|
||||
|
@ -10965,7 +10960,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
|
|||
|
||||
refType->mElementType = elementType;
|
||||
resolvedEntry->mValue = refType;
|
||||
BF_ASSERT(BfResolvedTypeSet::Hash(refType, &lookupCtx) == resolvedEntry->mHash);
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (BfResolvedTypeSet::Hash(refType, &lookupCtx) != resolvedEntry->mHash)
|
||||
{
|
||||
int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
|
||||
int typeHash = BfResolvedTypeSet::Hash(refType, &lookupCtx);
|
||||
BF_ASSERT(refHash == typeHash);
|
||||
}
|
||||
BF_ASSERT(BfResolvedTypeSet::Equals(refType, typeRef, &lookupCtx));
|
||||
#endif
|
||||
populateModule->InitType(refType, populateType);
|
||||
return ResolveTypeResult(typeRef, refType, populateType, resolveFlags);
|
||||
}
|
||||
|
|
|
@ -495,6 +495,39 @@ void BfFieldInstance::GetDataRange(int& dataIdx, int& dataCount)
|
|||
dataCount = maxMergedDataIdx - minMergedDataIdx;
|
||||
}
|
||||
|
||||
int BfFieldInstance::GetAlign(int packing)
|
||||
{
|
||||
int align = mResolvedType->mAlign;
|
||||
if (packing > 0)
|
||||
align = BF_MIN(align, packing);
|
||||
if (mCustomAttributes != NULL)
|
||||
{
|
||||
auto module = mOwner->mModule;
|
||||
for (auto& attrib : mCustomAttributes->mAttributes)
|
||||
{
|
||||
if (attrib.mType->IsInstanceOf(module->mCompiler->mAlignAttributeTypeDef))
|
||||
{
|
||||
align = 16; // System conservative default
|
||||
|
||||
if (!attrib.mCtorArgs.IsEmpty())
|
||||
{
|
||||
BfIRConstHolder* constHolder = module->mCurTypeInstance->mConstHolder;
|
||||
auto constant = constHolder->GetConstant(attrib.mCtorArgs[0]);
|
||||
if (constant != NULL)
|
||||
{
|
||||
int alignOverride = (int)BF_MAX(1, constant->mInt64);
|
||||
if ((alignOverride & (alignOverride - 1)) == 0)
|
||||
align = alignOverride;
|
||||
else
|
||||
module->Fail("Alignment must be a power of 2", attrib.GetRefNode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return align;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int64 BfDeferredMethodCallData::GenerateMethodId(BfModule* module, int64 methodId)
|
||||
|
|
|
@ -1413,6 +1413,7 @@ public:
|
|||
BfType* GetResolvedType();
|
||||
void SetResolvedType(BfType* type);
|
||||
void GetDataRange(int& dataIdx, int& dataCount);
|
||||
int GetAlign(int packing);
|
||||
};
|
||||
|
||||
enum BfMethodRefKind
|
||||
|
@ -1903,7 +1904,7 @@ public:
|
|||
bool mIsTypedPrimitive;
|
||||
bool mIsCRepr;
|
||||
bool mIsUnion;
|
||||
bool mIsPacked;
|
||||
uint8 mPacking;
|
||||
bool mIsSplattable;
|
||||
bool mHasUnderlyingArray;
|
||||
bool mTypeIncomplete;
|
||||
|
@ -1934,7 +1935,7 @@ public:
|
|||
mIsReified = true;
|
||||
mIsSplattable = false;
|
||||
mHasUnderlyingArray = false;
|
||||
mIsPacked = false;
|
||||
mPacking = 0;
|
||||
mBaseType = NULL;
|
||||
mCustomAttributes = NULL;
|
||||
mAttributeData = NULL;
|
||||
|
@ -1990,7 +1991,7 @@ public:
|
|||
int GetEndingInstanceAlignment() { if (mInstSize % mInstAlign == 0) return mInstAlign; return mInstSize % mInstAlign; }
|
||||
virtual bool HasTypeFailed() override { return mTypeFailed; }
|
||||
virtual bool IsReified() override { return mIsReified; }
|
||||
virtual bool NeedsExplicitAlignment() override { return !IsSizeAligned() || mIsPacked; }
|
||||
virtual bool NeedsExplicitAlignment() override { return !IsSizeAligned() || (mPacking != 0); }
|
||||
virtual bool IsDataIncomplete() override { return ((mTypeIncomplete) || (mBaseTypeMayBeIncomplete)) && (!mNeedsMethodProcessing); }
|
||||
virtual bool IsFinishingType() override { return mIsFinishingType; }
|
||||
virtual bool IsIncomplete() override { return (mTypeIncomplete) || (mBaseTypeMayBeIncomplete); }
|
||||
|
|
|
@ -191,6 +191,29 @@ namespace Tests
|
|||
Test.Assert(sn.mA == 123);
|
||||
}
|
||||
|
||||
[Align(16)]
|
||||
struct StructP
|
||||
{
|
||||
int32 mA;
|
||||
[Align(8)]
|
||||
int8 mB;
|
||||
}
|
||||
|
||||
[Align(16), Ordered]
|
||||
struct StructQ
|
||||
{
|
||||
int32 mA;
|
||||
[Align(8)]
|
||||
int8 mB;
|
||||
}
|
||||
|
||||
[Packed(2), Ordered]
|
||||
struct StructR
|
||||
{
|
||||
int8 mA;
|
||||
int32 mB;
|
||||
}
|
||||
|
||||
[Test]
|
||||
static void TestLayouts()
|
||||
{
|
||||
|
@ -225,6 +248,18 @@ namespace Tests
|
|||
Test.Assert(sizeof(StructJ) == 5);
|
||||
Test.Assert(alignof(StructJ) == 1);
|
||||
Test.Assert(strideof(StructJ) == 5);
|
||||
|
||||
Test.Assert(sizeof(StructP) == 8);
|
||||
Test.Assert(alignof(StructP) == 16);
|
||||
Test.Assert(strideof(StructP) == 16);
|
||||
|
||||
Test.Assert(sizeof(StructQ) == 9);
|
||||
Test.Assert(alignof(StructQ) == 16);
|
||||
Test.Assert(strideof(StructQ) == 16);
|
||||
|
||||
Test.Assert(sizeof(StructR) == 6);
|
||||
Test.Assert(alignof(StructR) == 2);
|
||||
Test.Assert(strideof(StructR) == 6);
|
||||
}
|
||||
|
||||
public int Test<T>(T val)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue